| // Copyright 2017 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef CC_PAINT_PAINT_FLAGS_H_ |
| #define CC_PAINT_PAINT_FLAGS_H_ |
| |
| #include <utility> |
| |
| #include "base/compiler_specific.h" |
| #include "cc/paint/color_filter.h" |
| #include "cc/paint/paint_export.h" |
| #include "third_party/skia/include/core/SkDrawLooper.h" |
| #include "third_party/skia/include/core/SkMaskFilter.h" |
| #include "third_party/skia/include/core/SkPaint.h" |
| #include "third_party/skia/include/core/SkPathEffect.h" |
| #include "third_party/skia/include/core/SkSamplingOptions.h" |
| |
| class SkCanvas; |
| |
| namespace cc { |
| class PaintFilter; |
| class PaintShader; |
| |
| class CC_PAINT_EXPORT PaintFlags { |
| public: |
| PaintFlags(); |
| PaintFlags(const PaintFlags& flags); |
| PaintFlags(PaintFlags&& other); |
| ~PaintFlags(); |
| |
| PaintFlags& operator=(const PaintFlags& other); |
| PaintFlags& operator=(PaintFlags&& other); |
| |
| enum Style { |
| kFill_Style = SkPaint::kFill_Style, |
| kStroke_Style = SkPaint::kStroke_Style, |
| }; |
| bool nothingToDraw() const; |
| ALWAYS_INLINE Style getStyle() const { |
| return static_cast<Style>(bitfields_.style_); |
| } |
| ALWAYS_INLINE void setStyle(Style style) { bitfields_.style_ = style; } |
| // TODO(crbug.com/1399566): Remove this function |
| ALWAYS_INLINE SkColor getColor() const { return color_.toSkColor(); } |
| ALWAYS_INLINE SkColor4f getColor4f() const { return color_; } |
| ALWAYS_INLINE void setColor(SkColor color) { |
| color_ = SkColor4f::FromColor(color); |
| } |
| ALWAYS_INLINE void setColor(SkColor4f color) { color_ = color; } |
| ALWAYS_INLINE float getAlphaf() const { return color_.fA; } |
| ALWAYS_INLINE bool isFullyTransparent() const { return color_.fA == 0.0f; } |
| ALWAYS_INLINE bool isOpaque() const { return color_.fA >= 1.0f; } |
| template <class F, class = std::enable_if_t<std::is_same_v<F, float>>> |
| ALWAYS_INLINE void setAlphaf(F a) { |
| color_.fA = a; |
| } |
| ALWAYS_INLINE void setBlendMode(SkBlendMode mode) { |
| bitfields_.blend_mode_ = static_cast<uint32_t>(mode); |
| } |
| ALWAYS_INLINE SkBlendMode getBlendMode() const { |
| return static_cast<SkBlendMode>(bitfields_.blend_mode_); |
| } |
| ALWAYS_INLINE bool isAntiAlias() const { return bitfields_.antialias_; } |
| ALWAYS_INLINE void setAntiAlias(bool aa) { bitfields_.antialias_ = aa; } |
| ALWAYS_INLINE bool isDither() const { return bitfields_.dither_; } |
| ALWAYS_INLINE void setDither(bool dither) { bitfields_.dither_ = dither; } |
| |
| enum class FilterQuality { |
| kNone, |
| kLow, |
| kMedium, |
| kHigh, |
| kLast = kHigh, |
| }; |
| ALWAYS_INLINE void setFilterQuality(FilterQuality quality) { |
| bitfields_.filter_quality_ = static_cast<uint32_t>(quality); |
| } |
| ALWAYS_INLINE FilterQuality getFilterQuality() const { |
| return static_cast<FilterQuality>(bitfields_.filter_quality_); |
| } |
| enum class DynamicRangeLimit { |
| kStandard, |
| kHigh, |
| kConstrainedHigh, |
| kLast = kConstrainedHigh, |
| }; |
| // Represents a weighted arithmetic mean of "standard", "constrained-high" and |
| // "high" in log-luminance space (which is equivalent to a geometric mean in |
| // linear luminance). |
| struct DynamicRangeLimitMixture { |
| explicit DynamicRangeLimitMixture(DynamicRangeLimit limit) { |
| switch (limit) { |
| case DynamicRangeLimit::kStandard: |
| standard_mix = 1.f; |
| break; |
| case DynamicRangeLimit::kConstrainedHigh: |
| constrained_high_mix = 1.f; |
| break; |
| case DynamicRangeLimit::kHigh: |
| break; |
| } |
| } |
| DynamicRangeLimitMixture(float standard_mix, float constrained_high_mix) |
| : standard_mix(standard_mix), |
| constrained_high_mix(constrained_high_mix) {} |
| friend bool operator==(const DynamicRangeLimitMixture&, |
| const DynamicRangeLimitMixture&) = default; |
| float standard_mix = 0.f; |
| float constrained_high_mix = 0.f; |
| // The weight for "high" is implicit and calculated as "one minus the |
| // others". |
| }; |
| ALWAYS_INLINE void setDynamicRangeLimit(DynamicRangeLimitMixture limit) { |
| bitfields_.dynamic_range_limit_standard_mix_ = |
| static_cast<uint32_t>(.5f + ((1 << 7) - 1) * limit.standard_mix); |
| bitfields_.dynamic_range_limit_constrained_high_mix_ = |
| static_cast<uint32_t>(.5f + |
| ((1 << 7) - 1) * limit.constrained_high_mix); |
| } |
| ALWAYS_INLINE DynamicRangeLimitMixture getDynamicRangeLimit() const { |
| return DynamicRangeLimitMixture( |
| /*standard_mix=*/(1.f / ((1 << 7) - 1)) * |
| bitfields_.dynamic_range_limit_standard_mix_, |
| /*constrained_high_mix=*/(1.f / ((1 << 7) - 1)) * |
| bitfields_.dynamic_range_limit_constrained_high_mix_); |
| } |
| ALWAYS_INLINE bool useDarkModeForImage() const { |
| return bitfields_.use_dark_mode_for_image_; |
| } |
| ALWAYS_INLINE void setUseDarkModeForImage(bool use_dark_mode_for_image) { |
| bitfields_.use_dark_mode_for_image_ = use_dark_mode_for_image; |
| } |
| ALWAYS_INLINE SkScalar getStrokeWidth() const { return width_; } |
| ALWAYS_INLINE void setStrokeWidth(SkScalar width) { width_ = width; } |
| ALWAYS_INLINE SkScalar getStrokeMiter() const { return miter_limit_; } |
| ALWAYS_INLINE void setStrokeMiter(SkScalar miter) { miter_limit_ = miter; } |
| enum Cap { |
| kButt_Cap = SkPaint::kButt_Cap, //!< begin/end contours with no extension |
| kRound_Cap = SkPaint::kRound_Cap, //!< begin/end contours with a |
| //! semi-circle extension |
| kSquare_Cap = SkPaint::kSquare_Cap, //!< begin/end contours with a half |
| //! square extension |
| kLast_Cap = kSquare_Cap, |
| kDefault_Cap = kButt_Cap |
| }; |
| ALWAYS_INLINE Cap getStrokeCap() const { |
| return static_cast<Cap>(bitfields_.cap_type_); |
| } |
| ALWAYS_INLINE void setStrokeCap(Cap cap) { bitfields_.cap_type_ = cap; } |
| enum Join { |
| kMiter_Join = SkPaint::kMiter_Join, |
| kRound_Join = SkPaint::kRound_Join, |
| kBevel_Join = SkPaint::kBevel_Join, |
| kLast_Join = kBevel_Join, |
| kDefault_Join = kMiter_Join |
| }; |
| ALWAYS_INLINE Join getStrokeJoin() const { |
| return static_cast<Join>(bitfields_.join_type_); |
| } |
| ALWAYS_INLINE void setStrokeJoin(Join join) { bitfields_.join_type_ = join; } |
| |
| ALWAYS_INLINE const sk_sp<ColorFilter>& getColorFilter() const { |
| return color_filter_; |
| } |
| ALWAYS_INLINE void setColorFilter(sk_sp<ColorFilter> filter) { |
| color_filter_ = std::move(filter); |
| } |
| ALWAYS_INLINE const sk_sp<SkMaskFilter>& getMaskFilter() const { |
| return mask_filter_; |
| } |
| ALWAYS_INLINE void setMaskFilter(sk_sp<SkMaskFilter> mask) { |
| mask_filter_ = std::move(mask); |
| } |
| |
| ALWAYS_INLINE const PaintShader* getShader() const { return shader_.get(); } |
| |
| // Returns true if the shader has been set on the flags. |
| ALWAYS_INLINE bool HasShader() const { return !!shader_; } |
| |
| // Returns whether the shader is opaque. Note that it is only valid to call |
| // this function if HasShader() returns true. |
| bool ShaderIsOpaque() const; |
| |
| void setShader(sk_sp<PaintShader> shader); |
| |
| ALWAYS_INLINE const sk_sp<SkPathEffect>& getPathEffect() const { |
| return path_effect_; |
| } |
| ALWAYS_INLINE void setPathEffect(sk_sp<SkPathEffect> effect) { |
| path_effect_ = std::move(effect); |
| } |
| bool getFillPath(const SkPath& src, |
| SkPath* dst, |
| const SkRect* cull_rect = nullptr, |
| SkScalar res_scale = 1) const; |
| |
| ALWAYS_INLINE const sk_sp<PaintFilter>& getImageFilter() const { |
| return image_filter_; |
| } |
| void setImageFilter(sk_sp<PaintFilter> filter); |
| |
| ALWAYS_INLINE const sk_sp<SkDrawLooper>& getLooper() const { |
| return draw_looper_; |
| } |
| ALWAYS_INLINE void setLooper(sk_sp<SkDrawLooper> looper) { |
| draw_looper_ = std::move(looper); |
| } |
| |
| // Returns true if this (of a drawOp) allows the sequence |
| // saveLayerAlphaf/drawOp/restore to be folded into a single drawOp by baking |
| // the alpha in the saveLayerAlphaf into the flags of the drawOp. |
| bool SupportsFoldingAlpha() const; |
| |
| // SkPaint does not support loopers, so callers of SkToPaint need |
| // to check for loopers manually (see getLooper()). |
| SkPaint ToSkPaint() const; |
| |
| template <typename Proc> |
| void DrawToSk(SkCanvas* canvas, Proc proc) const { |
| SkPaint paint = ToSkPaint(); |
| if (const sk_sp<SkDrawLooper>& looper = getLooper()) |
| looper->apply(canvas, paint, proc); |
| else |
| proc(canvas, paint); |
| } |
| |
| static SkSamplingOptions FilterQualityToSkSamplingOptions( |
| FilterQuality filter_quality); |
| |
| bool IsValid() const; |
| bool EqualsForTesting(const PaintFlags& other) const; |
| |
| bool HasDiscardableImages() const; |
| |
| private: |
| friend class PaintOpReader; |
| friend class PaintOpWriter; |
| |
| sk_sp<SkPathEffect> path_effect_; |
| sk_sp<PaintShader> shader_; |
| sk_sp<SkMaskFilter> mask_filter_; |
| sk_sp<ColorFilter> color_filter_; |
| sk_sp<SkDrawLooper> draw_looper_; |
| sk_sp<PaintFilter> image_filter_; |
| |
| // Match(ish) SkPaint defaults. SkPaintDefaults is not public, so this |
| // just uses these values and ignores any SkUserConfig overrides. |
| SkColor4f color_ = SkColors::kBlack; |
| float width_ = 0.f; |
| float miter_limit_ = 4.f; |
| |
| struct PaintFlagsBitfields { |
| uint32_t antialias_ : 1; |
| uint32_t dither_ : 1; |
| uint32_t cap_type_ : 2; |
| uint32_t join_type_ : 2; |
| uint32_t style_ : 2; |
| uint32_t blend_mode_ : 5; |
| uint32_t filter_quality_ : 2; |
| uint32_t dynamic_range_limit_standard_mix_ : 7; |
| uint32_t dynamic_range_limit_constrained_high_mix_ : 7; |
| // Specifies whether the compositor should use a dark mode filter when |
| // rasterizing image on the draw op with this PaintFlags. |
| uint32_t use_dark_mode_for_image_ : 1; |
| }; |
| |
| union { |
| PaintFlagsBitfields bitfields_; |
| uint32_t bitfields_uint_; |
| }; |
| }; |
| |
| } // namespace cc |
| |
| #endif // CC_PAINT_PAINT_FLAGS_H_ |