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

Unified 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 side-by-side diff with in-line comments
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 »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: third_party/WebKit/Source/platform/graphics/compositing/PropertyTreeManager.cpp
diff --git a/third_party/WebKit/Source/platform/graphics/compositing/PropertyTreeManager.cpp b/third_party/WebKit/Source/platform/graphics/compositing/PropertyTreeManager.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..74c6922ce5209069289de634da3bb3f100408f27
--- /dev/null
+++ b/third_party/WebKit/Source/platform/graphics/compositing/PropertyTreeManager.cpp
@@ -0,0 +1,424 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "platform/graphics/compositing/PropertyTreeManager.h"
+
+#include "cc/layers/layer.h"
+#include "cc/trees/clip_node.h"
+#include "cc/trees/effect_node.h"
+#include "cc/trees/property_tree.h"
+#include "cc/trees/scroll_node.h"
+#include "cc/trees/transform_node.h"
+#include "platform/graphics/paint/ClipPaintPropertyNode.h"
+#include "platform/graphics/paint/EffectPaintPropertyNode.h"
+#include "platform/graphics/paint/ScrollPaintPropertyNode.h"
+#include "platform/graphics/paint/TransformPaintPropertyNode.h"
+
+namespace blink {
+
+namespace {
+
+static constexpr int kInvalidNodeId = -1;
+// cc's property trees use 0 for the root node (always non-null).
+static constexpr int kRealRootNodeId = 0;
+// cc allocates special nodes for root effects such as the device scale.
+static constexpr int kSecondaryRootNodeId = 1;
+
+} // namespace
+
+PropertyTreeManager::PropertyTreeManager(cc::PropertyTrees& propertyTrees,
+ cc::Layer* rootLayer)
+ : m_propertyTrees(propertyTrees), m_rootLayer(rootLayer) {
+ setupRootTransformNode();
+ setupRootClipNode();
+ setupRootEffectNode();
+ setupRootScrollNode();
+}
+
+cc::TransformTree& PropertyTreeManager::transformTree() {
+ return m_propertyTrees.transform_tree;
+}
+
+cc::ClipTree& PropertyTreeManager::clipTree() {
+ return m_propertyTrees.clip_tree;
+}
+
+cc::EffectTree& PropertyTreeManager::effectTree() {
+ return m_propertyTrees.effect_tree;
+}
+
+cc::ScrollTree& PropertyTreeManager::scrollTree() {
+ return m_propertyTrees.scroll_tree;
+}
+
+const EffectPaintPropertyNode* PropertyTreeManager::currentEffectNode() const {
+ return m_effectStack.back().effect;
+}
+
+void PropertyTreeManager::setupRootTransformNode() {
+ // cc is hardcoded to use transform node index 1 for device scale and
+ // transform.
+ cc::TransformTree& transformTree = m_propertyTrees.transform_tree;
+ transformTree.clear();
+ cc::TransformNode& transformNode = *transformTree.Node(
+ transformTree.Insert(cc::TransformNode(), kRealRootNodeId));
+ DCHECK_EQ(transformNode.id, kSecondaryRootNodeId);
+ transformNode.source_node_id = transformNode.parent_id;
+ transformTree.SetTargetId(transformNode.id, kRealRootNodeId);
+ transformTree.SetContentTargetId(transformNode.id, kRealRootNodeId);
+
+ // TODO(jaydasika): We shouldn't set ToScreen and FromScreen of root
+ // transform node here. They should be set while updating transform tree in
+ // cc.
+ float deviceScaleFactor = m_rootLayer->GetLayerTree()->device_scale_factor();
+ gfx::Transform toScreen;
+ toScreen.Scale(deviceScaleFactor, deviceScaleFactor);
+ transformTree.SetToScreen(kRealRootNodeId, toScreen);
+ gfx::Transform fromScreen;
+ bool invertible = toScreen.GetInverse(&fromScreen);
+ DCHECK(invertible);
+ transformTree.SetFromScreen(kRealRootNodeId, fromScreen);
+ transformTree.set_needs_update(true);
+
+ m_transformNodeMap.set(TransformPaintPropertyNode::root(), transformNode.id);
+ m_rootLayer->SetTransformTreeIndex(transformNode.id);
+}
+
+void PropertyTreeManager::setupRootClipNode() {
+ // cc is hardcoded to use clip node index 1 for viewport clip.
+ cc::ClipTree& clipTree = m_propertyTrees.clip_tree;
+ clipTree.clear();
+ m_propertyTrees.layer_id_to_clip_node_index.clear();
+ cc::ClipNode& clipNode =
+ *clipTree.Node(clipTree.Insert(cc::ClipNode(), kRealRootNodeId));
+ DCHECK_EQ(clipNode.id, kSecondaryRootNodeId);
+
+ clipNode.resets_clip = true;
+ clipNode.owning_layer_id = m_rootLayer->id();
+ clipNode.clip_type = cc::ClipNode::ClipType::APPLIES_LOCAL_CLIP;
+ clipNode.clip = gfx::RectF(
+ gfx::SizeF(m_rootLayer->GetLayerTree()->device_viewport_size()));
+ clipNode.transform_id = kRealRootNodeId;
+ clipNode.target_transform_id = kRealRootNodeId;
+ clipNode.target_effect_id = kSecondaryRootNodeId;
+ m_propertyTrees.layer_id_to_clip_node_index[clipNode.owning_layer_id] =
+ clipNode.id;
+
+ m_clipNodeMap.set(ClipPaintPropertyNode::root(), clipNode.id);
+ m_rootLayer->SetClipTreeIndex(clipNode.id);
+}
+
+void PropertyTreeManager::setupRootEffectNode() {
+ // cc is hardcoded to use effect node index 1 for root render surface.
+ cc::EffectTree& effectTree = m_propertyTrees.effect_tree;
+ effectTree.clear();
+ m_propertyTrees.layer_id_to_effect_node_index.clear();
+ cc::EffectNode& effectNode =
+ *effectTree.Node(effectTree.Insert(cc::EffectNode(), kInvalidNodeId));
+ DCHECK_EQ(effectNode.id, kSecondaryRootNodeId);
+ effectNode.owning_layer_id = m_rootLayer->id();
+ effectNode.transform_id = kRealRootNodeId;
+ effectNode.clip_id = kSecondaryRootNodeId;
+ effectNode.has_render_surface = true;
+ m_propertyTrees.layer_id_to_effect_node_index[effectNode.owning_layer_id] =
+ effectNode.id;
+
+ m_effectStack.push_back(
+ BlinkEffectAndCcIdPair{EffectPaintPropertyNode::root(), effectNode.id});
+ m_rootLayer->SetEffectTreeIndex(effectNode.id);
+}
+
+void PropertyTreeManager::setupRootScrollNode() {
+ cc::ScrollTree& scrollTree = m_propertyTrees.scroll_tree;
+ scrollTree.clear();
+ m_propertyTrees.layer_id_to_scroll_node_index.clear();
+ cc::ScrollNode& scrollNode =
+ *scrollTree.Node(scrollTree.Insert(cc::ScrollNode(), kRealRootNodeId));
+ DCHECK_EQ(scrollNode.id, kSecondaryRootNodeId);
+ scrollNode.owning_layer_id = m_rootLayer->id();
+ scrollNode.transform_id = kSecondaryRootNodeId;
+ m_propertyTrees.layer_id_to_scroll_node_index[scrollNode.owning_layer_id] =
+ scrollNode.id;
+
+ m_scrollNodeMap.set(ScrollPaintPropertyNode::root(), scrollNode.id);
+ m_rootLayer->SetScrollTreeIndex(scrollNode.id);
+}
+
+int PropertyTreeManager::ensureCompositorTransformNode(
+ const TransformPaintPropertyNode* transformNode) {
+ DCHECK(transformNode);
+ // TODO(crbug.com/645615): Remove the failsafe here.
+ if (!transformNode)
+ return kSecondaryRootNodeId;
+
+ auto it = m_transformNodeMap.find(transformNode);
+ if (it != m_transformNodeMap.end())
+ return it->value;
+
+ scoped_refptr<cc::Layer> dummyLayer = cc::Layer::Create();
+ int parentId = ensureCompositorTransformNode(transformNode->parent());
+ int id = transformTree().Insert(cc::TransformNode(), parentId);
+
+ cc::TransformNode& compositorNode = *transformTree().Node(id);
+ transformTree().SetTargetId(id, kRealRootNodeId);
+ transformTree().SetContentTargetId(id, kRealRootNodeId);
+ compositorNode.source_node_id = parentId;
+
+ FloatPoint3D origin = transformNode->origin();
+ compositorNode.pre_local.matrix().setTranslate(-origin.x(), -origin.y(),
+ -origin.z());
+ compositorNode.local.matrix() =
+ TransformationMatrix::toSkMatrix44(transformNode->matrix());
+ compositorNode.post_local.matrix().setTranslate(origin.x(), origin.y(),
+ origin.z());
+ compositorNode.needs_local_transform_update = true;
+ compositorNode.flattens_inherited_transform =
+ transformNode->flattensInheritedTransform();
+ compositorNode.sorting_context_id = transformNode->renderingContextId();
+
+ m_rootLayer->AddChild(dummyLayer);
+ dummyLayer->SetTransformTreeIndex(id);
+ dummyLayer->SetClipTreeIndex(kSecondaryRootNodeId);
+ dummyLayer->SetEffectTreeIndex(kSecondaryRootNodeId);
+ dummyLayer->SetScrollTreeIndex(kRealRootNodeId);
+ dummyLayer->set_property_tree_sequence_number(kPropertyTreeSequenceNumber);
+
+ auto result = m_transformNodeMap.set(transformNode, id);
+ DCHECK(result.isNewEntry);
+ transformTree().set_needs_update(true);
+ return id;
+}
+
+int PropertyTreeManager::ensureCompositorClipNode(
+ const ClipPaintPropertyNode* clipNode) {
+ DCHECK(clipNode);
+ // TODO(crbug.com/645615): Remove the failsafe here.
+ if (!clipNode)
+ return kSecondaryRootNodeId;
+
+ auto it = m_clipNodeMap.find(clipNode);
+ if (it != m_clipNodeMap.end())
+ return it->value;
+
+ scoped_refptr<cc::Layer> dummyLayer = cc::Layer::Create();
+ int parentId = ensureCompositorClipNode(clipNode->parent());
+ int id = clipTree().Insert(cc::ClipNode(), parentId);
+
+ cc::ClipNode& compositorNode = *clipTree().Node(id);
+ compositorNode.owning_layer_id = dummyLayer->id();
+ m_propertyTrees.layer_id_to_clip_node_index[compositorNode.owning_layer_id] =
+ id;
+
+ // TODO(jbroman): Don't discard rounded corners.
+ compositorNode.clip = clipNode->clipRect().rect();
+ compositorNode.transform_id =
+ ensureCompositorTransformNode(clipNode->localTransformSpace());
+ compositorNode.target_transform_id = kRealRootNodeId;
+ compositorNode.target_effect_id = kSecondaryRootNodeId;
+ compositorNode.clip_type = cc::ClipNode::ClipType::APPLIES_LOCAL_CLIP;
+ compositorNode.layers_are_clipped = true;
+ compositorNode.layers_are_clipped_when_surfaces_disabled = true;
+
+ m_rootLayer->AddChild(dummyLayer);
+ dummyLayer->SetTransformTreeIndex(compositorNode.transform_id);
+ dummyLayer->SetClipTreeIndex(id);
+ dummyLayer->SetEffectTreeIndex(kSecondaryRootNodeId);
+ dummyLayer->SetScrollTreeIndex(kRealRootNodeId);
+ dummyLayer->set_property_tree_sequence_number(kPropertyTreeSequenceNumber);
+
+ auto result = m_clipNodeMap.set(clipNode, id);
+ DCHECK(result.isNewEntry);
+ clipTree().set_needs_update(true);
+ return id;
+}
+
+int PropertyTreeManager::ensureCompositorScrollNode(
+ const ScrollPaintPropertyNode* scrollNode) {
+ DCHECK(scrollNode);
+ // TODO(crbug.com/645615): Remove the failsafe here.
+ if (!scrollNode)
+ return kSecondaryRootNodeId;
+
+ auto it = m_scrollNodeMap.find(scrollNode);
+ if (it != m_scrollNodeMap.end())
+ return it->value;
+
+ int parentId = ensureCompositorScrollNode(scrollNode->parent());
+ int id = scrollTree().Insert(cc::ScrollNode(), parentId);
+
+ cc::ScrollNode& compositorNode = *scrollTree().Node(id);
+ compositorNode.owning_layer_id = parentId;
+ m_propertyTrees
+ .layer_id_to_scroll_node_index[compositorNode.owning_layer_id] = id;
+
+ compositorNode.scrollable = true;
+
+ compositorNode.scroll_clip_layer_bounds.SetSize(scrollNode->clip().width(),
+ scrollNode->clip().height());
+ compositorNode.bounds.SetSize(scrollNode->bounds().width(),
+ scrollNode->bounds().height());
+ compositorNode.user_scrollable_horizontal =
+ scrollNode->userScrollableHorizontal();
+ compositorNode.user_scrollable_vertical =
+ scrollNode->userScrollableVertical();
+ compositorNode.transform_id =
+ ensureCompositorTransformNode(scrollNode->scrollOffsetTranslation());
+ compositorNode.main_thread_scrolling_reasons =
+ scrollNode->mainThreadScrollingReasons();
+
+ auto result = m_scrollNodeMap.set(scrollNode, id);
+ DCHECK(result.isNewEntry);
+ scrollTree().set_needs_update(true);
+
+ return id;
+}
+
+void PropertyTreeManager::updateScrollOffset(int layerId, int scrollId) {
+ cc::ScrollNode& scrollNode = *scrollTree().Node(scrollId);
+ cc::TransformNode& transformNode =
+ *transformTree().Node(scrollNode.transform_id);
+
+ transformNode.scrolls = true;
+
+ // Blink creates a 2d transform node just for scroll offset whereas cc's
+ // transform node has a special scroll offset field. To handle this we
+ // adjust cc's transform node to remove the 2d scroll translation and
+ // let the cc scroll tree update the cc scroll offset.
+ DCHECK(transformNode.local.IsIdentityOr2DTranslation());
+ auto offset = transformNode.local.To2dTranslation();
+ transformNode.local.MakeIdentity();
+ scrollTree().SetScrollOffset(layerId,
+ gfx::ScrollOffset(-offset.x(), -offset.y()));
+ scrollTree().set_needs_update(true);
+}
+
+namespace {
+
+unsigned depth(const EffectPaintPropertyNode* node) {
+ unsigned result = 0;
+ for (; node; node = node->parent())
+ result++;
+ return result;
+}
+
+// TODO(chrishtr): templatize this to avoid duplication of
+// GeometryMapper::leastCommonAncestor.
+const EffectPaintPropertyNode* lowestCommonAncestor(
+ const EffectPaintPropertyNode* nodeA,
+ const EffectPaintPropertyNode* nodeB) {
+ // Optimized common case.
+ if (nodeA == nodeB)
+ return nodeA;
+
+ unsigned depthA = depth(nodeA), depthB = depth(nodeB);
+ while (depthA > depthB) {
+ nodeA = nodeA->parent();
+ depthA--;
+ }
+ while (depthB > depthA) {
+ nodeB = nodeB->parent();
+ depthB--;
+ }
+ DCHECK_EQ(depthA, depthB);
+ while (nodeA != nodeB) {
+ nodeA = nodeA->parent();
+ nodeB = nodeB->parent();
+ }
+ return nodeA;
+}
+
+} // namespace
+
+int PropertyTreeManager::switchToEffectNode(
+ const EffectPaintPropertyNode& nextEffect) {
+ const EffectPaintPropertyNode* ancestor =
+ lowestCommonAncestor(currentEffectNode(), &nextEffect);
+ DCHECK(ancestor) << "Malformed effect tree. All nodes must be descendant of "
+ "EffectPaintPropertyNode::root().";
+ while (currentEffectNode() != ancestor)
+ m_effectStack.pop_back();
+
+ // Now the current effect is the lowest common ancestor of previous effect
+ // and the next effect. That implies it is an existing node that already has
+ // at least one paint chunk or child effect, and we are going to either attach
+ // another paint chunk or child effect to it. We can no longer omit render
+ // surface for it even for opacity-only nodes.
+ // See comments in PropertyTreeManager::buildEffectNodesRecursively().
+ // TODO(crbug.com/504464): Remove premature optimization here.
+ if (currentEffectNode() && currentEffectNode()->opacity() != 1.f) {
+ effectTree()
+ .Node(getCurrentCompositorEffectNodeIndex())
+ ->has_render_surface = true;
+ }
+
+ buildEffectNodesRecursively(&nextEffect);
+
+ return getCurrentCompositorEffectNodeIndex();
+}
+
+void PropertyTreeManager::buildEffectNodesRecursively(
+ const EffectPaintPropertyNode* nextEffect) {
+ if (nextEffect == currentEffectNode())
+ return;
+ DCHECK(nextEffect);
+
+ buildEffectNodesRecursively(nextEffect->parent());
+ DCHECK_EQ(nextEffect->parent(), currentEffectNode());
+
+#if DCHECK_IS_ON()
+ DCHECK(!m_effectNodesConverted.contains(nextEffect))
+ << "Malformed paint artifact. Paint chunks under the same effect should "
+ "be contiguous.";
+ m_effectNodesConverted.add(nextEffect);
+#endif
+
+ // An effect node can't omit render surface if it has child with exotic
+ // blending mode. See comments below for more detail.
+ // TODO(crbug.com/504464): Remove premature optimization here.
+ if (nextEffect->blendMode() != SkBlendMode::kSrcOver) {
+ effectTree()
+ .Node(getCurrentCompositorEffectNodeIndex())
+ ->has_render_surface = true;
+ }
+
+ // We currently create dummy layers to host effect nodes and corresponding
+ // render surfaces. This should be removed once cc implements better support
+ // for freestanding property trees.
+ scoped_refptr<cc::Layer> dummyLayer = nextEffect->ensureDummyLayer();
+ m_rootLayer->AddChild(dummyLayer);
+
+ int outputClipId = ensureCompositorClipNode(nextEffect->outputClip());
+
+ cc::EffectNode& effectNode = *effectTree().Node(effectTree().Insert(
+ cc::EffectNode(), getCurrentCompositorEffectNodeIndex()));
+ effectNode.owning_layer_id = dummyLayer->id();
+ effectNode.clip_id = outputClipId;
+ // Every effect is supposed to have render surface enabled for grouping,
+ // but we can get away without one if the effect is opacity-only and has only
+ // one compositing child with kSrcOver blend mode. This is both for
+ // optimization and not introducing sub-pixel differences in layout tests.
+ // See PropertyTreeManager::switchToEffectNode() and above where we
+ // retrospectively enable render surface when more than one compositing child
+ // or a child with exotic blend mode is detected.
+ // TODO(crbug.com/504464): There is ongoing work in cc to delay render surface
+ // decision until later phase of the pipeline. Remove premature optimization
+ // here once the work is ready.
+ if (!nextEffect->filter().isEmpty() ||
+ nextEffect->blendMode() != SkBlendMode::kSrcOver)
+ effectNode.has_render_surface = true;
+ effectNode.opacity = nextEffect->opacity();
+ effectNode.filters = nextEffect->filter().asCcFilterOperations();
+ effectNode.blend_mode = nextEffect->blendMode();
+ m_propertyTrees.layer_id_to_effect_node_index[effectNode.owning_layer_id] =
+ effectNode.id;
+ m_effectStack.push_back(BlinkEffectAndCcIdPair{nextEffect, effectNode.id});
+
+ dummyLayer->set_property_tree_sequence_number(kPropertyTreeSequenceNumber);
+ dummyLayer->SetTransformTreeIndex(kSecondaryRootNodeId);
+ dummyLayer->SetClipTreeIndex(outputClipId);
+ dummyLayer->SetEffectTreeIndex(effectNode.id);
+ dummyLayer->SetScrollTreeIndex(kRealRootNodeId);
+}
+
+} // namespace blink
« 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