123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667 |
- // 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_shader.h"
- #include <utility>
- #include "base/atomic_sequence_num.h"
- #include "base/notreached.h"
- #include "base/stl_util.h"
- #include "cc/paint/image_provider.h"
- #include "cc/paint/paint_image_builder.h"
- #include "cc/paint/paint_op_writer.h"
- #include "cc/paint/paint_record.h"
- #include "third_party/skia/include/core/SkColorSpace.h"
- #include "third_party/skia/include/core/SkPictureRecorder.h"
- #include "third_party/skia/include/effects/SkGradientShader.h"
- namespace cc {
- namespace {
- base::AtomicSequenceNumber g_next_shader_id;
- sk_sp<SkPicture> ToSkPicture(sk_sp<PaintRecord> record,
- const SkRect& bounds,
- const gfx::SizeF* raster_scale,
- ImageProvider* image_provider) {
- SkPictureRecorder recorder;
- SkCanvas* canvas =
- recorder.beginRecording(SkRect::MakeWH(bounds.width(), bounds.height()));
- canvas->translate(-bounds.fLeft, -bounds.fTop);
- if (raster_scale)
- canvas->scale(raster_scale->width(), raster_scale->height());
- record->Playback(canvas, PlaybackParams(image_provider));
- return recorder.finishRecordingAsPicture();
- }
- bool CompareMatrices(const SkMatrix& a,
- const SkMatrix& b,
- bool ignore_scaling_differences) {
- if (!ignore_scaling_differences)
- return PaintOp::AreSkMatricesEqual(a, b);
- SkSize scale;
- SkMatrix a_without_scale;
- SkMatrix b_without_scale;
- const bool decomposes = a.decomposeScale(&scale, &a_without_scale);
- if (decomposes != b.decomposeScale(&scale, &b_without_scale))
- return false;
- if (!decomposes)
- return true;
- return PaintOp::AreSkMatricesEqual(a_without_scale, b_without_scale);
- }
- } // namespace
- const PaintShader::RecordShaderId PaintShader::kInvalidRecordShaderId = -1;
- sk_sp<PaintShader> PaintShader::MakeEmpty() {
- sk_sp<PaintShader> shader(new PaintShader(Type::kEmpty));
- shader->ResolveSkObjects();
- return shader;
- }
- sk_sp<PaintShader> PaintShader::MakeColor(SkColor4f color) {
- sk_sp<PaintShader> shader(new PaintShader(Type::kColor));
- // Just one color. Store it in the fallback color. Easy.
- shader->fallback_color_ = color;
- shader->ResolveSkObjects();
- return shader;
- }
- sk_sp<PaintShader> PaintShader::MakeLinearGradient(const SkPoint points[],
- const SkColor4f colors[],
- const SkScalar pos[],
- int count,
- SkTileMode mode,
- uint32_t flags,
- const SkMatrix* local_matrix,
- SkColor4f fallback_color) {
- sk_sp<PaintShader> shader(new PaintShader(Type::kLinearGradient));
- // There are always two points, the start and the end.
- shader->start_point_ = points[0];
- shader->end_point_ = points[1];
- shader->SetColorsAndPositions(colors, pos, count);
- shader->SetMatrixAndTiling(local_matrix, mode, mode);
- shader->SetFlagsAndFallback(flags, fallback_color);
- shader->ResolveSkObjects();
- return shader;
- }
- sk_sp<PaintShader> PaintShader::MakeRadialGradient(const SkPoint& center,
- SkScalar radius,
- const SkColor4f colors[],
- const SkScalar pos[],
- int count,
- SkTileMode mode,
- uint32_t flags,
- const SkMatrix* local_matrix,
- SkColor4f fallback_color) {
- sk_sp<PaintShader> shader(new PaintShader(Type::kRadialGradient));
- shader->center_ = center;
- shader->start_radius_ = shader->end_radius_ = radius;
- shader->SetColorsAndPositions(colors, pos, count);
- shader->SetMatrixAndTiling(local_matrix, mode, mode);
- shader->SetFlagsAndFallback(flags, fallback_color);
- shader->ResolveSkObjects();
- return shader;
- }
- sk_sp<PaintShader> PaintShader::MakeTwoPointConicalGradient(
- const SkPoint& start,
- SkScalar start_radius,
- const SkPoint& end,
- SkScalar end_radius,
- const SkColor4f colors[],
- const SkScalar pos[],
- int count,
- SkTileMode mode,
- uint32_t flags,
- const SkMatrix* local_matrix,
- SkColor4f fallback_color) {
- sk_sp<PaintShader> shader(new PaintShader(Type::kTwoPointConicalGradient));
- shader->start_point_ = start;
- shader->end_point_ = end;
- shader->start_radius_ = start_radius;
- shader->end_radius_ = end_radius;
- shader->SetColorsAndPositions(colors, pos, count);
- shader->SetMatrixAndTiling(local_matrix, mode, mode);
- shader->SetFlagsAndFallback(flags, fallback_color);
- shader->ResolveSkObjects();
- return shader;
- }
- sk_sp<PaintShader> PaintShader::MakeSweepGradient(SkScalar cx,
- SkScalar cy,
- const SkColor4f colors[],
- const SkScalar pos[],
- int color_count,
- SkTileMode mode,
- SkScalar start_degrees,
- SkScalar end_degrees,
- uint32_t flags,
- const SkMatrix* local_matrix,
- SkColor4f fallback_color) {
- sk_sp<PaintShader> shader(new PaintShader(Type::kSweepGradient));
- shader->center_ = SkPoint::Make(cx, cy);
- shader->start_degrees_ = start_degrees;
- shader->end_degrees_ = end_degrees;
- shader->SetColorsAndPositions(colors, pos, color_count);
- shader->SetMatrixAndTiling(local_matrix, mode, mode);
- shader->SetFlagsAndFallback(flags, fallback_color);
- shader->ResolveSkObjects();
- return shader;
- }
- sk_sp<PaintShader> PaintShader::MakeImage(const PaintImage& image,
- SkTileMode tx,
- SkTileMode ty,
- const SkMatrix* local_matrix,
- const SkRect* tile_rect) {
- sk_sp<PaintShader> shader(new PaintShader(Type::kImage));
- shader->image_ = image;
- shader->SetMatrixAndTiling(local_matrix, tx, ty);
- if (tile_rect) {
- DCHECK(image.IsPaintWorklet());
- shader->tile_ = *tile_rect;
- }
- shader->ResolveSkObjects();
- return shader;
- }
- sk_sp<PaintShader> PaintShader::MakePaintRecord(
- sk_sp<PaintRecord> record,
- const SkRect& tile,
- SkTileMode tx,
- SkTileMode ty,
- const SkMatrix* local_matrix,
- ScalingBehavior scaling_behavior) {
- sk_sp<PaintShader> shader(new PaintShader(Type::kPaintRecord));
- shader->record_ = std::move(record);
- shader->id_ = g_next_shader_id.GetNext();
- shader->tile_ = tile;
- shader->scaling_behavior_ = scaling_behavior;
- shader->SetMatrixAndTiling(local_matrix, tx, ty);
- shader->ResolveSkObjects();
- return shader;
- }
- // static
- size_t PaintShader::GetSerializedSize(const PaintShader* shader) {
- size_t bool_size = sizeof(bool);
- if (!shader)
- return bool_size;
- return bool_size + sizeof(shader->shader_type_) + sizeof(shader->flags_) +
- sizeof(shader->end_radius_) + sizeof(shader->start_radius_) +
- sizeof(shader->tx_) + sizeof(shader->ty_) +
- sizeof(shader->fallback_color_) + sizeof(shader->scaling_behavior_) +
- bool_size + sizeof(*shader->local_matrix_) + sizeof(shader->center_) +
- sizeof(shader->tile_) + sizeof(shader->start_point_) +
- sizeof(shader->end_point_) + sizeof(shader->start_degrees_) +
- sizeof(shader->end_degrees_) +
- PaintOpWriter::GetImageSize(shader->image_) +
- PaintOpWriter::GetImageSize(shader->image_) + bool_size +
- sizeof(shader->id_) +
- PaintOpWriter::GetRecordSize(shader->record_.get()) +
- sizeof(shader->colors_.size()) +
- shader->colors_.size() * sizeof(SkColor4f) +
- sizeof(shader->positions_.size()) +
- shader->positions_.size() * sizeof(SkScalar);
- }
- PaintShader::PaintShader(Type type) : shader_type_(type) {}
- PaintShader::~PaintShader() = default;
- bool PaintShader::has_discardable_images() const {
- return (image_ && !image_.IsTextureBacked()) ||
- (record_ && record_->HasDiscardableImages());
- }
- bool PaintShader::GetClampedRasterizationTileRect(const SkMatrix& ctm,
- int max_texture_size,
- SkRect* tile_rect) const {
- DCHECK_EQ(shader_type_, Type::kPaintRecord);
- // If we are using a fixed scale, the record is rasterized with the original
- // tile size and scaling is applied to the generated output.
- if (scaling_behavior_ == ScalingBehavior::kFixedScale) {
- *tile_rect = tile_;
- return true;
- }
- SkMatrix matrix = ctm;
- if (local_matrix_.has_value())
- matrix.preConcat(local_matrix_.value());
- *tile_rect =
- PaintRecord::GetFixedScaleBounds(matrix, tile_, max_texture_size);
- if (tile_rect->isEmpty())
- return false;
- return true;
- }
- sk_sp<PaintShader> PaintShader::CreateScaledPaintRecord(
- const SkMatrix& ctm,
- int max_texture_size,
- gfx::SizeF* raster_scale) const {
- DCHECK_EQ(shader_type_, Type::kPaintRecord);
- // If this is already fixed scale, then this is already good to go.
- if (scaling_behavior_ == ScalingBehavior::kFixedScale) {
- *raster_scale = gfx::SizeF(1.f, 1.f);
- return sk_ref_sp<PaintShader>(this);
- }
- // For creating a decoded PaintRecord shader, we need to do the following:
- // 1) Figure out the scale at which the record should be rasterization given
- // the ctm and local_matrix on the shader.
- // 2) Transform this record to an SkPicture with this scale and replace
- // encoded images in this record with decodes from the ImageProvider. This
- // is done by setting the raster_matrix_ for this shader to be used
- // in GetSkShader.
- // 3) Since the SkShader will use a scaled SkPicture, we use a kFixedScale for
- // the decoded shader which creates an SkPicture backed SkImage for
- // creating the decoded SkShader.
- // Note that the scaling logic here is replicated from
- // SkPictureShader::refBitmapShader.
- SkRect tile_rect;
- if (!GetClampedRasterizationTileRect(ctm, max_texture_size, &tile_rect))
- return nullptr;
- sk_sp<PaintShader> shader(new PaintShader(Type::kPaintRecord));
- shader->record_ = record_;
- shader->id_ = id_;
- shader->tile_ = tile_rect;
- // Use a fixed scale since we have already scaled the tile rect and fixed the
- // raster scale.
- shader->scaling_behavior_ = ScalingBehavior::kFixedScale;
- shader->tx_ = tx_;
- shader->ty_ = ty_;
- *raster_scale =
- gfx::SizeF(SkIntToScalar(tile_rect.width()) / tile_.width(),
- SkIntToScalar(tile_rect.height()) / tile_.height());
- shader->local_matrix_ = GetLocalMatrix();
- shader->local_matrix_->preScale(1 / raster_scale->width(),
- 1 / raster_scale->height());
- return shader;
- }
- sk_sp<PaintShader> PaintShader::CreatePaintWorkletRecord(
- ImageProvider* image_provider) const {
- DCHECK_EQ(shader_type_, Type::kImage);
- DCHECK(image_ && image_.IsPaintWorklet());
- ImageProvider::ScopedResult result =
- image_provider->GetRasterContent(DrawImage(image_));
- if (!result || !result.paint_record())
- return nullptr;
- SkMatrix local_matrix = GetLocalMatrix();
- return PaintShader::MakePaintRecord(
- sk_ref_sp<PaintRecord>(result.paint_record()), tile_, tx_, ty_,
- &local_matrix);
- }
- sk_sp<PaintShader> PaintShader::CreateDecodedImage(
- const SkMatrix& ctm,
- PaintFlags::FilterQuality quality,
- ImageProvider* image_provider,
- uint32_t* transfer_cache_entry_id,
- PaintFlags::FilterQuality* raster_quality,
- bool* needs_mips,
- gpu::Mailbox* mailbox) const {
- DCHECK_EQ(shader_type_, Type::kImage);
- if (!image_)
- return nullptr;
- SkMatrix total_image_matrix = GetLocalMatrix();
- total_image_matrix.preConcat(ctm);
- SkRect src_rect = SkRect::MakeIWH(image_.width(), image_.height());
- SkIRect int_src_rect;
- src_rect.roundOut(&int_src_rect);
- DrawImage draw_image(image_, false, int_src_rect, quality,
- SkM44(total_image_matrix));
- auto decoded_draw_image = image_provider->GetRasterContent(draw_image);
- if (!decoded_draw_image)
- return nullptr;
- auto decoded_image = decoded_draw_image.decoded_image();
- SkMatrix final_matrix = GetLocalMatrix();
- bool need_scale = !decoded_image.is_scale_adjustment_identity();
- if (need_scale) {
- final_matrix.preScale(1.f / decoded_image.scale_adjustment().width(),
- 1.f / decoded_image.scale_adjustment().height());
- }
- PaintImage decoded_paint_image;
- if (decoded_image.transfer_cache_entry_id()) {
- decoded_paint_image = image_;
- *transfer_cache_entry_id = *decoded_image.transfer_cache_entry_id();
- } else if (!decoded_image.mailbox().IsZero()) {
- decoded_paint_image = image_;
- *mailbox = decoded_image.mailbox();
- } else {
- DCHECK(decoded_image.image());
- sk_sp<SkImage> sk_image =
- sk_ref_sp<SkImage>(const_cast<SkImage*>(decoded_image.image().get()));
- decoded_paint_image =
- PaintImageBuilder::WithDefault()
- .set_id(image_.stable_id())
- .set_texture_image(std::move(sk_image),
- image_.GetContentIdForFrame(0u))
- .TakePaintImage();
- }
- // TODO(khushalsagar): Remove filter quality from DecodedDrawImage. All we
- // want to do is cap the filter quality used, but Gpu and Sw cache have
- // different behaviour. D:
- *raster_quality = decoded_image.filter_quality();
- *needs_mips = decoded_image.transfer_cache_entry_needs_mips();
- return PaintShader::MakeImage(decoded_paint_image, tx_, ty_, &final_matrix);
- }
- sk_sp<SkShader> PaintShader::GetSkShader(
- PaintFlags::FilterQuality quality) const {
- SkSamplingOptions sampling(
- PaintFlags::FilterQualityToSkSamplingOptions(quality));
- // TODO(crbug/1308932): Remove this helper vector colors and make all
- // SkColor4f.
- std::vector<SkColor> colors;
- colors.reserve(colors.size());
- for (auto& c : colors_)
- colors.push_back(c.toSkColor());
- switch (shader_type_) {
- case Type::kEmpty:
- return SkShaders::Empty();
- case Type::kColor:
- // This will be handled by the fallback check below.
- break;
- case Type::kLinearGradient: {
- SkPoint points[2] = {start_point_, end_point_};
- // TODO(crbug/1308932): Remove this helper vector colors and make all
- // SkColor4f.
- return SkGradientShader::MakeLinear(
- points, colors.data(),
- positions_.empty() ? nullptr : positions_.data(),
- static_cast<int>(colors.size()), tx_, flags_,
- base::OptionalOrNullptr(local_matrix_));
- }
- case Type::kRadialGradient:
- return SkGradientShader::MakeRadial(
- center_, start_radius_, colors_.data(),
- nullptr /*sk_sp<SkColorSpace>*/,
- positions_.empty() ? nullptr : positions_.data(),
- static_cast<int>(colors_.size()), tx_, flags_,
- base::OptionalOrNullptr(local_matrix_));
- case Type::kTwoPointConicalGradient:
- return SkGradientShader::MakeTwoPointConical(
- start_point_, start_radius_, end_point_, end_radius_, colors_.data(),
- nullptr /*sk_sp<SkColorSpace>*/,
- positions_.empty() ? nullptr : positions_.data(),
- static_cast<int>(colors_.size()), tx_, flags_,
- base::OptionalOrNullptr(local_matrix_));
- case Type::kSweepGradient:
- return SkGradientShader::MakeSweep(
- center_.x(), center_.y(), colors_.data(),
- nullptr /*sk_sp<SkColorSpace>*/,
- positions_.empty() ? nullptr : positions_.data(),
- static_cast<int>(colors_.size()), tx_, start_degrees_, end_degrees_,
- flags_, base::OptionalOrNullptr(local_matrix_));
- case Type::kImage:
- if (sk_cached_image_) {
- return sk_cached_image_->makeShader(
- tx_, ty_, sampling, base::OptionalOrNullptr(local_matrix_));
- }
- break;
- case Type::kPaintRecord:
- if (sk_cached_picture_) {
- switch (scaling_behavior_) {
- // For raster scale, we create a picture shader directly.
- case ScalingBehavior::kRasterAtScale:
- return sk_cached_picture_->makeShader(
- tx_, ty_, sampling.filter,
- base::OptionalOrNullptr(local_matrix_), nullptr);
- // For fixed scale, we create an image shader with an image backed by
- // the picture.
- case ScalingBehavior::kFixedScale: {
- auto image = SkImage::MakeFromPicture(
- sk_cached_picture_,
- SkISize::Make(tile_.width(), tile_.height()), nullptr, nullptr,
- SkImage::BitDepth::kU8, SkColorSpace::MakeSRGB());
- return image->makeShader(tx_, ty_, sampling,
- base::OptionalOrNullptr(local_matrix_));
- }
- }
- break;
- }
- break;
- case Type::kShaderCount:
- NOTREACHED();
- break;
- }
- // If we didn't create a shader for whatever reason, create a fallback
- // color one.
- return SkShaders::Color(fallback_color_.toSkColor());
- }
- void PaintShader::ResolveSkObjects(const gfx::SizeF* raster_scale,
- ImageProvider* image_provider) {
- switch (shader_type_) {
- case Type::kImage:
- if (image_ && !image_.IsPaintWorklet()) {
- sk_cached_image_ = image_.GetSkImage();
- }
- break;
- case Type::kPaintRecord: {
- // Create a recording at the desired scale if this record has images
- // which have been decoded before raster.
- sk_cached_picture_ =
- ToSkPicture(record_, tile_, raster_scale, image_provider);
- break;
- }
- default:
- break;
- }
- }
- void PaintShader::SetColorsAndPositions(const SkColor4f* colors,
- const SkScalar* positions,
- int count) {
- #if DCHECK_IS_ON()
- static const int kMaxShaderColorsSupported = 10000;
- DCHECK_GE(count, 2);
- DCHECK_LE(count, kMaxShaderColorsSupported);
- #endif
- colors_.assign(colors, colors + count);
- if (positions)
- positions_.assign(positions, positions + count);
- }
- void PaintShader::SetMatrixAndTiling(const SkMatrix* matrix,
- SkTileMode tx,
- SkTileMode ty) {
- if (matrix)
- local_matrix_ = *matrix;
- tx_ = tx;
- ty_ = ty;
- }
- void PaintShader::SetFlagsAndFallback(uint32_t flags,
- SkColor4f fallback_color) {
- flags_ = flags;
- fallback_color_ = fallback_color;
- }
- bool PaintShader::IsOpaque() const {
- switch (shader_type_) {
- case Type::kEmpty:
- return false;
- case Type::kColor:
- // This will be handled by the fallback check below.
- break;
- case Type::kLinearGradient: // fall-through
- case Type::kRadialGradient: // fall-through
- case Type::kSweepGradient:
- if (tx_ == SkTileMode::kDecal)
- return false;
- for (const auto& c : colors_)
- if (!c.isOpaque())
- return false;
- return true;
- case Type::kTwoPointConicalGradient:
- // Because two-point-conical can sometimes ignore its tiling and not draw
- // everywhere, we conservatively return false here. If we measure
- // performance reasons to be more aggressive here, we can ask Skia to
- // expose private functionality to compute this with having to actually
- // instantiate a sk_shader object.
- return false;
- case Type::kImage:
- if (tx_ == SkTileMode::kDecal || ty_ == SkTileMode::kDecal)
- return false;
- if (sk_cached_image_)
- return sk_cached_image_->isOpaque();
- return false;
- case Type::kPaintRecord:
- return false;
- case Type::kShaderCount:
- NOTREACHED();
- break;
- }
- return fallback_color_.isOpaque();
- }
- bool PaintShader::IsValid() const {
- switch (shader_type_) {
- case Type::kEmpty:
- case Type::kColor:
- return true;
- case Type::kSweepGradient:
- if (!std::isfinite(start_degrees_) || !std::isfinite(end_degrees_) ||
- start_degrees_ >= end_degrees_) {
- return false;
- }
- [[fallthrough]];
- case Type::kLinearGradient:
- case Type::kRadialGradient:
- case Type::kTwoPointConicalGradient:
- return colors_.size() >= 2 &&
- (positions_.empty() || positions_.size() == colors_.size());
- case Type::kImage:
- // We may not be able to decode the image, in which case it would be
- // false, but that would still make a valid shader.
- return true;
- case Type::kPaintRecord:
- return !!record_;
- case Type::kShaderCount:
- return false;
- }
- return false;
- }
- bool PaintShader::operator==(const PaintShader& other) const {
- if (shader_type_ != other.shader_type_)
- return false;
- // Record and image shaders are scaled during serialization.
- const bool ignore_scaling_differences =
- shader_type_ == PaintShader::Type::kPaintRecord ||
- shader_type_ == PaintShader::Type::kImage;
- // Variables that all shaders use.
- const SkMatrix& local_matrix = local_matrix_ ? *local_matrix_ : SkMatrix::I();
- const SkMatrix& other_local_matrix =
- other.local_matrix_ ? *other.local_matrix_ : SkMatrix::I();
- if (!CompareMatrices(local_matrix, other_local_matrix,
- ignore_scaling_differences)) {
- return false;
- }
- if (fallback_color_ != other.fallback_color_)
- return false;
- if (flags_ != other.flags_)
- return false;
- if (tx_ != other.tx_)
- return false;
- if (ty_ != other.ty_)
- return false;
- if (!ignore_scaling_differences &&
- scaling_behavior_ != other.scaling_behavior_)
- return false;
- // Variables that only some shaders use.
- switch (shader_type_) {
- case Type::kEmpty:
- case Type::kColor:
- break;
- case Type::kSweepGradient:
- if (!PaintOp::AreEqualEvenIfNaN(start_degrees_, other.start_degrees_))
- return false;
- if (!PaintOp::AreEqualEvenIfNaN(end_degrees_, other.end_degrees_))
- return false;
- [[fallthrough]];
- case Type::kLinearGradient:
- case Type::kRadialGradient:
- case Type::kTwoPointConicalGradient:
- if (!PaintOp::AreEqualEvenIfNaN(start_radius_, other.start_radius_))
- return false;
- if (!PaintOp::AreEqualEvenIfNaN(end_radius_, other.end_radius_))
- return false;
- if (!PaintOp::AreSkPointsEqual(center_, other.center_))
- return false;
- if (!PaintOp::AreSkPointsEqual(start_point_, other.start_point_))
- return false;
- if (!PaintOp::AreSkPointsEqual(end_point_, other.end_point_))
- return false;
- if (colors_ != other.colors_)
- return false;
- if (positions_.size() != other.positions_.size())
- return false;
- for (size_t i = 0; i < positions_.size(); ++i) {
- if (!PaintOp::AreEqualEvenIfNaN(positions_[i], other.positions_[i]))
- return false;
- }
- break;
- case Type::kImage:
- // TODO(enne): add comparison of images once those are serialized.
- break;
- case Type::kPaintRecord:
- // If we have a record but not other.record, or vice versa, then shaders
- // aren't the same.
- if (!record_ != !other.record_)
- return false;
- // tile_ and record_ intentionally omitted since they are modified on the
- // serialized shader based on the ctm.
- break;
- case Type::kShaderCount:
- break;
- }
- return true;
- }
- } // namespace cc
|