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