// Copyright 2017 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 "cc/paint/paint_flags.h" #include "cc/paint/paint_filter.h" #include "cc/paint/paint_op_buffer.h" #include "cc/paint/paint_op_writer.h" namespace { static bool affects_alpha(const SkColorFilter* cf) { return cf && !(cf->getFlags() & SkColorFilter::kAlphaUnchanged_Flag); } } // namespace namespace cc { PaintFlags::PaintFlags() { // Match SkPaint defaults. bitfields_uint_ = 0u; bitfields_.cap_type_ = SkPaint::kDefault_Cap; bitfields_.join_type_ = SkPaint::kDefault_Join; bitfields_.style_ = SkPaint::kFill_Style; bitfields_.text_encoding_ = SkPaint::kUTF8_TextEncoding; bitfields_.hinting_ = SkPaint::kNormal_Hinting; bitfields_.filter_quality_ = SkFilterQuality::kNone_SkFilterQuality; static_assert(sizeof(bitfields_) <= sizeof(bitfields_uint_), "Too many bitfields"); } PaintFlags::PaintFlags(const PaintFlags& flags) = default; PaintFlags::PaintFlags(PaintFlags&& other) = default; PaintFlags::~PaintFlags() { // TODO(enne): non-default dtor to investigate http://crbug.com/790915 // Sanity check accessing this object doesn't crash. blend_mode_ = static_cast(SkBlendMode::kLastMode); // Free refcounted objects one by one. typeface_.reset(); path_effect_.reset(); shader_.reset(); mask_filter_.reset(); color_filter_.reset(); draw_looper_.reset(); image_filter_.reset(); } PaintFlags& PaintFlags::operator=(const PaintFlags& other) = default; PaintFlags& PaintFlags::operator=(PaintFlags&& other) = default; void PaintFlags::setImageFilter(sk_sp filter) { image_filter_ = std::move(filter); } bool PaintFlags::nothingToDraw() const { // Duplicated from SkPaint to avoid having to construct an SkPaint to // answer this question. if (getLooper()) return false; switch (getBlendMode()) { case SkBlendMode::kSrcOver: case SkBlendMode::kSrcATop: case SkBlendMode::kDstOut: case SkBlendMode::kDstOver: case SkBlendMode::kPlus: if (getAlpha() == 0) { return !affects_alpha(color_filter_.get()) && !image_filter_; } break; case SkBlendMode::kDst: return true; default: break; } return false; } bool PaintFlags::getFillPath(const SkPath& src, SkPath* dst, const SkRect* cull_rect, SkScalar res_scale) const { SkPaint paint = ToSkPaint(); return paint.getFillPath(src, dst, cull_rect, res_scale); } bool PaintFlags::IsSimpleOpacity() const { uint32_t color = getColor(); if (SK_ColorTRANSPARENT != SkColorSetA(color, SK_AlphaTRANSPARENT)) return false; if (getBlendMode() != SkBlendMode::kSrcOver) return false; if (getLooper()) return false; if (getPathEffect()) return false; if (HasShader()) return false; if (getMaskFilter()) return false; if (getColorFilter()) return false; if (getImageFilter()) return false; return true; } bool PaintFlags::SupportsFoldingAlpha() const { if (getBlendMode() != SkBlendMode::kSrcOver) return false; if (getColorFilter()) return false; if (getImageFilter()) return false; if (getLooper()) return false; return true; } SkPaint PaintFlags::ToSkPaint() const { SkPaint paint; paint.setTypeface(typeface_); paint.setPathEffect(path_effect_); if (shader_) paint.setShader(shader_->GetSkShader()); paint.setMaskFilter(mask_filter_); paint.setColorFilter(color_filter_); paint.setDrawLooper(draw_looper_); if (image_filter_) paint.setImageFilter(image_filter_->cached_sk_filter_); paint.setTextSize(text_size_); paint.setColor(color_); paint.setStrokeWidth(width_); paint.setStrokeMiter(miter_limit_); paint.setBlendMode(getBlendMode()); paint.setFlags(bitfields_.flags_); paint.setStrokeCap(static_cast(getStrokeCap())); paint.setStrokeJoin(static_cast(getStrokeJoin())); paint.setStyle(static_cast(getStyle())); paint.setTextEncoding(static_cast(getTextEncoding())); paint.setHinting(static_cast(getHinting())); paint.setFilterQuality(getFilterQuality()); return paint; } bool PaintFlags::IsValid() const { return PaintOp::IsValidPaintFlagsSkBlendMode(getBlendMode()); } bool PaintFlags::operator==(const PaintFlags& other) const { // Can't just ToSkPaint and operator== here as SkPaint does pointer // comparisons on all the ref'd skia objects on the SkPaint, which // is not true after serialization. if (!PaintOp::AreEqualEvenIfNaN(getTextSize(), other.getTextSize())) return false; if (getColor() != other.getColor()) return false; if (!PaintOp::AreEqualEvenIfNaN(getStrokeWidth(), other.getStrokeWidth())) return false; if (!PaintOp::AreEqualEvenIfNaN(getStrokeMiter(), other.getStrokeMiter())) return false; if (getBlendMode() != other.getBlendMode()) return false; if (getStrokeCap() != other.getStrokeCap()) return false; if (getStrokeJoin() != other.getStrokeJoin()) return false; if (getStyle() != other.getStyle()) return false; if (getTextEncoding() != other.getTextEncoding()) return false; if (getHinting() != other.getHinting()) return false; if (getFilterQuality() != other.getFilterQuality()) return false; // TODO(enne): compare typeface too if (!PaintOp::AreSkFlattenablesEqual(getPathEffect().get(), other.getPathEffect().get())) { return false; } if (!PaintOp::AreSkFlattenablesEqual(getMaskFilter().get(), other.getMaskFilter().get())) { return false; } if (!PaintOp::AreSkFlattenablesEqual(getColorFilter().get(), other.getColorFilter().get())) { return false; } if (!PaintOp::AreSkFlattenablesEqual(getLooper().get(), other.getLooper().get())) { return false; } if (!getImageFilter() != !other.getImageFilter()) return false; if (getImageFilter() && *getImageFilter() != *other.getImageFilter()) return false; if (!getShader() != !other.getShader()) return false; if (getShader() && *getShader() != *other.getShader()) return false; return true; } bool PaintFlags::HasDiscardableImages() const { return (shader_ && shader_->has_discardable_images()) || (image_filter_ && image_filter_->has_discardable_images()); } size_t PaintFlags::GetSerializedSize() const { return sizeof(text_size_) + sizeof(color_) + sizeof(width_) + sizeof(miter_limit_) + sizeof(blend_mode_) + sizeof(bitfields_uint_) + PaintOpWriter::GetFlattenableSize(path_effect_.get()) + PaintOpWriter::Alignment() + PaintOpWriter::GetFlattenableSize(mask_filter_.get()) + PaintOpWriter::Alignment() + PaintOpWriter::GetFlattenableSize(color_filter_.get()) + PaintOpWriter::Alignment() + PaintOpWriter::GetFlattenableSize(draw_looper_.get()) + PaintFilter::GetFilterSize(image_filter_.get()) + PaintShader::GetSerializedSize(shader_.get()); } } // namespace cc