Fix the issue that Web Audio test case fails on PR3.
[framework/web/webkit-efl.git] / Source / WebCore / rendering / RenderGeometryMap.cpp
1 /*
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
29 #include "RenderLayer.h"
30 #include "RenderView.h"
31 #include "TransformState.h"
32 #include <wtf/TemporaryChange.h>
33
34 namespace WebCore {
35
36 RenderGeometryMap::RenderGeometryMap()
37     : m_insertionPosition(notFound)
38     , m_nonUniformStepsCount(0)
39     , m_transformedStepsCount(0)
40     , m_fixedStepsCount(0)
41 {
42 }
43
44 RenderGeometryMap::~RenderGeometryMap()
45 {
46 }
47
48 FloatPoint 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
61     FloatPoint rendererMappedResult = m_mapping.last().m_renderer->localToAbsolute(p, false, true);
62     ASSERT(rendererMappedResult == result);
63 #endif
64
65     return result;
66 }
67
68 FloatRect 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 {
76         TransformState transformState(TransformState::ApplyTransformDirection, rect.center(), rect);
77         mapToAbsolute(transformState);
78         result = transformState.lastPlanarQuad().boundingBox();
79     }
80
81 #if !ASSERT_DISABLED
82     FloatRect rendererMappedResult = m_mapping.last().m_renderer->localToAbsoluteQuad(rect).boundingBox();
83     // 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
91 void RenderGeometryMap::mapToAbsolute(TransformState& transformState) const
92 {
93     // If the mapping includes something like columns, we have to go via renderers.
94     if (hasNonUniformStep()) {
95         bool fixed = false;
96         m_mapping.last().m_renderer->mapLocalToContainer(0, fixed, true, transformState, RenderObject::ApplyContainerFlip);
97         return;
98     }
99     
100     bool inFixed = false;
101
102     for (int i = m_mapping.size() - 1; i >= 0; --i) {
103         const RenderGeometryMapStep& currentStep = m_mapping[i];
104
105         // If this box has a transform, it acts as a fixed position container
106         // for fixed descendants, which prevents the propagation of 'fixed'
107         // unless the layer itself is also fixed position.
108         if (currentStep.m_hasTransform && !currentStep.m_isFixedPosition)
109             inFixed = false;
110         else if (currentStep.m_isFixedPosition)
111             inFixed = true;
112
113         if (!i) {
114             if (currentStep.m_transform)
115                 transformState.applyTransform(*currentStep.m_transform.get());
116
117             // The root gets special treatment for fixed position
118             if (inFixed)
119                 transformState.move(currentStep.m_offset.width(), currentStep.m_offset.height());
120         } else {
121             TransformState::TransformAccumulation accumulate = currentStep.m_accumulatingTransform ? TransformState::AccumulateTransform : TransformState::FlattenTransform;
122             if (currentStep.m_transform)
123                 transformState.applyTransform(*currentStep.m_transform.get(), accumulate);
124             else
125                 transformState.move(currentStep.m_offset.width(), currentStep.m_offset.height(), accumulate);
126         }
127     }
128
129     transformState.flatten();    
130 }
131
132 void RenderGeometryMap::pushMappingsToAncestor(const RenderObject* renderer, const RenderBoxModelObject* ancestorRenderer)
133 {
134     // We need to push mappings in reverse order here, so do insertions rather than appends.
135     TemporaryChange<size_t> positionChange(m_insertionPosition, m_mapping.size());
136     do {
137         renderer = renderer->pushMappingToContainer(ancestorRenderer, *this);
138     } while (renderer && renderer != ancestorRenderer);
139
140     ASSERT(m_mapping.isEmpty() || m_mapping[0].m_renderer->isRenderView());
141 }
142
143 static bool canMapViaLayer(const RenderLayer* layer)
144 {
145     RenderStyle* style = layer->renderer()->style();
146     if (style->position() == FixedPosition || style->isFlippedBlocksWritingMode())
147         return false;
148     
149     if (layer->renderer()->hasColumns() || layer->renderer()->hasTransform())
150         return false;
151
152 #if ENABLE(SVG)
153     if (layer->renderer()->isSVGRoot())
154         return false;
155 #endif
156
157     return true;
158 }
159
160 void RenderGeometryMap::pushMappingsToAncestor(const RenderLayer* layer, const RenderLayer* ancestorLayer)
161 {
162     const RenderObject* renderer = layer->renderer();
163
164     // The simple case can be handled fast in the layer tree.
165     bool canConvertInLayerTree = ancestorLayer ? canMapViaLayer(ancestorLayer) : false;
166     for (const RenderLayer* current = layer; current != ancestorLayer && canConvertInLayerTree; current = current->parent())
167         canConvertInLayerTree = canMapViaLayer(current);
168
169     if (canConvertInLayerTree) {
170         TemporaryChange<size_t> positionChange(m_insertionPosition, m_mapping.size());
171         LayoutPoint layerOffset;
172         layer->convertToLayerCoords(ancestorLayer, layerOffset);
173         push(renderer, toLayoutSize(layerOffset), /*accumulatingTransform*/ true, /*isNonUniform*/ false, /*isFixedPosition*/ false, /*hasTransform*/ false);
174         return;
175     }
176     const RenderBoxModelObject* ancestorRenderer = ancestorLayer ? ancestorLayer->renderer() : 0;
177     pushMappingsToAncestor(renderer, ancestorRenderer);
178 }
179
180 void RenderGeometryMap::push(const RenderObject* renderer, const LayoutSize& offsetFromContainer, bool accumulatingTransform, bool isNonUniform, bool isFixedPosition, bool hasTransform)
181 {
182     ASSERT(m_insertionPosition != notFound);
183
184     m_mapping.insert(m_insertionPosition, RenderGeometryMapStep(renderer, accumulatingTransform, isNonUniform, isFixedPosition, hasTransform));
185
186     RenderGeometryMapStep& step = m_mapping[m_insertionPosition];
187     step.m_offset = offsetFromContainer;
188
189     stepInserted(step);
190 }
191
192 void RenderGeometryMap::push(const RenderObject* renderer, const TransformationMatrix& t, bool accumulatingTransform, bool isNonUniform, bool isFixedPosition, bool hasTransform)
193 {
194     ASSERT(m_insertionPosition != notFound);
195
196     m_mapping.insert(m_insertionPosition, RenderGeometryMapStep(renderer, accumulatingTransform, isNonUniform, isFixedPosition, hasTransform));
197     
198     RenderGeometryMapStep& step = m_mapping[m_insertionPosition];
199     if (!t.isIntegerTranslation())
200         step.m_transform = adoptPtr(new TransformationMatrix(t));
201     else
202         step.m_offset = LayoutSize(t.e(), t.f());
203
204     stepInserted(step);
205 }
206
207 void RenderGeometryMap::pushView(const RenderView* view, const LayoutSize& scrollOffset, const TransformationMatrix* t)
208 {
209     ASSERT(m_insertionPosition != notFound);
210     ASSERT(!m_insertionPosition); // The view should always be the first step.
211
212     m_mapping.insert(m_insertionPosition, RenderGeometryMapStep(view, false, false, false, t));
213     
214     RenderGeometryMapStep& step = m_mapping[m_insertionPosition];
215     step.m_offset = scrollOffset;
216     if (t)
217         step.m_transform = adoptPtr(new TransformationMatrix(*t));
218     
219     stepInserted(step);
220 }
221
222 void RenderGeometryMap::popMappingsToAncestor(const RenderBoxModelObject* ancestorRenderer)
223 {
224     ASSERT(m_mapping.size());
225
226     while (m_mapping.size() && m_mapping.last().m_renderer != ancestorRenderer) {
227         stepRemoved(m_mapping.last());
228         m_mapping.removeLast();
229     }
230 }
231
232 void RenderGeometryMap::popMappingsToAncestor(const RenderLayer* ancestorLayer)
233 {
234     const RenderBoxModelObject* ancestorRenderer = ancestorLayer ? ancestorLayer->renderer() : 0;
235     popMappingsToAncestor(ancestorRenderer);
236 }
237
238 void RenderGeometryMap::stepInserted(const RenderGeometryMapStep& step)
239 {
240     // RenderView's offset, is only applied when we have fixed-positions.
241     if (!step.m_renderer->isRenderView())
242         m_accumulatedOffset += step.m_offset;
243
244     if (step.m_isNonUniform)
245         ++m_nonUniformStepsCount;
246
247     if (step.m_transform)
248         ++m_transformedStepsCount;
249     
250     if (step.m_isFixedPosition)
251         ++m_fixedStepsCount;
252 }
253
254 void RenderGeometryMap::stepRemoved(const RenderGeometryMapStep& step)
255 {
256     // RenderView's offset, is only applied when we have fixed-positions.
257     if (!step.m_renderer->isRenderView())
258         m_accumulatedOffset -= step.m_offset;
259
260     if (step.m_isNonUniform) {
261         ASSERT(m_nonUniformStepsCount);
262         --m_nonUniformStepsCount;
263     }
264
265     if (step.m_transform) {
266         ASSERT(m_transformedStepsCount);
267         --m_transformedStepsCount;
268     }
269
270     if (step.m_isFixedPosition) {
271         ASSERT(m_fixedStepsCount);
272         --m_fixedStepsCount;
273     }
274 }
275
276 } // namespace WebCore