blob: 04ecff6f3e4118ef75b8702c188850e53b30b434 [file] [log] [blame]
// 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_ = static_cast<unsigned>(SkFontHinting::kNormal);
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<uint32_t>(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<PaintFilter> 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<SkPaint::Cap>(getStrokeCap()));
paint.setStrokeJoin(static_cast<SkPaint::Join>(getStrokeJoin()));
paint.setStyle(static_cast<SkPaint::Style>(getStyle()));
paint.setTextEncoding(static_cast<SkPaint::TextEncoding>(getTextEncoding()));
paint.setHinting(static_cast<SkFontHinting>(getHinting()));
paint.setFilterQuality(getFilterQuality());
return paint;
}
SkFont PaintFlags::ToSkFont() const {
SkFont font;
font.setTypeface(typeface_);
font.setSize(text_size_);
font.setHinting(static_cast<SkFontHinting>(getHinting()));
font.setForceAutoHinting(isAutohinted());
font.setSubpixel(isSubpixelText());
if (isAntiAlias()) {
if (isLCDRenderText()) {
font.setEdging(SkFont::Edging::kSubpixelAntiAlias);
} else {
font.setEdging(SkFont::Edging::kAntiAlias);
}
}
return font;
}
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