Use is<>() / downcast<>() for all remaining RenderObject subclasses
[WebKit-https.git] / Source / WebCore / rendering / LayoutState.cpp
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
35 namespace WebCore {
36
37 LayoutState::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() && is<RenderInline>(*container))
57                 m_paintOffset += downcast<RenderInline>(*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()) && is<RenderMultiColumnFlowThread>(*renderer))
116         downcast<RenderMultiColumnFlowThread>(*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() && is<RenderBlockFlow>(*renderer))
120         establishLineGrid(downcast<RenderBlockFlow>(renderer));
121
122     // FIXME: <http://bugs.webkit.org/show_bug.cgi?id=13443> Apply control clip if present.
123 }
124
125 LayoutState::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         auto& containerBox = downcast<RenderBox>(*container);
146         m_clipRect = LayoutRect(toLayoutPoint(m_paintOffset), containerBox.cachedSizeForOverflowClip());
147         m_paintOffset -= containerBox.scrolledContentOffset();
148     }
149 }
150 void LayoutState::clearPaginationInformation()
151 {
152     m_pageLogicalHeight = m_next->m_pageLogicalHeight;
153     m_pageOffset = m_next->m_pageOffset;
154 }
155
156 LayoutUnit 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
163 void 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
175 void 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