Upstream version 6.35.121.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / rendering / compositing / CompositingReasonFinder.cpp
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "config.h"
6 #include "core/rendering/compositing/CompositingReasonFinder.h"
7
8 #include "CSSPropertyNames.h"
9 #include "HTMLNames.h"
10 #include "core/animation/ActiveAnimations.h"
11 #include "core/frame/FrameView.h"
12 #include "core/frame/LocalFrame.h"
13 #include "core/frame/Settings.h"
14 #include "core/html/HTMLCanvasElement.h"
15 #include "core/html/HTMLIFrameElement.h"
16 #include "core/html/HTMLMediaElement.h"
17 #include "core/html/canvas/CanvasRenderingContext.h"
18 #include "core/page/Chrome.h"
19 #include "core/page/Page.h"
20 #include "core/rendering/RenderApplet.h"
21 #include "core/rendering/RenderEmbeddedObject.h"
22 #include "core/rendering/RenderFullScreen.h"
23 #include "core/rendering/RenderGeometryMap.h"
24 #include "core/rendering/RenderIFrame.h"
25 #include "core/rendering/RenderLayer.h"
26 #include "core/rendering/RenderLayerStackingNode.h"
27 #include "core/rendering/RenderLayerStackingNodeIterator.h"
28 #include "core/rendering/RenderReplica.h"
29 #include "core/rendering/RenderVideo.h"
30 #include "core/rendering/RenderView.h"
31 #include "core/rendering/compositing/RenderLayerCompositor.h"
32
33 namespace WebCore {
34
35 CompositingReasonFinder::CompositingReasonFinder(RenderView& renderView)
36     : m_renderView(renderView)
37     , m_compositingTriggers(static_cast<CompositingTriggerFlags>(AllCompositingTriggers))
38 {
39 }
40
41 void CompositingReasonFinder::updateTriggers()
42 {
43     m_compositingTriggers = m_renderView.document().page()->chrome().client().allowedCompositingTriggers();
44 }
45
46 bool CompositingReasonFinder::has3DTransformTrigger() const
47 {
48     return m_compositingTriggers & ThreeDTransformTrigger;
49 }
50
51 bool CompositingReasonFinder::hasAnimationTrigger() const
52 {
53     return m_compositingTriggers & AnimationTrigger;
54 }
55
56 bool CompositingReasonFinder::isMainFrame() const
57 {
58     // FIXME: LocalFrame::isMainFrame() is probably better.
59     return !m_renderView.document().ownerElement();
60 }
61
62 CompositingReasons CompositingReasonFinder::directReasons(const RenderLayer* layer, bool* needToRecomputeCompositingRequirements) const
63 {
64     CompositingReasons styleReasons = layer->styleDeterminedCompositingReasons();
65     ASSERT(styleDeterminedReasons(layer->renderer()) == styleReasons);
66     return styleReasons | nonStyleDeterminedDirectReasons(layer, needToRecomputeCompositingRequirements);
67 }
68
69 // This information doesn't appear to be incorporated into CompositingReasons.
70 bool CompositingReasonFinder::requiresCompositingForScrollableFrame() const
71 {
72     // Need this done first to determine overflow.
73     ASSERT(!m_renderView.needsLayout());
74     if (isMainFrame())
75         return false;
76
77     if (!(m_compositingTriggers & ScrollableInnerFrameTrigger))
78         return false;
79
80     FrameView* frameView = m_renderView.frameView();
81     return frameView->isScrollable();
82 }
83
84 CompositingReasons CompositingReasonFinder::styleDeterminedReasons(RenderObject* renderer) const
85 {
86     CompositingReasons directReasons = CompositingReasonNone;
87
88     if (requiresCompositingForTransform(renderer))
89         directReasons |= CompositingReason3DTransform;
90
91     if (requiresCompositingForBackfaceVisibilityHidden(renderer))
92         directReasons |= CompositingReasonBackfaceVisibilityHidden;
93
94     if (requiresCompositingForFilters(renderer))
95         directReasons |= CompositingReasonFilters;
96
97     if (requiresCompositingForWillChange(renderer))
98         directReasons |= CompositingReasonWillChange;
99
100     ASSERT(!(directReasons & ~CompositingReasonComboAllStyleDeterminedReasons));
101     return directReasons;
102 }
103
104 bool CompositingReasonFinder::requiresCompositingForTransform(RenderObject* renderer) const
105 {
106     if (!(m_compositingTriggers & ThreeDTransformTrigger))
107         return false;
108
109     // Note that we ask the renderer if it has a transform, because the style may have transforms,
110     // but the renderer may be an inline that doesn't suppport them.
111     return renderer->hasTransform() && renderer->style()->transform().has3DOperation();
112 }
113
114 bool CompositingReasonFinder::requiresCompositingForBackfaceVisibilityHidden(RenderObject* renderer) const
115 {
116     if (!(m_compositingTriggers & ThreeDTransformTrigger))
117         return false;
118
119     return renderer->style()->backfaceVisibility() == BackfaceVisibilityHidden;
120 }
121
122 bool CompositingReasonFinder::requiresCompositingForFilters(RenderObject* renderer) const
123 {
124     if (!(m_compositingTriggers & FilterTrigger))
125         return false;
126
127     return renderer->hasFilter();
128 }
129
130 bool CompositingReasonFinder::requiresCompositingForWillChange(const RenderObject* renderer) const
131 {
132     if (renderer->style()->hasWillChangeCompositingHint())
133         return true;
134
135     if (!(m_compositingTriggers & GPURasterizationTrigger))
136         return false;
137
138     return renderer->style()->hasWillChangeGpuRasterizationHint();
139 }
140
141 CompositingReasons CompositingReasonFinder::nonStyleDeterminedDirectReasons(const RenderLayer* layer, bool* needToRecomputeCompositingRequirements) const
142 {
143     CompositingReasons directReasons = CompositingReasonNone;
144     RenderObject* renderer = layer->renderer();
145
146     if (requiresCompositingForAnimation(renderer))
147         directReasons |= CompositingReasonActiveAnimation;
148
149     if (m_renderView.compositorDrivenAcceleratedScrollingEnabled()) {
150         if (requiresCompositingForOutOfFlowClipping(layer))
151             directReasons |= CompositingReasonOutOfFlowClipping;
152
153         if (requiresCompositingForOverflowScrollingParent(layer))
154             directReasons |= CompositingReasonOverflowScrollingParent;
155     }
156
157     if (requiresCompositingForOverflowScrolling(layer))
158         directReasons |= CompositingReasonOverflowScrollingTouch;
159
160     if (requiresCompositingForPosition(renderer, layer, 0, needToRecomputeCompositingRequirements))
161         directReasons |= renderer->style()->position() == FixedPosition ? CompositingReasonPositionFixed : CompositingReasonPositionSticky;
162
163     directReasons |= renderer->additionalCompositingReasons(m_compositingTriggers);
164
165     ASSERT(!(directReasons & CompositingReasonComboAllStyleDeterminedReasons));
166     return directReasons;
167 }
168
169 bool CompositingReasonFinder::requiresCompositingForAnimation(RenderObject* renderer) const
170 {
171     if (!(m_compositingTriggers & AnimationTrigger))
172         return false;
173
174     return shouldCompositeForActiveAnimations(*renderer);
175 }
176
177 bool CompositingReasonFinder::requiresCompositingForOutOfFlowClipping(const RenderLayer* layer) const
178 {
179     return layer->isUnclippedDescendant();
180 }
181
182 bool CompositingReasonFinder::requiresCompositingForOverflowScrollingParent(const RenderLayer* layer) const
183 {
184     return layer->scrollParent();
185 }
186
187 bool CompositingReasonFinder::requiresCompositingForOverflowScrolling(const RenderLayer* layer) const
188 {
189     return layer->needsCompositedScrolling();
190 }
191
192 bool CompositingReasonFinder::isViewportConstrainedFixedOrStickyLayer(const RenderLayer* layer)
193 {
194     if (layer->renderer()->isStickyPositioned())
195         return !layer->enclosingOverflowClipLayer(ExcludeSelf);
196
197     if (layer->renderer()->style()->position() != FixedPosition)
198         return false;
199
200     for (const RenderLayerStackingNode* stackingContainer = layer->stackingNode(); stackingContainer;
201         stackingContainer = stackingContainer->ancestorStackingContainerNode()) {
202         if (stackingContainer->layer()->compositingState() != NotComposited
203             && stackingContainer->layer()->renderer()->style()->position() == FixedPosition)
204             return false;
205     }
206
207     return true;
208 }
209
210 bool CompositingReasonFinder::requiresCompositingForPosition(RenderObject* renderer, const RenderLayer* layer, RenderLayer::ViewportConstrainedNotCompositedReason* viewportConstrainedNotCompositedReason, bool* needToRecomputeCompositingRequirements) const
211 {
212     // position:fixed elements that create their own stacking context (e.g. have an explicit z-index,
213     // opacity, transform) can get their own composited layer. A stacking context is required otherwise
214     // z-index and clipping will be broken.
215     if (!renderer->isPositioned())
216         return false;
217
218     EPosition position = renderer->style()->position();
219     bool isFixed = renderer->isOutOfFlowPositioned() && position == FixedPosition;
220     // FIXME: The isStackingContainer check here is redundant. Fixed position elements are always stacking contexts.
221     if (isFixed && !layer->stackingNode()->isStackingContainer())
222         return false;
223
224     bool isSticky = renderer->isInFlowPositioned() && position == StickyPosition;
225     if (!isFixed && !isSticky)
226         return false;
227
228     // FIXME: acceleratedCompositingForFixedPositionEnabled should probably be renamed acceleratedCompositingForViewportConstrainedPositionEnabled().
229     if (Settings* settings = m_renderView.document().settings()) {
230         if (!settings->acceleratedCompositingForFixedPositionEnabled())
231             return false;
232     }
233
234     if (isSticky)
235         return isViewportConstrainedFixedOrStickyLayer(layer);
236
237     RenderObject* container = renderer->container();
238     // If the renderer is not hooked up yet then we have to wait until it is.
239     if (!container) {
240         *needToRecomputeCompositingRequirements = true;
241         return false;
242     }
243
244     // Don't promote fixed position elements that are descendants of a non-view container, e.g. transformed elements.
245     // They will stay fixed wrt the container rather than the enclosing frame.
246     if (container != &m_renderView) {
247         if (viewportConstrainedNotCompositedReason)
248             *viewportConstrainedNotCompositedReason = RenderLayer::NotCompositedForNonViewContainer;
249         return false;
250     }
251
252     // If the fixed-position element does not have any scrollable ancestor between it and
253     // its container, then we do not need to spend compositor resources for it. Start by
254     // assuming we can opt-out (i.e. no scrollable ancestor), and refine the answer below.
255     bool hasScrollableAncestor = false;
256
257     // The FrameView has the scrollbars associated with the top level viewport, so we have to
258     // check the FrameView in addition to the hierarchy of ancestors.
259     FrameView* frameView = m_renderView.frameView();
260     if (frameView && frameView->isScrollable())
261         hasScrollableAncestor = true;
262
263     RenderLayer* ancestor = layer->parent();
264     while (ancestor && !hasScrollableAncestor) {
265         if (frameView->containsScrollableArea(ancestor->scrollableArea()))
266             hasScrollableAncestor = true;
267         if (ancestor->renderer() == &m_renderView)
268             break;
269         ancestor = ancestor->parent();
270     }
271
272     if (!hasScrollableAncestor) {
273         if (viewportConstrainedNotCompositedReason)
274             *viewportConstrainedNotCompositedReason = RenderLayer::NotCompositedForUnscrollableAncestors;
275         return false;
276     }
277
278     // Subsequent tests depend on layout. If we can't tell now, just keep things the way they are until layout is done.
279     if (m_renderView.document().lifecycle().state() < DocumentLifecycle::LayoutClean) {
280         *needToRecomputeCompositingRequirements = true;
281         return layer->hasCompositedLayerMapping();
282     }
283
284     bool paintsContent = layer->isVisuallyNonEmpty() || layer->hasVisibleDescendant();
285     if (!paintsContent) {
286         if (viewportConstrainedNotCompositedReason)
287             *viewportConstrainedNotCompositedReason = RenderLayer::NotCompositedForNoVisibleContent;
288         return false;
289     }
290
291     // Fixed position elements that are invisible in the current view don't get their own layer.
292     if (FrameView* frameView = m_renderView.frameView()) {
293         LayoutRect viewBounds = frameView->viewportConstrainedVisibleContentRect();
294         LayoutRect layerBounds = layer->calculateLayerBounds(layer->compositor()->rootRenderLayer(), 0,
295             RenderLayer::DefaultCalculateLayerBoundsFlags
296             | RenderLayer::ExcludeHiddenDescendants
297             | RenderLayer::DontConstrainForMask
298             | RenderLayer::IncludeCompositedDescendants
299             | RenderLayer::PretendLayerHasOwnBacking);
300         if (!viewBounds.intersects(enclosingIntRect(layerBounds))) {
301             if (viewportConstrainedNotCompositedReason) {
302                 *viewportConstrainedNotCompositedReason = RenderLayer::NotCompositedForBoundsOutOfView;
303                 *needToRecomputeCompositingRequirements = true;
304             }
305             return false;
306         }
307     }
308
309     return true;
310 }
311
312 }