summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/platform/graphics/paint/effect_paint_property_node.h
blob: dc14d2c48411ca5ed1d53a807fe19a8060c49992 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
// 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.

#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_PAINT_EFFECT_PAINT_PROPERTY_NODE_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_PAINT_EFFECT_PAINT_PROPERTY_NODE_H_

#include <algorithm>

#include "components/viz/common/shared_element_resource_id.h"
#include "third_party/blink/renderer/platform/graphics/compositor_element_id.h"
#include "third_party/blink/renderer/platform/graphics/compositor_filter_operations.h"
#include "third_party/blink/renderer/platform/graphics/document_transition_shared_element_id.h"
#include "third_party/blink/renderer/platform/graphics/paint/clip_paint_property_node.h"
#include "third_party/blink/renderer/platform/graphics/paint/paint_property_node.h"
#include "third_party/blink/renderer/platform/graphics/paint/transform_paint_property_node.h"
#include "third_party/blink/renderer/platform/platform_export.h"
#include "ui/gfx/geometry/rect_f.h"
#include "ui/gfx/geometry/rrect_f.h"

namespace blink {

class PropertyTreeState;

// Effect nodes are abstraction of isolated groups, along with optional effects
// that can be applied to the composited output of the group.
//
// The effect tree is rooted at a node with no parent. This root node should
// not be modified.
class EffectPaintPropertyNode;

class PLATFORM_EXPORT EffectPaintPropertyNodeOrAlias
    : public PaintPropertyNode<EffectPaintPropertyNodeOrAlias,
                               EffectPaintPropertyNode> {
 public:
  // Checks if the accumulated effect from |this| to |relative_to_state
  // .Effect()| has changed, at least significance of |change|, in the space of
  // |relative_to_state.Transform()|. We check for changes of not only effect
  // nodes, but also LocalTransformSpace relative to |relative_to_state
  // .Transform()| of the effect nodes having filters that move pixels. Change
  // of OutputClip is not checked and the caller should check in other ways.
  // |transform_not_to_check| specifies the transform node that the caller has
  // checked or will check its change in other ways and this function should
  // treat it as unchanged.
  bool Changed(
      PaintPropertyChangeType change,
      const PropertyTreeState& relative_to_state,
      const TransformPaintPropertyNodeOrAlias* transform_not_to_check) const;

  void ClearChangedToRoot(int sequence_number) const;

 protected:
  using PaintPropertyNode::PaintPropertyNode;
};

class EffectPaintPropertyNodeAlias : public EffectPaintPropertyNodeOrAlias {
 public:
  static scoped_refptr<EffectPaintPropertyNodeAlias> Create(
      const EffectPaintPropertyNodeOrAlias& parent) {
    return base::AdoptRef(new EffectPaintPropertyNodeAlias(parent));
  }

  PaintPropertyChangeType SetParent(
      const EffectPaintPropertyNodeOrAlias& parent) {
    DCHECK(IsParentAlias());
    return PaintPropertyNode::SetParent(parent);
  }

 private:
  explicit EffectPaintPropertyNodeAlias(
      const EffectPaintPropertyNodeOrAlias& parent)
      : EffectPaintPropertyNodeOrAlias(parent, kParentAlias) {}
};

class PLATFORM_EXPORT EffectPaintPropertyNode
    : public EffectPaintPropertyNodeOrAlias {
 public:
  struct AnimationState {
    AnimationState() {}
    bool is_running_opacity_animation_on_compositor = false;
    bool is_running_filter_animation_on_compositor = false;
    bool is_running_backdrop_filter_animation_on_compositor = false;
  };

  struct BackdropFilterInfo {
    CompositorFilterOperations operations;
    gfx::RRectF bounds;
    // The compositor element id for any masks that are applied to elements that
    // also have backdrop-filters applied.
    CompositorElementId mask_element_id;
  };

  // To make it less verbose and more readable to construct and update a node,
  // a struct with default values is used to represent the state.
  struct PLATFORM_EXPORT State {
    // The local transform space serves two purposes:
    // 1. Assign a depth mapping for 3D depth sorting against other paint chunks
    //    and effects under the same parent.
    // 2. Some effects are spatial (namely blur filter and reflection), the
    //    effect parameters will be specified in the local space.
    scoped_refptr<const TransformPaintPropertyNodeOrAlias>
        local_transform_space;
    // The output of the effect can be optionally clipped when composited onto
    // the current backdrop.
    scoped_refptr<const ClipPaintPropertyNodeOrAlias> output_clip;
    // Optionally a number of effects can be applied to the composited output.
    // The chain of effects will be applied in the following order:
    // === Begin of effects ===
    CompositorFilterOperations filter;
    std::unique_ptr<BackdropFilterInfo> backdrop_filter_info;
    float opacity = 1;
    SkBlendMode blend_mode = SkBlendMode::kSrcOver;
    // === End of effects ===
    CompositingReasons direct_compositing_reasons = CompositingReason::kNone;
    CompositorElementId compositor_element_id;

    // An identifier for a document transition shared element. `id.valid()`
    // returns true if this has been set, and false otherwise.
    blink::DocumentTransitionSharedElementId document_transition_shared_element_id;

    // An identifier to tag shared element resources generated and cached in the
    // Viz process. This generated resource can be used as content for other
    // elements.
    viz::SharedElementResourceId shared_element_resource_id;

    PaintPropertyChangeType ComputeChange(
        const State& other,
        const AnimationState& animation_state) const;
  };

  // This node is really a sentinel, and does not represent a real effect.
  static const EffectPaintPropertyNode& Root();

  static scoped_refptr<EffectPaintPropertyNode> Create(
      const EffectPaintPropertyNodeOrAlias& parent,
      State&& state) {
    return base::AdoptRef(
        new EffectPaintPropertyNode(&parent, std::move(state)));
  }

  PaintPropertyChangeType Update(
      const EffectPaintPropertyNodeOrAlias& parent,
      State&& state,
      const AnimationState& animation_state = AnimationState()) {
    auto parent_changed = SetParent(parent);
    auto state_changed = state_.ComputeChange(state, animation_state);
    if (state_changed != PaintPropertyChangeType::kUnchanged) {
      state_ = std::move(state);
      AddChanged(state_changed);
    }
    return std::max(parent_changed, state_changed);
  }

  const EffectPaintPropertyNode& Unalias() const = delete;
  bool IsParentAlias() const = delete;

  const TransformPaintPropertyNodeOrAlias& LocalTransformSpace() const {
    return *state_.local_transform_space;
  }
  const ClipPaintPropertyNodeOrAlias* OutputClip() const {
    return state_.output_clip.get();
  }

  SkBlendMode BlendMode() const {
    return state_.blend_mode;
  }
  float Opacity() const {
    return state_.opacity;
  }
  const CompositorFilterOperations& Filter() const {
    return state_.filter;
  }

  const CompositorFilterOperations* BackdropFilter() const {
    if (!state_.backdrop_filter_info)
      return nullptr;
    DCHECK(!state_.backdrop_filter_info->operations.IsEmpty());
    return &state_.backdrop_filter_info->operations;
  }

  const gfx::RRectF& BackdropFilterBounds() const {
    DCHECK(state_.backdrop_filter_info);
    return state_.backdrop_filter_info->bounds;
  }

  CompositorElementId BackdropMaskElementId() const {
    DCHECK(state_.backdrop_filter_info);
    return state_.backdrop_filter_info->mask_element_id;
  }

  bool HasFilterThatMovesPixels() const {
    return state_.filter.HasFilterThatMovesPixels();
  }

  bool HasRealEffects() const {
    return Opacity() != 1.0f || BlendMode() != SkBlendMode::kSrcOver ||
           !Filter().IsEmpty() || BackdropFilter();
  }

  bool IsOpacityOnly() const {
    return BlendMode() == SkBlendMode::kSrcOver && Filter().IsEmpty() &&
           !BackdropFilter();
  }

  // Returns a rect covering the pixels that can be affected by pixels in
  // |inputRect|. The rects are in the space of localTransformSpace.
  gfx::RectF MapRect(const gfx::RectF& input_rect) const;

  bool HasDirectCompositingReasons() const {
    return state_.direct_compositing_reasons != CompositingReason::kNone;
  }
  bool RequiresCompositingForBackdropFilterMask() const {
    return state_.direct_compositing_reasons &
           CompositingReason::kBackdropFilterMask;
  }

  bool FlattensAtLeafOf3DScene() const {
    return state_.direct_compositing_reasons &
           CompositingReason::kTransform3DSceneLeaf;
  }

  bool HasActiveOpacityAnimation() const {
    return state_.direct_compositing_reasons &
           CompositingReason::kActiveOpacityAnimation;
  }
  bool HasActiveFilterAnimation() const {
    return state_.direct_compositing_reasons &
           CompositingReason::kActiveFilterAnimation;
  }
  bool HasActiveBackdropFilterAnimation() const {
    return state_.direct_compositing_reasons &
           CompositingReason::kActiveBackdropFilterAnimation;
  }

  bool RequiresCompositingForWillChangeOpacity() const {
    return state_.direct_compositing_reasons &
           CompositingReason::kWillChangeOpacity;
  }
  bool RequiresCompositingForWillChangeFilter() const {
    return state_.direct_compositing_reasons &
           CompositingReason::kWillChangeFilter;
  }
  bool RequiresCompositingForWillChangeBackdropFilter() const {
    return state_.direct_compositing_reasons &
           CompositingReason::kWillChangeBackdropFilter;
  }

  // True if opacity is not 1.0, or could become non-1.0 without a compositing
  // update via a compositor animation or direct update.
  bool MayHaveOpacity() const {
    return Opacity() != 1.0f || HasActiveOpacityAnimation() ||
           RequiresCompositingForWillChangeOpacity();
  }
  // True if the filter is not empty, or could become non-empty without a
  // compositing update via a compositor animation or direct update.
  bool MayHaveFilter() const {
    return !Filter().IsEmpty() || HasActiveFilterAnimation() ||
           RequiresCompositingForWillChangeFilter();
  }
  // True if the backdrop filter is not empty, or could become non-empty
  // without a compositing update via a compositor animation or direct update.
  bool MayHaveBackdropFilter() const {
    return BackdropFilter() || HasActiveBackdropFilterAnimation() ||
           RequiresCompositingForWillChangeBackdropFilter();
  }

  // Whether the effect node uses the backdrop as an input. This includes
  // exotic blending modes and backdrop filters.
  bool MayHaveBackdropEffect() const {
    return BlendMode() != SkBlendMode::kSrcOver || MayHaveBackdropFilter();
  }

  // True if this effect can produce drawable content on its own. For example,
  // a drop-shadow filter will draw a drop shadow even if the filtered content
  // is entirely empty.
  bool DrawsContent() const {
    return MayHaveFilter() || MayHaveBackdropEffect();
  }

  CompositingReasons DirectCompositingReasonsForDebugging() const {
    return state_.direct_compositing_reasons;
  }

  const CompositorElementId& GetCompositorElementId() const {
    return state_.compositor_element_id;
  }

  const blink::DocumentTransitionSharedElementId&
  DocumentTransitionSharedElementId() const {
    return state_.document_transition_shared_element_id;
  }

  const viz::SharedElementResourceId& SharedElementResourceId() const {
    return state_.shared_element_resource_id;
  }

  std::unique_ptr<JSONObject> ToJSON() const;

 private:
  EffectPaintPropertyNode(const EffectPaintPropertyNodeOrAlias* parent,
                          State&& state)
      : EffectPaintPropertyNodeOrAlias(parent), state_(std::move(state)) {}

  using EffectPaintPropertyNodeOrAlias::SetParent;

  State state_;
};

}  // namespace blink

#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_PAINT_EFFECT_PAINT_PROPERTY_NODE_H_