Upstream version 7.36.149.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/frame/FrameView.h"
11 #include "core/frame/LocalFrame.h"
12 #include "core/frame/Settings.h"
13 #include "core/html/HTMLCanvasElement.h"
14 #include "core/html/HTMLIFrameElement.h"
15 #include "core/html/HTMLMediaElement.h"
16 #include "core/html/canvas/CanvasRenderingContext.h"
17 #include "core/page/Chrome.h"
18 #include "core/page/Page.h"
19 #include "core/rendering/RenderApplet.h"
20 #include "core/rendering/RenderEmbeddedObject.h"
21 #include "core/rendering/RenderFullScreen.h"
22 #include "core/rendering/RenderGeometryMap.h"
23 #include "core/rendering/RenderIFrame.h"
24 #include "core/rendering/RenderLayer.h"
25 #include "core/rendering/RenderLayerStackingNode.h"
26 #include "core/rendering/RenderLayerStackingNodeIterator.h"
27 #include "core/rendering/RenderReplica.h"
28 #include "core/rendering/RenderVideo.h"
29 #include "core/rendering/RenderView.h"
30 #include "core/rendering/compositing/RenderLayerCompositor.h"
31
32 namespace WebCore {
33
34 CompositingReasonFinder::CompositingReasonFinder(RenderView& renderView)
35     : m_renderView(renderView)
36     , m_compositingTriggers(static_cast<CompositingTriggerFlags>(AllCompositingTriggers))
37 {
38     updateTriggers();
39 }
40
41 void CompositingReasonFinder::updateTriggers()
42 {
43     m_compositingTriggers = 0;
44
45     Settings& settings = m_renderView.document().page()->settings();
46     if (settings.acceleratedCompositingForVideoEnabled())
47         m_compositingTriggers |= VideoTrigger;
48     if (settings.acceleratedCompositingForCanvasEnabled())
49         m_compositingTriggers |= CanvasTrigger;
50     if (settings.compositedScrollingForFramesEnabled())
51         m_compositingTriggers |= ScrollableInnerFrameTrigger;
52     if (settings.acceleratedCompositingForFiltersEnabled())
53         m_compositingTriggers |= FilterTrigger;
54
55     // We map both these settings to universal overlow scrolling.
56     // FIXME: Replace these settings with a generic compositing setting for HighDPI.
57     if (settings.acceleratedCompositingForOverflowScrollEnabled() || settings.compositorDrivenAcceleratedScrollingEnabled())
58         m_compositingTriggers |= OverflowScrollTrigger;
59
60     // FIXME: acceleratedCompositingForFixedPositionEnabled should be renamed acceleratedCompositingForViewportConstrainedPositionEnabled().
61     // Or the sticky and fixed position elements should be behind different flags.
62     if (settings.acceleratedCompositingForFixedPositionEnabled())
63         m_compositingTriggers |= ViewportConstrainedPositionedTrigger;
64 }
65
66 bool CompositingReasonFinder::hasOverflowScrollTrigger() const
67 {
68     return m_compositingTriggers & OverflowScrollTrigger;
69 }
70
71 // FIXME: This is a temporary trigger for enabling the old, opt-in path for
72 // accelerated overflow scroll. It should be removed once the "universal"
73 // path is ready (crbug.com/254111).
74 bool CompositingReasonFinder::hasLegacyOverflowScrollTrigger() const
75 {
76     return m_compositingTriggers & LegacyOverflowScrollTrigger;
77 }
78
79 bool CompositingReasonFinder::isMainFrame() const
80 {
81     // FIXME: LocalFrame::isMainFrame() is probably better.
82     return !m_renderView.document().ownerElement();
83 }
84
85 CompositingReasons CompositingReasonFinder::directReasons(const RenderLayer* layer, bool* needToRecomputeCompositingRequirements) const
86 {
87     CompositingReasons styleReasons = layer->styleDeterminedCompositingReasons();
88     ASSERT(styleDeterminedReasons(layer->renderer()) == styleReasons);
89     return styleReasons | nonStyleDeterminedDirectReasons(layer, needToRecomputeCompositingRequirements);
90 }
91
92 // This information doesn't appear to be incorporated into CompositingReasons.
93 bool CompositingReasonFinder::requiresCompositingForScrollableFrame() const
94 {
95     // Need this done first to determine overflow.
96     ASSERT(!m_renderView.needsLayout());
97     if (isMainFrame())
98         return false;
99
100     if (!(m_compositingTriggers & ScrollableInnerFrameTrigger))
101         return false;
102
103     FrameView* frameView = m_renderView.frameView();
104     return frameView->isScrollable();
105 }
106
107 CompositingReasons CompositingReasonFinder::styleDeterminedReasons(RenderObject* renderer) const
108 {
109     CompositingReasons directReasons = CompositingReasonNone;
110
111     if (requiresCompositingForTransform(renderer))
112         directReasons |= CompositingReason3DTransform;
113
114     if (requiresCompositingForBackfaceVisibilityHidden(renderer))
115         directReasons |= CompositingReasonBackfaceVisibilityHidden;
116
117     if (requiresCompositingForAnimation(renderer))
118         directReasons |= CompositingReasonActiveAnimation;
119
120     if (requiresCompositingForFilters(renderer))
121         directReasons |= CompositingReasonFilters;
122
123     if (requiresCompositingForWillChangeCompositingHint(renderer))
124         directReasons |= CompositingReasonWillChangeCompositingHint;
125
126     ASSERT(!(directReasons & ~CompositingReasonComboAllStyleDeterminedReasons));
127     return directReasons;
128 }
129
130 bool CompositingReasonFinder::requiresCompositingForTransform(RenderObject* renderer) const
131 {
132     // Note that we ask the renderer if it has a transform, because the style may have transforms,
133     // but the renderer may be an inline that doesn't suppport them.
134     return renderer->hasTransform() && renderer->style()->transform().has3DOperation();
135 }
136
137 bool CompositingReasonFinder::requiresCompositingForBackfaceVisibilityHidden(RenderObject* renderer) const
138 {
139     return renderer->style()->backfaceVisibility() == BackfaceVisibilityHidden;
140 }
141
142 bool CompositingReasonFinder::requiresCompositingForFilters(RenderObject* renderer) const
143 {
144     if (!(m_compositingTriggers & FilterTrigger))
145         return false;
146
147     return renderer->hasFilter();
148 }
149
150 bool CompositingReasonFinder::requiresCompositingForWillChangeCompositingHint(const RenderObject* renderer) const
151 {
152     return renderer->style()->hasWillChangeCompositingHint();
153 }
154
155 CompositingReasons CompositingReasonFinder::nonStyleDeterminedDirectReasons(const RenderLayer* layer, bool* needToRecomputeCompositingRequirements) const
156 {
157     CompositingReasons directReasons = CompositingReasonNone;
158     RenderObject* renderer = layer->renderer();
159
160     if (hasOverflowScrollTrigger()) {
161         if (requiresCompositingForOutOfFlowClipping(layer))
162             directReasons |= CompositingReasonOutOfFlowClipping;
163
164         if (requiresCompositingForOverflowScrollingParent(layer))
165             directReasons |= CompositingReasonOverflowScrollingParent;
166     }
167
168     if (requiresCompositingForOverflowScrolling(layer))
169         directReasons |= CompositingReasonOverflowScrollingTouch;
170
171     if (requiresCompositingForPositionSticky(renderer, layer))
172         directReasons |= CompositingReasonPositionSticky;
173
174     if (requiresCompositingForPositionFixed(renderer, layer, 0, needToRecomputeCompositingRequirements))
175         directReasons |= CompositingReasonPositionFixed;
176
177     directReasons |= renderer->additionalCompositingReasons(m_compositingTriggers);
178
179     ASSERT(!(directReasons & CompositingReasonComboAllStyleDeterminedReasons));
180     return directReasons;
181 }
182
183 bool CompositingReasonFinder::requiresCompositingForAnimation(RenderObject* renderer) const
184 {
185     return renderer->style()->shouldCompositeForCurrentAnimations();
186 }
187
188 bool CompositingReasonFinder::requiresCompositingForOutOfFlowClipping(const RenderLayer* layer) const
189 {
190     return layer->isUnclippedDescendant();
191 }
192
193 bool CompositingReasonFinder::requiresCompositingForOverflowScrollingParent(const RenderLayer* layer) const
194 {
195     if (!hasOverflowScrollTrigger())
196         return false;
197     return layer->scrollParent();
198 }
199
200 bool CompositingReasonFinder::requiresCompositingForOverflowScrolling(const RenderLayer* layer) const
201 {
202     return layer->needsCompositedScrolling();
203 }
204
205 bool CompositingReasonFinder::requiresCompositingForPosition(RenderObject* renderer, const RenderLayer* layer, RenderLayer::ViewportConstrainedNotCompositedReason* viewportConstrainedNotCompositedReason, bool* needToRecomputeCompositingRequirements) const
206 {
207     return requiresCompositingForPositionSticky(renderer, layer) || requiresCompositingForPositionFixed(renderer, layer, viewportConstrainedNotCompositedReason, needToRecomputeCompositingRequirements);
208 }
209
210 bool CompositingReasonFinder::requiresCompositingForPositionSticky(RenderObject* renderer, const RenderLayer* layer) const
211 {
212     if (!(m_compositingTriggers & ViewportConstrainedPositionedTrigger))
213         return false;
214     if (renderer->style()->position() != StickyPosition)
215         return false;
216     // FIXME: This probably isn't correct for accelerated overflow scrolling. crbug.com/361723
217     // Instead it should return false only if the layer is not inside a scrollable region.
218     return !layer->enclosingOverflowClipLayer(ExcludeSelf);
219 }
220
221 bool CompositingReasonFinder::requiresCompositingForPositionFixed(RenderObject* renderer, const RenderLayer* layer, RenderLayer::ViewportConstrainedNotCompositedReason* viewportConstrainedNotCompositedReason, bool* needToRecomputeCompositingRequirements) const
222 {
223     if (!(m_compositingTriggers & ViewportConstrainedPositionedTrigger))
224         return false;
225
226     if (renderer->style()->position() != FixedPosition)
227         return false;
228
229     RenderObject* container = renderer->container();
230     // If the renderer is not hooked up yet then we have to wait until it is.
231     if (!container) {
232         *needToRecomputeCompositingRequirements = true;
233         return false;
234     }
235
236     // Don't promote fixed position elements that are descendants of a non-view container, e.g. transformed elements.
237     // They will stay fixed wrt the container rather than the enclosing frame.
238     if (container != &m_renderView) {
239         if (viewportConstrainedNotCompositedReason)
240             *viewportConstrainedNotCompositedReason = RenderLayer::NotCompositedForNonViewContainer;
241         return false;
242     }
243
244     // If the fixed-position element does not have any scrollable ancestor between it and
245     // its container, then we do not need to spend compositor resources for it. Start by
246     // assuming we can opt-out (i.e. no scrollable ancestor), and refine the answer below.
247     bool hasScrollableAncestor = false;
248
249     // The FrameView has the scrollbars associated with the top level viewport, so we have to
250     // check the FrameView in addition to the hierarchy of ancestors.
251     FrameView* frameView = m_renderView.frameView();
252     if (frameView && frameView->isScrollable())
253         hasScrollableAncestor = true;
254
255     RenderLayer* ancestor = layer->parent();
256     while (ancestor && !hasScrollableAncestor) {
257         if (ancestor->scrollsOverflow())
258             hasScrollableAncestor = true;
259         if (ancestor->renderer() == &m_renderView)
260             break;
261         ancestor = ancestor->parent();
262     }
263
264     if (!hasScrollableAncestor) {
265         if (viewportConstrainedNotCompositedReason)
266             *viewportConstrainedNotCompositedReason = RenderLayer::NotCompositedForUnscrollableAncestors;
267         return false;
268     }
269
270     // Subsequent tests depend on layout. If we can't tell now, just keep things the way they are until layout is done.
271     if (m_renderView.document().lifecycle().state() < DocumentLifecycle::LayoutClean) {
272         *needToRecomputeCompositingRequirements = true;
273         return layer->hasCompositedLayerMapping();
274     }
275
276     bool paintsContent = layer->isVisuallyNonEmpty() || layer->hasVisibleDescendant();
277     if (!paintsContent) {
278         if (viewportConstrainedNotCompositedReason)
279             *viewportConstrainedNotCompositedReason = RenderLayer::NotCompositedForNoVisibleContent;
280         return false;
281     }
282
283     // Fixed position elements that are invisible in the current view don't get their own layer.
284     if (FrameView* frameView = m_renderView.frameView()) {
285         LayoutRect viewBounds = frameView->viewportConstrainedVisibleContentRect();
286         LayoutRect layerBounds = layer->boundingBoxForCompositing(layer->compositor()->rootRenderLayer(), RenderLayer::ApplyBoundsChickenEggHacks);
287         if (!viewBounds.intersects(enclosingIntRect(layerBounds))) {
288             if (viewportConstrainedNotCompositedReason) {
289                 *viewportConstrainedNotCompositedReason = RenderLayer::NotCompositedForBoundsOutOfView;
290                 *needToRecomputeCompositingRequirements = true;
291             }
292             return false;
293         }
294     }
295
296     return true;
297 }
298
299 }