Commit 4a99e579 authored by Vladimir Levin's avatar Vladimir Levin Committed by Commit Bot

cc/paint: Serialize PaintShaders (mostly).

This patch adds serialization to PaintShaders, with the exception of
PaintImage and PaintRecord.

R=enne@chromium.org

Bug: 737629
Cq-Include-Trybots: master.tryserver.blink:linux_trusty_blink_rel
Change-Id: Idbaf512f2f0c12df8edd6bcd459af0ddaaff4126
Reviewed-on: https://chromium-review.googlesource.com/590675
Commit-Queue: Vladimir Levin <vmpstr@chromium.org>
Reviewed-by: default avatarenne <enne@chromium.org>
Cr-Commit-Position: refs/heads/master@{#491889}
parent 2c099c8f
...@@ -8,6 +8,8 @@ ...@@ -8,6 +8,8 @@
#include "cc/paint/decoded_draw_image.h" #include "cc/paint/decoded_draw_image.h"
#include "cc/paint/display_item_list.h" #include "cc/paint/display_item_list.h"
#include "cc/paint/image_provider.h" #include "cc/paint/image_provider.h"
#include "cc/paint/paint_op_reader.h"
#include "cc/paint/paint_op_writer.h"
#include "cc/test/skia_common.h" #include "cc/test/skia_common.h"
#include "cc/test/test_skcanvas.h" #include "cc/test/test_skcanvas.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
...@@ -25,49 +27,110 @@ using testing::Mock; ...@@ -25,49 +27,110 @@ using testing::Mock;
namespace cc { namespace cc {
namespace { namespace {
// An arbitrary size guaranteed to fit the size of any serialized op in this // An arbitrary size guaranteed to fit the size of any serialized op in this
// unit test. This can also be used for deserialized op size safely in this // unit test. This can also be used for deserialized op size safely in this
// unit test suite as generally deserialized ops are smaller. // unit test suite as generally deserialized ops are smaller.
static constexpr size_t kBufferBytesPerOp = 1000 + sizeof(LargestPaintOp); static constexpr size_t kBufferBytesPerOp = 1000 + sizeof(LargestPaintOp);
} // namespace
void ExpectFlattenableEqual(SkFlattenable* expected, SkFlattenable* actual) { class PaintOpSerializationTestUtils {
sk_sp<SkData> expected_data(SkValidatingSerializeFlattenable(expected)); public:
sk_sp<SkData> actual_data(SkValidatingSerializeFlattenable(actual)); static void ExpectFlattenableEqual(SkFlattenable* expected,
ASSERT_EQ(expected_data->size(), actual_data->size()); SkFlattenable* actual) {
EXPECT_TRUE(expected_data->equals(actual_data.get())); sk_sp<SkData> expected_data(SkValidatingSerializeFlattenable(expected));
} sk_sp<SkData> actual_data(SkValidatingSerializeFlattenable(actual));
ASSERT_EQ(expected_data->size(), actual_data->size());
void ExpectPaintFlagsEqual(const PaintFlags& expected, EXPECT_TRUE(expected_data->equals(actual_data.get()));
const PaintFlags& actual) { }
// Can't just ToSkPaint and operator== here as SkPaint does pointer
// comparisons on all the ref'd skia objects on the SkPaint, which static void ExpectPaintShadersEqual(const PaintShader* one,
// is not true after serialization. const PaintShader* two) {
EXPECT_EQ(expected.getTextSize(), actual.getTextSize()); if (!one) {
EXPECT_EQ(expected.getColor(), actual.getColor()); EXPECT_FALSE(two);
EXPECT_EQ(expected.getStrokeWidth(), actual.getStrokeWidth()); return;
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 ASSERT_TRUE(one);
ASSERT_TRUE(two);
EXPECT_EQ(one->shader_type_, two->shader_type_);
EXPECT_EQ(one->flags_, two->flags_);
EXPECT_EQ(one->end_radius_, two->end_radius_);
EXPECT_EQ(one->start_radius_, two->start_radius_);
EXPECT_EQ(one->tx_, two->tx_);
EXPECT_EQ(one->ty_, two->ty_);
EXPECT_EQ(one->fallback_color_, two->fallback_color_);
EXPECT_EQ(one->scaling_behavior_, two->scaling_behavior_);
if (one->local_matrix_) {
EXPECT_TRUE(two->local_matrix_.has_value());
EXPECT_TRUE(*one->local_matrix_ == *two->local_matrix_);
} else {
EXPECT_FALSE(two->local_matrix_.has_value());
}
EXPECT_EQ(one->center_, two->center_);
EXPECT_EQ(one->tile_, two->tile_);
EXPECT_EQ(one->start_point_, two->start_point_);
EXPECT_EQ(one->end_point_, two->end_point_);
EXPECT_THAT(one->colors_, testing::ElementsAreArray(two->colors_));
EXPECT_THAT(one->positions_, testing::ElementsAreArray(two->positions_));
}
static void ExpectPaintFlagsEqual(const PaintFlags& expected,
const PaintFlags& actual) {
// 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 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());
ExpectPaintShadersEqual(expected.getShader(), actual.getShader());
}
static void FillArbitraryShaderValues(PaintShader* shader, bool use_matrix) {
shader->shader_type_ = PaintShader::Type::kTwoPointConicalGradient;
shader->flags_ = 12345;
shader->end_radius_ = 12.3f;
shader->start_radius_ = 13.4f;
shader->tx_ = SkShader::kRepeat_TileMode;
shader->ty_ = SkShader::kMirror_TileMode;
shader->fallback_color_ = SkColorSetARGB(254, 252, 250, 248);
shader->scaling_behavior_ = PaintShader::ScalingBehavior::kRasterAtScale;
if (use_matrix) {
shader->local_matrix_.emplace(SkMatrix::I());
shader->local_matrix_->setSkewX(10);
shader->local_matrix_->setSkewY(20);
}
shader->center_ = SkPoint::Make(50, 40);
shader->tile_ = SkRect::MakeXYWH(7, 77, 777, 7777);
shader->start_point_ = SkPoint::Make(-1, -5);
shader->end_point_ = SkPoint::Make(13, -13);
// TODO(vmpstr): Add PaintImage/PaintRecord.
shader->colors_ = {SkColorSetARGB(1, 2, 3, 4), SkColorSetARGB(5, 6, 7, 8),
SkColorSetARGB(9, 0, 1, 2)};
shader->positions_ = {0.f, 0.4f, 1.f};
}
};
TEST(PaintOpBufferTest, Empty) { TEST(PaintOpBufferTest, Empty) {
PaintOpBuffer buffer; PaintOpBuffer buffer;
...@@ -112,7 +175,8 @@ class PaintOpAppendTest : public ::testing::Test { ...@@ -112,7 +175,8 @@ class PaintOpAppendTest : public ::testing::Test {
ASSERT_EQ(iter->GetType(), PaintOpType::SaveLayer); ASSERT_EQ(iter->GetType(), PaintOpType::SaveLayer);
SaveLayerOp* save_op = static_cast<SaveLayerOp*>(*iter); SaveLayerOp* save_op = static_cast<SaveLayerOp*>(*iter);
EXPECT_EQ(save_op->bounds, rect_); EXPECT_EQ(save_op->bounds, rect_);
ExpectPaintFlagsEqual(save_op->flags, flags_); PaintOpSerializationTestUtils::ExpectPaintFlagsEqual(save_op->flags,
flags_);
++iter; ++iter;
ASSERT_EQ(iter->GetType(), PaintOpType::Save); ASSERT_EQ(iter->GetType(), PaintOpType::Save);
...@@ -1117,6 +1181,7 @@ std::vector<PaintFlags> test_flags = { ...@@ -1117,6 +1181,7 @@ std::vector<PaintFlags> test_flags = {
flags.setTextEncoding(PaintFlags::kGlyphID_TextEncoding); flags.setTextEncoding(PaintFlags::kGlyphID_TextEncoding);
flags.setHinting(PaintFlags::kNormal_Hinting); flags.setHinting(PaintFlags::kNormal_Hinting);
flags.setFilterQuality(SkFilterQuality::kMedium_SkFilterQuality); flags.setFilterQuality(SkFilterQuality::kMedium_SkFilterQuality);
flags.setShader(PaintShader::MakeColor(SkColorSetARGB(1, 2, 3, 4)));
return flags; return flags;
}(), }(),
[] { [] {
...@@ -1154,6 +1219,38 @@ std::vector<PaintFlags> test_flags = { ...@@ -1154,6 +1219,38 @@ std::vector<PaintFlags> test_flags = {
flags.setImageFilter(SkOffsetImageFilter::Make(10, 11, nullptr)); flags.setImageFilter(SkOffsetImageFilter::Make(10, 11, nullptr));
sk_sp<PaintShader> shader = PaintShader::MakeColor(SK_ColorTRANSPARENT);
PaintOpSerializationTestUtils::FillArbitraryShaderValues(shader.get(),
true);
flags.setShader(std::move(shader));
return flags;
}(),
[] {
PaintFlags flags;
flags.setShader(PaintShader::MakeColor(SkColorSetARGB(12, 34, 56, 78)));
return flags;
}(),
[] {
PaintFlags flags;
sk_sp<PaintShader> shader = PaintShader::MakeColor(SK_ColorTRANSPARENT);
PaintOpSerializationTestUtils::FillArbitraryShaderValues(shader.get(),
false);
flags.setShader(std::move(shader));
return flags;
}(),
[] {
PaintFlags flags;
SkPoint points[2] = {SkPoint::Make(1, 2), SkPoint::Make(3, 4)};
SkColor colors[3] = {SkColorSetARGB(1, 2, 3, 4),
SkColorSetARGB(4, 3, 2, 1),
SkColorSetARGB(0, 10, 20, 30)};
SkScalar positions[3] = {0.f, 0.3f, 1.f};
flags.setShader(PaintShader::MakeLinearGradient(
points, colors, positions, 3, SkShader::kMirror_TileMode));
return flags; return flags;
}(), }(),
PaintFlags(), PaintFlags(),
...@@ -1596,7 +1693,7 @@ void PushTranslateOps(PaintOpBuffer* buffer) { ...@@ -1596,7 +1693,7 @@ void PushTranslateOps(PaintOpBuffer* buffer) {
} }
void CompareFlags(const PaintFlags& original, const PaintFlags& written) { void CompareFlags(const PaintFlags& original, const PaintFlags& written) {
ExpectPaintFlagsEqual(original, written); PaintOpSerializationTestUtils::ExpectPaintFlagsEqual(original, written);
} }
void CompareImages(const PaintImage& original, const PaintImage& written) {} void CompareImages(const PaintImage& original, const PaintImage& written) {}
......
...@@ -7,15 +7,35 @@ ...@@ -7,15 +7,35 @@
#include <stddef.h> #include <stddef.h>
#include "cc/paint/paint_flags.h" #include "cc/paint/paint_flags.h"
#include "cc/paint/paint_shader.h"
#include "third_party/skia/include/core/SkFlattenableSerialization.h" #include "third_party/skia/include/core/SkFlattenableSerialization.h"
#include "third_party/skia/include/core/SkPath.h" #include "third_party/skia/include/core/SkPath.h"
#include "third_party/skia/include/core/SkRRect.h" #include "third_party/skia/include/core/SkRRect.h"
#include "third_party/skia/include/core/SkTextBlob.h" #include "third_party/skia/include/core/SkTextBlob.h"
namespace cc { namespace cc {
namespace {
bool IsValidPaintShaderType(PaintShader::Type type) {
return static_cast<uint8_t>(type) <
static_cast<uint8_t>(PaintShader::Type::kShaderCount);
}
bool IsValidSkShaderTileMode(SkShader::TileMode mode) {
return mode < SkShader::kTileModeCount;
}
bool IsValidPaintShaderScalingBehavior(PaintShader::ScalingBehavior behavior) {
return behavior == PaintShader::ScalingBehavior::kRasterAtScale ||
behavior == PaintShader::ScalingBehavior::kFixedScale;
}
} // namespace
template <typename T> template <typename T>
void PaintOpReader::ReadSimple(T* val) { void PaintOpReader::ReadSimple(T* val) {
if (!AlignMemory(alignof(T)))
valid_ = false;
if (remaining_bytes_ < sizeof(T)) if (remaining_bytes_ < sizeof(T))
valid_ = false; valid_ = false;
if (!valid_) if (!valid_)
...@@ -33,6 +53,8 @@ void PaintOpReader::ReadFlattenable(sk_sp<T>* val) { ...@@ -33,6 +53,8 @@ void PaintOpReader::ReadFlattenable(sk_sp<T>* val) {
ReadSimple(&bytes); ReadSimple(&bytes);
if (remaining_bytes_ < bytes) if (remaining_bytes_ < bytes)
valid_ = false; valid_ = false;
if (!SkIsAlign4(reinterpret_cast<uintptr_t>(memory_)))
valid_ = false;
if (!valid_) if (!valid_)
return; return;
if (bytes == 0) if (bytes == 0)
...@@ -123,12 +145,16 @@ void PaintOpReader::Read(PaintFlags* flags) { ...@@ -123,12 +145,16 @@ void PaintOpReader::Read(PaintFlags* flags) {
ReadSimple(&flags->bitfields_uint_); ReadSimple(&flags->bitfields_uint_);
// TODO(enne): ReadTypeface, http://crbug.com/737629 // TODO(enne): ReadTypeface, http://crbug.com/737629
// Flattenables must be read at 4-byte boundary, which should be the case
// here.
ReadFlattenable(&flags->path_effect_); ReadFlattenable(&flags->path_effect_);
// TODO(enne): ReadPaintShader, http://crbug.com/737629
ReadFlattenable(&flags->mask_filter_); ReadFlattenable(&flags->mask_filter_);
ReadFlattenable(&flags->color_filter_); ReadFlattenable(&flags->color_filter_);
ReadFlattenable(&flags->draw_looper_); ReadFlattenable(&flags->draw_looper_);
ReadFlattenable(&flags->image_filter_); ReadFlattenable(&flags->image_filter_);
Read(&flags->shader_);
} }
void PaintOpReader::Read(PaintImage* image) { void PaintOpReader::Read(PaintImage* image) {
...@@ -161,4 +187,85 @@ void PaintOpReader::Read(sk_sp<SkTextBlob>* blob) { ...@@ -161,4 +187,85 @@ void PaintOpReader::Read(sk_sp<SkTextBlob>* blob) {
// TODO(enne): implement SkTextBlob serialization: http://crbug.com/737629 // TODO(enne): implement SkTextBlob serialization: http://crbug.com/737629
} }
void PaintOpReader::Read(sk_sp<PaintShader>* shader) {
bool has_shader = false;
ReadSimple(&has_shader);
if (!has_shader) {
*shader = nullptr;
return;
}
PaintShader::Type shader_type;
ReadSimple(&shader_type);
// Avoid creating a shader if something is invalid.
if (!valid_ || !IsValidPaintShaderType(shader_type)) {
valid_ = false;
return;
}
*shader = sk_sp<PaintShader>(new PaintShader(shader_type));
PaintShader& ref = **shader;
ReadSimple(&ref.flags_);
ReadSimple(&ref.end_radius_);
ReadSimple(&ref.start_radius_);
ReadSimple(&ref.tx_);
ReadSimple(&ref.ty_);
if (!IsValidSkShaderTileMode(ref.tx_) || !IsValidSkShaderTileMode(ref.ty_))
valid_ = false;
ReadSimple(&ref.fallback_color_);
ReadSimple(&ref.scaling_behavior_);
if (!IsValidPaintShaderScalingBehavior(ref.scaling_behavior_))
valid_ = false;
bool has_local_matrix = false;
ReadSimple(&has_local_matrix);
if (has_local_matrix) {
ref.local_matrix_.emplace();
ReadSimple(&*ref.local_matrix_);
}
ReadSimple(&ref.center_);
ReadSimple(&ref.tile_);
ReadSimple(&ref.start_point_);
ReadSimple(&ref.end_point_);
// TODO(vmpstr): Read PaintImage image_. http://crbug.com/737629
// TODO(vmpstr): Read sk_sp<PaintRecord> record_. http://crbug.com/737629
decltype(ref.colors_)::size_type colors_size = 0;
ReadSimple(&colors_size);
size_t colors_bytes = colors_size * sizeof(SkColor);
if (colors_bytes > remaining_bytes_) {
valid_ = false;
return;
}
ref.colors_.resize(colors_size);
ReadData(colors_bytes, ref.colors_.data());
decltype(ref.positions_)::size_type positions_size = 0;
ReadSimple(&positions_size);
size_t positions_bytes = positions_size * sizeof(SkScalar);
if (positions_bytes > remaining_bytes_) {
valid_ = false;
return;
}
ref.positions_.resize(positions_size);
ReadData(positions_size * sizeof(SkScalar), ref.positions_.data());
// We don't write the cached shader, so don't attempt to read it either.
}
bool PaintOpReader::AlignMemory(size_t alignment) {
// Due to the math below, alignment must be a power of two.
DCHECK_GT(alignment, 0u);
DCHECK_EQ(alignment & (alignment - 1), 0u);
uintptr_t memory = reinterpret_cast<uintptr_t>(memory_);
// The following is equivalent to:
// padding = (alignment - memory % alignment) % alignment;
// because alignment is a power of two. This doesn't use modulo operator
// however, since it can be slow.
size_t padding = ((memory + alignment - 1) & ~(alignment - 1)) - memory;
if (padding > remaining_bytes_)
return false;
memory_ += padding;
remaining_bytes_ -= padding;
return true;
}
} // namespace cc } // namespace cc
...@@ -7,13 +7,16 @@ ...@@ -7,13 +7,16 @@
#include <vector> #include <vector>
#include "cc/paint/paint_export.h"
#include "cc/paint/paint_op_writer.h" #include "cc/paint/paint_op_writer.h"
namespace cc { namespace cc {
class PaintShader;
// PaintOpReader takes garbage |memory| and clobbers it with successive // PaintOpReader takes garbage |memory| and clobbers it with successive
// read functions. // read functions.
class PaintOpReader { class CC_PAINT_EXPORT PaintOpReader {
public: public:
PaintOpReader(const void* memory, size_t size) PaintOpReader(const void* memory, size_t size)
: memory_(static_cast<const char*>(memory) + : memory_(static_cast<const char*>(memory) +
...@@ -40,6 +43,7 @@ class PaintOpReader { ...@@ -40,6 +43,7 @@ class PaintOpReader {
void Read(PaintImage* image); void Read(PaintImage* image);
void Read(sk_sp<SkData>* data); void Read(sk_sp<SkData>* data);
void Read(sk_sp<SkTextBlob>* blob); void Read(sk_sp<SkTextBlob>* blob);
void Read(sk_sp<PaintShader>* shader);
void Read(SkClipOp* op) { void Read(SkClipOp* op) {
uint8_t value = 0u; uint8_t value = 0u;
...@@ -69,6 +73,10 @@ class PaintOpReader { ...@@ -69,6 +73,10 @@ class PaintOpReader {
template <typename T> template <typename T>
void ReadFlattenable(sk_sp<T>* val); void ReadFlattenable(sk_sp<T>* val);
// Attempts to align the memory to the given alignment. Returns false if there
// is unsufficient bytes remaining to do this padding.
bool AlignMemory(size_t alignment);
const char* memory_ = nullptr; const char* memory_ = nullptr;
size_t remaining_bytes_ = 0u; size_t remaining_bytes_ = 0u;
bool valid_ = true; bool valid_ = true;
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include "cc/paint/paint_op_writer.h" #include "cc/paint/paint_op_writer.h"
#include "cc/paint/paint_flags.h" #include "cc/paint/paint_flags.h"
#include "cc/paint/paint_shader.h"
#include "third_party/skia/include/core/SkFlattenableSerialization.h" #include "third_party/skia/include/core/SkFlattenableSerialization.h"
#include "third_party/skia/include/core/SkTextBlob.h" #include "third_party/skia/include/core/SkTextBlob.h"
...@@ -13,7 +14,9 @@ namespace cc { ...@@ -13,7 +14,9 @@ namespace cc {
template <typename T> template <typename T>
void PaintOpWriter::WriteSimple(const T& val) { void PaintOpWriter::WriteSimple(const T& val) {
static_assert(base::is_trivially_copyable<T>::value, ""); static_assert(base::is_trivially_copyable<T>::value, "");
if (sizeof(T) > remaining_bytes_) if (!AlignMemory(alignof(T)))
valid_ = false;
if (remaining_bytes_ < sizeof(T))
valid_ = false; valid_ = false;
if (!valid_) if (!valid_)
return; return;
...@@ -25,6 +28,8 @@ void PaintOpWriter::WriteSimple(const T& val) { ...@@ -25,6 +28,8 @@ void PaintOpWriter::WriteSimple(const T& val) {
} }
void PaintOpWriter::WriteFlattenable(const SkFlattenable* val) { void PaintOpWriter::WriteFlattenable(const SkFlattenable* val) {
DCHECK(SkIsAlign4(reinterpret_cast<uintptr_t>(memory_)))
<< "Flattenable must start writing at 4 byte alignment.";
// TODO(enne): change skia API to make this a const parameter. // TODO(enne): change skia API to make this a const parameter.
sk_sp<SkData> data( sk_sp<SkData> data(
SkValidatingSerializeFlattenable(const_cast<SkFlattenable*>(val))); SkValidatingSerializeFlattenable(const_cast<SkFlattenable*>(val)));
...@@ -79,12 +84,16 @@ void PaintOpWriter::Write(const PaintFlags& flags) { ...@@ -79,12 +84,16 @@ void PaintOpWriter::Write(const PaintFlags& flags) {
WriteSimple(flags.bitfields_uint_); WriteSimple(flags.bitfields_uint_);
// TODO(enne): WriteTypeface, http://crbug.com/737629 // TODO(enne): WriteTypeface, http://crbug.com/737629
// Flattenables must be written starting at a 4 byte boundary, which should be
// the case here.
WriteFlattenable(flags.path_effect_.get()); WriteFlattenable(flags.path_effect_.get());
// TODO(enne): WritePaintShader, http://crbug.com/737629
WriteFlattenable(flags.mask_filter_.get()); WriteFlattenable(flags.mask_filter_.get());
WriteFlattenable(flags.color_filter_.get()); WriteFlattenable(flags.color_filter_.get());
WriteFlattenable(flags.draw_looper_.get()); WriteFlattenable(flags.draw_looper_.get());
WriteFlattenable(flags.image_filter_.get()); WriteFlattenable(flags.image_filter_.get());
Write(flags.shader_.get());
} }
void PaintOpWriter::Write(const PaintImage& image, ImageDecodeCache* cache) { void PaintOpWriter::Write(const PaintImage& image, ImageDecodeCache* cache) {
...@@ -107,6 +116,46 @@ void PaintOpWriter::Write(const sk_sp<SkTextBlob>& blob) { ...@@ -107,6 +116,46 @@ void PaintOpWriter::Write(const sk_sp<SkTextBlob>& blob) {
// TODO(enne): implement SkTextBlob serialization: http://crbug.com/737629 // TODO(enne): implement SkTextBlob serialization: http://crbug.com/737629
} }
void PaintOpWriter::Write(const PaintShader* shader) {
if (!shader) {
WriteSimple(false);
return;
}
// TODO(vmpstr): This could be optimized to only serialize fields relevant to
// the specific shader type. If done, then corresponding reading and tests
// would have to also be updated.
WriteSimple(true);
WriteSimple(shader->shader_type_);
WriteSimple(shader->flags_);
WriteSimple(shader->end_radius_);
WriteSimple(shader->start_radius_);
WriteSimple(shader->tx_);
WriteSimple(shader->ty_);
WriteSimple(shader->fallback_color_);
WriteSimple(shader->scaling_behavior_);
if (shader->local_matrix_) {
Write(true);
WriteSimple(*shader->local_matrix_);
} else {
Write(false);
}
WriteSimple(shader->center_);
WriteSimple(shader->tile_);
WriteSimple(shader->start_point_);
WriteSimple(shader->end_point_);
// TODO(vmpstr): Write PaintImage image_. http://crbug.com/737629
// TODO(vmpstr): Write sk_sp<PaintRecord> record_. http://crbug.com/737629
WriteSimple(shader->colors_.size());
WriteData(shader->colors_.size() * sizeof(SkColor), shader->colors_.data());
WriteSimple(shader->positions_.size());
WriteData(shader->positions_.size() * sizeof(SkScalar),
shader->positions_.data());
// Explicitly don't write the cached_shader_ because that can be regenerated
// using other fields.
}
void PaintOpWriter::WriteData(size_t bytes, const void* input) { void PaintOpWriter::WriteData(size_t bytes, const void* input) {
if (bytes > remaining_bytes_) if (bytes > remaining_bytes_)
valid_ = false; valid_ = false;
...@@ -125,4 +174,23 @@ void PaintOpWriter::WriteArray(size_t count, const SkPoint* input) { ...@@ -125,4 +174,23 @@ void PaintOpWriter::WriteArray(size_t count, const SkPoint* input) {
WriteData(bytes, input); WriteData(bytes, input);
} }
bool PaintOpWriter::AlignMemory(size_t alignment) {
// Due to the math below, alignment must be a power of two.
DCHECK_GT(alignment, 0u);
DCHECK_EQ(alignment & (alignment - 1), 0u);
uintptr_t memory = reinterpret_cast<uintptr_t>(memory_);
// The following is equivalent to:
// padding = (alignment - memory % alignment) % alignment;
// because alignment is a power of two. This doesn't use modulo operator
// however, since it can be slow.
size_t padding = ((memory + alignment - 1) & ~(alignment - 1)) - memory;
if (padding > remaining_bytes_)
return false;
memory_ += padding;
remaining_bytes_ -= padding;
return true;
}
} // namespace cc } // namespace cc
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#define CC_PAINT_PAINT_OP_WRITER_H_ #define CC_PAINT_PAINT_OP_WRITER_H_
#include "cc/paint/paint_canvas.h" #include "cc/paint/paint_canvas.h"
#include "cc/paint/paint_export.h"
struct SkRect; struct SkRect;
struct SkIRect; struct SkIRect;
...@@ -14,8 +15,9 @@ class SkRRect; ...@@ -14,8 +15,9 @@ class SkRRect;
namespace cc { namespace cc {
class ImageDecodeCache; class ImageDecodeCache;
class PaintShader;
class PaintOpWriter { class CC_PAINT_EXPORT PaintOpWriter {
public: public:
PaintOpWriter(void* memory, size_t size) PaintOpWriter(void* memory, size_t size)
: memory_(static_cast<char*>(memory) + HeaderBytes()), : memory_(static_cast<char*>(memory) + HeaderBytes()),
...@@ -46,6 +48,7 @@ class PaintOpWriter { ...@@ -46,6 +48,7 @@ class PaintOpWriter {
void Write(const PaintImage& image, ImageDecodeCache* cache); void Write(const PaintImage& image, ImageDecodeCache* cache);
void Write(const sk_sp<SkData>& data); void Write(const sk_sp<SkData>& data);
void Write(const sk_sp<SkTextBlob>& blob); void Write(const sk_sp<SkTextBlob>& blob);
void Write(const PaintShader* shader);
void Write(SkClipOp op) { Write(static_cast<uint8_t>(op)); } void Write(SkClipOp op) { Write(static_cast<uint8_t>(op)); }
void Write(PaintCanvas::AnnotationType type) { void Write(PaintCanvas::AnnotationType type) {
...@@ -62,6 +65,10 @@ class PaintOpWriter { ...@@ -62,6 +65,10 @@ class PaintOpWriter {
void WriteFlattenable(const SkFlattenable* val); void WriteFlattenable(const SkFlattenable* val);
// Attempts to align the memory to the given alignment. Returns false if there
// is unsufficient bytes remaining to do this padding.
bool AlignMemory(size_t alignment);
char* memory_ = nullptr; char* memory_ = nullptr;
size_t size_ = 0u; size_t size_ = 0u;
size_t remaining_bytes_ = 0u; size_t remaining_bytes_ = 0u;
......
...@@ -22,7 +22,7 @@ using PaintRecord = PaintOpBuffer; ...@@ -22,7 +22,7 @@ using PaintRecord = PaintOpBuffer;
class CC_PAINT_EXPORT PaintShader : public SkRefCnt { class CC_PAINT_EXPORT PaintShader : public SkRefCnt {
public: public:
enum class Type { enum class Type : uint8_t {
kColor, kColor,
kLinearGradient, kLinearGradient,
kRadialGradient, kRadialGradient,
...@@ -36,7 +36,7 @@ class CC_PAINT_EXPORT PaintShader : public SkRefCnt { ...@@ -36,7 +36,7 @@ class CC_PAINT_EXPORT PaintShader : public SkRefCnt {
// Scaling behavior dictates how a PaintRecord shader will behave. Use // Scaling behavior dictates how a PaintRecord shader will behave. Use
// RasterAtScale to create a picture shader. Use FixedScale to create an image // RasterAtScale to create a picture shader. Use FixedScale to create an image
// shader that is backed by the paint record. // shader that is backed by the paint record.
enum class ScalingBehavior { kRasterAtScale, kFixedScale }; enum class ScalingBehavior : uint8_t { kRasterAtScale, kFixedScale };
static sk_sp<PaintShader> MakeColor(SkColor color); static sk_sp<PaintShader> MakeColor(SkColor color);
...@@ -115,6 +115,9 @@ class CC_PAINT_EXPORT PaintShader : public SkRefCnt { ...@@ -115,6 +115,9 @@ class CC_PAINT_EXPORT PaintShader : public SkRefCnt {
private: private:
friend class PaintFlags; friend class PaintFlags;
friend class PaintOpReader;
friend class PaintOpSerializationTestUtils;
friend class PaintOpWriter;
explicit PaintShader(Type type); explicit PaintShader(Type type);
......
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