15c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/*
25c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Copyright (C) 2012 Apple Inc.  All rights reserved.
35c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
45c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Redistribution and use in source and binary forms, with or without
55c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * modification, are permitted provided that the following conditions
65c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * are met:
75c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * 1. Redistributions of source code must retain the above copyright
85c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *    notice, this list of conditions and the following disclaimer.
95c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * 2. Redistributions in binary form must reproduce the above copyright
105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *    notice, this list of conditions and the following disclaimer in the
115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *    documentation and/or other materials provided with the distribution.
125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "config.h"
2753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/rendering/RenderMultiColumnSet.h"
285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/rendering/PaintInfo.h"
3053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/rendering/RenderLayer.h"
3153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/rendering/RenderMultiColumnFlowThread.h"
325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
33926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)using namespace std;
345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)namespace WebCore {
365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
37926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)RenderMultiColumnSet::RenderMultiColumnSet(RenderFlowThread* flowThread)
38323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles)    : RenderRegion(0, flowThread)
39d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    , m_columnHeight(0)
4009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    , m_maxColumnHeight(RenderFlowThread::maxLogicalHeight())
4109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    , m_minSpaceShortage(RenderFlowThread::maxLogicalHeight())
42926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    , m_minimumColumnHeight(0)
43926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles){
44926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)}
45926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
46f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo LiuRenderMultiColumnSet* RenderMultiColumnSet::createAnonymous(RenderFlowThread* flowThread, RenderStyle* parentStyle)
475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
488abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)    Document& document = flowThread->document();
49f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)    RenderMultiColumnSet* renderer = new RenderMultiColumnSet(flowThread);
508abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)    renderer->setDocumentForAnonymous(&document);
51f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu    renderer->setStyle(RenderStyle::createAnonymousStyleWithDisplay(parentStyle, BLOCK));
52926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    return renderer;
535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
55f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo LiuRenderMultiColumnSet* RenderMultiColumnSet::nextSiblingMultiColumnSet() const
56f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu{
57f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu    for (RenderObject* sibling = nextSibling(); sibling; sibling = sibling->nextSibling()) {
58f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu        if (sibling->isRenderMultiColumnSet())
59f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu            return toRenderMultiColumnSet(sibling);
60f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu    }
61f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu    return 0;
62f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu}
63f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu
64d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)RenderMultiColumnSet* RenderMultiColumnSet::previousSiblingMultiColumnSet() const
65d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles){
66d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    for (RenderObject* sibling = previousSibling(); sibling; sibling = sibling->previousSibling()) {
67d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)        if (sibling->isRenderMultiColumnSet())
68d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)            return toRenderMultiColumnSet(sibling);
69d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    }
70d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    return 0;
71d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)}
72d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)
73f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo LiuLayoutSize RenderMultiColumnSet::flowThreadTranslationAtOffset(LayoutUnit blockOffset) const
74f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu{
75f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu    unsigned columnIndex = columnIndexAtOffset(blockOffset);
76f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu    LayoutRect portionRect(flowThreadPortionRectAt(columnIndex));
77f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu    flipForWritingMode(portionRect);
78f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu    LayoutRect columnRect(columnRectAt(columnIndex));
79f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu    flipForWritingMode(columnRect);
80f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu    return contentBoxRect().location() + columnRect.location() - portionRect.location();
81f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu}
82f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu
83591b958dee2cf159d33a0b931e6231072eaf38d5Ben MurdochLayoutUnit RenderMultiColumnSet::heightAdjustedForSetOffset(LayoutUnit height) const
84591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch{
85d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    // Adjust for the top offset within the content box of the multicol container (containing
86d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    // block), unless this is the first set. We know that the top offset for the first set will be
87d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    // zero, but if the multicol container has non-zero top border or padding, the set's top offset
88d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    // (initially being 0 and relative to the border box) will be negative until it has been laid
89d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    // out. Had we used this bogus offset, we would calculate the wrong height, and risk performing
90d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    // a wasted layout iteration. Of course all other sets (if any) have this problem in the first
91d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    // layout pass too, but there's really nothing we can do there until the flow thread has been
92d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    // laid out anyway.
93d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    if (previousSiblingMultiColumnSet()) {
94d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)        RenderBlockFlow* multicolBlock = multiColumnBlockFlow();
95d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)        LayoutUnit contentLogicalTop = logicalTop() - multicolBlock->borderAndPaddingBefore();
96d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)        height -= contentLogicalTop;
97d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    }
98591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch    return max(height, LayoutUnit(1)); // Let's avoid zero height, as that would probably cause an infinite amount of columns to be created.
99591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch}
100591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch
1015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)LayoutUnit RenderMultiColumnSet::pageLogicalTopForOffset(LayoutUnit offset) const
1025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
103591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch    unsigned columnIndex = columnIndexAtOffset(offset, AssumeNewColumns);
104d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    return logicalTopInFlowThread() + columnIndex * pageLogicalHeight();
1055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
107591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdochvoid RenderMultiColumnSet::setAndConstrainColumnHeight(LayoutUnit newHeight)
108591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch{
109d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    m_columnHeight = newHeight;
110d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    if (m_columnHeight > m_maxColumnHeight)
111d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)        m_columnHeight = m_maxColumnHeight;
112591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch    // FIXME: the height may also be affected by the enclosing pagination context, if any.
113591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch}
114591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch
11509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)unsigned RenderMultiColumnSet::findRunWithTallestColumns() const
116591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch{
11709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    unsigned indexWithLargestHeight = 0;
11809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    LayoutUnit largestHeight;
119d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    LayoutUnit previousOffset = logicalTopInFlowThread();
12009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    size_t runCount = m_contentRuns.size();
12109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    ASSERT(runCount);
12209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    for (size_t i = 0; i < runCount; i++) {
12309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        const ContentRun& run = m_contentRuns[i];
12409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        LayoutUnit height = run.columnLogicalHeight(previousOffset);
12509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        if (largestHeight < height) {
12609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            largestHeight = height;
12709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            indexWithLargestHeight = i;
12809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        }
12909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        previousOffset = run.breakOffset();
13009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    }
13109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    return indexWithLargestHeight;
13209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)}
13309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
13409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)void RenderMultiColumnSet::distributeImplicitBreaks()
13509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles){
13609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)#ifndef NDEBUG
13709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    // There should be no implicit breaks assumed at this point.
138d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    for (unsigned i = 0; i < m_contentRuns.size(); i++)
13909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        ASSERT(!m_contentRuns[i].assumedImplicitBreaks());
14009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)#endif // NDEBUG
14109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
142323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles)    // Insert a final content run to encompass all content. This will include overflow if this is
143323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles)    // the last set.
144d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    addContentRun(logicalBottomInFlowThread());
145d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    unsigned columnCount = m_contentRuns.size();
14609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
14709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    // If there is room for more breaks (to reach the used value of column-count), imagine that we
14809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    // insert implicit breaks at suitable locations. At any given time, the content run with the
14909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    // currently tallest columns will get another implicit break "inserted", which will increase its
15009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    // column count by one and shrink its columns' height. Repeat until we have the desired total
15109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    // number of breaks. The largest column height among the runs will then be the initial column
15209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    // height for the balancer to use.
153d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    while (columnCount < usedColumnCount()) {
15409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        unsigned index = findRunWithTallestColumns();
15509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        m_contentRuns[index].assumeAnotherImplicitBreak();
156d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)        columnCount++;
15709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    }
15809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)}
159591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch
160d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)LayoutUnit RenderMultiColumnSet::calculateColumnHeight(BalancedHeightCalculation calculationMode) const
16109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles){
162d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    if (calculationMode == GuessFromFlowThreadPortion) {
163d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)        // Initial balancing. Start with the lowest imaginable column height. We use the tallest
164d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)        // content run (after having "inserted" implicit breaks), and find its start offset (by
165d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)        // looking at the previous run's end offset, or, if there's no previous run, the set's start
166d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)        // offset in the flow thread).
16709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        unsigned index = findRunWithTallestColumns();
168d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)        LayoutUnit startOffset = index > 0 ? m_contentRuns[index - 1].breakOffset() : logicalTopInFlowThread();
16909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        return std::max<LayoutUnit>(m_contentRuns[index].columnLogicalHeight(startOffset), m_minimumColumnHeight);
170591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch    }
171591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch
172d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    if (actualColumnCount() <= usedColumnCount()) {
173591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch        // With the current column height, the content fits without creating overflowing columns. We're done.
174d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)        return m_columnHeight;
17509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    }
17609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
177d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    if (m_contentRuns.size() >= usedColumnCount()) {
17809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        // Too many forced breaks to allow any implicit breaks. Initial balancing should already
17909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        // have set a good height. There's nothing more we should do.
180d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)        return m_columnHeight;
181591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch    }
182591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch
183591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch    // If the initial guessed column height wasn't enough, stretch it now. Stretch by the lowest
184591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch    // amount of space shortage found during layout.
185591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch
18609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    ASSERT(m_minSpaceShortage > 0); // We should never _shrink_ the height!
18709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    ASSERT(m_minSpaceShortage != RenderFlowThread::maxLogicalHeight()); // If this happens, we probably have a bug.
18809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    if (m_minSpaceShortage == RenderFlowThread::maxLogicalHeight())
189d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)        return m_columnHeight; // So bail out rather than looping infinitely.
190591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch
191d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    return m_columnHeight + m_minSpaceShortage;
19209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)}
19309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
194d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)void RenderMultiColumnSet::addContentRun(LayoutUnit endOffsetFromFirstPage)
19509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles){
196d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    if (!multiColumnFlowThread()->requiresBalancing())
19709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        return;
198d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    if (!m_contentRuns.isEmpty() && endOffsetFromFirstPage <= m_contentRuns.last().breakOffset())
19909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        return;
20009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    // Append another item as long as we haven't exceeded used column count. What ends up in the
20109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    // overflow area shouldn't affect column balancing.
202d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    if (m_contentRuns.size() < usedColumnCount())
203d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)        m_contentRuns.append(ContentRun(endOffsetFromFirstPage));
20409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)}
20509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
206d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)bool RenderMultiColumnSet::recalculateColumnHeight(BalancedHeightCalculation calculationMode)
20709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles){
208d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    ASSERT(multiColumnFlowThread()->requiresBalancing());
20909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
210d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    LayoutUnit oldColumnHeight = m_columnHeight;
211d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    if (calculationMode == GuessFromFlowThreadPortion) {
212d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)        // Post-process the content runs and find out where the implicit breaks will occur.
21309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        distributeImplicitBreaks();
214d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    }
215d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    LayoutUnit newColumnHeight = calculateColumnHeight(calculationMode);
21609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    setAndConstrainColumnHeight(newColumnHeight);
21709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
21809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    // After having calculated an initial column height, the multicol container typically needs at
21909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    // least one more layout pass with a new column height, but if a height was specified, we only
22009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    // need to do this if we think that we need less space than specified. Conversely, if we
22109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    // determined that the columns need to be as tall as the specified height of the container, we
22209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    // have already laid it out correctly, and there's no need for another pass.
22309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
224d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    // We can get rid of the content runs now, if we haven't already done so. They are only needed
225d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    // to calculate the initial balanced column height. In fact, we have to get rid of them before
226d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    // the next layout pass, since each pass will rebuild this.
227d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    m_contentRuns.clear();
228d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)
229d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    if (m_columnHeight == oldColumnHeight)
23009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        return false; // No change. We're done.
23109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
23209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    m_minSpaceShortage = RenderFlowThread::maxLogicalHeight();
23309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    return true; // Need another pass.
234591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch}
235591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch
236591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdochvoid RenderMultiColumnSet::recordSpaceShortage(LayoutUnit spaceShortage)
237591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch{
238591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch    if (spaceShortage >= m_minSpaceShortage)
239591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch        return;
240591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch
241591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch    // The space shortage is what we use as our stretch amount. We need a positive number here in
242591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch    // order to get anywhere.
243591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch    ASSERT(spaceShortage > 0);
244591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch
245591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch    m_minSpaceShortage = spaceShortage;
246591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch}
247591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch
248d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)void RenderMultiColumnSet::resetColumnHeight()
2495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
250d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    // Nuke previously stored minimum column height. Contents may have changed for all we know.
251d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    m_minimumColumnHeight = 0;
252591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch
253d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    m_maxColumnHeight = calculateMaxColumnHeight();
254591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch
255d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    LayoutUnit oldColumnHeight = pageLogicalHeight();
256591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch
257d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    if (multiColumnFlowThread()->requiresBalancing())
258d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)        m_columnHeight = 0;
259d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    else
260f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu        setAndConstrainColumnHeight(heightAdjustedForSetOffset(multiColumnFlowThread()->columnHeightAvailable()));
261591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch
262d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    if (pageLogicalHeight() != oldColumnHeight)
263d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)        setChildNeedsLayout(MarkOnlyThis);
26409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
265d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    // Content runs are only needed in the initial layout pass, in order to find an initial column
266d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    // height, and should have been deleted afterwards. We're about to rebuild the content runs, so
267d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    // the list needs to be empty.
268d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    ASSERT(m_contentRuns.isEmpty());
2695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
271323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles)void RenderMultiColumnSet::expandToEncompassFlowThreadContentsIfNeeded()
272323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles){
273323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles)    ASSERT(multiColumnFlowThread()->lastMultiColumnSet() == this);
274323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles)    LayoutRect rect(flowThreadPortionRect());
275323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles)
276323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles)    // Get the offset within the flow thread in its block progression direction. Then get the
277323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles)    // flow thread's remaining logical height including its overflow and expand our rect
278323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles)    // to encompass that remaining height and overflow. The idea is that we will generate
279323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles)    // additional columns and pages to hold that overflow, since people do write bad
280323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles)    // content like <body style="height:0px"> in multi-column layouts.
281323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles)    bool isHorizontal = flowThread()->isHorizontalWritingMode();
282323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles)    LayoutUnit logicalTopOffset = isHorizontal ? rect.y() : rect.x();
283323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles)    LayoutRect layoutRect = flowThread()->layoutOverflowRect();
284323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles)    LayoutUnit logicalHeightWithOverflow = (isHorizontal ? layoutRect.maxY() : layoutRect.maxX()) - logicalTopOffset;
285323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles)    setFlowThreadPortionRect(LayoutRect(rect.x(), rect.y(), isHorizontal ? rect.width() : logicalHeightWithOverflow, isHorizontal ? logicalHeightWithOverflow : rect.height()));
286323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles)}
287323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles)
288591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdochvoid RenderMultiColumnSet::computeLogicalHeight(LayoutUnit, LayoutUnit logicalTop, LogicalExtentComputedValues& computedValues) const
2895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
290d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    computedValues.m_extent = m_columnHeight;
291591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch    computedValues.m_position = logicalTop;
2925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
294d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)LayoutUnit RenderMultiColumnSet::calculateMaxColumnHeight() const
295d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles){
296d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    RenderBlockFlow* multicolBlock = multiColumnBlockFlow();
297d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    RenderStyle* multicolStyle = multicolBlock->style();
298d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    LayoutUnit availableHeight = multiColumnFlowThread()->columnHeightAvailable();
299d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    LayoutUnit maxColumnHeight = availableHeight ? availableHeight : RenderFlowThread::maxLogicalHeight();
300d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    if (!multicolStyle->logicalMaxHeight().isUndefined()) {
301d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)        LayoutUnit logicalMaxHeight = multicolBlock->computeContentLogicalHeight(multicolStyle->logicalMaxHeight(), -1);
302d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)        if (logicalMaxHeight != -1 && maxColumnHeight > logicalMaxHeight)
303d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)            maxColumnHeight = logicalMaxHeight;
304d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    }
305d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    return heightAdjustedForSetOffset(maxColumnHeight);
306d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)}
307d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)
3085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)LayoutUnit RenderMultiColumnSet::columnGap() const
3095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
310d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    RenderBlockFlow* parentBlock = multiColumnBlockFlow();
311926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    if (parentBlock->style()->hasNormalColumnGap())
312926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        return parentBlock->style()->fontDescription().computedPixelSize(); // "1em" is recommended as the normal gap setting. Matches <p> margins.
313926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    return parentBlock->style()->columnGap();
3145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
3155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
316d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)unsigned RenderMultiColumnSet::actualColumnCount() const
3175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
318591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch    // We must always return a value of 1 or greater. Column count = 0 is a meaningless situation,
319591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch    // and will confuse and cause problems in other parts of the code.
320d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    if (!pageLogicalHeight())
321591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch        return 1;
322591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch
323926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    // Our portion rect determines our column count. We have as many columns as needed to fit all the content.
3245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    LayoutUnit logicalHeightInColumns = flowThread()->isHorizontalWritingMode() ? flowThreadPortionRect().height() : flowThreadPortionRect().width();
325d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    if (!logicalHeightInColumns)
326d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        return 1;
327d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
328d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    unsigned count = ceil(logicalHeightInColumns.toFloat() / pageLogicalHeight().toFloat());
329591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch    ASSERT(count >= 1);
330591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch    return count;
3315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
3325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)LayoutRect RenderMultiColumnSet::columnRectAt(unsigned index) const
3345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
335d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    LayoutUnit colLogicalWidth = pageLogicalWidth();
336d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    LayoutUnit colLogicalHeight = pageLogicalHeight();
3375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    LayoutUnit colLogicalTop = borderBefore() + paddingBefore();
3385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    LayoutUnit colLogicalLeft = borderAndPaddingLogicalLeft();
339926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    LayoutUnit colGap = columnGap();
3405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (style()->isLeftToRightDirection())
3415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        colLogicalLeft += index * (colLogicalWidth + colGap);
3425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    else
3435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        colLogicalLeft += contentLogicalWidth() - colLogicalWidth - index * (colLogicalWidth + colGap);
3445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (isHorizontalWritingMode())
3465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return LayoutRect(colLogicalLeft, colLogicalTop, colLogicalWidth, colLogicalHeight);
3475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return LayoutRect(colLogicalTop, colLogicalLeft, colLogicalHeight, colLogicalWidth);
3485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
3495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
350591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdochunsigned RenderMultiColumnSet::columnIndexAtOffset(LayoutUnit offset, ColumnIndexCalculationMode mode) const
3515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
3525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    LayoutRect portionRect(flowThreadPortionRect());
353591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch
3545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Handle the offset being out of range.
355591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch    LayoutUnit flowThreadLogicalTop = isHorizontalWritingMode() ? portionRect.y() : portionRect.x();
3565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (offset < flowThreadLogicalTop)
3575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return 0;
358591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch    // If we're laying out right now, we cannot constrain against some logical bottom, since it
359591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch    // isn't known yet. Otherwise, just return the last column if we're past the logical bottom.
360591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch    if (mode == ClampToExistingColumns) {
361591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch        LayoutUnit flowThreadLogicalBottom = isHorizontalWritingMode() ? portionRect.maxY() : portionRect.maxX();
362591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch        if (offset >= flowThreadLogicalBottom)
363d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)            return actualColumnCount() - 1;
364591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch    }
365591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch
3665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Just divide by the column height to determine the correct column.
367d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    return (offset - flowThreadLogicalTop).toFloat() / pageLogicalHeight().toFloat();
3685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
3695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)LayoutRect RenderMultiColumnSet::flowThreadPortionRectAt(unsigned index) const
3715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
3725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    LayoutRect portionRect = flowThreadPortionRect();
3735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (isHorizontalWritingMode())
374d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)        portionRect = LayoutRect(portionRect.x(), portionRect.y() + index * pageLogicalHeight(), portionRect.width(), pageLogicalHeight());
3755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    else
376d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)        portionRect = LayoutRect(portionRect.x() + index * pageLogicalHeight(), portionRect.y(), pageLogicalHeight(), portionRect.height());
3775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return portionRect;
3785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
3795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
380926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)LayoutRect RenderMultiColumnSet::flowThreadPortionOverflowRect(const LayoutRect& portionRect, unsigned index, unsigned colCount, LayoutUnit colGap) const
3815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
3825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // This function determines the portion of the flow thread that paints for the column. Along the inline axis, columns are
3835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // unclipped at outside edges (i.e., the first and last column in the set), and they clip to half the column
3845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // gap along interior edges.
3855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    //
3865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // In the block direction, we will not clip overflow out of the top of the first column, or out of the bottom of
3875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // the last column. This applies only to the true first column and last column across all column sets.
3885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    //
3895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // FIXME: Eventually we will know overflow on a per-column basis, but we can't do this until we have a painting
3905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // mode that understands not to paint contents from a previous column in the overflow area of a following column.
3915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // This problem applies to regions and pages as well and is not unique to columns.
3925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    bool isFirstColumn = !index;
3935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    bool isLastColumn = index == colCount - 1;
394926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    bool isLeftmostColumn = style()->isLeftToRightDirection() ? isFirstColumn : isLastColumn;
395926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    bool isRightmostColumn = style()->isLeftToRightDirection() ? isLastColumn : isFirstColumn;
3961e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)
3971e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    // Calculate the overflow rectangle, based on the flow thread's, clipped at column logical
3981e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    // top/bottom unless it's the first/last column.
3991e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    LayoutRect overflowRect = overflowRectForFlowThreadPortion(portionRect, isFirstColumn && isFirstRegion(), isLastColumn && isLastRegion());
4001e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)
4011e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    // Avoid overflowing into neighboring columns, by clipping in the middle of adjacent column
4021e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    // gaps. Also make sure that we avoid rounding errors.
4035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (isHorizontalWritingMode()) {
4041e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)        if (!isLeftmostColumn)
4055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            overflowRect.shiftXEdgeTo(portionRect.x() - colGap / 2);
4061e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)        if (!isRightmostColumn)
4071e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)            overflowRect.shiftMaxXEdgeTo(portionRect.maxX() + colGap - colGap / 2);
4085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    } else {
4091e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)        if (!isLeftmostColumn)
4105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            overflowRect.shiftYEdgeTo(portionRect.y() - colGap / 2);
4111e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)        if (!isRightmostColumn)
4121e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)            overflowRect.shiftMaxYEdgeTo(portionRect.maxY() + colGap - colGap / 2);
4135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
4141e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    return overflowRect;
4155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
4165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
417926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)void RenderMultiColumnSet::paintObject(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
4185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
419926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    if (style()->visibility() != VISIBLE)
420926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        return;
421926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
42209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    RenderBlockFlow::paintObject(paintInfo, paintOffset);
423926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
424926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    // FIXME: Right now we're only painting in the foreground phase.
4255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Columns should technically respect phases and allow for background/float/foreground overlap etc., just like
426926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    // RenderBlocks do. Note this is a pretty minor issue, since the old column implementation clipped columns
4275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // anyway, thus making it impossible for them to overlap one another. It's also really unlikely that the columns
4285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // would overlap another block.
429926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    if (!m_flowThread || !isValid() || (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseSelection))
430926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        return;
431926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
4325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    paintColumnRules(paintInfo, paintOffset);
4335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
4345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void RenderMultiColumnSet::paintColumnRules(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
4365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
4375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (paintInfo.context->paintingDisabled())
4385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
4395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
440d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    RenderStyle* blockStyle = multiColumnBlockFlow()->style();
4417757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    const Color& ruleColor = resolveColor(blockStyle, CSSPropertyWebkitColumnRuleColor);
4425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    bool ruleTransparent = blockStyle->columnRuleIsTransparent();
4435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    EBorderStyle ruleStyle = blockStyle->columnRuleStyle();
4445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    LayoutUnit ruleThickness = blockStyle->columnRuleWidth();
4455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    LayoutUnit colGap = columnGap();
446926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    bool renderRule = ruleStyle > BHIDDEN && !ruleTransparent;
4475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!renderRule)
4485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
4495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
450d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    unsigned colCount = actualColumnCount();
4515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (colCount <= 1)
4525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
4535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    bool antialias = shouldAntialiasLines(paintInfo.context);
4555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    bool leftToRight = style()->isLeftToRightDirection();
4575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    LayoutUnit currLogicalLeftOffset = leftToRight ? LayoutUnit() : contentLogicalWidth();
4585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    LayoutUnit ruleAdd = borderAndPaddingLogicalLeft();
4595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    LayoutUnit ruleLogicalLeft = leftToRight ? LayoutUnit() : contentLogicalWidth();
460d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    LayoutUnit inlineDirectionSize = pageLogicalWidth();
4615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    BoxSide boxSide = isHorizontalWritingMode()
4625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        ? leftToRight ? BSLeft : BSRight
4635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        : leftToRight ? BSTop : BSBottom;
4645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (unsigned i = 0; i < colCount; i++) {
4665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // Move to the next position.
4675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (leftToRight) {
4685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            ruleLogicalLeft += inlineDirectionSize + colGap / 2;
4695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            currLogicalLeftOffset += inlineDirectionSize + colGap;
4705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        } else {
4715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            ruleLogicalLeft -= (inlineDirectionSize + colGap / 2);
4725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            currLogicalLeftOffset -= (inlineDirectionSize + colGap);
4735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
474926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
4755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // Now paint the column rule.
4765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (i < colCount - 1) {
4775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            LayoutUnit ruleLeft = isHorizontalWritingMode() ? paintOffset.x() + ruleLogicalLeft - ruleThickness / 2 + ruleAdd : paintOffset.x() + borderLeft() + paddingLeft();
4785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            LayoutUnit ruleRight = isHorizontalWritingMode() ? ruleLeft + ruleThickness : ruleLeft + contentWidth();
4795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            LayoutUnit ruleTop = isHorizontalWritingMode() ? paintOffset.y() + borderTop() + paddingTop() : paintOffset.y() + ruleLogicalLeft - ruleThickness / 2 + ruleAdd;
4805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            LayoutUnit ruleBottom = isHorizontalWritingMode() ? ruleTop + contentHeight() : ruleTop + ruleThickness;
4815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            IntRect pixelSnappedRuleRect = pixelSnappedIntRectFromEdges(ruleLeft, ruleTop, ruleRight, ruleBottom);
4825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            drawLineForBoxSide(paintInfo.context, pixelSnappedRuleRect.x(), pixelSnappedRuleRect.y(), pixelSnappedRuleRect.maxX(), pixelSnappedRuleRect.maxY(), boxSide, ruleColor, ruleStyle, 0, 0, antialias);
4835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
48402772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
4855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        ruleLogicalLeft = currLogicalLeftOffset;
4865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
4875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
4885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
48953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)void RenderMultiColumnSet::repaintFlowThreadContent(const LayoutRect& repaintRect) const
4905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
4915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Figure out the start and end columns and only check within that range so that we don't walk the
4925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // entire column set. Put the repaint rect into flow thread coordinates by flipping it first.
4935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    LayoutRect flowThreadRepaintRect(repaintRect);
4945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    flowThread()->flipForWritingMode(flowThreadRepaintRect);
49502772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
4965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Now we can compare this rect with the flow thread portions owned by each column. First let's
4975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // just see if the repaint rect intersects our flow thread portion at all.
4985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    LayoutRect clippedRect(flowThreadRepaintRect);
4995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    clippedRect.intersect(RenderRegion::flowThreadPortionOverflowRect());
5005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (clippedRect.isEmpty())
5015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
50202772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
5035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Now we know we intersect at least one column. Let's figure out the logical top and logical
5045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // bottom of the area we're repainting.
5055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    LayoutUnit repaintLogicalTop = isHorizontalWritingMode() ? flowThreadRepaintRect.y() : flowThreadRepaintRect.x();
5065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    LayoutUnit repaintLogicalBottom = (isHorizontalWritingMode() ? flowThreadRepaintRect.maxY() : flowThreadRepaintRect.maxX()) - 1;
50702772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
5085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    unsigned startColumn = columnIndexAtOffset(repaintLogicalTop);
5095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    unsigned endColumn = columnIndexAtOffset(repaintLogicalBottom);
51002772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
5115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    LayoutUnit colGap = columnGap();
512d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    unsigned colCount = actualColumnCount();
5135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (unsigned i = startColumn; i <= endColumn; i++) {
5145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        LayoutRect colRect = columnRectAt(i);
51502772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
5165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // Get the portion of the flow thread that corresponds to this column.
5175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        LayoutRect flowThreadPortion = flowThreadPortionRectAt(i);
51802772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
5195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // Now get the overflow rect that corresponds to the column.
5205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        LayoutRect flowThreadOverflowPortion = flowThreadPortionOverflowRect(flowThreadPortion, i, colCount, colGap);
5215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // Do a repaint for this specific column.
52353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        repaintFlowThreadContentRectangle(repaintRect, flowThreadPortion, flowThreadOverflowPortion, colRect.location());
5245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
5255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
5265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
527926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)void RenderMultiColumnSet::collectLayerFragments(LayerFragments& fragments, const LayoutRect& layerBoundingBox, const LayoutRect& dirtyRect)
528926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles){
5291e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    // The two rectangles passed to this method are physical, except that we pretend that there's
5301e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    // only one long column (that's how a flow thread works).
5311e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    //
5321e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    // Then there's the output from this method - the stuff we put into the list of fragments. The
5331e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    // fragment.paginationOffset point is the actual physical translation required to get from a
5341e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    // location in the flow thread to a location in a given column. The fragment.paginationClip
5351e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    // rectangle, on the other hand, is in the same coordinate system as the two rectangles passed
5361e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    // to this method (flow thread coordinates).
5371e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    //
5381e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    // All other rectangles in this method are sized physically, and the inline direction coordinate
5391e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    // is physical too, but the block direction coordinate is "logical top". This is the same as
5401e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    // e.g. RenderBox::frameRect(). These rectangles also pretend that there's only one long column,
5411e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    // i.e. they are for the flow thread.
5421e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)
5431e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    // Put the layer bounds into flow thread-local coordinates by flipping it first. Since we're in
5441e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    // a renderer, most rectangles are represented this way.
545926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    LayoutRect layerBoundsInFlowThread(layerBoundingBox);
546926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    flowThread()->flipForWritingMode(layerBoundsInFlowThread);
547926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
548926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    // Now we can compare with the flow thread portions owned by each column. First let's
549926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    // see if the rect intersects our flow thread portion at all.
550926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    LayoutRect clippedRect(layerBoundsInFlowThread);
551926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    clippedRect.intersect(RenderRegion::flowThreadPortionOverflowRect());
552926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    if (clippedRect.isEmpty())
553926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        return;
55402772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
555926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    // Now we know we intersect at least one column. Let's figure out the logical top and logical
556926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    // bottom of the area we're checking.
557926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    LayoutUnit layerLogicalTop = isHorizontalWritingMode() ? layerBoundsInFlowThread.y() : layerBoundsInFlowThread.x();
558926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    LayoutUnit layerLogicalBottom = (isHorizontalWritingMode() ? layerBoundsInFlowThread.maxY() : layerBoundsInFlowThread.maxX()) - 1;
55902772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
560926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    // Figure out the start and end columns and only check within that range so that we don't walk the
561926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    // entire column set.
562926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    unsigned startColumn = columnIndexAtOffset(layerLogicalTop);
563926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    unsigned endColumn = columnIndexAtOffset(layerLogicalBottom);
56402772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
565d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    LayoutUnit colLogicalWidth = pageLogicalWidth();
566926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    LayoutUnit colGap = columnGap();
567d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    unsigned colCount = actualColumnCount();
56802772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
569926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    for (unsigned i = startColumn; i <= endColumn; i++) {
570926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        // Get the portion of the flow thread that corresponds to this column.
571926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        LayoutRect flowThreadPortion = flowThreadPortionRectAt(i);
57202772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
573926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        // Now get the overflow rect that corresponds to the column.
574926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        LayoutRect flowThreadOverflowPortion = flowThreadPortionOverflowRect(flowThreadPortion, i, colCount, colGap);
575926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
576926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        // In order to create a fragment we must intersect the portion painted by this column.
577926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        LayoutRect clippedRect(layerBoundsInFlowThread);
578926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        clippedRect.intersect(flowThreadOverflowPortion);
579926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        if (clippedRect.isEmpty())
580926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)            continue;
58102772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
582926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        // We also need to intersect the dirty rect. We have to apply a translation and shift based off
583926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        // our column index.
584926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        LayoutPoint translationOffset;
585926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        LayoutUnit inlineOffset = i * (colLogicalWidth + colGap);
586926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        if (!style()->isLeftToRightDirection())
587926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)            inlineOffset = -inlineOffset;
588926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        translationOffset.setX(inlineOffset);
589926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        LayoutUnit blockOffset = isHorizontalWritingMode() ? -flowThreadPortion.y() : -flowThreadPortion.x();
590926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        if (isFlippedBlocksWritingMode(style()->writingMode()))
591926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)            blockOffset = -blockOffset;
592926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        translationOffset.setY(blockOffset);
593926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        if (!isHorizontalWritingMode())
594926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)            translationOffset = translationOffset.transposedPoint();
595926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        // FIXME: The translation needs to include the multicolumn set's content offset within the
596926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        // multicolumn block as well. This won't be an issue until we start creating multiple multicolumn sets.
597926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
598926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        // Shift the dirty rect to be in flow thread coordinates with this translation applied.
5991e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)        LayoutRect translatedDirtyRect(dirtyRect);
600926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        translatedDirtyRect.moveBy(-translationOffset);
60102772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
602926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        // See if we intersect the dirty rect.
6031e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)        clippedRect = layerBoundingBox;
604926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        clippedRect.intersect(translatedDirtyRect);
605926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        if (clippedRect.isEmpty())
606926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)            continue;
60702772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
608926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        // Something does need to paint in this column. Make a fragment now and supply the physical translation
609926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        // offset and the clip rect for the column with that offset applied.
610926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        LayerFragment fragment;
611926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        fragment.paginationOffset = translationOffset;
61202772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
613926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        LayoutRect flippedFlowThreadOverflowPortion(flowThreadOverflowPortion);
6141e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)        // Flip it into more a physical (RenderLayer-style) rectangle.
6151e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)        flowThread()->flipForWritingMode(flippedFlowThreadOverflowPortion);
616926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        fragment.paginationClip = flippedFlowThreadOverflowPortion;
617926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        fragments.append(fragment);
618926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    }
619926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)}
620926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
621d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)void RenderMultiColumnSet::addOverflowFromChildren()
622d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles){
623d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    unsigned colCount = actualColumnCount();
624d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    if (!colCount)
625d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)        return;
626d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)
627d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    LayoutRect lastRect = columnRectAt(colCount - 1);
628d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    addLayoutOverflow(lastRect);
629d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    if (!hasOverflowClip())
630d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)        addVisualOverflow(lastRect);
631d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)}
632d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)
6335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)const char* RenderMultiColumnSet::renderName() const
63402772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch{
6355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return "RenderMultiColumnSet";
6365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
6375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
639