Move parseFontFaceDescriptor to CSSPropertyParser.cpp
[chromium-blink-merge.git] / third_party / WebKit / Source / core / layout / LayoutGeometryMap.cpp
blobc7dedbb93608fdde59e22e4b9feead9d1eb39cfe
1 /*
2 * Copyright (C) 2012 Apple Inc. All rights reserved.
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.
13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, 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 COMPUTER, 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.
26 #include "config.h"
27 #include "core/layout/LayoutGeometryMap.h"
29 #include "core/frame/LocalFrame.h"
30 #include "core/layout/LayoutView.h"
31 #include "core/paint/DeprecatedPaintLayer.h"
32 #include "platform/geometry/TransformState.h"
33 #include "wtf/TemporaryChange.h"
35 namespace blink {
37 LayoutGeometryMap::LayoutGeometryMap(MapCoordinatesFlags flags)
38 : m_insertionPosition(kNotFound)
39 , m_nonUniformStepsCount(0)
40 , m_transformedStepsCount(0)
41 , m_fixedStepsCount(0)
42 , m_mapCoordinatesFlags(flags)
46 LayoutGeometryMap::~LayoutGeometryMap()
50 void LayoutGeometryMap::mapToContainer(TransformState& transformState, const LayoutBoxModelObject* container) const
52 // If the mapping includes something like columns, we have to go via layoutObjects.
53 if (hasNonUniformStep()) {
54 m_mapping.last().m_layoutObject->mapLocalToContainer(container, transformState, ApplyContainerFlip | m_mapCoordinatesFlags);
55 transformState.flatten();
56 return;
59 bool inFixed = false;
60 #if ENABLE(ASSERT)
61 bool foundContainer = !container || (m_mapping.size() && m_mapping[0].m_layoutObject == container);
62 #endif
64 for (int i = m_mapping.size() - 1; i >= 0; --i) {
65 const LayoutGeometryMapStep& currentStep = m_mapping[i];
67 // If container is the root LayoutView (step 0) we want to apply its fixed position offset.
68 if (i > 0 && currentStep.m_layoutObject == container) {
69 #if ENABLE(ASSERT)
70 foundContainer = true;
71 #endif
72 break;
75 // If this box has a transform, it acts as a fixed position container
76 // for fixed descendants, which prevents the propagation of 'fixed'
77 // unless the layer itself is also fixed position.
78 if (i && currentStep.m_hasTransform && !currentStep.m_isFixedPosition)
79 inFixed = false;
80 else if (currentStep.m_isFixedPosition)
81 inFixed = true;
83 ASSERT(!i == isTopmostLayoutView(currentStep.m_layoutObject));
85 if (!i) {
86 // A null container indicates mapping through the root LayoutView, so including its transform (the page scale).
87 if (!container && currentStep.m_transform)
88 transformState.applyTransform(*currentStep.m_transform.get());
89 } else {
90 TransformState::TransformAccumulation accumulate = currentStep.m_accumulatingTransform ? TransformState::AccumulateTransform : TransformState::FlattenTransform;
91 if (currentStep.m_transform)
92 transformState.applyTransform(*currentStep.m_transform.get(), accumulate);
93 else
94 transformState.move(currentStep.m_offset.width(), currentStep.m_offset.height(), accumulate);
97 if (inFixed && !currentStep.m_offsetForFixedPosition.isZero()) {
98 ASSERT(currentStep.m_layoutObject->isLayoutView());
99 transformState.move(currentStep.m_offsetForFixedPosition);
103 ASSERT(foundContainer);
104 transformState.flatten();
107 FloatPoint LayoutGeometryMap::mapToContainer(const FloatPoint& p, const LayoutBoxModelObject* container) const
109 FloatPoint result;
111 if (!hasFixedPositionStep() && !hasTransformStep() && !hasNonUniformStep() && (!container || (m_mapping.size() && container == m_mapping[0].m_layoutObject))) {
112 result = p + m_accumulatedOffset;
113 } else {
114 TransformState transformState(TransformState::ApplyTransformDirection, p);
115 mapToContainer(transformState, container);
116 result = transformState.lastPlanarPoint();
119 #if ENABLE(ASSERT)
120 if (m_mapping.size() > 0) {
121 const LayoutObject* lastLayoutObject = m_mapping.last().m_layoutObject;
122 const DeprecatedPaintLayer* layer = lastLayoutObject->enclosingLayer();
124 // Bounds for invisible layers are intentionally not calculated, and are
125 // therefore not necessarily expected to be correct here. This is ok,
126 // because they will be recomputed if the layer becomes visible.
127 if (!layer || !layer->subtreeIsInvisible()) {
128 FloatPoint layoutObjectMappedResult = lastLayoutObject->localToContainerPoint(p, container, m_mapCoordinatesFlags);
130 ASSERT(roundedIntPoint(layoutObjectMappedResult) == roundedIntPoint(result));
133 #endif
135 return result;
138 #ifndef NDEBUG
139 // Handy function to call from gdb while debugging mismatched point/rect errors.
140 void LayoutGeometryMap::dumpSteps() const
142 fprintf(stderr, "LayoutGeometryMap::dumpSteps accumulatedOffset=%d,%d\n", m_accumulatedOffset.width().toInt(), m_accumulatedOffset.height().toInt());
143 for (int i = m_mapping.size() - 1; i >= 0; --i) {
144 fprintf(stderr, " [%d] %s: offset=%d,%d", i,
145 m_mapping[i].m_layoutObject->debugName().ascii().data(),
146 m_mapping[i].m_offset.width().toInt(),
147 m_mapping[i].m_offset.height().toInt());
148 if (m_mapping[i].m_hasTransform)
149 fprintf(stderr, " hasTransform");
150 fprintf(stderr, "\n");
153 #endif
155 FloatQuad LayoutGeometryMap::mapToContainer(const FloatRect& rect, const LayoutBoxModelObject* container) const
157 FloatQuad result;
159 if (!hasFixedPositionStep() && !hasTransformStep() && !hasNonUniformStep() && (!container || (m_mapping.size() && container == m_mapping[0].m_layoutObject))) {
160 result = rect;
161 result.move(m_accumulatedOffset);
162 } else {
163 TransformState transformState(TransformState::ApplyTransformDirection, rect.center(), rect);
164 mapToContainer(transformState, container);
165 result = transformState.lastPlanarQuad();
168 #if ENABLE(ASSERT)
169 if (m_mapping.size() > 0) {
170 const LayoutObject* lastLayoutObject = m_mapping.last().m_layoutObject;
171 const DeprecatedPaintLayer* layer = lastLayoutObject->enclosingLayer();
173 // Bounds for invisible layers are intentionally not calculated, and are
174 // therefore not necessarily expected to be correct here. This is ok,
175 // because they will be recomputed if the layer becomes visible.
176 if (!layer->subtreeIsInvisible() && lastLayoutObject->style()->visibility() == VISIBLE) {
177 FloatRect layoutObjectMappedResult = lastLayoutObject->localToContainerQuad(rect, container, m_mapCoordinatesFlags).boundingBox();
179 // Inspector creates layoutObjects with negative width <https://bugs.webkit.org/show_bug.cgi?id=87194>.
180 // Taking FloatQuad bounds avoids spurious assertions because of that.
181 ASSERT(enclosingIntRect(layoutObjectMappedResult) == enclosingIntRect(result.boundingBox()));
184 #endif
186 return result;
189 void LayoutGeometryMap::pushMappingsToAncestor(const LayoutObject* layoutObject, const LayoutBoxModelObject* ancestorLayoutObject)
191 // We need to push mappings in reverse order here, so do insertions rather than appends.
192 TemporaryChange<size_t> positionChange(m_insertionPosition, m_mapping.size());
193 do {
194 layoutObject = layoutObject->pushMappingToContainer(ancestorLayoutObject, *this);
195 } while (layoutObject && layoutObject != ancestorLayoutObject);
197 ASSERT(m_mapping.isEmpty() || isTopmostLayoutView(m_mapping[0].m_layoutObject));
200 static bool canMapBetweenLayoutObjects(const LayoutObject* layoutObject, const LayoutObject* ancestor)
202 for (const LayoutObject* current = layoutObject; ; current = current->parent()) {
203 const ComputedStyle& style = current->styleRef();
204 if (style.position() == FixedPosition || style.isFlippedBlocksWritingMode())
205 return false;
207 if (current->hasTransformRelatedProperty() || current->isLayoutFlowThread() || current->isSVGRoot())
208 return false;
210 if (current == ancestor)
211 break;
214 return true;
217 void LayoutGeometryMap::pushMappingsToAncestor(const DeprecatedPaintLayer* layer, const DeprecatedPaintLayer* ancestorLayer)
219 const LayoutObject* layoutObject = layer->layoutObject();
221 bool crossDocument = ancestorLayer && layer->layoutObject()->frame() != ancestorLayer->layoutObject()->frame();
222 ASSERT(!crossDocument || m_mapCoordinatesFlags & TraverseDocumentBoundaries);
224 // We have to visit all the layoutObjects to detect flipped blocks. This might defeat the gains
225 // from mapping via layers.
226 bool canConvertInLayerTree = (ancestorLayer && !crossDocument) ? canMapBetweenLayoutObjects(layer->layoutObject(), ancestorLayer->layoutObject()) : false;
228 // fprintf(stderr, "LayoutGeometryMap::pushMappingsToAncestor from layer %p to layer %p, canConvertInLayerTree=%d\n", layer, ancestorLayer, canConvertInLayerTree);
230 if (canConvertInLayerTree) {
231 LayoutPoint layerOffset;
232 layer->convertToLayerCoords(ancestorLayer, layerOffset);
234 // The LayoutView must be pushed first.
235 if (!m_mapping.size()) {
236 ASSERT(ancestorLayer->layoutObject()->isLayoutView());
237 pushMappingsToAncestor(ancestorLayer->layoutObject(), 0);
240 TemporaryChange<size_t> positionChange(m_insertionPosition, m_mapping.size());
241 bool accumulatingTransform = layer->layoutObject()->style()->preserves3D() || ancestorLayer->layoutObject()->style()->preserves3D();
242 push(layoutObject, toLayoutSize(layerOffset), accumulatingTransform, /*isNonUniform*/ false, /*isFixedPosition*/ false, /*hasTransform*/ false);
243 return;
245 const LayoutBoxModelObject* ancestorLayoutObject = ancestorLayer ? ancestorLayer->layoutObject() : 0;
246 pushMappingsToAncestor(layoutObject, ancestorLayoutObject);
249 void LayoutGeometryMap::push(const LayoutObject* layoutObject, const LayoutSize& offsetFromContainer, bool accumulatingTransform, bool isNonUniform, bool isFixedPosition, bool hasTransform, LayoutSize offsetForFixedPosition)
251 // fprintf(stderr, "LayoutGeometryMap::push %p %d,%d isNonUniform=%d\n", layoutObject, offsetFromContainer.width().toInt(), offsetFromContainer.height().toInt(), isNonUniform);
253 ASSERT(m_insertionPosition != kNotFound);
254 ASSERT(!layoutObject->isLayoutView() || !m_insertionPosition || m_mapCoordinatesFlags & TraverseDocumentBoundaries);
255 ASSERT(offsetForFixedPosition.isZero() || layoutObject->isLayoutView());
257 m_mapping.insert(m_insertionPosition, LayoutGeometryMapStep(layoutObject, accumulatingTransform, isNonUniform, isFixedPosition, hasTransform));
259 LayoutGeometryMapStep& step = m_mapping[m_insertionPosition];
260 step.m_offset = offsetFromContainer;
261 step.m_offsetForFixedPosition = offsetForFixedPosition;
263 stepInserted(step);
266 void LayoutGeometryMap::push(const LayoutObject* layoutObject, const TransformationMatrix& t, bool accumulatingTransform, bool isNonUniform, bool isFixedPosition, bool hasTransform, LayoutSize offsetForFixedPosition)
268 ASSERT(m_insertionPosition != kNotFound);
269 ASSERT(!layoutObject->isLayoutView() || !m_insertionPosition || m_mapCoordinatesFlags & TraverseDocumentBoundaries);
270 ASSERT(offsetForFixedPosition.isZero() || layoutObject->isLayoutView());
272 m_mapping.insert(m_insertionPosition, LayoutGeometryMapStep(layoutObject, accumulatingTransform, isNonUniform, isFixedPosition, hasTransform));
274 LayoutGeometryMapStep& step = m_mapping[m_insertionPosition];
275 step.m_offsetForFixedPosition = offsetForFixedPosition;
277 if (!t.isIntegerTranslation())
278 step.m_transform = adoptPtr(new TransformationMatrix(t));
279 else
280 step.m_offset = LayoutSize(t.e(), t.f());
282 stepInserted(step);
285 void LayoutGeometryMap::popMappingsToAncestor(const LayoutBoxModelObject* ancestorLayoutObject)
287 ASSERT(m_mapping.size());
289 while (m_mapping.size() && m_mapping.last().m_layoutObject != ancestorLayoutObject) {
290 stepRemoved(m_mapping.last());
291 m_mapping.removeLast();
295 void LayoutGeometryMap::popMappingsToAncestor(const DeprecatedPaintLayer* ancestorLayer)
297 const LayoutBoxModelObject* ancestorLayoutObject = ancestorLayer ? ancestorLayer->layoutObject() : 0;
298 popMappingsToAncestor(ancestorLayoutObject);
301 void LayoutGeometryMap::stepInserted(const LayoutGeometryMapStep& step)
303 m_accumulatedOffset += step.m_offset;
305 if (step.m_isNonUniform)
306 ++m_nonUniformStepsCount;
308 if (step.m_transform)
309 ++m_transformedStepsCount;
311 if (step.m_isFixedPosition)
312 ++m_fixedStepsCount;
315 void LayoutGeometryMap::stepRemoved(const LayoutGeometryMapStep& step)
317 m_accumulatedOffset -= step.m_offset;
319 if (step.m_isNonUniform) {
320 ASSERT(m_nonUniformStepsCount);
321 --m_nonUniformStepsCount;
324 if (step.m_transform) {
325 ASSERT(m_transformedStepsCount);
326 --m_transformedStepsCount;
329 if (step.m_isFixedPosition) {
330 ASSERT(m_fixedStepsCount);
331 --m_fixedStepsCount;
335 #if ENABLE(ASSERT)
336 bool LayoutGeometryMap::isTopmostLayoutView(const LayoutObject* layoutObject) const
338 if (!layoutObject->isLayoutView())
339 return false;
341 // If we're not working with multiple LayoutViews, then any view is considered
342 // "topmost" (to preserve original behavior).
343 if (!(m_mapCoordinatesFlags & TraverseDocumentBoundaries))
344 return true;
346 return layoutObject->frame()->isMainFrame();
348 #endif
350 } // namespace blink