blob: edf59787c5c98ea8f9fef4251a971eb5427f8304 [file] [log] [blame]
simon.fraser@apple.comca41ec62012-05-25 21:42:32 +00001/*
2 * Copyright (C) 2012 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 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.
24 */
25
26#include "config.h"
27#include "RenderGeometryMap.h"
28
antti@apple.com308c6052012-06-25 00:14:23 +000029#include "RenderLayer.h"
simon.fraser@apple.comca41ec62012-05-25 21:42:32 +000030#include "RenderView.h"
31#include "TransformState.h"
antti@apple.com308c6052012-06-25 00:14:23 +000032#include <wtf/TemporaryChange.h>
simon.fraser@apple.comca41ec62012-05-25 21:42:32 +000033
34namespace WebCore {
35
simon.fraser@apple.comca41ec62012-05-25 21:42:32 +000036RenderGeometryMap::RenderGeometryMap()
37 : m_insertionPosition(notFound)
38 , m_nonUniformStepsCount(0)
39 , m_transformedStepsCount(0)
40 , m_fixedStepsCount(0)
41{
42}
43
44RenderGeometryMap::~RenderGeometryMap()
45{
46}
47
48FloatPoint RenderGeometryMap::absolutePoint(const FloatPoint& p) const
49{
50 FloatPoint result;
51
52 if (!hasFixedPositionStep() && !hasTransformStep() && !hasNonUniformStep())
53 result = p + m_accumulatedOffset;
54 else {
55 TransformState transformState(TransformState::ApplyTransformDirection, p);
56 mapToAbsolute(transformState);
57 result = transformState.lastPlanarPoint();
58 }
59
60#if !ASSERT_DISABLED
antti@apple.com9b9dc6a2012-06-28 18:58:21 +000061 FloatPoint rendererMappedResult = m_mapping.last().m_renderer->localToAbsolute(p, false, true);
simon.fraser@apple.comca41ec62012-05-25 21:42:32 +000062 ASSERT(rendererMappedResult == result);
63#endif
64
65 return result;
66}
67
68FloatRect RenderGeometryMap::absoluteRect(const FloatRect& rect) const
69{
70 FloatRect result;
71
72 if (!hasFixedPositionStep() && !hasTransformStep() && !hasNonUniformStep()) {
73 result = rect;
74 result.move(m_accumulatedOffset);
75 } else {
simon.fraser@apple.com0e7f7d92012-05-27 00:43:12 +000076 TransformState transformState(TransformState::ApplyTransformDirection, rect.center(), rect);
simon.fraser@apple.comca41ec62012-05-25 21:42:32 +000077 mapToAbsolute(transformState);
78 result = transformState.lastPlanarQuad().boundingBox();
79 }
80
81#if !ASSERT_DISABLED
antti@apple.com9b9dc6a2012-06-28 18:58:21 +000082 FloatRect rendererMappedResult = m_mapping.last().m_renderer->localToAbsoluteQuad(rect).boundingBox();
simon.fraser@apple.comca41ec62012-05-25 21:42:32 +000083 // Inspector creates renderers with negative width <https://bugs.webkit.org/show_bug.cgi?id=87194>.
84 // Taking FloatQuad bounds avoids spurious assertions because of that.
85 ASSERT(enclosingIntRect(rendererMappedResult) == enclosingIntRect(FloatQuad(result).boundingBox()));
86#endif
87
88 return result;
89}
90
91void RenderGeometryMap::mapToAbsolute(TransformState& transformState) const
92{
93 // If the mapping includes something like columns, we have to go via renderers.
94 if (hasNonUniformStep()) {
leviw@chromium.org0d464292012-08-03 22:23:42 +000095 m_mapping.last().m_renderer->mapLocalToContainer(0, transformState, UseTransforms | ApplyContainerFlip);
simon.fraser@apple.comca41ec62012-05-25 21:42:32 +000096 return;
97 }
98
99 bool inFixed = false;
100
101 for (int i = m_mapping.size() - 1; i >= 0; --i) {
antti@apple.com9b9dc6a2012-06-28 18:58:21 +0000102 const RenderGeometryMapStep& currentStep = m_mapping[i];
simon.fraser@apple.comca41ec62012-05-25 21:42:32 +0000103
enne@google.comca104612012-05-30 19:51:38 +0000104 // If this box has a transform, it acts as a fixed position container
105 // for fixed descendants, which prevents the propagation of 'fixed'
106 // unless the layer itself is also fixed position.
antti@apple.com9b9dc6a2012-06-28 18:58:21 +0000107 if (currentStep.m_hasTransform && !currentStep.m_isFixedPosition)
enne@google.comca104612012-05-30 19:51:38 +0000108 inFixed = false;
antti@apple.com9b9dc6a2012-06-28 18:58:21 +0000109 else if (currentStep.m_isFixedPosition)
enne@google.comca104612012-05-30 19:51:38 +0000110 inFixed = true;
simon.fraser@apple.comca41ec62012-05-25 21:42:32 +0000111
112 if (!i) {
antti@apple.com9b9dc6a2012-06-28 18:58:21 +0000113 if (currentStep.m_transform)
114 transformState.applyTransform(*currentStep.m_transform.get());
simon.fraser@apple.comca41ec62012-05-25 21:42:32 +0000115
116 // The root gets special treatment for fixed position
117 if (inFixed)
antti@apple.com9b9dc6a2012-06-28 18:58:21 +0000118 transformState.move(currentStep.m_offset.width(), currentStep.m_offset.height());
simon.fraser@apple.comca41ec62012-05-25 21:42:32 +0000119 } else {
antti@apple.com9b9dc6a2012-06-28 18:58:21 +0000120 TransformState::TransformAccumulation accumulate = currentStep.m_accumulatingTransform ? TransformState::AccumulateTransform : TransformState::FlattenTransform;
121 if (currentStep.m_transform)
122 transformState.applyTransform(*currentStep.m_transform.get(), accumulate);
simon.fraser@apple.comca41ec62012-05-25 21:42:32 +0000123 else
antti@apple.com9b9dc6a2012-06-28 18:58:21 +0000124 transformState.move(currentStep.m_offset.width(), currentStep.m_offset.height(), accumulate);
simon.fraser@apple.comca41ec62012-05-25 21:42:32 +0000125 }
126 }
127
128 transformState.flatten();
129}
130
antti@apple.com308c6052012-06-25 00:14:23 +0000131void RenderGeometryMap::pushMappingsToAncestor(const RenderObject* renderer, const RenderBoxModelObject* ancestorRenderer)
simon.fraser@apple.comca41ec62012-05-25 21:42:32 +0000132{
simon.fraser@apple.comca41ec62012-05-25 21:42:32 +0000133 // We need to push mappings in reverse order here, so do insertions rather than appends.
antti@apple.com308c6052012-06-25 00:14:23 +0000134 TemporaryChange<size_t> positionChange(m_insertionPosition, m_mapping.size());
simon.fraser@apple.comca41ec62012-05-25 21:42:32 +0000135 do {
antti@apple.com308c6052012-06-25 00:14:23 +0000136 renderer = renderer->pushMappingToContainer(ancestorRenderer, *this);
137 } while (renderer && renderer != ancestorRenderer);
commit-queue@webkit.orgdfad0c62012-07-14 01:08:07 +0000138
139 ASSERT(m_mapping.isEmpty() || m_mapping[0].m_renderer->isRenderView());
antti@apple.com308c6052012-06-25 00:14:23 +0000140}
141
simon.fraser@apple.com56e37042012-07-11 22:26:55 +0000142static bool canMapViaLayer(const RenderLayer* layer)
143{
144 RenderStyle* style = layer->renderer()->style();
145 if (style->position() == FixedPosition || style->isFlippedBlocksWritingMode())
146 return false;
147
148 if (layer->renderer()->hasColumns() || layer->renderer()->hasTransform())
149 return false;
150
151#if ENABLE(SVG)
152 if (layer->renderer()->isSVGRoot())
153 return false;
154#endif
155
156 return true;
157}
158
antti@apple.com308c6052012-06-25 00:14:23 +0000159void RenderGeometryMap::pushMappingsToAncestor(const RenderLayer* layer, const RenderLayer* ancestorLayer)
160{
161 const RenderObject* renderer = layer->renderer();
162
163 // The simple case can be handled fast in the layer tree.
simon.fraser@apple.com56e37042012-07-11 22:26:55 +0000164 bool canConvertInLayerTree = ancestorLayer ? canMapViaLayer(ancestorLayer) : false;
antti@apple.com308c6052012-06-25 00:14:23 +0000165 for (const RenderLayer* current = layer; current != ancestorLayer && canConvertInLayerTree; current = current->parent())
simon.fraser@apple.com56e37042012-07-11 22:26:55 +0000166 canConvertInLayerTree = canMapViaLayer(current);
antti@apple.com308c6052012-06-25 00:14:23 +0000167
168 if (canConvertInLayerTree) {
169 TemporaryChange<size_t> positionChange(m_insertionPosition, m_mapping.size());
170 LayoutPoint layerOffset;
171 layer->convertToLayerCoords(ancestorLayer, layerOffset);
172 push(renderer, toLayoutSize(layerOffset), /*accumulatingTransform*/ true, /*isNonUniform*/ false, /*isFixedPosition*/ false, /*hasTransform*/ false);
173 return;
174 }
175 const RenderBoxModelObject* ancestorRenderer = ancestorLayer ? ancestorLayer->renderer() : 0;
176 pushMappingsToAncestor(renderer, ancestorRenderer);
simon.fraser@apple.comca41ec62012-05-25 21:42:32 +0000177}
178
179void RenderGeometryMap::push(const RenderObject* renderer, const LayoutSize& offsetFromContainer, bool accumulatingTransform, bool isNonUniform, bool isFixedPosition, bool hasTransform)
180{
181 ASSERT(m_insertionPosition != notFound);
antti@apple.com9b9dc6a2012-06-28 18:58:21 +0000182
183 m_mapping.insert(m_insertionPosition, RenderGeometryMapStep(renderer, accumulatingTransform, isNonUniform, isFixedPosition, hasTransform));
184
185 RenderGeometryMapStep& step = m_mapping[m_insertionPosition];
186 step.m_offset = offsetFromContainer;
187
188 stepInserted(step);
simon.fraser@apple.comca41ec62012-05-25 21:42:32 +0000189}
190
191void RenderGeometryMap::push(const RenderObject* renderer, const TransformationMatrix& t, bool accumulatingTransform, bool isNonUniform, bool isFixedPosition, bool hasTransform)
192{
193 ASSERT(m_insertionPosition != notFound);
194
antti@apple.com9b9dc6a2012-06-28 18:58:21 +0000195 m_mapping.insert(m_insertionPosition, RenderGeometryMapStep(renderer, accumulatingTransform, isNonUniform, isFixedPosition, hasTransform));
simon.fraser@apple.com3ddd0132012-06-27 01:31:22 +0000196
antti@apple.com9b9dc6a2012-06-28 18:58:21 +0000197 RenderGeometryMapStep& step = m_mapping[m_insertionPosition];
198 if (!t.isIntegerTranslation())
199 step.m_transform = adoptPtr(new TransformationMatrix(t));
200 else
201 step.m_offset = LayoutSize(t.e(), t.f());
202
203 stepInserted(step);
simon.fraser@apple.comca41ec62012-05-25 21:42:32 +0000204}
205
206void RenderGeometryMap::pushView(const RenderView* view, const LayoutSize& scrollOffset, const TransformationMatrix* t)
207{
208 ASSERT(m_insertionPosition != notFound);
commit-queue@webkit.orgdfad0c62012-07-14 01:08:07 +0000209 ASSERT(!m_insertionPosition); // The view should always be the first step.
antti@apple.com9b9dc6a2012-06-28 18:58:21 +0000210
211 m_mapping.insert(m_insertionPosition, RenderGeometryMapStep(view, false, false, false, t));
212
213 RenderGeometryMapStep& step = m_mapping[m_insertionPosition];
214 step.m_offset = scrollOffset;
215 if (t)
216 step.m_transform = adoptPtr(new TransformationMatrix(*t));
217
218 stepInserted(step);
simon.fraser@apple.comca41ec62012-05-25 21:42:32 +0000219}
220
antti@apple.com308c6052012-06-25 00:14:23 +0000221void RenderGeometryMap::popMappingsToAncestor(const RenderBoxModelObject* ancestorRenderer)
simon.fraser@apple.comca41ec62012-05-25 21:42:32 +0000222{
223 ASSERT(m_mapping.size());
224
antti@apple.com9b9dc6a2012-06-28 18:58:21 +0000225 while (m_mapping.size() && m_mapping.last().m_renderer != ancestorRenderer) {
226 stepRemoved(m_mapping.last());
simon.fraser@apple.comca41ec62012-05-25 21:42:32 +0000227 m_mapping.removeLast();
228 }
229}
230
antti@apple.com308c6052012-06-25 00:14:23 +0000231void RenderGeometryMap::popMappingsToAncestor(const RenderLayer* ancestorLayer)
232{
233 const RenderBoxModelObject* ancestorRenderer = ancestorLayer ? ancestorLayer->renderer() : 0;
234 popMappingsToAncestor(ancestorRenderer);
235}
236
simon.fraser@apple.comca41ec62012-05-25 21:42:32 +0000237void RenderGeometryMap::stepInserted(const RenderGeometryMapStep& step)
238{
commit-queue@webkit.orgdfad0c62012-07-14 01:08:07 +0000239 // RenderView's offset, is only applied when we have fixed-positions.
240 if (!step.m_renderer->isRenderView())
simon.fraser@apple.comca41ec62012-05-25 21:42:32 +0000241 m_accumulatedOffset += step.m_offset;
242
243 if (step.m_isNonUniform)
244 ++m_nonUniformStepsCount;
245
246 if (step.m_transform)
247 ++m_transformedStepsCount;
248
249 if (step.m_isFixedPosition)
250 ++m_fixedStepsCount;
251}
252
253void RenderGeometryMap::stepRemoved(const RenderGeometryMapStep& step)
254{
commit-queue@webkit.orgdfad0c62012-07-14 01:08:07 +0000255 // RenderView's offset, is only applied when we have fixed-positions.
256 if (!step.m_renderer->isRenderView())
simon.fraser@apple.comca41ec62012-05-25 21:42:32 +0000257 m_accumulatedOffset -= step.m_offset;
258
259 if (step.m_isNonUniform) {
260 ASSERT(m_nonUniformStepsCount);
261 --m_nonUniformStepsCount;
262 }
263
264 if (step.m_transform) {
265 ASSERT(m_transformedStepsCount);
266 --m_transformedStepsCount;
267 }
268
269 if (step.m_isFixedPosition) {
270 ASSERT(m_fixedStepsCount);
271 --m_fixedStepsCount;
272 }
273}
274
275} // namespace WebCore