1/* 2 * Copyright (C) 2007, 2013 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 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. 24 */ 25 26#include "config.h" 27#include "LayoutState.h" 28 29#include "RenderFlowThread.h" 30#include "RenderInline.h" 31#include "RenderLayer.h" 32#include "RenderMultiColumnFlowThread.h" 33#include "RenderView.h" 34 35namespace WebCore { 36 37LayoutState::LayoutState(std::unique_ptr<LayoutState> next, RenderBox* renderer, const LayoutSize& offset, LayoutUnit pageLogicalHeight, bool pageLogicalHeightChanged) 38 : m_lineGrid(0) 39 , m_next(WTF::move(next)) 40#ifndef NDEBUG 41 , m_renderer(renderer) 42#endif 43{ 44 ASSERT(m_next); 45 46 bool fixed = renderer->isOutOfFlowPositioned() && renderer->style().position() == FixedPosition; 47 if (fixed) { 48 // FIXME: This doesn't work correctly with transforms. 49 FloatPoint fixedOffset = renderer->view().localToAbsolute(FloatPoint(), IsFixed); 50 m_paintOffset = LayoutSize(fixedOffset.x(), fixedOffset.y()) + offset; 51 } else 52 m_paintOffset = m_next->m_paintOffset + offset; 53 54 if (renderer->isOutOfFlowPositioned() && !fixed) { 55 if (RenderElement* container = renderer->container()) { 56 if (container->isInFlowPositioned() && container->isRenderInline()) 57 m_paintOffset += toRenderInline(container)->offsetForInFlowPositionedInline(renderer); 58 } 59 } 60 61 m_layoutOffset = m_paintOffset; 62 63 if (renderer->isInFlowPositioned() && renderer->hasLayer()) 64 m_paintOffset += renderer->layer()->offsetForInFlowPosition(); 65 66 m_clipped = !fixed && m_next->m_clipped; 67 if (m_clipped) 68 m_clipRect = m_next->m_clipRect; 69 70 if (renderer->hasOverflowClip()) { 71 LayoutRect clipRect(toLayoutPoint(m_paintOffset) + renderer->view().layoutDelta(), renderer->cachedSizeForOverflowClip()); 72 if (m_clipped) 73 m_clipRect.intersect(clipRect); 74 else { 75 m_clipRect = clipRect; 76 m_clipped = true; 77 } 78 79 m_paintOffset -= renderer->scrolledContentOffset(); 80 } 81 82 // If we establish a new page height, then cache the offset to the top of the first page. 83 // We can compare this later on to figure out what part of the page we're actually on, 84 if (pageLogicalHeight || renderer->isRenderFlowThread()) { 85 m_pageLogicalHeight = pageLogicalHeight; 86 bool isFlipped = renderer->style().isFlippedBlocksWritingMode(); 87 m_pageOffset = LayoutSize(m_layoutOffset.width() + (!isFlipped ? renderer->borderLeft() + renderer->paddingLeft() : renderer->borderRight() + renderer->paddingRight()), 88 m_layoutOffset.height() + (!isFlipped ? renderer->borderTop() + renderer->paddingTop() : renderer->borderBottom() + renderer->paddingBottom())); 89 m_pageLogicalHeightChanged = pageLogicalHeightChanged; 90 m_isPaginated = true; 91 } else { 92 // If we don't establish a new page height, then propagate the old page height and offset down. 93 m_pageLogicalHeight = m_next->m_pageLogicalHeight; 94 m_pageLogicalHeightChanged = m_next->m_pageLogicalHeightChanged; 95 m_pageOffset = m_next->m_pageOffset; 96 97 // Disable pagination for objects we don't support. For now this includes overflow:scroll/auto, inline blocks and 98 // writing mode roots. 99 if (renderer->isUnsplittableForPagination()) { 100 m_pageLogicalHeight = 0; 101 m_isPaginated = false; 102 } else 103 m_isPaginated = m_pageLogicalHeight || renderer->flowThreadContainingBlock(); 104 } 105 106 // Propagate line grid information. 107 propagateLineGridInfo(renderer); 108 109 m_layoutDelta = m_next->m_layoutDelta; 110#if !ASSERT_DISABLED && ENABLE(SATURATED_LAYOUT_ARITHMETIC) 111 m_layoutDeltaXSaturated = m_next->m_layoutDeltaXSaturated; 112 m_layoutDeltaYSaturated = m_next->m_layoutDeltaYSaturated; 113#endif 114 115 if (lineGrid() && (lineGrid()->style().writingMode() == renderer->style().writingMode()) && renderer->isRenderMultiColumnFlowThread()) 116 toRenderMultiColumnFlowThread(renderer)->computeLineGridPaginationOrigin(*this); 117 118 // If we have a new grid to track, then add it to our set. 119 if (renderer->style().lineGrid() != RenderStyle::initialLineGrid() && renderer->isRenderBlockFlow()) 120 establishLineGrid(toRenderBlockFlow(renderer)); 121 122 // FIXME: <http://bugs.webkit.org/show_bug.cgi?id=13443> Apply control clip if present. 123} 124 125LayoutState::LayoutState(RenderObject& root) 126 : m_clipped(false) 127 , m_isPaginated(false) 128 , m_pageLogicalHeightChanged(false) 129#if !ASSERT_DISABLED && ENABLE(SATURATED_LAYOUT_ARITHMETIC) 130 , m_layoutDeltaXSaturated(false) 131 , m_layoutDeltaYSaturated(false) 132#endif 133 , m_lineGrid(0) 134 , m_pageLogicalHeight(0) 135#ifndef NDEBUG 136 , m_renderer(&root) 137#endif 138{ 139 RenderElement* container = root.container(); 140 FloatPoint absContentPoint = container->localToAbsolute(FloatPoint(), UseTransforms); 141 m_paintOffset = LayoutSize(absContentPoint.x(), absContentPoint.y()); 142 143 if (container->hasOverflowClip()) { 144 m_clipped = true; 145 RenderBox* containerBox = toRenderBox(container); 146 m_clipRect = LayoutRect(toLayoutPoint(m_paintOffset), containerBox->cachedSizeForOverflowClip()); 147 m_paintOffset -= containerBox->scrolledContentOffset(); 148 } 149} 150void LayoutState::clearPaginationInformation() 151{ 152 m_pageLogicalHeight = m_next->m_pageLogicalHeight; 153 m_pageOffset = m_next->m_pageOffset; 154} 155 156LayoutUnit LayoutState::pageLogicalOffset(RenderBox* child, LayoutUnit childLogicalOffset) const 157{ 158 if (child->isHorizontalWritingMode()) 159 return m_layoutOffset.height() + childLogicalOffset - m_pageOffset.height(); 160 return m_layoutOffset.width() + childLogicalOffset - m_pageOffset.width(); 161} 162 163void LayoutState::propagateLineGridInfo(RenderBox* renderer) 164{ 165 // Disable line grids for objects we don't support. For now this includes overflow:scroll/auto, inline blocks and 166 // writing mode roots. 167 if (!m_next || renderer->isUnsplittableForPagination()) 168 return; 169 170 m_lineGrid = m_next->m_lineGrid; 171 m_lineGridOffset = m_next->m_lineGridOffset; 172 m_lineGridPaginationOrigin = m_next->m_lineGridPaginationOrigin; 173} 174 175void LayoutState::establishLineGrid(RenderBlockFlow* block) 176{ 177 // First check to see if this grid has been established already. 178 if (m_lineGrid) { 179 if (m_lineGrid->style().lineGrid() == block->style().lineGrid()) 180 return; 181 RenderBlockFlow* currentGrid = m_lineGrid; 182 for (LayoutState* currentState = m_next.get(); currentState; currentState = currentState->m_next.get()) { 183 if (currentState->m_lineGrid == currentGrid) 184 continue; 185 currentGrid = currentState->m_lineGrid; 186 if (!currentGrid) 187 break; 188 if (currentGrid->style().lineGrid() == block->style().lineGrid()) { 189 m_lineGrid = currentGrid; 190 m_lineGridOffset = currentState->m_lineGridOffset; 191 return; 192 } 193 } 194 } 195 196 // We didn't find an already-established grid with this identifier. Our render object establishes the grid. 197 m_lineGrid = block; 198 m_lineGridOffset = m_layoutOffset; 199} 200 201} // namespace WebCore 202