summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/platform/graphics/paint/effect_paint_property_node.h
blob: 9c039137fd995f679c0ac23b7cf6f961b4d051e7 (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
// 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 "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/graphics_types.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/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 PLATFORM_EXPORT EffectPaintPropertyNode
    : public PaintPropertyNode<EffectPaintPropertyNode> {
 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;
  };

  // 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 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 TransformPaintPropertyNode> local_transform_space;
    // The output of the effect can be optionally clipped when composited onto
    // the current backdrop.
    scoped_refptr<const ClipPaintPropertyNode> 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 ===
    ColorFilter color_filter = kColorFilterNone;
    CompositorFilterOperations filter;
    float opacity = 1;
    CompositorFilterOperations backdrop_filter;
    base::Optional<gfx::RRectF> backdrop_filter_bounds;
    SkBlendMode blend_mode = SkBlendMode::kSrcOver;
    // === End of effects ===
    CompositingReasons direct_compositing_reasons = CompositingReason::kNone;
    CompositorElementId compositor_element_id;
    // The compositor element id for any masks that are applied to elements that
    // also have backdrop-filters applied.
    CompositorElementId backdrop_mask_element_id;
    // TODO(crbug.com/900241): Use direct_compositing_reasons to check for
    // active animations when we can track animations for each property type.
    bool has_active_opacity_animation = false;
    bool has_active_filter_animation = false;
    bool has_active_backdrop_filter_animation = false;
    // The offset of the origin of filters in local_transform_space.
    FloatPoint filters_origin;

    PaintPropertyChangeType ComputeChange(
        const State& other,
        const AnimationState& animation_state) {
      if (local_transform_space != other.local_transform_space ||
          output_clip != other.output_clip ||
          color_filter != other.color_filter ||
          backdrop_filter_bounds != other.backdrop_filter_bounds ||
          blend_mode != other.blend_mode ||
          filters_origin != other.filters_origin) {
        return PaintPropertyChangeType::kChangedOnlyValues;
      }
      bool opacity_changed = opacity != other.opacity;
      bool opacity_change_is_simple =
          opacity_changed && opacity != 1.f && other.opacity != 1.f;
      if (opacity_changed && !opacity_change_is_simple &&
          !animation_state.is_running_opacity_animation_on_compositor) {
        return PaintPropertyChangeType::kChangedOnlyValues;
      }
      bool filter_changed = filter != other.filter;
      if (filter_changed &&
          !animation_state.is_running_filter_animation_on_compositor) {
        return PaintPropertyChangeType::kChangedOnlyValues;
      }
      bool backdrop_filter_changed = backdrop_filter != other.backdrop_filter;
      if (backdrop_filter_changed &&
          !animation_state.is_running_backdrop_filter_animation_on_compositor) {
        return PaintPropertyChangeType::kChangedOnlyValues;
      }
      bool non_reraster_values_changed =
          direct_compositing_reasons != other.direct_compositing_reasons ||
          compositor_element_id != other.compositor_element_id;
      bool simple_values_changed =
          opacity_change_is_simple &&
          !animation_state.is_running_opacity_animation_on_compositor;
      if (non_reraster_values_changed && simple_values_changed)
        return PaintPropertyChangeType::kChangedOnlyValues;
      if (non_reraster_values_changed)
        return PaintPropertyChangeType::kChangedOnlyNonRerasterValues;
      if (simple_values_changed)
        return PaintPropertyChangeType::kChangedOnlySimpleValues;

      if (opacity_changed || filter_changed || backdrop_filter_changed) {
        return PaintPropertyChangeType::kChangedOnlyCompositedValues;
      }
      return PaintPropertyChangeType::kUnchanged;
    }
  };

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

  static scoped_refptr<EffectPaintPropertyNode> Create(
      const EffectPaintPropertyNode& parent,
      State&& state) {
    return base::AdoptRef(new EffectPaintPropertyNode(
        &parent, std::move(state), false /* is_parent_alias */));
  }
  static scoped_refptr<EffectPaintPropertyNode> CreateAlias(
      const EffectPaintPropertyNode& parent) {
    return base::AdoptRef(new EffectPaintPropertyNode(
        &parent, State{}, true /* is_parent_alias */));
  }

  PaintPropertyChangeType Update(
      const EffectPaintPropertyNode& 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) {
      DCHECK(!IsParentAlias()) << "Changed the state of an alias node.";
      state_ = std::move(state);
      AddChanged(state_changed);
    }
    return std::max(parent_changed, state_changed);
  }

  // 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 TransformPaintPropertyNode* transform_not_to_check) const;

  const TransformPaintPropertyNode& LocalTransformSpace() const {
    DCHECK(!Parent() || !IsParentAlias());
    return *state_.local_transform_space;
  }
  const ClipPaintPropertyNode* OutputClip() const {
    DCHECK(!Parent() || !IsParentAlias());
    return state_.output_clip.get();
  }

  SkBlendMode BlendMode() const {
    DCHECK(!Parent() || !IsParentAlias());
    return state_.blend_mode;
  }
  float Opacity() const {
    DCHECK(!Parent() || !IsParentAlias());
    return state_.opacity;
  }
  const CompositorFilterOperations& Filter() const {
    DCHECK(!Parent() || !IsParentAlias());
    return state_.filter;
  }
  ColorFilter GetColorFilter() const {
    DCHECK(!Parent() || !IsParentAlias());
    return state_.color_filter;
  }

  const CompositorFilterOperations& BackdropFilter() const {
    return state_.backdrop_filter;
  }

  const base::Optional<gfx::RRectF>& BackdropFilterBounds() const {
    return state_.backdrop_filter_bounds;
  }

  const CompositorElementId& BackdropMaskElementId() const {
    return state_.backdrop_mask_element_id;
  }

  bool HasFilterThatMovesPixels() const {
    DCHECK(!Parent() || !IsParentAlias());
    return state_.filter.HasFilterThatMovesPixels();
  }

  FloatPoint FiltersOrigin() const {
    DCHECK(!Parent() || !IsParentAlias());
    return state_.filters_origin;
  }

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

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

  bool HasDirectCompositingReasons() const {
    return DirectCompositingReasons() != CompositingReason::kNone;
  }

  // TODO(crbug.com/900241): Use HaveActiveXXXAnimation() instead of this
  // function when we can track animations for each property type.
  bool RequiresCompositingForAnimation() const {
    return DirectCompositingReasons() &
           CompositingReason::kComboActiveAnimation;
  }
  bool HasActiveOpacityAnimation() const {
    return state_.has_active_opacity_animation;
    // TODO(crbug.com/900241): Use the following code when we can track
    // animations for each property type.
    // return DirectCompositingReasons() &
    //        CompositingReason::kActiveOpacityAnimation;
  }
  bool HasActiveFilterAnimation() const {
    return state_.has_active_filter_animation;
    // TODO(crbug.com/900241): Use the following code when we can track
    // animations for each property type.
    // return DirectCompositingReasons() &
    //        CompositingReason::kActiveFilterAnimation;
  }
  bool HasActiveBackdropFilterAnimation() const {
    return state_.has_active_backdrop_filter_animation;
    // TODO(crbug.com/900241): Use the following code when we can track
    // animations for each property type.
    // return DirectCompositingReasons() &
    //        CompositingReason::kActiveBackdropFilterAnimation;
  }

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

  CompositingReasons DirectCompositingReasonsForDebugging() const {
    return DirectCompositingReasons();
  }

  const CompositorElementId& GetCompositorElementId() const {
    DCHECK(!Parent() || !IsParentAlias());
    return state_.compositor_element_id;
  }

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

  // Returns memory usage of this node plus ancestors.
  size_t TreeMemoryUsageInBytes() const;

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

  CompositingReasons DirectCompositingReasons() const {
    DCHECK(!Parent() || !IsParentAlias());
    return state_.direct_compositing_reasons;
  }

  State state_;
};

}  // namespace blink

#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_PAINT_EFFECT_PAINT_PROPERTY_NODE_H_