Commit 491d1097 authored by Xianzhu Wang's avatar Xianzhu Wang Committed by Commit Bot

[BGPT] Generate effect node for rotated clip and force render surface

Cc requires that a rectangular clip is 2d-axis-aligned with the render
surface to correctly apply the clip. When we find that a rectangular
clip is not 2d-axis-aligned with the render surface, we should create
an effect node and let it create a render surface.

Bug: 890919
Cq-Include-Trybots: luci.chromium.try:linux-blink-gen-property-trees;luci.chromium.try:linux_layout_tests_slimming_paint_v2;master.tryserver.blink:linux_trusty_blink_rel
Change-Id: I6f7b462d5506949d1571c60231e066d27b9a238d
Reviewed-on: https://chromium-review.googlesource.com/1244104Reviewed-by: default avatarPhilip Rogers <pdr@chromium.org>
Commit-Queue: Xianzhu Wang <wangxianzhu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#596304}
parent c99cbb2f
...@@ -154,6 +154,7 @@ Bug(none) css3/blending/background-blend-mode-overlapping-accelerated-elements.h ...@@ -154,6 +154,7 @@ Bug(none) css3/blending/background-blend-mode-overlapping-accelerated-elements.h
# Benign subpixel differences. # Benign subpixel differences.
Bug(none) transforms/3d/point-mapping/3d-point-mapping-deep.html [ Failure ] Bug(none) transforms/3d/point-mapping/3d-point-mapping-deep.html [ Failure ]
Bug(none) transforms/3d/point-mapping/3d-point-mapping-preserve-3d.html [ Failure ] Bug(none) transforms/3d/point-mapping/3d-point-mapping-preserve-3d.html [ Failure ]
Bug(none) compositing/direct-image-compositing.html [ Failure ]
Bug(none) compositing/masks/direct-image-mask.html [ Failure ] Bug(none) compositing/masks/direct-image-mask.html [ Failure ]
Bug(none) compositing/geometry/layer-due-to-layer-children.html [ Failure ] Bug(none) compositing/geometry/layer-due-to-layer-children.html [ Failure ]
Bug(none) compositing/perpendicular-layer-sorting.html [ Failure ] Bug(none) compositing/perpendicular-layer-sorting.html [ Failure ]
......
{
"layers": [
{
"name": "LayoutView #document",
"bounds": [800, 600],
"drawsContent": false,
"backgroundColor": "#FFFFFF"
},
{
"name": "Scrolling Layer",
"bounds": [800, 600],
"drawsContent": false
},
{
"name": "Scrolling Contents Layer",
"bounds": [800, 600],
"contentsOpaque": true,
"backgroundColor": "#FFFFFF"
},
{
"name": "LayoutBlockFlow DIV",
"bounds": [240, 240],
"transform": 2
},
{
"name": "Child Containment Layer",
"position": [20, 20],
"bounds": [200, 200],
"drawsContent": false,
"transform": 2
},
{
"name": "LayoutBlockFlow DIV",
"position": [20, 20],
"bounds": [400, 400],
"contentsOpaque": true,
"backgroundColor": "#0000FF",
"transform": 2
}
],
"transforms": [
{
"id": 1,
"transform": [
[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 1, 0],
[108, 100, 0, 1]
]
},
{
"id": 2,
"parent": 1,
"transform": [
[0.707106781186548, 0.707106781186548, 0, 0],
[-0.707106781186548, 0.707106781186548, 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1]
],
"origin": [120, 120]
}
]
}
<!DOCTYPE html>
<div style="margin: 100px; transform: rotate(45deg); overflow: hidden;
width: 200px; height: 200px; border: 20px solid green">
<div style="will-change: transform; width: 400px; height: 400px; background: blue"></div>
</div>
<script>
if (window.testRunner)
testRunner.setCustomTextOutput(internals.layerTreeAsText(document));
</script>
{
"layers": [
{
"name": "LayoutView #document",
"bounds": [800, 600],
"drawsContent": false,
"backgroundColor": "#FFFFFF"
},
{
"name": "Scrolling Layer",
"bounds": [800, 600],
"drawsContent": false
},
{
"name": "Scrolling Contents Layer",
"bounds": [800, 600],
"contentsOpaque": true,
"backgroundColor": "#FFFFFF"
},
{
"name": "LayoutBlockFlow DIV",
"bounds": [240, 240],
"drawsContent": false,
"transform": 2
},
{
"name": "LayoutBlockFlow DIV",
"bounds": [240, 240],
"opacity": 0.899999976158142,
"transform": 2
},
{
"name": "Ancestor Clipping Layer",
"position": [20, 20],
"bounds": [200, 200],
"drawsContent": false,
"transform": 2
},
{
"name": "LayoutBlockFlow DIV",
"position": [20, 20],
"bounds": [400, 400],
"contentsOpaque": true,
"backgroundColor": "#0000FF",
"transform": 2
},
{
"name": "LayoutBlockFlow (positioned) DIV",
"position": [20, 0],
"bounds": [400, 100],
"contentsOpaque": true,
"backgroundColor": "#00FFFF",
"transform": 2
},
{
"name": "Ancestor Clipping Layer",
"position": [20, 20],
"bounds": [200, 200],
"drawsContent": false,
"transform": 2
},
{
"name": "LayoutBlockFlow (relative positioned) DIV",
"position": [20, 20],
"bounds": [100, 400],
"contentsOpaque": true,
"backgroundColor": "#FF00FF",
"transform": 2
}
],
"transforms": [
{
"id": 1,
"transform": [
[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 1, 0],
[108, 100, 0, 1]
]
},
{
"id": 2,
"parent": 1,
"transform": [
[0.707106781186548, 0.707106781186548, 0, 0],
[-0.707106781186548, 0.707106781186548, 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1]
],
"origin": [120, 120]
}
]
}
<!DOCTYPE html>
<div style="margin: 100px; width: 240px; height: 240px; transform: rotate(45deg)">
<div style="opacity: 0.9">
<div style="overflow: hidden; width: 200px; height: 200px; border: 20px solid green">
<div style="will-change: transform; width: 400px; height: 400px; background: blue"></div>
<div style="position: fixed; top: 0; width: 400px; height: 100px; background: cyan"></div>
<div style="will-change: transform; z-index: 1; position: relative; top: -400px; width: 100px; height: 400px; background: magenta"></div>
</div>
</div>
</div>
<script>
if (window.testRunner)
testRunner.setCustomTextOutput(internals.layerTreeAsText(document));
</script>
{
"layers": [
{
"name": "LayoutView #document",
"bounds": [800, 600],
"drawsContent": false,
"backgroundColor": "#FFFFFF"
},
{
"name": "Scrolling Layer",
"bounds": [800, 600],
"drawsContent": false
},
{
"name": "Scrolling Contents Layer",
"bounds": [800, 600],
"contentsOpaque": true,
"backgroundColor": "#FFFFFF"
},
{
"name": "LayoutBlockFlow DIV",
"bounds": [240, 240],
"transform": 2
},
{
"name": "Ancestor Clipping Layer",
"position": [20, 20],
"bounds": [200, 200],
"drawsContent": false,
"transform": 2
},
{
"name": "LayoutBlockFlow DIV",
"position": [20, 20],
"bounds": [400, 400],
"contentsOpaque": true,
"backgroundColor": "#0000FF",
"transform": 2
}
],
"transforms": [
{
"id": 1,
"transform": [
[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 1, 0],
[108, 100, 0, 1]
]
},
{
"id": 2,
"parent": 1,
"transform": [
[0.707106781186548, 0.707106781186548, 0, 0],
[-0.707106781186548, 0.707106781186548, 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1]
],
"origin": [120, 120]
}
]
}
{
"layers": [
{
"name": "LayoutView #document",
"bounds": [800, 600],
"drawsContent": false,
"backgroundColor": "#FFFFFF"
},
{
"name": "Scrolling Layer",
"bounds": [800, 600],
"drawsContent": false
},
{
"name": "Scrolling Contents Layer",
"bounds": [800, 600],
"contentsOpaque": true,
"backgroundColor": "#FFFFFF"
},
{
"name": "LayoutBlockFlow DIV",
"bounds": [300, 100],
"transform": 2
},
{
"name": "Ancestor Clipping Layer",
"bounds": [100, 100],
"drawsContent": false,
"transform": 2
},
{
"name": "LayoutBlockFlow (relative positioned) DIV",
"bounds": [200, 100],
"contentsOpaque": true,
"backgroundColor": "#008000",
"transform": 2
},
{
"name": "LayoutBlockFlow (positioned) DIV",
"bounds": [200, 22],
"contentsOpaque": true,
"backgroundColor": "#FFFF00",
"transform": 2
},
{
"name": "Ancestor Clipping Layer",
"bounds": [100, 100],
"drawsContent": false,
"transform": 2
},
{
"name": "LayoutBlockFlow (relative positioned) DIV",
"bounds": [50, 200],
"contentsOpaque": true,
"backgroundColor": "#FF0000",
"transform": 2
}
],
"transforms": [
{
"id": 1,
"transform": [
[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 1, 0],
[108, 100, 0, 1]
]
},
{
"id": 2,
"parent": 1,
"transform": [
[0.707106781186548, 0.707106781186548, 0, 0],
[-0.707106781186548, 0.707106781186548, 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1]
],
"origin": [150, 50]
}
]
}
<!DOCTYPE html>
<div style="margin: 100px; width: 300px; transform: rotate(45deg)">
<div style="position: absolute; width: 200px; height: 22px; background: yellow; z-index: 1; will-change: transform"></div>
<div style="width: 100px; height: 100px; overflow: hidden">
<div style="position: relative; width: 200px; height: 100px; background: green; will-change: transform"></div>
<div style="position: relative; top: -100px; z-index: 2; width: 50px; height: 200px; background: red; will-change: transform"></div>
</div>
</div>
<script>
if (window.testRunner)
testRunner.setCustomTextOutput(internals.layerTreeAsText(document));
</script>
<!DOCTYPE html>
<div style="margin: 100px; width: 240px; height: 240px; transform: rotate(45deg)">
<div style="overflow: hidden; width: 200px; height: 200px; border: 20px solid green">
<div style="will-change: transform; width: 400px; height: 400px; background: blue"></div>
</div>
</div>
<script>
if (window.testRunner)
testRunner.setCustomTextOutput(internals.layerTreeAsText(document));
</script>
{
"layers": [
{
"name": "LayoutView #document",
"bounds": [800, 600],
"drawsContent": false,
"backgroundColor": "#FFFFFF"
},
{
"name": "Scrolling Layer",
"bounds": [800, 600],
"drawsContent": false
},
{
"name": "Scrolling Contents Layer",
"bounds": [800, 600],
"contentsOpaque": true,
"backgroundColor": "#FFFFFF"
},
{
"name": "LayoutBlockFlow DIV",
"bounds": [240, 240],
"transform": 2
},
{
"name": "LayoutBlockFlow DIV",
"position": [20, 20],
"bounds": [400, 400],
"contentsOpaque": true,
"backgroundColor": "#0000FF",
"transform": 2
}
],
"transforms": [
{
"id": 1,
"transform": [
[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 1, 0],
[108, 100, 0, 1]
]
},
{
"id": 2,
"parent": 1,
"transform": [
[0.707106781186548, 0.707106781186548, 0, 0],
[-0.707106781186548, 0.707106781186548, 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1]
],
"origin": [120, 120]
}
]
}
{
"layers": [
{
"name": "LayoutView #document",
"bounds": [800, 600],
"drawsContent": false,
"backgroundColor": "#FFFFFF"
},
{
"name": "Scrolling Layer",
"bounds": [800, 600],
"drawsContent": false
},
{
"name": "Scrolling Contents Layer",
"bounds": [800, 600],
"contentsOpaque": true,
"backgroundColor": "#FFFFFF"
},
{
"name": "LayoutBlockFlow DIV",
"bounds": [240, 240],
"drawsContent": false,
"transform": 2
},
{
"name": "LayoutBlockFlow DIV",
"bounds": [240, 240],
"opacity": 0.899999976158142,
"transform": 2
},
{
"name": "LayoutBlockFlow DIV",
"position": [20, 20],
"bounds": [400, 400],
"contentsOpaque": true,
"backgroundColor": "#0000FF",
"transform": 2
},
{
"name": "LayoutBlockFlow (positioned) DIV",
"position": [20, 0],
"bounds": [400, 100],
"contentsOpaque": true,
"backgroundColor": "#00FFFF",
"transform": 2
},
{
"name": "LayoutBlockFlow (relative positioned) DIV",
"position": [20, 20],
"bounds": [100, 400],
"contentsOpaque": true,
"backgroundColor": "#FF00FF",
"transform": 2
}
],
"transforms": [
{
"id": 1,
"transform": [
[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 1, 0],
[108, 100, 0, 1]
]
},
{
"id": 2,
"parent": 1,
"transform": [
[0.707106781186548, 0.707106781186548, 0, 0],
[-0.707106781186548, 0.707106781186548, 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1]
],
"origin": [120, 120]
}
]
}
{
"layers": [
{
"name": "LayoutView #document",
"bounds": [800, 600],
"drawsContent": false,
"backgroundColor": "#FFFFFF"
},
{
"name": "Scrolling Layer",
"bounds": [800, 600],
"drawsContent": false
},
{
"name": "Scrolling Contents Layer",
"bounds": [800, 600],
"contentsOpaque": true,
"backgroundColor": "#FFFFFF"
},
{
"name": "LayoutBlockFlow DIV",
"bounds": [240, 240],
"transform": 2
},
{
"name": "LayoutBlockFlow DIV",
"position": [20, 20],
"bounds": [400, 400],
"contentsOpaque": true,
"backgroundColor": "#0000FF",
"transform": 2
}
],
"transforms": [
{
"id": 1,
"transform": [
[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 1, 0],
[108, 100, 0, 1]
]
},
{
"id": 2,
"parent": 1,
"transform": [
[0.707106781186548, 0.707106781186548, 0, 0],
[-0.707106781186548, 0.707106781186548, 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1]
],
"origin": [120, 120]
}
]
}
{
"layers": [
{
"name": "LayoutView #document",
"bounds": [800, 600],
"drawsContent": false,
"backgroundColor": "#FFFFFF"
},
{
"name": "Scrolling Layer",
"bounds": [800, 600],
"drawsContent": false
},
{
"name": "Scrolling Contents Layer",
"bounds": [800, 600],
"contentsOpaque": true,
"backgroundColor": "#FFFFFF"
},
{
"name": "LayoutBlockFlow DIV",
"bounds": [300, 100],
"transform": 2
},
{
"name": "LayoutBlockFlow (relative positioned) DIV",
"bounds": [200, 100],
"contentsOpaque": true,
"backgroundColor": "#008000",
"transform": 2
},
{
"name": "LayoutBlockFlow (positioned) DIV",
"bounds": [200, 22],
"contentsOpaque": true,
"backgroundColor": "#FFFF00",
"transform": 2
},
{
"name": "LayoutBlockFlow (relative positioned) DIV",
"bounds": [50, 200],
"contentsOpaque": true,
"backgroundColor": "#FF0000",
"transform": 2
}
],
"transforms": [
{
"id": 1,
"transform": [
[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 1, 0],
[108, 100, 0, 1]
]
},
{
"id": 2,
"parent": 1,
"transform": [
[0.707106781186548, 0.707106781186548, 0, 0],
[-0.707106781186548, 0.707106781186548, 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1]
],
"origin": [150, 50]
}
]
}
{
"layers": [
{
"name": "LayoutView #document",
"bounds": [800, 600],
"contentsOpaque": true,
"backgroundColor": "#FFFFFF"
},
{
"name": "LayoutBlockFlow DIV",
"position": [20, 20],
"bounds": [400, 400],
"contentsOpaque": true,
"backgroundColor": "#0000FF",
"transform": 2
}
],
"transforms": [
{
"id": 1,
"transform": [
[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 1, 0],
[108, 100, 0, 1]
]
},
{
"id": 2,
"parent": 1,
"transform": [
[0.707106781186548, 0.707106781186548, 0, 0],
[-0.707106781186548, 0.707106781186548, 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1]
],
"origin": [120, 120]
}
]
}
{
"layers": [
{
"name": "LayoutView #document",
"bounds": [800, 600],
"contentsOpaque": true,
"backgroundColor": "#FFFFFF"
},
{
"name": "LayoutBlockFlow DIV",
"bounds": [240, 240],
"transform": 2
},
{
"name": "LayoutBlockFlow DIV",
"position": [20, 20],
"bounds": [400, 400],
"contentsOpaque": true,
"backgroundColor": "#0000FF",
"transform": 2
},
{
"name": "LayoutBlockFlow (positioned) DIV",
"position": [20, 0],
"bounds": [400, 100],
"contentsOpaque": true,
"backgroundColor": "#00FFFF",
"transform": 2
},
{
"name": "LayoutBlockFlow (relative positioned) DIV",
"position": [20, 20],
"bounds": [100, 400],
"contentsOpaque": true,
"backgroundColor": "#FF00FF",
"transform": 2
}
],
"transforms": [
{
"id": 1,
"transform": [
[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 1, 0],
[108, 100, 0, 1]
]
},
{
"id": 2,
"parent": 1,
"transform": [
[0.707106781186548, 0.707106781186548, 0, 0],
[-0.707106781186548, 0.707106781186548, 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1]
],
"origin": [120, 120]
}
]
}
{
"layers": [
{
"name": "LayoutView #document",
"bounds": [800, 600],
"contentsOpaque": true,
"backgroundColor": "#FFFFFF"
},
{
"name": "LayoutBlockFlow DIV",
"position": [20, 20],
"bounds": [400, 400],
"contentsOpaque": true,
"backgroundColor": "#0000FF",
"transform": 2
}
],
"transforms": [
{
"id": 1,
"transform": [
[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 1, 0],
[108, 100, 0, 1]
]
},
{
"id": 2,
"parent": 1,
"transform": [
[0.707106781186548, 0.707106781186548, 0, 0],
[-0.707106781186548, 0.707106781186548, 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1]
],
"origin": [120, 120]
}
]
}
{
"layers": [
{
"name": "LayoutView #document",
"bounds": [800, 600],
"contentsOpaque": true,
"backgroundColor": "#FFFFFF"
},
{
"name": "LayoutBlockFlow (relative positioned) DIV",
"bounds": [200, 100],
"contentsOpaque": true,
"backgroundColor": "#008000",
"transform": 2
},
{
"name": "LayoutBlockFlow (positioned) DIV",
"bounds": [200, 22],
"contentsOpaque": true,
"backgroundColor": "#FFFF00",
"transform": 2
},
{
"name": "LayoutBlockFlow (relative positioned) DIV",
"bounds": [50, 200],
"contentsOpaque": true,
"backgroundColor": "#FF0000",
"transform": 2
}
],
"transforms": [
{
"id": 1,
"transform": [
[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 1, 0],
[108, 100, 0, 1]
]
},
{
"id": 2,
"parent": 1,
"transform": [
[0.707106781186548, 0.707106781186548, 0, 0],
[-0.707106781186548, 0.707106781186548, 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1]
],
"origin": [150, 50]
}
]
}
...@@ -19,6 +19,7 @@ class Layer; ...@@ -19,6 +19,7 @@ class Layer;
class PropertyTrees; class PropertyTrees;
class ScrollTree; class ScrollTree;
class TransformTree; class TransformTree;
struct EffectNode;
struct TransformNode; struct TransformNode;
} }
...@@ -126,10 +127,39 @@ class PropertyTreeManager { ...@@ -126,10 +127,39 @@ class PropertyTreeManager {
bool effect_is_newly_built); bool effect_is_newly_built);
void EmitClipMaskLayer(); void EmitClipMaskLayer();
void CloseCcEffect(); void CloseCcEffect();
bool IsCurrentCcEffectSynthetic() const { bool IsCurrentCcEffectSynthetic() const {
return current_effect_type_ != CcEffectType::kEffect; return current_.effect_type != CcEffectType::kEffect;
}
bool IsCurrentCcEffectSyntheticForNonTrivialClip() const {
return current_.effect_type == CcEffectType::kSyntheticForNonTrivialClip;
} }
// The type of operation the current cc effect node applies.
enum class CcEffectType {
// The cc effect corresponds to a Blink effect node.
kEffect,
// The cc effect is synthetic for a blink clip node that has to be
// rasterized because the clip is non-trivial.
kSyntheticForNonTrivialClip,
// The cc effect is synthetic to create a render surface that is
// 2d-axis-aligned with a blink clip node that is non-2d-axis-aligned
// in the the original render surface. Cc requires a rectangular clip to be
// 2d-axis-aligned with the render surface to correctly apply the clip.
// TODO(crbug.com/504464): This will be changed when we move render surface
// decision logic into the cc compositor thread.
kSyntheticFor2dAxisAlignment,
};
base::Optional<CcEffectType> NeedsSyntheticEffect(
const ClipPaintPropertyNode&) const;
void SetCurrentEffectState(const cc::EffectNode&,
CcEffectType,
const EffectPaintPropertyNode*,
const ClipPaintPropertyNode*);
void SetCurrentEffectHasRenderSurface();
cc::TransformTree& GetTransformTree(); cc::TransformTree& GetTransformTree();
cc::ClipTree& GetClipTree(); cc::ClipTree& GetClipTree();
cc::EffectTree& GetEffectTree(); cc::EffectTree& GetEffectTree();
...@@ -158,32 +188,36 @@ class PropertyTreeManager { ...@@ -158,32 +188,36 @@ class PropertyTreeManager {
HashMap<const ClipPaintPropertyNode*, int> clip_node_map_; HashMap<const ClipPaintPropertyNode*, int> clip_node_map_;
HashMap<const ScrollPaintPropertyNode*, int> scroll_node_map_; HashMap<const ScrollPaintPropertyNode*, int> scroll_node_map_;
// The cc effect node that has the corresponding drawing state to the struct EffectState {
// effect and clip state from the last SwitchToEffectNodeWithSynthesizedClip. // The cc effect node that has the corresponding drawing state to the
int current_effect_id_; // effect and clip state from the last
// The type of operation the current cc effect node applies. kEffect means // SwitchToEffectNodeWithSynthesizedClip.
// it corresponds to a Blink effect node. kSynthesizedClip means it implements
// a Blink clip node that has to be rasterized.
enum class CcEffectType { kEffect, kSynthesizedClip } current_effect_type_;
// The effect state of the current cc effect node.
const EffectPaintPropertyNode* current_effect_;
// The clip state of the current cc effect node. This value may be shallower
// than the one passed into SwitchToEffectNodeWithSynthesizedClip because not
// every clip needs to be synthesized as cc effect.
// Is set to output clip of the effect if the type is kEffect, or set to the
// synthesized clip node if the type is kSynthesizedClip.
const ClipPaintPropertyNode* current_clip_;
// This keep track of cc effect stack. Whenever a new cc effect is nested,
// a new entry is pushed, and the entry will be popped when the effect closed.
// Note: This is a "restore stack", i.e. the top element does not represent
// the current state, but the state prior to most recent push.
struct EffectStackEntry {
int effect_id; int effect_id;
CcEffectType effect_type; CcEffectType effect_type;
// The effect state of the cc effect node.
const EffectPaintPropertyNode* effect; const EffectPaintPropertyNode* effect;
// The clip state of the cc effect node. This value may be shallower than
// the one passed into SwitchToEffectNodeWithSynthesizedClip because not
// every clip needs to be synthesized as cc effect.
// Is set to output clip of the effect if the type is kEffect, or set to the
// synthesized clip node if the type is kSyntheticForNonTrivialClip.
const ClipPaintPropertyNode* clip; const ClipPaintPropertyNode* clip;
// The transform space of the containing render surface.
// TODO(crbug.com/504464): Remove this when move render surface decision
// logic into cc compositor thread.
const TransformPaintPropertyNode* render_surface_transform;
}; };
Vector<EffectStackEntry> effect_stack_;
// The current effect state. Virtually it's the top of the effect stack if
// it and effect_stack_ are treated as a whole stack.
EffectState current_;
// This keep track of cc effect stack. Whenever a new cc effect is nested,
// a new entry is pushed, and the entry will be popped when the effect closed.
// Note: This is a "restore stack", i.e. the top element does not represent
// the current state (which is in current_), but the state prior to most
// recent push.
Vector<EffectState> effect_stack_;
#if DCHECK_IS_ON() #if DCHECK_IS_ON()
HashSet<const EffectPaintPropertyNode*> effect_nodes_converted_; HashSet<const EffectPaintPropertyNode*> effect_nodes_converted_;
......
...@@ -1827,6 +1827,56 @@ bool TransformationMatrix::IsIntegerTranslation() const { ...@@ -1827,6 +1827,56 @@ bool TransformationMatrix::IsIntegerTranslation() const {
return true; return true;
} }
// This is the same as gfx::Transform::Preserves2dAxisAlignment().
bool TransformationMatrix::Preserves2dAxisAlignment() const {
// Check whether an axis aligned 2-dimensional rect would remain axis-aligned
// after being transformed by this matrix (and implicitly projected by
// dropping any non-zero z-values).
//
// The 4th column can be ignored because translations don't affect axis
// alignment. The 3rd column can be ignored because we are assuming 2d
// inputs, where z-values will be zero. The 3rd row can also be ignored
// because we are assuming 2d outputs, and any resulting z-value is dropped
// anyway. For the inner 2x2 portion, the only effects that keep a rect axis
// aligned are (1) swapping axes and (2) scaling axes. This can be checked by
// verifying only 1 element of every column and row is non-zero. Degenerate
// cases that project the x or y dimension to zero are considered to preserve
// axis alignment.
//
// If the matrix does have perspective component that is affected by x or y
// values: The current implementation conservatively assumes that axis
// alignment is not preserved.
bool has_x_or_y_perspective = M14() != 0 || M24() != 0;
if (has_x_or_y_perspective)
return false;
constexpr double kEpsilon = std::numeric_limits<double>::epsilon();
int num_non_zero_in_row_1 = 0;
int num_non_zero_in_row_2 = 0;
int num_non_zero_in_col_1 = 0;
int num_non_zero_in_col_2 = 0;
if (std::abs(M11()) > kEpsilon) {
num_non_zero_in_col_1++;
num_non_zero_in_row_1++;
}
if (std::abs(M12()) > kEpsilon) {
num_non_zero_in_col_1++;
num_non_zero_in_row_2++;
}
if (std::abs(M21()) > kEpsilon) {
num_non_zero_in_col_2++;
num_non_zero_in_row_1++;
}
if (std::abs(M22()) > kEpsilon) {
num_non_zero_in_col_2++;
num_non_zero_in_row_2++;
}
return num_non_zero_in_row_1 <= 1 && num_non_zero_in_row_2 <= 1 &&
num_non_zero_in_col_1 <= 1 && num_non_zero_in_col_2 <= 1;
}
FloatSize TransformationMatrix::To2DTranslation() const { FloatSize TransformationMatrix::To2DTranslation() const {
DCHECK(IsIdentityOr2DTranslation()); DCHECK(IsIdentityOr2DTranslation());
return FloatSize(matrix_[3][0], matrix_[3][1]); return FloatSize(matrix_[3][0], matrix_[3][1]);
......
...@@ -474,6 +474,10 @@ class PLATFORM_EXPORT TransformationMatrix { ...@@ -474,6 +474,10 @@ class PLATFORM_EXPORT TransformationMatrix {
bool IsIntegerTranslation() const; bool IsIntegerTranslation() const;
// Returns true if axis-aligned 2d rects will remain axis-aligned after being
// transformed by this matrix.
bool Preserves2dAxisAlignment() const;
// If this transformation is identity or 2D translation, returns the // If this transformation is identity or 2D translation, returns the
// translation. // translation.
FloatSize To2DTranslation() const; FloatSize To2DTranslation() const;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment