Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(46)

Side by Side Diff: third_party/WebKit/Source/platform/graphics/compositing/PropertyTreeManager.cpp

Issue 2627113005: Factor PropertyTreeManager out of PaintArtifactCompositor. (Closed)
Patch Set: Sync to head. Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « third_party/WebKit/Source/platform/graphics/compositing/PropertyTreeManager.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2015 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 "platform/graphics/compositing/PropertyTreeManager.h"
6
7 #include "cc/layers/layer.h"
8 #include "cc/trees/clip_node.h"
9 #include "cc/trees/effect_node.h"
10 #include "cc/trees/property_tree.h"
11 #include "cc/trees/scroll_node.h"
12 #include "cc/trees/transform_node.h"
13 #include "platform/graphics/paint/ClipPaintPropertyNode.h"
14 #include "platform/graphics/paint/EffectPaintPropertyNode.h"
15 #include "platform/graphics/paint/ScrollPaintPropertyNode.h"
16 #include "platform/graphics/paint/TransformPaintPropertyNode.h"
17
18 namespace blink {
19
20 namespace {
21
22 static constexpr int kInvalidNodeId = -1;
23 // cc's property trees use 0 for the root node (always non-null).
24 static constexpr int kRealRootNodeId = 0;
25 // cc allocates special nodes for root effects such as the device scale.
26 static constexpr int kSecondaryRootNodeId = 1;
27
28 } // namespace
29
30 PropertyTreeManager::PropertyTreeManager(cc::PropertyTrees& propertyTrees,
31 cc::Layer* rootLayer)
32 : m_propertyTrees(propertyTrees), m_rootLayer(rootLayer) {
33 setupRootTransformNode();
34 setupRootClipNode();
35 setupRootEffectNode();
36 setupRootScrollNode();
37 }
38
39 cc::TransformTree& PropertyTreeManager::transformTree() {
40 return m_propertyTrees.transform_tree;
41 }
42
43 cc::ClipTree& PropertyTreeManager::clipTree() {
44 return m_propertyTrees.clip_tree;
45 }
46
47 cc::EffectTree& PropertyTreeManager::effectTree() {
48 return m_propertyTrees.effect_tree;
49 }
50
51 cc::ScrollTree& PropertyTreeManager::scrollTree() {
52 return m_propertyTrees.scroll_tree;
53 }
54
55 const EffectPaintPropertyNode* PropertyTreeManager::currentEffectNode() const {
56 return m_effectStack.back().effect;
57 }
58
59 void PropertyTreeManager::setupRootTransformNode() {
60 // cc is hardcoded to use transform node index 1 for device scale and
61 // transform.
62 cc::TransformTree& transformTree = m_propertyTrees.transform_tree;
63 transformTree.clear();
64 cc::TransformNode& transformNode = *transformTree.Node(
65 transformTree.Insert(cc::TransformNode(), kRealRootNodeId));
66 DCHECK_EQ(transformNode.id, kSecondaryRootNodeId);
67 transformNode.source_node_id = transformNode.parent_id;
68 transformTree.SetTargetId(transformNode.id, kRealRootNodeId);
69 transformTree.SetContentTargetId(transformNode.id, kRealRootNodeId);
70
71 // TODO(jaydasika): We shouldn't set ToScreen and FromScreen of root
72 // transform node here. They should be set while updating transform tree in
73 // cc.
74 float deviceScaleFactor = m_rootLayer->GetLayerTree()->device_scale_factor();
75 gfx::Transform toScreen;
76 toScreen.Scale(deviceScaleFactor, deviceScaleFactor);
77 transformTree.SetToScreen(kRealRootNodeId, toScreen);
78 gfx::Transform fromScreen;
79 bool invertible = toScreen.GetInverse(&fromScreen);
80 DCHECK(invertible);
81 transformTree.SetFromScreen(kRealRootNodeId, fromScreen);
82 transformTree.set_needs_update(true);
83
84 m_transformNodeMap.set(TransformPaintPropertyNode::root(), transformNode.id);
85 m_rootLayer->SetTransformTreeIndex(transformNode.id);
86 }
87
88 void PropertyTreeManager::setupRootClipNode() {
89 // cc is hardcoded to use clip node index 1 for viewport clip.
90 cc::ClipTree& clipTree = m_propertyTrees.clip_tree;
91 clipTree.clear();
92 m_propertyTrees.layer_id_to_clip_node_index.clear();
93 cc::ClipNode& clipNode =
94 *clipTree.Node(clipTree.Insert(cc::ClipNode(), kRealRootNodeId));
95 DCHECK_EQ(clipNode.id, kSecondaryRootNodeId);
96
97 clipNode.resets_clip = true;
98 clipNode.owning_layer_id = m_rootLayer->id();
99 clipNode.clip_type = cc::ClipNode::ClipType::APPLIES_LOCAL_CLIP;
100 clipNode.clip = gfx::RectF(
101 gfx::SizeF(m_rootLayer->GetLayerTree()->device_viewport_size()));
102 clipNode.transform_id = kRealRootNodeId;
103 clipNode.target_transform_id = kRealRootNodeId;
104 clipNode.target_effect_id = kSecondaryRootNodeId;
105 m_propertyTrees.layer_id_to_clip_node_index[clipNode.owning_layer_id] =
106 clipNode.id;
107
108 m_clipNodeMap.set(ClipPaintPropertyNode::root(), clipNode.id);
109 m_rootLayer->SetClipTreeIndex(clipNode.id);
110 }
111
112 void PropertyTreeManager::setupRootEffectNode() {
113 // cc is hardcoded to use effect node index 1 for root render surface.
114 cc::EffectTree& effectTree = m_propertyTrees.effect_tree;
115 effectTree.clear();
116 m_propertyTrees.layer_id_to_effect_node_index.clear();
117 cc::EffectNode& effectNode =
118 *effectTree.Node(effectTree.Insert(cc::EffectNode(), kInvalidNodeId));
119 DCHECK_EQ(effectNode.id, kSecondaryRootNodeId);
120 effectNode.owning_layer_id = m_rootLayer->id();
121 effectNode.transform_id = kRealRootNodeId;
122 effectNode.clip_id = kSecondaryRootNodeId;
123 effectNode.has_render_surface = true;
124 m_propertyTrees.layer_id_to_effect_node_index[effectNode.owning_layer_id] =
125 effectNode.id;
126
127 m_effectStack.push_back(
128 BlinkEffectAndCcIdPair{EffectPaintPropertyNode::root(), effectNode.id});
129 m_rootLayer->SetEffectTreeIndex(effectNode.id);
130 }
131
132 void PropertyTreeManager::setupRootScrollNode() {
133 cc::ScrollTree& scrollTree = m_propertyTrees.scroll_tree;
134 scrollTree.clear();
135 m_propertyTrees.layer_id_to_scroll_node_index.clear();
136 cc::ScrollNode& scrollNode =
137 *scrollTree.Node(scrollTree.Insert(cc::ScrollNode(), kRealRootNodeId));
138 DCHECK_EQ(scrollNode.id, kSecondaryRootNodeId);
139 scrollNode.owning_layer_id = m_rootLayer->id();
140 scrollNode.transform_id = kSecondaryRootNodeId;
141 m_propertyTrees.layer_id_to_scroll_node_index[scrollNode.owning_layer_id] =
142 scrollNode.id;
143
144 m_scrollNodeMap.set(ScrollPaintPropertyNode::root(), scrollNode.id);
145 m_rootLayer->SetScrollTreeIndex(scrollNode.id);
146 }
147
148 int PropertyTreeManager::ensureCompositorTransformNode(
149 const TransformPaintPropertyNode* transformNode) {
150 DCHECK(transformNode);
151 // TODO(crbug.com/645615): Remove the failsafe here.
152 if (!transformNode)
153 return kSecondaryRootNodeId;
154
155 auto it = m_transformNodeMap.find(transformNode);
156 if (it != m_transformNodeMap.end())
157 return it->value;
158
159 scoped_refptr<cc::Layer> dummyLayer = cc::Layer::Create();
160 int parentId = ensureCompositorTransformNode(transformNode->parent());
161 int id = transformTree().Insert(cc::TransformNode(), parentId);
162
163 cc::TransformNode& compositorNode = *transformTree().Node(id);
164 transformTree().SetTargetId(id, kRealRootNodeId);
165 transformTree().SetContentTargetId(id, kRealRootNodeId);
166 compositorNode.source_node_id = parentId;
167
168 FloatPoint3D origin = transformNode->origin();
169 compositorNode.pre_local.matrix().setTranslate(-origin.x(), -origin.y(),
170 -origin.z());
171 compositorNode.local.matrix() =
172 TransformationMatrix::toSkMatrix44(transformNode->matrix());
173 compositorNode.post_local.matrix().setTranslate(origin.x(), origin.y(),
174 origin.z());
175 compositorNode.needs_local_transform_update = true;
176 compositorNode.flattens_inherited_transform =
177 transformNode->flattensInheritedTransform();
178 compositorNode.sorting_context_id = transformNode->renderingContextId();
179
180 m_rootLayer->AddChild(dummyLayer);
181 dummyLayer->SetTransformTreeIndex(id);
182 dummyLayer->SetClipTreeIndex(kSecondaryRootNodeId);
183 dummyLayer->SetEffectTreeIndex(kSecondaryRootNodeId);
184 dummyLayer->SetScrollTreeIndex(kRealRootNodeId);
185 dummyLayer->set_property_tree_sequence_number(kPropertyTreeSequenceNumber);
186
187 auto result = m_transformNodeMap.set(transformNode, id);
188 DCHECK(result.isNewEntry);
189 transformTree().set_needs_update(true);
190 return id;
191 }
192
193 int PropertyTreeManager::ensureCompositorClipNode(
194 const ClipPaintPropertyNode* clipNode) {
195 DCHECK(clipNode);
196 // TODO(crbug.com/645615): Remove the failsafe here.
197 if (!clipNode)
198 return kSecondaryRootNodeId;
199
200 auto it = m_clipNodeMap.find(clipNode);
201 if (it != m_clipNodeMap.end())
202 return it->value;
203
204 scoped_refptr<cc::Layer> dummyLayer = cc::Layer::Create();
205 int parentId = ensureCompositorClipNode(clipNode->parent());
206 int id = clipTree().Insert(cc::ClipNode(), parentId);
207
208 cc::ClipNode& compositorNode = *clipTree().Node(id);
209 compositorNode.owning_layer_id = dummyLayer->id();
210 m_propertyTrees.layer_id_to_clip_node_index[compositorNode.owning_layer_id] =
211 id;
212
213 // TODO(jbroman): Don't discard rounded corners.
214 compositorNode.clip = clipNode->clipRect().rect();
215 compositorNode.transform_id =
216 ensureCompositorTransformNode(clipNode->localTransformSpace());
217 compositorNode.target_transform_id = kRealRootNodeId;
218 compositorNode.target_effect_id = kSecondaryRootNodeId;
219 compositorNode.clip_type = cc::ClipNode::ClipType::APPLIES_LOCAL_CLIP;
220 compositorNode.layers_are_clipped = true;
221 compositorNode.layers_are_clipped_when_surfaces_disabled = true;
222
223 m_rootLayer->AddChild(dummyLayer);
224 dummyLayer->SetTransformTreeIndex(compositorNode.transform_id);
225 dummyLayer->SetClipTreeIndex(id);
226 dummyLayer->SetEffectTreeIndex(kSecondaryRootNodeId);
227 dummyLayer->SetScrollTreeIndex(kRealRootNodeId);
228 dummyLayer->set_property_tree_sequence_number(kPropertyTreeSequenceNumber);
229
230 auto result = m_clipNodeMap.set(clipNode, id);
231 DCHECK(result.isNewEntry);
232 clipTree().set_needs_update(true);
233 return id;
234 }
235
236 int PropertyTreeManager::ensureCompositorScrollNode(
237 const ScrollPaintPropertyNode* scrollNode) {
238 DCHECK(scrollNode);
239 // TODO(crbug.com/645615): Remove the failsafe here.
240 if (!scrollNode)
241 return kSecondaryRootNodeId;
242
243 auto it = m_scrollNodeMap.find(scrollNode);
244 if (it != m_scrollNodeMap.end())
245 return it->value;
246
247 int parentId = ensureCompositorScrollNode(scrollNode->parent());
248 int id = scrollTree().Insert(cc::ScrollNode(), parentId);
249
250 cc::ScrollNode& compositorNode = *scrollTree().Node(id);
251 compositorNode.owning_layer_id = parentId;
252 m_propertyTrees
253 .layer_id_to_scroll_node_index[compositorNode.owning_layer_id] = id;
254
255 compositorNode.scrollable = true;
256
257 compositorNode.scroll_clip_layer_bounds.SetSize(scrollNode->clip().width(),
258 scrollNode->clip().height());
259 compositorNode.bounds.SetSize(scrollNode->bounds().width(),
260 scrollNode->bounds().height());
261 compositorNode.user_scrollable_horizontal =
262 scrollNode->userScrollableHorizontal();
263 compositorNode.user_scrollable_vertical =
264 scrollNode->userScrollableVertical();
265 compositorNode.transform_id =
266 ensureCompositorTransformNode(scrollNode->scrollOffsetTranslation());
267 compositorNode.main_thread_scrolling_reasons =
268 scrollNode->mainThreadScrollingReasons();
269
270 auto result = m_scrollNodeMap.set(scrollNode, id);
271 DCHECK(result.isNewEntry);
272 scrollTree().set_needs_update(true);
273
274 return id;
275 }
276
277 void PropertyTreeManager::updateScrollOffset(int layerId, int scrollId) {
278 cc::ScrollNode& scrollNode = *scrollTree().Node(scrollId);
279 cc::TransformNode& transformNode =
280 *transformTree().Node(scrollNode.transform_id);
281
282 transformNode.scrolls = true;
283
284 // Blink creates a 2d transform node just for scroll offset whereas cc's
285 // transform node has a special scroll offset field. To handle this we
286 // adjust cc's transform node to remove the 2d scroll translation and
287 // let the cc scroll tree update the cc scroll offset.
288 DCHECK(transformNode.local.IsIdentityOr2DTranslation());
289 auto offset = transformNode.local.To2dTranslation();
290 transformNode.local.MakeIdentity();
291 scrollTree().SetScrollOffset(layerId,
292 gfx::ScrollOffset(-offset.x(), -offset.y()));
293 scrollTree().set_needs_update(true);
294 }
295
296 namespace {
297
298 unsigned depth(const EffectPaintPropertyNode* node) {
299 unsigned result = 0;
300 for (; node; node = node->parent())
301 result++;
302 return result;
303 }
304
305 // TODO(chrishtr): templatize this to avoid duplication of
306 // GeometryMapper::leastCommonAncestor.
307 const EffectPaintPropertyNode* lowestCommonAncestor(
308 const EffectPaintPropertyNode* nodeA,
309 const EffectPaintPropertyNode* nodeB) {
310 // Optimized common case.
311 if (nodeA == nodeB)
312 return nodeA;
313
314 unsigned depthA = depth(nodeA), depthB = depth(nodeB);
315 while (depthA > depthB) {
316 nodeA = nodeA->parent();
317 depthA--;
318 }
319 while (depthB > depthA) {
320 nodeB = nodeB->parent();
321 depthB--;
322 }
323 DCHECK_EQ(depthA, depthB);
324 while (nodeA != nodeB) {
325 nodeA = nodeA->parent();
326 nodeB = nodeB->parent();
327 }
328 return nodeA;
329 }
330
331 } // namespace
332
333 int PropertyTreeManager::switchToEffectNode(
334 const EffectPaintPropertyNode& nextEffect) {
335 const EffectPaintPropertyNode* ancestor =
336 lowestCommonAncestor(currentEffectNode(), &nextEffect);
337 DCHECK(ancestor) << "Malformed effect tree. All nodes must be descendant of "
338 "EffectPaintPropertyNode::root().";
339 while (currentEffectNode() != ancestor)
340 m_effectStack.pop_back();
341
342 // Now the current effect is the lowest common ancestor of previous effect
343 // and the next effect. That implies it is an existing node that already has
344 // at least one paint chunk or child effect, and we are going to either attach
345 // another paint chunk or child effect to it. We can no longer omit render
346 // surface for it even for opacity-only nodes.
347 // See comments in PropertyTreeManager::buildEffectNodesRecursively().
348 // TODO(crbug.com/504464): Remove premature optimization here.
349 if (currentEffectNode() && currentEffectNode()->opacity() != 1.f) {
350 effectTree()
351 .Node(getCurrentCompositorEffectNodeIndex())
352 ->has_render_surface = true;
353 }
354
355 buildEffectNodesRecursively(&nextEffect);
356
357 return getCurrentCompositorEffectNodeIndex();
358 }
359
360 void PropertyTreeManager::buildEffectNodesRecursively(
361 const EffectPaintPropertyNode* nextEffect) {
362 if (nextEffect == currentEffectNode())
363 return;
364 DCHECK(nextEffect);
365
366 buildEffectNodesRecursively(nextEffect->parent());
367 DCHECK_EQ(nextEffect->parent(), currentEffectNode());
368
369 #if DCHECK_IS_ON()
370 DCHECK(!m_effectNodesConverted.contains(nextEffect))
371 << "Malformed paint artifact. Paint chunks under the same effect should "
372 "be contiguous.";
373 m_effectNodesConverted.add(nextEffect);
374 #endif
375
376 // An effect node can't omit render surface if it has child with exotic
377 // blending mode. See comments below for more detail.
378 // TODO(crbug.com/504464): Remove premature optimization here.
379 if (nextEffect->blendMode() != SkBlendMode::kSrcOver) {
380 effectTree()
381 .Node(getCurrentCompositorEffectNodeIndex())
382 ->has_render_surface = true;
383 }
384
385 // We currently create dummy layers to host effect nodes and corresponding
386 // render surfaces. This should be removed once cc implements better support
387 // for freestanding property trees.
388 scoped_refptr<cc::Layer> dummyLayer = nextEffect->ensureDummyLayer();
389 m_rootLayer->AddChild(dummyLayer);
390
391 int outputClipId = ensureCompositorClipNode(nextEffect->outputClip());
392
393 cc::EffectNode& effectNode = *effectTree().Node(effectTree().Insert(
394 cc::EffectNode(), getCurrentCompositorEffectNodeIndex()));
395 effectNode.owning_layer_id = dummyLayer->id();
396 effectNode.clip_id = outputClipId;
397 // Every effect is supposed to have render surface enabled for grouping,
398 // but we can get away without one if the effect is opacity-only and has only
399 // one compositing child with kSrcOver blend mode. This is both for
400 // optimization and not introducing sub-pixel differences in layout tests.
401 // See PropertyTreeManager::switchToEffectNode() and above where we
402 // retrospectively enable render surface when more than one compositing child
403 // or a child with exotic blend mode is detected.
404 // TODO(crbug.com/504464): There is ongoing work in cc to delay render surface
405 // decision until later phase of the pipeline. Remove premature optimization
406 // here once the work is ready.
407 if (!nextEffect->filter().isEmpty() ||
408 nextEffect->blendMode() != SkBlendMode::kSrcOver)
409 effectNode.has_render_surface = true;
410 effectNode.opacity = nextEffect->opacity();
411 effectNode.filters = nextEffect->filter().asCcFilterOperations();
412 effectNode.blend_mode = nextEffect->blendMode();
413 m_propertyTrees.layer_id_to_effect_node_index[effectNode.owning_layer_id] =
414 effectNode.id;
415 m_effectStack.push_back(BlinkEffectAndCcIdPair{nextEffect, effectNode.id});
416
417 dummyLayer->set_property_tree_sequence_number(kPropertyTreeSequenceNumber);
418 dummyLayer->SetTransformTreeIndex(kSecondaryRootNodeId);
419 dummyLayer->SetClipTreeIndex(outputClipId);
420 dummyLayer->SetEffectTreeIndex(effectNode.id);
421 dummyLayer->SetScrollTreeIndex(kRealRootNodeId);
422 }
423
424 } // namespace blink
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/platform/graphics/compositing/PropertyTreeManager.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698