| OLD | NEW | 
|    1 /* |    1 /* | 
|    2  * Copyright (C) 2012 Apple Inc.  All rights reserved. |    2  * Copyright (C) 2012 Apple Inc.  All rights reserved. | 
|    3  * |    3  * | 
|    4  * Redistribution and use in source and binary forms, with or without |    4  * Redistribution and use in source and binary forms, with or without | 
|    5  * modification, are permitted provided that the following conditions |    5  * modification, are permitted provided that the following conditions | 
|    6  * are met: |    6  * are met: | 
|    7  * 1. Redistributions of source code must retain the above copyright |    7  * 1. Redistributions of source code must retain the above copyright | 
|    8  *    notice, this list of conditions and the following disclaimer. |    8  *    notice, this list of conditions and the following disclaimer. | 
|    9  * 2. Redistributions in binary form must reproduce the above copyright |    9  * 2. Redistributions in binary form must reproduce the above copyright | 
|   10  *    notice, this list of conditions and the following disclaimer in the |   10  *    notice, this list of conditions and the following disclaimer in the | 
|   11  *    documentation and/or other materials provided with the distribution. |   11  *    documentation and/or other materials provided with the distribution. | 
|   12  * |   12  * | 
|   13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY |   13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY | 
|   14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |   14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 
|   15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |   15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 
|   16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR |   16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR | 
|   17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |   17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | 
|   18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |   18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | 
|   19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |   19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | 
|   20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |   20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | 
|   21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |   21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 
|   22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |   22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 
|   23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |   23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
|   24  */ |   24  */ | 
|   25  |   25  | 
|   26 #include "config.h" |   26 #include "config.h" | 
|   27 #include "core/rendering/RenderMultiColumnSet.h" |   27 #include "core/rendering/RenderMultiColumnSet.h" | 
|   28  |   28  | 
 |   29 #include "core/layout/MultiColumnFragmentainerGroup.h" | 
|   29 #include "core/paint/MultiColumnSetPainter.h" |   30 #include "core/paint/MultiColumnSetPainter.h" | 
|   30 #include "core/rendering/RenderMultiColumnFlowThread.h" |   31 #include "core/rendering/RenderMultiColumnFlowThread.h" | 
|   31  |   32  | 
|   32 namespace blink { |   33 namespace blink { | 
|   33  |   34  | 
|   34 RenderMultiColumnSet::RenderMultiColumnSet(RenderFlowThread* flowThread) |   35 RenderMultiColumnSet::RenderMultiColumnSet(RenderFlowThread* flowThread) | 
|   35     : RenderRegion(0, flowThread) |   36     : RenderRegion(0, flowThread) | 
|   36     , m_columnHeight(0) |   37     , m_fragmentainerGroups(*this) | 
|   37     , m_maxColumnHeight(RenderFlowThread::maxLogicalHeight()) |  | 
|   38     , m_minSpaceShortage(RenderFlowThread::maxLogicalHeight()) |  | 
|   39     , m_minimumColumnHeight(0) |  | 
|   40 { |   38 { | 
|   41 } |   39 } | 
|   42  |   40  | 
|   43 RenderMultiColumnSet* RenderMultiColumnSet::createAnonymous(RenderFlowThread& fl
     owThread, const LayoutStyle& parentStyle) |   41 RenderMultiColumnSet* RenderMultiColumnSet::createAnonymous(RenderFlowThread& fl
     owThread, const LayoutStyle& parentStyle) | 
|   44 { |   42 { | 
|   45     Document& document = flowThread.document(); |   43     Document& document = flowThread.document(); | 
|   46     RenderMultiColumnSet* renderer = new RenderMultiColumnSet(&flowThread); |   44     RenderMultiColumnSet* renderer = new RenderMultiColumnSet(&flowThread); | 
|   47     renderer->setDocumentForAnonymous(&document); |   45     renderer->setDocumentForAnonymous(&document); | 
|   48     renderer->setStyle(LayoutStyle::createAnonymousStyleWithDisplay(parentStyle,
      BLOCK)); |   46     renderer->setStyle(LayoutStyle::createAnonymousStyleWithDisplay(parentStyle,
      BLOCK)); | 
|   49     return renderer; |   47     return renderer; | 
|   50 } |   48 } | 
|   51  |   49  | 
 |   50 MultiColumnFragmentainerGroup& RenderMultiColumnSet::fragmentainerGroupAtFlowThr
     eadOffset(LayoutUnit) | 
 |   51 { | 
 |   52     // FIXME: implement this, once we have support for multiple rows. | 
 |   53     return m_fragmentainerGroups.first(); | 
 |   54 } | 
 |   55  | 
 |   56 const MultiColumnFragmentainerGroup& RenderMultiColumnSet::fragmentainerGroupAtF
     lowThreadOffset(LayoutUnit) const | 
 |   57 { | 
 |   58     // FIXME: implement this, once we have support for multiple rows. | 
 |   59     return m_fragmentainerGroups.first(); | 
 |   60 } | 
 |   61  | 
 |   62 LayoutUnit RenderMultiColumnSet::pageLogicalHeight() const | 
 |   63 { | 
 |   64     // FIXME: pageLogicalHeight() needs to take a flow thread offset parameter, 
     so that we can | 
 |   65     // locate the right row. | 
 |   66     return firstFragmentainerGroup().logicalHeight(); | 
 |   67 } | 
 |   68  | 
|   52 RenderMultiColumnSet* RenderMultiColumnSet::nextSiblingMultiColumnSet() const |   69 RenderMultiColumnSet* RenderMultiColumnSet::nextSiblingMultiColumnSet() const | 
|   53 { |   70 { | 
|   54     for (LayoutObject* sibling = nextSibling(); sibling; sibling = sibling->next
     Sibling()) { |   71     for (LayoutObject* sibling = nextSibling(); sibling; sibling = sibling->next
     Sibling()) { | 
|   55         if (sibling->isRenderMultiColumnSet()) |   72         if (sibling->isRenderMultiColumnSet()) | 
|   56             return toRenderMultiColumnSet(sibling); |   73             return toRenderMultiColumnSet(sibling); | 
|   57     } |   74     } | 
|   58     return 0; |   75     return 0; | 
|   59 } |   76 } | 
|   60  |   77  | 
|   61 RenderMultiColumnSet* RenderMultiColumnSet::previousSiblingMultiColumnSet() cons
     t |   78 RenderMultiColumnSet* RenderMultiColumnSet::previousSiblingMultiColumnSet() cons
     t | 
|   62 { |   79 { | 
|   63     for (LayoutObject* sibling = previousSibling(); sibling; sibling = sibling->
     previousSibling()) { |   80     for (LayoutObject* sibling = previousSibling(); sibling; sibling = sibling->
     previousSibling()) { | 
|   64         if (sibling->isRenderMultiColumnSet()) |   81         if (sibling->isRenderMultiColumnSet()) | 
|   65             return toRenderMultiColumnSet(sibling); |   82             return toRenderMultiColumnSet(sibling); | 
|   66     } |   83     } | 
|   67     return 0; |   84     return 0; | 
|   68 } |   85 } | 
|   69  |   86  | 
|   70 void RenderMultiColumnSet::setLogicalTopInFlowThread(LayoutUnit logicalTop) |   87 LayoutUnit RenderMultiColumnSet::logicalTopInFlowThread() const | 
|   71 { |   88 { | 
|   72     LayoutRect rect = flowThreadPortionRect(); |   89     return firstFragmentainerGroup().logicalTopInFlowThread(); | 
|   73     if (isHorizontalWritingMode()) |  | 
|   74         rect.setY(logicalTop); |  | 
|   75     else |  | 
|   76         rect.setX(logicalTop); |  | 
|   77     setFlowThreadPortionRect(rect); |  | 
|   78 } |   90 } | 
|   79  |   91  | 
|   80 void RenderMultiColumnSet::setLogicalBottomInFlowThread(LayoutUnit logicalBottom
     ) |   92 LayoutUnit RenderMultiColumnSet::logicalBottomInFlowThread() const | 
|   81 { |   93 { | 
|   82     LayoutRect rect = flowThreadPortionRect(); |   94     return lastFragmentainerGroup().logicalBottomInFlowThread(); | 
|   83     if (isHorizontalWritingMode()) |  | 
|   84         rect.shiftMaxYEdgeTo(logicalBottom); |  | 
|   85     else |  | 
|   86         rect.shiftMaxXEdgeTo(logicalBottom); |  | 
|   87     setFlowThreadPortionRect(rect); |  | 
|   88 } |   95 } | 
|   89  |   96  | 
|   90 bool RenderMultiColumnSet::heightIsAuto() const |   97 bool RenderMultiColumnSet::heightIsAuto() const | 
|   91 { |   98 { | 
|   92     RenderMultiColumnFlowThread* flowThread = multiColumnFlowThread(); |   99     RenderMultiColumnFlowThread* flowThread = multiColumnFlowThread(); | 
|   93     if (!flowThread->isRenderPagedFlowThread()) { |  100     if (!flowThread->isRenderPagedFlowThread()) { | 
|   94         if (multiColumnBlockFlow()->style()->columnFill() == ColumnFillBalance) |  101         if (multiColumnBlockFlow()->style()->columnFill() == ColumnFillBalance) | 
|   95             return true; |  102             return true; | 
|   96         if (RenderBox* next = nextSiblingBox()) { |  103         if (RenderBox* next = nextSiblingBox()) { | 
|   97             if (next->isRenderMultiColumnSpannerPlaceholder()) { |  104             if (next->isRenderMultiColumnSpannerPlaceholder()) { | 
|   98                 // If we're followed by a spanner, we need to balance. |  105                 // If we're followed by a spanner, we need to balance. | 
|   99                 return true; |  106                 return true; | 
|  100             } |  107             } | 
|  101         } |  108         } | 
|  102     } |  109     } | 
|  103     return !flowThread->columnHeightAvailable(); |  110     return !flowThread->columnHeightAvailable(); | 
|  104 } |  111 } | 
|  105  |  112  | 
|  106 LayoutSize RenderMultiColumnSet::flowThreadTranslationAtOffset(LayoutUnit blockO
     ffset) const |  113 LayoutSize RenderMultiColumnSet::flowThreadTranslationAtOffset(LayoutUnit blockO
     ffset) const | 
|  107 { |  114 { | 
|  108     unsigned columnIndex = columnIndexAtOffset(blockOffset); |  115     const MultiColumnFragmentainerGroup& row = fragmentainerGroupAtFlowThreadOff
     set(blockOffset); | 
|  109     LayoutRect portionRect(flowThreadPortionRectAt(columnIndex)); |  116     return row.offsetFromColumnSet() + row.flowThreadTranslationAtOffset(blockOf
     fset); | 
|  110     flipForWritingMode(portionRect); |  | 
|  111     LayoutRect columnRect(columnRectAt(columnIndex)); |  | 
|  112     flipForWritingMode(columnRect); |  | 
|  113     return toLayoutPoint(contentBoxOffset()) + columnRect.location() - portionRe
     ct.location(); |  | 
|  114 } |  117 } | 
|  115  |  118  | 
|  116 LayoutUnit RenderMultiColumnSet::heightAdjustedForSetOffset(LayoutUnit height) c
     onst |  119 void RenderMultiColumnSet::updateMinimumColumnHeight(LayoutUnit offsetInFlowThre
     ad, LayoutUnit height) | 
|  117 { |  120 { | 
|  118     // Adjust for the top offset within the content box of the multicol containe
     r (containing |  121     fragmentainerGroupAtFlowThreadOffset(offsetInFlowThread).updateMinimumColumn
     Height(height); | 
|  119     // block), unless this is the first set. We know that the top offset for the
      first set will be |  | 
|  120     // zero, but if the multicol container has non-zero top border or padding, t
     he set's top offset |  | 
|  121     // (initially being 0 and relative to the border box) will be negative until
      it has been laid |  | 
|  122     // out. Had we used this bogus offset, we would calculate the wrong height, 
     and risk performing |  | 
|  123     // a wasted layout iteration. Of course all other sets (if any) have this pr
     oblem in the first |  | 
|  124     // layout pass too, but there's really nothing we can do there until the flo
     w thread has been |  | 
|  125     // laid out anyway. |  | 
|  126     if (previousSiblingMultiColumnSet()) { |  | 
|  127         RenderBlockFlow* multicolBlock = multiColumnBlockFlow(); |  | 
|  128         LayoutUnit contentLogicalTop = logicalTop() - multicolBlock->borderAndPa
     ddingBefore(); |  | 
|  129         height -= contentLogicalTop; |  | 
|  130     } |  | 
|  131     return max(height, LayoutUnit(1)); // Let's avoid zero height, as that would
      probably cause an infinite amount of columns to be created. |  | 
|  132 } |  122 } | 
|  133  |  123  | 
|  134 LayoutUnit RenderMultiColumnSet::pageLogicalTopForOffset(LayoutUnit offset) cons
     t |  124 LayoutUnit RenderMultiColumnSet::pageLogicalTopForOffset(LayoutUnit offset) cons
     t | 
|  135 { |  125 { | 
|  136     unsigned columnIndex = columnIndexAtOffset(offset, AssumeNewColumns); |  126     return fragmentainerGroupAtFlowThreadOffset(offset).columnLogicalTopForOffse
     t(offset); | 
|  137     return logicalTopInFlowThread() + columnIndex * pageLogicalHeight(); |  | 
|  138 } |  | 
|  139  |  | 
|  140 void RenderMultiColumnSet::setAndConstrainColumnHeight(LayoutUnit newHeight) |  | 
|  141 { |  | 
|  142     m_columnHeight = newHeight; |  | 
|  143     if (m_columnHeight > m_maxColumnHeight) |  | 
|  144         m_columnHeight = m_maxColumnHeight; |  | 
|  145     // FIXME: the height may also be affected by the enclosing pagination contex
     t, if any. |  | 
|  146 } |  | 
|  147  |  | 
|  148 unsigned RenderMultiColumnSet::findRunWithTallestColumns() const |  | 
|  149 { |  | 
|  150     unsigned indexWithLargestHeight = 0; |  | 
|  151     LayoutUnit largestHeight; |  | 
|  152     LayoutUnit previousOffset = logicalTopInFlowThread(); |  | 
|  153     size_t runCount = m_contentRuns.size(); |  | 
|  154     ASSERT(runCount); |  | 
|  155     for (size_t i = 0; i < runCount; i++) { |  | 
|  156         const ContentRun& run = m_contentRuns[i]; |  | 
|  157         LayoutUnit height = run.columnLogicalHeight(previousOffset); |  | 
|  158         if (largestHeight < height) { |  | 
|  159             largestHeight = height; |  | 
|  160             indexWithLargestHeight = i; |  | 
|  161         } |  | 
|  162         previousOffset = run.breakOffset(); |  | 
|  163     } |  | 
|  164     return indexWithLargestHeight; |  | 
|  165 } |  | 
|  166  |  | 
|  167 void RenderMultiColumnSet::distributeImplicitBreaks() |  | 
|  168 { |  | 
|  169 #if ENABLE(ASSERT) |  | 
|  170     // There should be no implicit breaks assumed at this point. |  | 
|  171     for (unsigned i = 0; i < m_contentRuns.size(); i++) |  | 
|  172         ASSERT(!m_contentRuns[i].assumedImplicitBreaks()); |  | 
|  173 #endif // ENABLE(ASSERT) |  | 
|  174  |  | 
|  175     // Insert a final content run to encompass all content. This will include ov
     erflow if this is |  | 
|  176     // the last set. |  | 
|  177     addContentRun(logicalBottomInFlowThread()); |  | 
|  178     unsigned columnCount = m_contentRuns.size(); |  | 
|  179  |  | 
|  180     // If there is room for more breaks (to reach the used value of column-count
     ), imagine that we |  | 
|  181     // insert implicit breaks at suitable locations. At any given time, the cont
     ent run with the |  | 
|  182     // currently tallest columns will get another implicit break "inserted", whi
     ch will increase its |  | 
|  183     // column count by one and shrink its columns' height. Repeat until we have 
     the desired total |  | 
|  184     // number of breaks. The largest column height among the runs will then be t
     he initial column |  | 
|  185     // height for the balancer to use. |  | 
|  186     while (columnCount < usedColumnCount()) { |  | 
|  187         unsigned index = findRunWithTallestColumns(); |  | 
|  188         m_contentRuns[index].assumeAnotherImplicitBreak(); |  | 
|  189         columnCount++; |  | 
|  190     } |  | 
|  191 } |  | 
|  192  |  | 
|  193 LayoutUnit RenderMultiColumnSet::calculateColumnHeight(BalancedHeightCalculation
      calculationMode) const |  | 
|  194 { |  | 
|  195     if (calculationMode == GuessFromFlowThreadPortion) { |  | 
|  196         // Initial balancing. Start with the lowest imaginable column height. We
      use the tallest |  | 
|  197         // content run (after having "inserted" implicit breaks), and find its s
     tart offset (by |  | 
|  198         // looking at the previous run's end offset, or, if there's no previous 
     run, the set's start |  | 
|  199         // offset in the flow thread). |  | 
|  200         unsigned index = findRunWithTallestColumns(); |  | 
|  201         LayoutUnit startOffset = index > 0 ? m_contentRuns[index - 1].breakOffse
     t() : logicalTopInFlowThread(); |  | 
|  202         return std::max<LayoutUnit>(m_contentRuns[index].columnLogicalHeight(sta
     rtOffset), m_minimumColumnHeight); |  | 
|  203     } |  | 
|  204  |  | 
|  205     if (actualColumnCount() <= usedColumnCount()) { |  | 
|  206         // With the current column height, the content fits without creating ove
     rflowing columns. We're done. |  | 
|  207         return m_columnHeight; |  | 
|  208     } |  | 
|  209  |  | 
|  210     if (m_contentRuns.size() >= usedColumnCount()) { |  | 
|  211         // Too many forced breaks to allow any implicit breaks. Initial balancin
     g should already |  | 
|  212         // have set a good height. There's nothing more we should do. |  | 
|  213         return m_columnHeight; |  | 
|  214     } |  | 
|  215  |  | 
|  216     // If the initial guessed column height wasn't enough, stretch it now. Stret
     ch by the lowest |  | 
|  217     // amount of space shortage found during layout. |  | 
|  218  |  | 
|  219     ASSERT(m_minSpaceShortage > 0); // We should never _shrink_ the height! |  | 
|  220     ASSERT(m_minSpaceShortage != RenderFlowThread::maxLogicalHeight()); // If th
     is happens, we probably have a bug. |  | 
|  221     if (m_minSpaceShortage == RenderFlowThread::maxLogicalHeight()) |  | 
|  222         return m_columnHeight; // So bail out rather than looping infinitely. |  | 
|  223  |  | 
|  224     return m_columnHeight + m_minSpaceShortage; |  | 
|  225 } |  127 } | 
|  226  |  128  | 
|  227 void RenderMultiColumnSet::addContentRun(LayoutUnit endOffsetFromFirstPage) |  129 void RenderMultiColumnSet::addContentRun(LayoutUnit endOffsetFromFirstPage) | 
|  228 { |  130 { | 
|  229     if (!heightIsAuto()) |  131     if (!heightIsAuto()) | 
|  230         return; |  132         return; | 
|  231     if (!m_contentRuns.isEmpty() && endOffsetFromFirstPage <= m_contentRuns.last
     ().breakOffset()) |  133     fragmentainerGroupAtFlowThreadOffset(endOffsetFromFirstPage).addContentRun(e
     ndOffsetFromFirstPage); | 
|  232         return; |  | 
|  233     // Append another item as long as we haven't exceeded used column count. Wha
     t ends up in the |  | 
|  234     // overflow area shouldn't affect column balancing. |  | 
|  235     if (m_contentRuns.size() < usedColumnCount()) |  | 
|  236         m_contentRuns.append(ContentRun(endOffsetFromFirstPage)); |  | 
|  237 } |  134 } | 
|  238  |  135  | 
|  239 bool RenderMultiColumnSet::recalculateColumnHeight(BalancedHeightCalculation cal
     culationMode) |  136 bool RenderMultiColumnSet::recalculateColumnHeight(BalancedColumnHeightCalculati
     on calculationMode) | 
|  240 { |  137 { | 
|  241     LayoutUnit oldColumnHeight = m_columnHeight; |  138     bool changed = false; | 
|  242  |  139     for (auto& group : m_fragmentainerGroups) | 
|  243     m_maxColumnHeight = calculateMaxColumnHeight(); |  140         changed = group.recalculateColumnHeight(calculationMode) || changed; | 
|  244  |  141     return changed; | 
|  245     if (heightIsAuto()) { |  | 
|  246         if (calculationMode == GuessFromFlowThreadPortion) { |  | 
|  247             // Post-process the content runs and find out where the implicit bre
     aks will occur. |  | 
|  248             distributeImplicitBreaks(); |  | 
|  249         } |  | 
|  250         LayoutUnit newColumnHeight = calculateColumnHeight(calculationMode); |  | 
|  251         setAndConstrainColumnHeight(newColumnHeight); |  | 
|  252         // After having calculated an initial column height, the multicol contai
     ner typically needs at |  | 
|  253         // least one more layout pass with a new column height, but if a height 
     was specified, we only |  | 
|  254         // need to do this if we think that we need less space than specified. C
     onversely, if we |  | 
|  255         // determined that the columns need to be as tall as the specified heigh
     t of the container, we |  | 
|  256         // have already laid it out correctly, and there's no need for another p
     ass. |  | 
|  257     } else { |  | 
|  258         // The position of the column set may have changed, in which case height
      available for |  | 
|  259         // columns may have changed as well. |  | 
|  260         setAndConstrainColumnHeight(m_columnHeight); |  | 
|  261     } |  | 
|  262  |  | 
|  263     // We can get rid of the content runs now, if we haven't already done so. Th
     ey are only needed |  | 
|  264     // to calculate the initial balanced column height. In fact, we have to get 
     rid of them before |  | 
|  265     // the next layout pass, since each pass will rebuild this. |  | 
|  266     m_contentRuns.clear(); |  | 
|  267  |  | 
|  268     if (m_columnHeight == oldColumnHeight) |  | 
|  269         return false; // No change. We're done. |  | 
|  270  |  | 
|  271     m_minSpaceShortage = RenderFlowThread::maxLogicalHeight(); |  | 
|  272     return true; // Need another pass. |  | 
|  273 } |  142 } | 
|  274  |  143  | 
|  275 void RenderMultiColumnSet::recordSpaceShortage(LayoutUnit spaceShortage) |  144 void RenderMultiColumnSet::recordSpaceShortage(LayoutUnit offsetInFlowThread, La
     youtUnit spaceShortage) | 
|  276 { |  145 { | 
|  277     if (spaceShortage >= m_minSpaceShortage) |  146     fragmentainerGroupAtFlowThreadOffset(offsetInFlowThread).recordSpaceShortage
     (spaceShortage); | 
|  278         return; |  | 
|  279  |  | 
|  280     // The space shortage is what we use as our stretch amount. We need a positi
     ve number here in |  | 
|  281     // order to get anywhere. |  | 
|  282     ASSERT(spaceShortage > 0); |  | 
|  283  |  | 
|  284     m_minSpaceShortage = spaceShortage; |  | 
|  285 } |  147 } | 
|  286  |  148  | 
|  287 void RenderMultiColumnSet::resetColumnHeight() |  149 void RenderMultiColumnSet::resetColumnHeight() | 
|  288 { |  150 { | 
|  289     // Nuke previously stored minimum column height. Contents may have changed f
     or all we know. |  151     m_fragmentainerGroups.deleteExtraGroups(); | 
|  290     m_minimumColumnHeight = 0; |  152     m_fragmentainerGroups.first().resetColumnHeight(); | 
 |  153 } | 
|  291  |  154  | 
|  292     m_maxColumnHeight = calculateMaxColumnHeight(); |  155 void RenderMultiColumnSet::beginFlow(LayoutUnit offsetInFlowThread) | 
 |  156 { | 
 |  157     // At this point layout is exactly at the beginning of this set. Store block
      offset from flow | 
 |  158     // thread start. | 
 |  159     m_fragmentainerGroups.first().setLogicalTopInFlowThread(offsetInFlowThread); | 
 |  160 } | 
|  293  |  161  | 
|  294     LayoutUnit oldColumnHeight = pageLogicalHeight(); |  162 void RenderMultiColumnSet::endFlow(LayoutUnit offsetInFlowThread) | 
|  295  |  163 { | 
|  296     if (heightIsAuto()) |  164     // At this point layout is exactly at the end of this set. Store block offse
     t from flow thread | 
|  297         m_columnHeight = 0; |  165     // start. This set is now considered "flowed", although we may have to revis
     it it later (with | 
|  298     else |  166     // beginFlow()), e.g. if a subtree in the flow thread has to be laid out ove
     r again because the | 
|  299         setAndConstrainColumnHeight(heightAdjustedForSetOffset(multiColumnFlowTh
     read()->columnHeightAvailable())); |  167     // initial margin collapsing estimates were wrong. | 
|  300  |  168     m_fragmentainerGroups.last().setLogicalBottomInFlowThread(offsetInFlowThread
     ); | 
|  301     if (pageLogicalHeight() != oldColumnHeight) |  | 
|  302         setChildNeedsLayout(MarkOnlyThis); |  | 
|  303  |  | 
|  304     // Content runs are only needed in the initial layout pass, in order to find
      an initial column |  | 
|  305     // height, and should have been deleted afterwards. We're about to rebuild t
     he content runs, so |  | 
|  306     // the list needs to be empty. |  | 
|  307     ASSERT(m_contentRuns.isEmpty()); |  | 
|  308 } |  169 } | 
|  309  |  170  | 
|  310 void RenderMultiColumnSet::expandToEncompassFlowThreadContentsIfNeeded() |  171 void RenderMultiColumnSet::expandToEncompassFlowThreadContentsIfNeeded() | 
|  311 { |  172 { | 
|  312     ASSERT(multiColumnFlowThread()->lastMultiColumnSet() == this); |  173     ASSERT(multiColumnFlowThread()->lastMultiColumnSet() == this); | 
|  313     LayoutRect rect(flowThreadPortionRect()); |  174     // FIXME: this may result in the need for creating additional rows, since th
     ere may not be | 
|  314  |  175     // enough space remaining in the currently last row. | 
|  315     // Get the offset within the flow thread in its block progression direction.
      Then get the |  176     m_fragmentainerGroups.last().expandToEncompassFlowThreadOverflow(); | 
|  316     // flow thread's remaining logical height including its overflow and expand 
     our rect |  | 
|  317     // to encompass that remaining height and overflow. The idea is that we will
      generate |  | 
|  318     // additional columns and pages to hold that overflow, since people do write
      bad |  | 
|  319     // content like <body style="height:0px"> in multi-column layouts. |  | 
|  320     bool isHorizontal = flowThread()->isHorizontalWritingMode(); |  | 
|  321     LayoutUnit logicalTopOffset = isHorizontal ? rect.y() : rect.x(); |  | 
|  322     LayoutRect layoutRect = flowThread()->layoutOverflowRect(); |  | 
|  323     LayoutUnit logicalHeightWithOverflow = (isHorizontal ? layoutRect.maxY() : l
     ayoutRect.maxX()) - logicalTopOffset; |  | 
|  324     setFlowThreadPortionRect(LayoutRect(rect.x(), rect.y(), isHorizontal ? rect.
     width() : logicalHeightWithOverflow, isHorizontal ? logicalHeightWithOverflow : 
     rect.height())); |  | 
|  325 } |  177 } | 
|  326  |  178  | 
|  327 void RenderMultiColumnSet::computeLogicalHeight(LayoutUnit, LayoutUnit logicalTo
     p, LogicalExtentComputedValues& computedValues) const |  179 void RenderMultiColumnSet::computeLogicalHeight(LayoutUnit, LayoutUnit logicalTo
     p, LogicalExtentComputedValues& computedValues) const | 
|  328 { |  180 { | 
|  329     computedValues.m_extent = m_columnHeight; |  181     LayoutUnit logicalHeight; | 
 |  182     for (const auto& group : m_fragmentainerGroups) | 
 |  183         logicalHeight += group.logicalHeight(); | 
 |  184     computedValues.m_extent = logicalHeight; | 
|  330     computedValues.m_position = logicalTop; |  185     computedValues.m_position = logicalTop; | 
|  331 } |  186 } | 
|  332  |  187  | 
|  333 LayoutUnit RenderMultiColumnSet::calculateMaxColumnHeight() const |  | 
|  334 { |  | 
|  335     RenderBlockFlow* multicolBlock = multiColumnBlockFlow(); |  | 
|  336     const LayoutStyle& multicolStyle = multicolBlock->styleRef(); |  | 
|  337     LayoutUnit availableHeight = multiColumnFlowThread()->columnHeightAvailable(
     ); |  | 
|  338     LayoutUnit maxColumnHeight = availableHeight ? availableHeight : RenderFlowT
     hread::maxLogicalHeight(); |  | 
|  339     if (!multicolStyle.logicalMaxHeight().isMaxSizeNone()) { |  | 
|  340         LayoutUnit logicalMaxHeight = multicolBlock->computeContentLogicalHeight
     (multicolStyle.logicalMaxHeight(), -1); |  | 
|  341         if (logicalMaxHeight != -1 && maxColumnHeight > logicalMaxHeight) |  | 
|  342             maxColumnHeight = logicalMaxHeight; |  | 
|  343     } |  | 
|  344     return heightAdjustedForSetOffset(maxColumnHeight); |  | 
|  345 } |  | 
|  346  |  | 
|  347 LayoutUnit RenderMultiColumnSet::columnGap() const |  188 LayoutUnit RenderMultiColumnSet::columnGap() const | 
|  348 { |  189 { | 
|  349     RenderBlockFlow* parentBlock = multiColumnBlockFlow(); |  190     RenderBlockFlow* parentBlock = multiColumnBlockFlow(); | 
|  350     if (parentBlock->style()->hasNormalColumnGap()) |  191     if (parentBlock->style()->hasNormalColumnGap()) | 
|  351         return parentBlock->style()->fontDescription().computedPixelSize(); // "
     1em" is recommended as the normal gap setting. Matches <p> margins. |  192         return parentBlock->style()->fontDescription().computedPixelSize(); // "
     1em" is recommended as the normal gap setting. Matches <p> margins. | 
|  352     return parentBlock->style()->columnGap(); |  193     return parentBlock->style()->columnGap(); | 
|  353 } |  194 } | 
|  354  |  195  | 
|  355 unsigned RenderMultiColumnSet::actualColumnCount() const |  196 unsigned RenderMultiColumnSet::actualColumnCount() const | 
|  356 { |  197 { | 
|  357     // We must always return a value of 1 or greater. Column count = 0 is a mean
     ingless situation, |  198     // FIXME: remove this method. It's a meaningless question to ask the set "ho
     w many columns do | 
|  358     // and will confuse and cause problems in other parts of the code. |  199     // you actually have?", since that may vary for each row. | 
|  359     if (!pageLogicalHeight()) |  200     return firstFragmentainerGroup().actualColumnCount(); | 
|  360         return 1; |  | 
|  361  |  | 
|  362     // Our portion rect determines our column count. We have as many columns as 
     needed to fit all the content. |  | 
|  363     LayoutUnit logicalHeightInColumns = flowThread()->isHorizontalWritingMode() 
     ? flowThreadPortionRect().height() : flowThreadPortionRect().width(); |  | 
|  364     if (!logicalHeightInColumns) |  | 
|  365         return 1; |  | 
|  366  |  | 
|  367     unsigned count = ceil(logicalHeightInColumns.toFloat() / pageLogicalHeight()
     .toFloat()); |  | 
|  368     ASSERT(count >= 1); |  | 
|  369     return count; |  | 
|  370 } |  | 
|  371  |  | 
|  372 LayoutRect RenderMultiColumnSet::columnRectAt(unsigned index) const |  | 
|  373 { |  | 
|  374     LayoutUnit colLogicalWidth = pageLogicalWidth(); |  | 
|  375     LayoutUnit colLogicalHeight = pageLogicalHeight(); |  | 
|  376     LayoutUnit colLogicalTop = borderBefore() + paddingBefore(); |  | 
|  377     LayoutUnit colLogicalLeft = borderAndPaddingLogicalLeft(); |  | 
|  378     LayoutUnit colGap = columnGap(); |  | 
|  379  |  | 
|  380     if (multiColumnFlowThread()->progressionIsInline()) { |  | 
|  381         if (style()->isLeftToRightDirection()) |  | 
|  382             colLogicalLeft += index * (colLogicalWidth + colGap); |  | 
|  383         else |  | 
|  384             colLogicalLeft += contentLogicalWidth() - colLogicalWidth - index * 
     (colLogicalWidth + colGap); |  | 
|  385     } else { |  | 
|  386         colLogicalTop += index * (colLogicalHeight + colGap); |  | 
|  387     } |  | 
|  388  |  | 
|  389     if (isHorizontalWritingMode()) |  | 
|  390         return LayoutRect(colLogicalLeft, colLogicalTop, colLogicalWidth, colLog
     icalHeight); |  | 
|  391     return LayoutRect(colLogicalTop, colLogicalLeft, colLogicalHeight, colLogica
     lWidth); |  | 
|  392 } |  | 
|  393  |  | 
|  394 unsigned RenderMultiColumnSet::columnIndexAtOffset(LayoutUnit offset, ColumnInde
     xCalculationMode mode) const |  | 
|  395 { |  | 
|  396     LayoutRect portionRect(flowThreadPortionRect()); |  | 
|  397  |  | 
|  398     // Handle the offset being out of range. |  | 
|  399     LayoutUnit flowThreadLogicalTop = isHorizontalWritingMode() ? portionRect.y(
     ) : portionRect.x(); |  | 
|  400     if (offset < flowThreadLogicalTop) |  | 
|  401         return 0; |  | 
|  402     // If we're laying out right now, we cannot constrain against some logical b
     ottom, since it |  | 
|  403     // isn't known yet. Otherwise, just return the last column if we're past the
      logical bottom. |  | 
|  404     if (mode == ClampToExistingColumns) { |  | 
|  405         LayoutUnit flowThreadLogicalBottom = isHorizontalWritingMode() ? portion
     Rect.maxY() : portionRect.maxX(); |  | 
|  406         if (offset >= flowThreadLogicalBottom) |  | 
|  407             return actualColumnCount() - 1; |  | 
|  408     } |  | 
|  409  |  | 
|  410     if (LayoutUnit pageLogicalHeight = this->pageLogicalHeight()) |  | 
|  411         return (offset - flowThreadLogicalTop).toFloat() / pageLogicalHeight.toF
     loat(); |  | 
|  412  |  | 
|  413     return 0; |  | 
|  414 } |  | 
|  415  |  | 
|  416 LayoutRect RenderMultiColumnSet::flowThreadPortionRectAt(unsigned index) const |  | 
|  417 { |  | 
|  418     LayoutRect portionRect = flowThreadPortionRect(); |  | 
|  419     if (isHorizontalWritingMode()) |  | 
|  420         portionRect = LayoutRect(portionRect.x(), portionRect.y() + index * page
     LogicalHeight(), portionRect.width(), pageLogicalHeight()); |  | 
|  421     else |  | 
|  422         portionRect = LayoutRect(portionRect.x() + index * pageLogicalHeight(), 
     portionRect.y(), pageLogicalHeight(), portionRect.height()); |  | 
|  423     return portionRect; |  | 
|  424 } |  | 
|  425  |  | 
|  426 LayoutRect RenderMultiColumnSet::flowThreadPortionOverflowRect(const LayoutRect&
      portionRect, unsigned index, unsigned colCount, LayoutUnit colGap) const |  | 
|  427 { |  | 
|  428     // This function determines the portion of the flow thread that paints for t
     he column. Along the inline axis, columns are |  | 
|  429     // unclipped at outside edges (i.e., the first and last column in the set), 
     and they clip to half the column |  | 
|  430     // gap along interior edges. |  | 
|  431     // |  | 
|  432     // In the block direction, we will not clip overflow out of the top of the f
     irst column, or out of the bottom of |  | 
|  433     // the last column. This applies only to the true first column and last colu
     mn across all column sets. |  | 
|  434     // |  | 
|  435     // FIXME: Eventually we will know overflow on a per-column basis, but we can
     't do this until we have a painting |  | 
|  436     // mode that understands not to paint contents from a previous column in the
      overflow area of a following column. |  | 
|  437     // This problem applies to regions and pages as well and is not unique to co
     lumns. |  | 
|  438     bool isFirstColumn = !index; |  | 
|  439     bool isLastColumn = index == colCount - 1; |  | 
|  440     bool isLeftmostColumn = style()->isLeftToRightDirection() ? isFirstColumn : 
     isLastColumn; |  | 
|  441     bool isRightmostColumn = style()->isLeftToRightDirection() ? isLastColumn : 
     isFirstColumn; |  | 
|  442  |  | 
|  443     // Calculate the overflow rectangle, based on the flow thread's, clipped at 
     column logical |  | 
|  444     // top/bottom unless it's the first/last column. |  | 
|  445     LayoutRect overflowRect = overflowRectForFlowThreadPortion(portionRect, isFi
     rstColumn && isFirstRegion(), isLastColumn && isLastRegion()); |  | 
|  446  |  | 
|  447     // Avoid overflowing into neighboring columns, by clipping in the middle of 
     adjacent column |  | 
|  448     // gaps. Also make sure that we avoid rounding errors. |  | 
|  449     if (isHorizontalWritingMode()) { |  | 
|  450         if (!isLeftmostColumn) |  | 
|  451             overflowRect.shiftXEdgeTo(portionRect.x() - colGap / 2); |  | 
|  452         if (!isRightmostColumn) |  | 
|  453             overflowRect.shiftMaxXEdgeTo(portionRect.maxX() + colGap - colGap / 
     2); |  | 
|  454     } else { |  | 
|  455         if (!isLeftmostColumn) |  | 
|  456             overflowRect.shiftYEdgeTo(portionRect.y() - colGap / 2); |  | 
|  457         if (!isRightmostColumn) |  | 
|  458             overflowRect.shiftMaxYEdgeTo(portionRect.maxY() + colGap - colGap / 
     2); |  | 
|  459     } |  | 
|  460     return overflowRect; |  | 
|  461 } |  201 } | 
|  462  |  202  | 
|  463 void RenderMultiColumnSet::paintObject(const PaintInfo& paintInfo, const LayoutP
     oint& paintOffset) |  203 void RenderMultiColumnSet::paintObject(const PaintInfo& paintInfo, const LayoutP
     oint& paintOffset) | 
|  464 { |  204 { | 
|  465     MultiColumnSetPainter(*this).paintObject(paintInfo, paintOffset); |  205     MultiColumnSetPainter(*this).paintObject(paintInfo, paintOffset); | 
|  466 } |  206 } | 
|  467  |  207  | 
|  468 void RenderMultiColumnSet::collectLayerFragments(LayerFragments& fragments, cons
     t LayoutRect& layerBoundingBox, const LayoutRect& dirtyRect) |  208 void RenderMultiColumnSet::collectLayerFragments(LayerFragments& fragments, cons
     t LayoutRect& layerBoundingBox, const LayoutRect& dirtyRect) | 
|  469 { |  209 { | 
|  470     // |layerBoundingBox| is in the flow thread coordinate space, relative to th
     e top/left edge of |  210     for (const auto& group : m_fragmentainerGroups) | 
|  471     // the flow thread, but note that it has been converted with respect to writ
     ing mode (so that |  211         group.collectLayerFragments(fragments, layerBoundingBox, dirtyRect); | 
|  472     // it's visual/physical in that sense). |  | 
|  473     // |  | 
|  474     // |dirtyRect| is visual, relative to the multicol container. |  | 
|  475     // |  | 
|  476     // Then there's the output from this method - the stuff we put into the list
      of fragments. The |  | 
|  477     // fragment.paginationOffset point is the actual visual translation required
      to get from a |  | 
|  478     // location in the flow thread to a location in a given column. The fragment
     .paginationClip |  | 
|  479     // rectangle, on the other hand, is in flow thread coordinates. |  | 
|  480     // |  | 
|  481     // All other rectangles in this method are sized physically, and the inline 
     direction coordinate |  | 
|  482     // is physical too, but the block direction coordinate is "logical top". Thi
     s is the same as |  | 
|  483     // e.g. RenderBox::frameRect(). These rectangles also pretend that there's o
     nly one long column, |  | 
|  484     // i.e. they are for the flow thread. |  | 
|  485  |  | 
|  486     // Put the layer bounds into flow thread-local coordinates by flipping it fi
     rst. Since we're in |  | 
|  487     // a renderer, most rectangles are represented this way. |  | 
|  488     LayoutRect layerBoundsInFlowThread(layerBoundingBox); |  | 
|  489     flowThread()->flipForWritingMode(layerBoundsInFlowThread); |  | 
|  490  |  | 
|  491     // Now we can compare with the flow thread portions owned by each column. Fi
     rst let's |  | 
|  492     // see if the rect intersects our flow thread portion at all. |  | 
|  493     LayoutRect clippedRect(layerBoundsInFlowThread); |  | 
|  494     clippedRect.intersect(RenderRegion::flowThreadPortionOverflowRect()); |  | 
|  495     if (clippedRect.isEmpty()) |  | 
|  496         return; |  | 
|  497  |  | 
|  498     // Now we know we intersect at least one column. Let's figure out the logica
     l top and logical |  | 
|  499     // bottom of the area we're checking. |  | 
|  500     LayoutUnit layerLogicalTop = isHorizontalWritingMode() ? layerBoundsInFlowTh
     read.y() : layerBoundsInFlowThread.x(); |  | 
|  501     LayoutUnit layerLogicalBottom = (isHorizontalWritingMode() ? layerBoundsInFl
     owThread.maxY() : layerBoundsInFlowThread.maxX()) - 1; |  | 
|  502  |  | 
|  503     // Figure out the start and end columns and only check within that range so 
     that we don't walk the |  | 
|  504     // entire column set. |  | 
|  505     unsigned startColumn = columnIndexAtOffset(layerLogicalTop); |  | 
|  506     unsigned endColumn = columnIndexAtOffset(layerLogicalBottom); |  | 
|  507  |  | 
|  508     LayoutUnit colLogicalWidth = pageLogicalWidth(); |  | 
|  509     LayoutUnit colGap = columnGap(); |  | 
|  510     unsigned colCount = actualColumnCount(); |  | 
|  511  |  | 
|  512     RenderMultiColumnFlowThread* flowThread = multiColumnFlowThread(); |  | 
|  513     bool progressionIsInline = flowThread->progressionIsInline(); |  | 
|  514     bool leftToRight = style()->isLeftToRightDirection(); |  | 
|  515  |  | 
|  516     LayoutUnit initialBlockOffset = logicalTop() - flowThread->logicalTop(); |  | 
|  517  |  | 
|  518     for (unsigned i = startColumn; i <= endColumn; i++) { |  | 
|  519         // Get the portion of the flow thread that corresponds to this column. |  | 
|  520         LayoutRect flowThreadPortion = flowThreadPortionRectAt(i); |  | 
|  521  |  | 
|  522         // Now get the overflow rect that corresponds to the column. |  | 
|  523         LayoutRect flowThreadOverflowPortion = flowThreadPortionOverflowRect(flo
     wThreadPortion, i, colCount, colGap); |  | 
|  524  |  | 
|  525         // In order to create a fragment we must intersect the portion painted b
     y this column. |  | 
|  526         LayoutRect clippedRect(layerBoundsInFlowThread); |  | 
|  527         clippedRect.intersect(flowThreadOverflowPortion); |  | 
|  528         if (clippedRect.isEmpty()) |  | 
|  529             continue; |  | 
|  530  |  | 
|  531         // We also need to intersect the dirty rect. We have to apply a translat
     ion and shift based off |  | 
|  532         // our column index. |  | 
|  533         LayoutPoint translationOffset; |  | 
|  534         LayoutUnit inlineOffset = progressionIsInline ? i * (colLogicalWidth + c
     olGap) : LayoutUnit(); |  | 
|  535         if (!leftToRight) |  | 
|  536             inlineOffset = -inlineOffset; |  | 
|  537         translationOffset.setX(inlineOffset); |  | 
|  538         LayoutUnit blockOffset; |  | 
|  539         if (progressionIsInline) { |  | 
|  540             blockOffset = initialBlockOffset + (isHorizontalWritingMode() ? -flo
     wThreadPortion.y() : -flowThreadPortion.x()); |  | 
|  541         } else { |  | 
|  542             // Column gap can apply in the block direction for page fragmentaine
     rs. |  | 
|  543             // There is currently no spec which calls for column-gap to apply |  | 
|  544             // for page fragmentainers at all, but it's applied here for compati
     bility |  | 
|  545             // with the old multicolumn implementation. |  | 
|  546             blockOffset = i * colGap; |  | 
|  547         } |  | 
|  548         if (isFlippedBlocksWritingMode(style()->writingMode())) |  | 
|  549             blockOffset = -blockOffset; |  | 
|  550         translationOffset.setY(blockOffset); |  | 
|  551         if (!isHorizontalWritingMode()) |  | 
|  552             translationOffset = translationOffset.transposedPoint(); |  | 
|  553         // FIXME: The translation needs to include the multicolumn set's content
      offset within the |  | 
|  554         // multicolumn block as well. This won't be an issue until we start crea
     ting multiple multicolumn sets. |  | 
|  555  |  | 
|  556         // Shift the dirty rect to be in flow thread coordinates with this trans
     lation applied. |  | 
|  557         LayoutRect translatedDirtyRect(dirtyRect); |  | 
|  558         translatedDirtyRect.moveBy(-translationOffset); |  | 
|  559  |  | 
|  560         // See if we intersect the dirty rect. |  | 
|  561         clippedRect = layerBoundingBox; |  | 
|  562         clippedRect.intersect(translatedDirtyRect); |  | 
|  563         if (clippedRect.isEmpty()) |  | 
|  564             continue; |  | 
|  565  |  | 
|  566         // Something does need to paint in this column. Make a fragment now and 
     supply the physical translation |  | 
|  567         // offset and the clip rect for the column with that offset applied. |  | 
|  568         LayerFragment fragment; |  | 
|  569         fragment.paginationOffset = translationOffset; |  | 
|  570  |  | 
|  571         LayoutRect flippedFlowThreadOverflowPortion(flowThreadOverflowPortion); |  | 
|  572         // Flip it into more a physical (Layer-style) rectangle. |  | 
|  573         flowThread->flipForWritingMode(flippedFlowThreadOverflowPortion); |  | 
|  574         fragment.paginationClip = flippedFlowThreadOverflowPortion; |  | 
|  575         fragments.append(fragment); |  | 
|  576     } |  | 
|  577 } |  212 } | 
|  578  |  213  | 
|  579 void RenderMultiColumnSet::addOverflowFromChildren() |  214 void RenderMultiColumnSet::addOverflowFromChildren() | 
|  580 { |  215 { | 
|  581     unsigned colCount = actualColumnCount(); |  216     LayoutRect overflowRect; | 
|  582     if (!colCount) |  217     for (const auto& group : m_fragmentainerGroups) { | 
|  583         return; |  218         LayoutRect rect = group.calculateOverflow(); | 
|  584  |  219         rect.move(group.offsetFromColumnSet()); | 
|  585     LayoutRect lastRect = columnRectAt(colCount - 1); |  220         overflowRect.unite(rect); | 
|  586     addLayoutOverflow(lastRect); |  221     } | 
 |  222     addLayoutOverflow(overflowRect); | 
|  587     if (!hasOverflowClip()) |  223     if (!hasOverflowClip()) | 
|  588         addVisualOverflow(lastRect); |  224         addVisualOverflow(overflowRect); | 
|  589 } |  225 } | 
|  590  |  226  | 
|  591 const char* RenderMultiColumnSet::renderName() const |  227 const char* RenderMultiColumnSet::renderName() const | 
|  592 { |  228 { | 
|  593     return "RenderMultiColumnSet"; |  229     return "RenderMultiColumnSet"; | 
|  594 } |  230 } | 
|  595  |  231  | 
|  596 void RenderMultiColumnSet::insertedIntoTree() |  232 void RenderMultiColumnSet::insertedIntoTree() | 
|  597 { |  233 { | 
|  598     RenderRegion::insertedIntoTree(); |  234     RenderRegion::insertedIntoTree(); | 
| (...skipping 24 matching lines...) Expand all  Loading... | 
|  623 } |  259 } | 
|  624  |  260  | 
|  625 void RenderMultiColumnSet::detachRegion() |  261 void RenderMultiColumnSet::detachRegion() | 
|  626 { |  262 { | 
|  627     if (m_flowThread) { |  263     if (m_flowThread) { | 
|  628         m_flowThread->removeRegionFromThread(this); |  264         m_flowThread->removeRegionFromThread(this); | 
|  629         m_flowThread = 0; |  265         m_flowThread = 0; | 
|  630     } |  266     } | 
|  631 } |  267 } | 
|  632  |  268  | 
 |  269 LayoutRect RenderMultiColumnSet::flowThreadPortionRect() const | 
 |  270 { | 
 |  271     LayoutRect portionRect(LayoutUnit(), logicalTopInFlowThread(), pageLogicalWi
     dth(), logicalHeightInFlowThread()); | 
 |  272     if (!isHorizontalWritingMode()) | 
 |  273         return portionRect.transposedRect(); | 
 |  274     return portionRect; | 
|  633 } |  275 } | 
 |  276  | 
 |  277 } | 
| OLD | NEW |