Commit 813d15c1 authored by Adrienne Walker's avatar Adrienne Walker Committed by Commit Bot

cc: Add serialization of most of PaintFlags

This adds serialization/deserialization/testing for most of the
internals of PaintFlags.  SkValidatingSerializeFlattenable is used for
more complex Skia objects.

Still remaining to be handled are PaintShader and SkTypeface.
Additionally, SkValidatingSerializeFlattenable ignores
SkPictureImageFilters for security purposes and so these will have to be
handled in some other manner in the future.

This serialization is not yet called while running Chrome yet.  This is
all for testing purposes at this point.

Bug: 737629
Cq-Include-Trybots: master.tryserver.blink:linux_trusty_blink_rel
Change-Id: Ic1787721e7518367dca0c40f7a6a438bca980701
Reviewed-on: https://chromium-review.googlesource.com/578321Reviewed-by: default avatarVladimir Levin <vmpstr@chromium.org>
Commit-Queue: enne <enne@chromium.org>
Cr-Commit-Position: refs/heads/master@{#488678}
parent e24ae394
......@@ -14,15 +14,19 @@ static bool affects_alpha(const SkColorFilter* cf) {
namespace cc {
// Match SkPaint defaults.
PaintFlags::PaintFlags()
: flags_(0u),
cap_type_(SkPaint::kDefault_Cap),
join_type_(SkPaint::kDefault_Join),
style_(SkPaint::kFill_Style),
text_encoding_(SkPaint::kUTF8_TextEncoding),
hinting_(SkPaint::kNormal_Hinting),
filter_quality_(SkFilterQuality::kNone_SkFilterQuality) {}
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;
......@@ -104,12 +108,11 @@ SkPaint PaintFlags::ToSkPaint() const {
paint.setDrawLooper(draw_looper_);
paint.setImageFilter(image_filter_);
paint.setTextSize(text_size_);
paint.setTextScaleX(text_scale_x_);
paint.setColor(color_);
paint.setStrokeWidth(width_);
paint.setStrokeMiter(miter_limit_);
paint.setBlendMode(getBlendMode());
paint.setFlags(flags_);
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()));
......
......@@ -34,8 +34,10 @@ class CC_PAINT_EXPORT PaintFlags {
kStrokeAndFill_Style = SkPaint::kStrokeAndFill_Style,
};
bool nothingToDraw() const;
ALWAYS_INLINE Style getStyle() const { return static_cast<Style>(style_); }
ALWAYS_INLINE void setStyle(Style style) { style_ = style; }
ALWAYS_INLINE Style getStyle() const {
return static_cast<Style>(bitfields_.style_);
}
ALWAYS_INLINE void setStyle(Style style) { bitfields_.style_ = style; }
ALWAYS_INLINE SkColor getColor() const { return color_; }
ALWAYS_INLINE void setColor(SkColor color) { color_ = color; }
ALWAYS_INLINE uint8_t getAlpha() const { return SkColorGetA(color_); }
......@@ -50,25 +52,25 @@ class CC_PAINT_EXPORT PaintFlags {
return static_cast<SkBlendMode>(blend_mode_);
}
ALWAYS_INLINE bool isAntiAlias() const {
return !!(flags_ & SkPaint::kAntiAlias_Flag);
return !!(bitfields_.flags_ & SkPaint::kAntiAlias_Flag);
}
ALWAYS_INLINE void setAntiAlias(bool aa) {
SetInternalFlag(aa, SkPaint::kAntiAlias_Flag);
}
ALWAYS_INLINE bool isVerticalText() const {
return !!(flags_ & SkPaint::kVerticalText_Flag);
return !!(bitfields_.flags_ & SkPaint::kVerticalText_Flag);
}
ALWAYS_INLINE void setVerticalText(bool vertical) {
SetInternalFlag(vertical, SkPaint::kVerticalText_Flag);
}
ALWAYS_INLINE bool isSubpixelText() const {
return !!(flags_ & SkPaint::kSubpixelText_Flag);
return !!(bitfields_.flags_ & SkPaint::kSubpixelText_Flag);
}
ALWAYS_INLINE void setSubpixelText(bool subpixel_text) {
SetInternalFlag(subpixel_text, SkPaint::kSubpixelText_Flag);
}
ALWAYS_INLINE bool isLCDRenderText() const {
return !!(flags_ & SkPaint::kLCDRenderText_Flag);
return !!(bitfields_.flags_ & SkPaint::kLCDRenderText_Flag);
}
ALWAYS_INLINE void setLCDRenderText(bool lcd_text) {
SetInternalFlag(lcd_text, SkPaint::kLCDRenderText_Flag);
......@@ -80,17 +82,19 @@ class CC_PAINT_EXPORT PaintFlags {
kFull_Hinting = SkPaint::kFull_Hinting
};
ALWAYS_INLINE Hinting getHinting() const {
return static_cast<Hinting>(hinting_);
return static_cast<Hinting>(bitfields_.hinting_);
}
ALWAYS_INLINE void setHinting(Hinting hinting) {
bitfields_.hinting_ = hinting;
}
ALWAYS_INLINE void setHinting(Hinting hinting) { hinting_ = hinting; }
ALWAYS_INLINE bool isAutohinted() const {
return !!(flags_ & SkPaint::kAutoHinting_Flag);
return !!(bitfields_.flags_ & SkPaint::kAutoHinting_Flag);
}
ALWAYS_INLINE void setAutohinted(bool use_auto_hinter) {
SetInternalFlag(use_auto_hinter, SkPaint::kAutoHinting_Flag);
}
ALWAYS_INLINE bool isDither() const {
return !!(flags_ & SkPaint::kDither_Flag);
return !!(bitfields_.flags_ & SkPaint::kDither_Flag);
}
ALWAYS_INLINE void setDither(bool dither) {
SetInternalFlag(dither, SkPaint::kDither_Flag);
......@@ -102,18 +106,18 @@ class CC_PAINT_EXPORT PaintFlags {
kGlyphID_TextEncoding = SkPaint::kGlyphID_TextEncoding
};
ALWAYS_INLINE TextEncoding getTextEncoding() const {
return static_cast<TextEncoding>(text_encoding_);
return static_cast<TextEncoding>(bitfields_.text_encoding_);
}
ALWAYS_INLINE void setTextEncoding(TextEncoding encoding) {
text_encoding_ = encoding;
bitfields_.text_encoding_ = encoding;
}
ALWAYS_INLINE SkScalar getTextSize() const { return text_size_; }
ALWAYS_INLINE void setTextSize(SkScalar text_size) { text_size_ = text_size; }
ALWAYS_INLINE void setFilterQuality(SkFilterQuality quality) {
filter_quality_ = quality;
bitfields_.filter_quality_ = quality;
}
ALWAYS_INLINE SkFilterQuality getFilterQuality() const {
return static_cast<SkFilterQuality>(filter_quality_);
return static_cast<SkFilterQuality>(bitfields_.filter_quality_);
}
ALWAYS_INLINE SkScalar getStrokeWidth() const { return width_; }
ALWAYS_INLINE void setStrokeWidth(SkScalar width) { width_ = width; }
......@@ -128,8 +132,10 @@ class CC_PAINT_EXPORT PaintFlags {
kLast_Cap = kSquare_Cap,
kDefault_Cap = kButt_Cap
};
ALWAYS_INLINE Cap getStrokeCap() const { return static_cast<Cap>(cap_type_); }
ALWAYS_INLINE void setStrokeCap(Cap cap) { cap_type_ = 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,
......@@ -138,9 +144,9 @@ class CC_PAINT_EXPORT PaintFlags {
kDefault_Join = kMiter_Join
};
ALWAYS_INLINE Join getStrokeJoin() const {
return static_cast<Join>(join_type_);
return static_cast<Join>(bitfields_.join_type_);
}
ALWAYS_INLINE void setStrokeJoin(Join join) { join_type_ = join; }
ALWAYS_INLINE void setStrokeJoin(Join join) { bitfields_.join_type_ = join; }
ALWAYS_INLINE const sk_sp<SkTypeface>& getTypeface() const {
return typeface_;
......@@ -215,9 +221,9 @@ class CC_PAINT_EXPORT PaintFlags {
ALWAYS_INLINE void SetInternalFlag(bool value, uint32_t mask) {
if (value)
flags_ |= mask;
bitfields_.flags_ |= mask;
else
flags_ &= ~mask;
bitfields_.flags_ &= ~mask;
}
sk_sp<SkTypeface> typeface_;
......@@ -231,13 +237,12 @@ class CC_PAINT_EXPORT PaintFlags {
// Match(ish) SkPaint defaults. SkPaintDefaults is not public, so this
// just uses these values and ignores any SkUserConfig overrides.
float text_size_ = 12.f;
float text_scale_x_ = 1.f;
float text_skew_x_ = 0.f;
SkColor color_ = SK_ColorBLACK;
float width_ = 0.f;
float miter_limit_ = 4.f;
uint32_t blend_mode_ = static_cast<uint32_t>(SkBlendMode::kSrcOver);
struct PaintFlagsBitfields {
uint32_t flags_ : 16;
uint32_t cap_type_ : 2;
uint32_t join_type_ : 2;
......@@ -245,6 +250,12 @@ class CC_PAINT_EXPORT PaintFlags {
uint32_t text_encoding_ : 2;
uint32_t hinting_ : 2;
uint32_t filter_quality_ : 2;
};
union {
PaintFlagsBitfields bitfields_;
uint32_t bitfields_uint_;
};
};
} // namespace cc
......
......@@ -9,8 +9,13 @@
#include "cc/test/skia_common.h"
#include "cc/test/test_skcanvas.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkFlattenableSerialization.h"
#include "third_party/skia/include/core/SkWriteBuffer.h"
#include "third_party/skia/include/effects/SkBlurMaskFilter.h"
#include "third_party/skia/include/effects/SkColorMatrixFilter.h"
#include "third_party/skia/include/effects/SkDashPathEffect.h"
#include "third_party/skia/include/effects/SkLayerDrawLooper.h"
#include "third_party/skia/include/effects/SkOffsetImageFilter.h"
using testing::_;
using testing::Property;
......@@ -25,11 +30,40 @@ void Playback(PaintOpBuffer* buffer,
buffer->Playback(canvas, nullptr, &indices);
}
void ExpectFlattenableEqual(SkFlattenable* expected, SkFlattenable* actual) {
sk_sp<SkData> expected_data(SkValidatingSerializeFlattenable(expected));
sk_sp<SkData> actual_data(SkValidatingSerializeFlattenable(actual));
ASSERT_EQ(expected_data->size(), actual_data->size());
EXPECT_TRUE(expected_data->equals(actual_data.get()));
}
void ExpectPaintFlagsEqual(const PaintFlags& expected,
const PaintFlags& actual) {
SkPaint expected_paint = expected.ToSkPaint();
SkPaint actual_paint = actual.ToSkPaint();
EXPECT_TRUE(expected_paint == actual_paint);
// 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.
EXPECT_EQ(expected.getTextSize(), actual.getTextSize());
EXPECT_EQ(expected.getColor(), actual.getColor());
EXPECT_EQ(expected.getStrokeWidth(), actual.getStrokeWidth());
EXPECT_EQ(expected.getStrokeMiter(), actual.getStrokeMiter());
EXPECT_EQ(expected.getBlendMode(), actual.getBlendMode());
EXPECT_EQ(expected.getStrokeCap(), actual.getStrokeCap());
EXPECT_EQ(expected.getStrokeJoin(), actual.getStrokeJoin());
EXPECT_EQ(expected.getStyle(), actual.getStyle());
EXPECT_EQ(expected.getTextEncoding(), actual.getTextEncoding());
EXPECT_EQ(expected.getHinting(), actual.getHinting());
EXPECT_EQ(expected.getFilterQuality(), actual.getFilterQuality());
// TODO(enne): compare typeface and shader too
ExpectFlattenableEqual(expected.getPathEffect().get(),
actual.getPathEffect().get());
ExpectFlattenableEqual(expected.getMaskFilter().get(),
actual.getMaskFilter().get());
ExpectFlattenableEqual(expected.getColorFilter().get(),
actual.getColorFilter().get());
ExpectFlattenableEqual(expected.getLooper().get(), actual.getLooper().get());
ExpectFlattenableEqual(expected.getImageFilter().get(),
actual.getImageFilter().get());
}
} // namespace
......@@ -997,9 +1031,63 @@ std::vector<SkPath> test_paths = {
SkPath(),
};
// TODO(enne): make this more real.
std::vector<PaintFlags> test_flags = {
PaintFlags(), PaintFlags(), PaintFlags(), PaintFlags(), PaintFlags(),
PaintFlags(),
[] {
PaintFlags flags;
flags.setTextSize(82.7f);
flags.setColor(SK_ColorMAGENTA);
flags.setStrokeWidth(4.2f);
flags.setStrokeMiter(5.91f);
flags.setBlendMode(SkBlendMode::kDst);
flags.setStrokeCap(PaintFlags::kSquare_Cap);
flags.setStrokeJoin(PaintFlags::kBevel_Join);
flags.setStyle(PaintFlags::kStrokeAndFill_Style);
flags.setTextEncoding(PaintFlags::kGlyphID_TextEncoding);
flags.setHinting(PaintFlags::kNormal_Hinting);
flags.setFilterQuality(SkFilterQuality::kMedium_SkFilterQuality);
return flags;
}(),
[] {
PaintFlags flags;
flags.setTextSize(0.0f);
flags.setColor(SK_ColorCYAN);
flags.setAlpha(103);
flags.setStrokeWidth(0.32f);
flags.setStrokeMiter(7.98f);
flags.setBlendMode(SkBlendMode::kSrcOut);
flags.setStrokeCap(PaintFlags::kRound_Cap);
flags.setStrokeJoin(PaintFlags::kRound_Join);
flags.setStyle(PaintFlags::kFill_Style);
flags.setTextEncoding(PaintFlags::kUTF32_TextEncoding);
flags.setHinting(PaintFlags::kSlight_Hinting);
flags.setFilterQuality(SkFilterQuality::kHigh_SkFilterQuality);
SkScalar intervals[] = {1.f, 1.f};
flags.setPathEffect(SkDashPathEffect::Make(intervals, 2, 0));
flags.setMaskFilter(
SkBlurMaskFilter::Make(SkBlurStyle::kOuter_SkBlurStyle, 4.3f,
test_rects[0], kHigh_SkBlurQuality));
flags.setColorFilter(SkColorMatrixFilter::MakeLightingFilter(
SK_ColorYELLOW, SK_ColorGREEN));
SkLayerDrawLooper::Builder looper_builder;
looper_builder.addLayer();
looper_builder.addLayer(2.3f, 4.5f);
SkLayerDrawLooper::LayerInfo layer_info;
layer_info.fPaintBits |= SkLayerDrawLooper::kMaskFilter_Bit;
layer_info.fColorMode = SkBlendMode::kDst;
layer_info.fOffset.set(-1.f, 5.2f);
looper_builder.addLayer(layer_info);
flags.setLooper(looper_builder.detach());
flags.setImageFilter(SkOffsetImageFilter::Make(10, 11, nullptr));
return flags;
}(),
PaintFlags(),
PaintFlags(),
PaintFlags(),
};
std::vector<SkColor> test_colors = {
......@@ -1429,7 +1517,9 @@ void PushTranslateOps(PaintOpBuffer* buffer) {
buffer->push<TranslateOp>(test_floats[i], test_floats[i + 1]);
}
void CompareFlags(const PaintFlags& original, const PaintFlags& written) {}
void CompareFlags(const PaintFlags& original, const PaintFlags& written) {
ExpectPaintFlagsEqual(original, written);
}
void CompareImages(const PaintImage& original, const PaintImage& written) {}
......@@ -1878,7 +1968,7 @@ class PaintOpSerializationTest : public ::testing::TestWithParam<uint8_t> {
void ResizeOutputBuffer() {
// An arbitrary deserialization buffer size that should fit all the ops
// in the buffer_.
output_size_ = (100 + sizeof(LargestPaintOp)) * buffer_.size();
output_size_ = (1000 + sizeof(LargestPaintOp)) * buffer_.size();
output_.reset(static_cast<char*>(
base::AlignedAlloc(output_size_, PaintOpBuffer::PaintOpAlign)));
}
......@@ -1984,7 +2074,7 @@ TEST_P(PaintOpSerializationTest, DeserializationFailures) {
char* current = static_cast<char*>(output_.get());
static constexpr size_t kAlign = PaintOpBuffer::PaintOpAlign;
static constexpr size_t kOutputOpSize = sizeof(LargestPaintOp) + 100;
static constexpr size_t kOutputOpSize = sizeof(LargestPaintOp) + 1000;
std::unique_ptr<char, base::AlignedFreeDeleter> deserialize_buffer_(
static_cast<char*>(base::AlignedAlloc(kOutputOpSize, kAlign)));
......
......@@ -7,6 +7,7 @@
#include <stddef.h>
#include "cc/paint/paint_flags.h"
#include "third_party/skia/include/core/SkFlattenableSerialization.h"
#include "third_party/skia/include/core/SkPath.h"
#include "third_party/skia/include/core/SkRRect.h"
#include "third_party/skia/include/core/SkTextBlob.h"
......@@ -26,6 +27,26 @@ void PaintOpReader::ReadSimple(T* val) {
remaining_bytes_ -= sizeof(T);
}
template <typename T>
void PaintOpReader::ReadFlattenable(sk_sp<T>* val) {
size_t bytes = 0;
ReadSimple(&bytes);
if (remaining_bytes_ < bytes)
valid_ = false;
if (!valid_)
return;
if (bytes == 0)
return;
val->reset(static_cast<T*>(SkValidatingDeserializeFlattenable(
memory_, bytes, T::GetFlattenableType())));
if (!val)
valid_ = false;
memory_ += bytes;
remaining_bytes_ -= bytes;
}
void PaintOpReader::ReadData(size_t bytes, void* data) {
if (remaining_bytes_ < bytes)
valid_ = false;
......@@ -94,7 +115,20 @@ void PaintOpReader::Read(SkPath* path) {
}
void PaintOpReader::Read(PaintFlags* flags) {
// TODO(enne): implement PaintFlags serialization: http://crbug.com/737629
Read(&flags->text_size_);
ReadSimple(&flags->color_);
Read(&flags->width_);
Read(&flags->miter_limit_);
ReadSimple(&flags->blend_mode_);
ReadSimple(&flags->bitfields_uint_);
// TODO(enne): ReadTypeface, http://crbug.com/737629
ReadFlattenable(&flags->path_effect_);
// TODO(enne): ReadPaintShader, http://crbug.com/737629
ReadFlattenable(&flags->mask_filter_);
ReadFlattenable(&flags->color_filter_);
ReadFlattenable(&flags->draw_looper_);
ReadFlattenable(&flags->image_filter_);
}
void PaintOpReader::Read(PaintImage* image) {
......
......@@ -66,6 +66,9 @@ class PaintOpReader {
template <typename T>
void ReadSimple(T* val);
template <typename T>
void ReadFlattenable(sk_sp<T>* val);
const char* memory_ = nullptr;
size_t remaining_bytes_ = 0u;
bool valid_ = true;
......
......@@ -5,6 +5,7 @@
#include "cc/paint/paint_op_writer.h"
#include "cc/paint/paint_flags.h"
#include "third_party/skia/include/core/SkFlattenableSerialization.h"
#include "third_party/skia/include/core/SkTextBlob.h"
namespace cc {
......@@ -23,6 +24,16 @@ void PaintOpWriter::WriteSimple(const T& val) {
remaining_bytes_ -= sizeof(T);
}
void PaintOpWriter::WriteFlattenable(const SkFlattenable* val) {
// TODO(enne): change skia API to make this a const parameter.
sk_sp<SkData> data(
SkValidatingSerializeFlattenable(const_cast<SkFlattenable*>(val)));
Write(data->size());
if (!data->isEmpty())
WriteData(data->size(), data->data());
}
void PaintOpWriter::Write(size_t data) {
WriteSimple(data);
}
......@@ -60,7 +71,20 @@ void PaintOpWriter::Write(const SkPath& path) {
}
void PaintOpWriter::Write(const PaintFlags& flags) {
// TODO(enne): implement PaintFlags serialization: http://crbug.com/737629
Write(flags.text_size_);
WriteSimple(flags.color_);
Write(flags.width_);
Write(flags.miter_limit_);
WriteSimple(flags.blend_mode_);
WriteSimple(flags.bitfields_uint_);
// TODO(enne): WriteTypeface, http://crbug.com/737629
WriteFlattenable(flags.path_effect_.get());
// TODO(enne): WritePaintShader, http://crbug.com/737629
WriteFlattenable(flags.mask_filter_.get());
WriteFlattenable(flags.color_filter_.get());
WriteFlattenable(flags.draw_looper_.get());
WriteFlattenable(flags.image_filter_.get());
}
void PaintOpWriter::Write(const PaintImage& image, ImageDecodeCache* cache) {
......
......@@ -60,6 +60,8 @@ class PaintOpWriter {
template <typename T>
void WriteSimple(const T& val);
void WriteFlattenable(const SkFlattenable* val);
char* memory_ = nullptr;
size_t size_ = 0u;
size_t remaining_bytes_ = 0u;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment