[go: nahoru, domu]

blob: e73d5da27db05c92dd5ad5d384263e5c053e56a5 [file] [log] [blame]
vmpstr7b99c9582017-06-08 21:39:451// Copyright 2017 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "cc/paint/paint_shader.h"
6
Adrienne Walker90b79a22018-05-08 21:40:427#include "base/atomic_sequence_num.h"
Khushal67c8c742018-05-16 18:05:058#include "cc/paint/paint_image_builder.h"
Khushal252af332018-02-14 05:03:099#include "cc/paint/paint_op_writer.h"
vmpstr7b99c9582017-06-08 21:39:4510#include "cc/paint/paint_record.h"
Khushal7ae9c792017-10-05 22:26:3211#include "third_party/skia/include/core/SkPictureRecorder.h"
vmpstr7b99c9582017-06-08 21:39:4512#include "third_party/skia/include/effects/SkGradientShader.h"
13
14namespace cc {
Khushal7ae9c792017-10-05 22:26:3215namespace {
Lei Zhang868717c2018-05-09 04:33:5616base::AtomicSequenceNumber g_next_shader_id;
Khushal7ae9c792017-10-05 22:26:3217
18sk_sp<SkPicture> ToSkPicture(sk_sp<PaintRecord> record,
19 const SkRect& bounds,
Khushal9fd411f2018-01-20 02:09:5120 const gfx::SizeF* raster_scale,
Khushal7ae9c792017-10-05 22:26:3221 ImageProvider* image_provider) {
22 SkPictureRecorder recorder;
Adrienne Walkerc4bdc13e2018-06-27 00:56:3023 SkCanvas* canvas =
24 recorder.beginRecording(SkRect::MakeWH(bounds.width(), bounds.height()));
25 canvas->translate(-bounds.fLeft, -bounds.fTop);
Khushal9fd411f2018-01-20 02:09:5126 if (raster_scale)
27 canvas->scale(raster_scale->width(), raster_scale->height());
Wei Li2a9bfe42018-01-13 05:42:5628 record->Playback(canvas, PlaybackParams(image_provider));
Khushal7ae9c792017-10-05 22:26:3229 return recorder.finishRecordingAsPicture();
30}
31
Khushal67c8c742018-05-16 18:05:0532bool CompareMatrices(const SkMatrix& a,
33 const SkMatrix& b,
34 bool ignore_scaling_differences) {
35 if (!ignore_scaling_differences)
36 return PaintOp::AreSkMatricesEqual(a, b);
37
38 SkSize scale;
39 SkMatrix a_without_scale;
40 SkMatrix b_without_scale;
Khushal67c8c742018-05-16 18:05:0541
Khushalceacc10a2018-06-01 17:53:5342 const bool decomposes = a.decomposeScale(&scale, &a_without_scale);
43 if (decomposes != b.decomposeScale(&scale, &b_without_scale))
44 return false;
45
46 if (!decomposes)
47 return true;
Khushal67c8c742018-05-16 18:05:0548 return PaintOp::AreSkMatricesEqual(a_without_scale, b_without_scale);
49}
50
Khushal515436e22019-04-05 05:03:5151SkRect AdjustForMaxTextureSize(SkRect tile, int max_texture_size) {
52 if (max_texture_size == 0)
53 return tile;
54
55 if (tile.width() < max_texture_size && tile.height() < max_texture_size)
56 return tile;
57
58 float down_scale = max_texture_size / std::max(tile.width(), tile.height());
59 tile = SkRect::MakeXYWH(tile.x(), tile.y(),
60 SkScalarFloorToScalar(tile.width() * down_scale),
61 SkScalarFloorToScalar(tile.height() * down_scale));
62 return tile;
63}
64
Khushal7ae9c792017-10-05 22:26:3265} // namespace
vmpstr7b99c9582017-06-08 21:39:4566
Adrienne Walker90b79a22018-05-08 21:40:4267const PaintShader::RecordShaderId PaintShader::kInvalidRecordShaderId = -1;
68
Florin Malitac677eac2018-11-08 18:51:1869sk_sp<PaintShader> PaintShader::MakeEmpty() {
70 sk_sp<PaintShader> shader(new PaintShader(Type::kEmpty));
71
72 shader->CreateSkShader();
73 return shader;
74}
75
Adrienne Walker8d85c9d72017-07-07 23:16:4676sk_sp<PaintShader> PaintShader::MakeColor(SkColor color) {
Vladimir Levin7440d462017-07-21 23:53:5177 sk_sp<PaintShader> shader(new PaintShader(Type::kColor));
Vladimir Levin4ca1c842017-07-10 22:09:3178
79 // Just one color. Store it in the fallback color. Easy.
80 shader->fallback_color_ = color;
81
Khushala866a802017-10-05 18:21:0082 shader->CreateSkShader();
Vladimir Levin4ca1c842017-07-10 22:09:3183 return shader;
vmpstr7b99c9582017-06-08 21:39:4584}
85
Adrienne Walker8d85c9d72017-07-07 23:16:4686sk_sp<PaintShader> PaintShader::MakeLinearGradient(const SkPoint points[],
87 const SkColor colors[],
88 const SkScalar pos[],
89 int count,
Mike Reed500aabf2019-04-04 12:50:3290 SkTileMode mode,
Adrienne Walker8d85c9d72017-07-07 23:16:4691 uint32_t flags,
92 const SkMatrix* local_matrix,
93 SkColor fallback_color) {
Vladimir Levin7440d462017-07-21 23:53:5194 sk_sp<PaintShader> shader(new PaintShader(Type::kLinearGradient));
Vladimir Levin4ca1c842017-07-10 22:09:3195
96 // There are always two points, the start and the end.
97 shader->start_point_ = points[0];
98 shader->end_point_ = points[1];
99 shader->SetColorsAndPositions(colors, pos, count);
100 shader->SetMatrixAndTiling(local_matrix, mode, mode);
101 shader->SetFlagsAndFallback(flags, fallback_color);
102
Khushala866a802017-10-05 18:21:00103 shader->CreateSkShader();
Vladimir Levin4ca1c842017-07-10 22:09:31104 return shader;
vmpstr7b99c9582017-06-08 21:39:45105}
106
Adrienne Walker8d85c9d72017-07-07 23:16:46107sk_sp<PaintShader> PaintShader::MakeRadialGradient(const SkPoint& center,
108 SkScalar radius,
109 const SkColor colors[],
110 const SkScalar pos[],
Vladimir Levin4ca1c842017-07-10 22:09:31111 int count,
Mike Reed500aabf2019-04-04 12:50:32112 SkTileMode mode,
Adrienne Walker8d85c9d72017-07-07 23:16:46113 uint32_t flags,
114 const SkMatrix* local_matrix,
115 SkColor fallback_color) {
Vladimir Levin7440d462017-07-21 23:53:51116 sk_sp<PaintShader> shader(new PaintShader(Type::kRadialGradient));
Vladimir Levin4ca1c842017-07-10 22:09:31117
118 shader->center_ = center;
119 shader->start_radius_ = shader->end_radius_ = radius;
120 shader->SetColorsAndPositions(colors, pos, count);
121 shader->SetMatrixAndTiling(local_matrix, mode, mode);
122 shader->SetFlagsAndFallback(flags, fallback_color);
123
Khushala866a802017-10-05 18:21:00124 shader->CreateSkShader();
Vladimir Levin4ca1c842017-07-10 22:09:31125 return shader;
vmpstr7b99c9582017-06-08 21:39:45126}
127
Adrienne Walker8d85c9d72017-07-07 23:16:46128sk_sp<PaintShader> PaintShader::MakeTwoPointConicalGradient(
vmpstr7b99c9582017-06-08 21:39:45129 const SkPoint& start,
130 SkScalar start_radius,
131 const SkPoint& end,
132 SkScalar end_radius,
133 const SkColor colors[],
134 const SkScalar pos[],
Vladimir Levin4ca1c842017-07-10 22:09:31135 int count,
Mike Reed500aabf2019-04-04 12:50:32136 SkTileMode mode,
vmpstr7b99c9582017-06-08 21:39:45137 uint32_t flags,
138 const SkMatrix* local_matrix,
139 SkColor fallback_color) {
Vladimir Levin7440d462017-07-21 23:53:51140 sk_sp<PaintShader> shader(new PaintShader(Type::kTwoPointConicalGradient));
Vladimir Levin4ca1c842017-07-10 22:09:31141
142 shader->start_point_ = start;
143 shader->end_point_ = end;
144 shader->start_radius_ = start_radius;
145 shader->end_radius_ = end_radius;
146 shader->SetColorsAndPositions(colors, pos, count);
147 shader->SetMatrixAndTiling(local_matrix, mode, mode);
148 shader->SetFlagsAndFallback(flags, fallback_color);
149
Khushala866a802017-10-05 18:21:00150 shader->CreateSkShader();
Vladimir Levin4ca1c842017-07-10 22:09:31151 return shader;
vmpstr7b99c9582017-06-08 21:39:45152}
153
Adrienne Walker8d85c9d72017-07-07 23:16:46154sk_sp<PaintShader> PaintShader::MakeSweepGradient(SkScalar cx,
155 SkScalar cy,
156 const SkColor colors[],
157 const SkScalar pos[],
158 int color_count,
Mike Reed500aabf2019-04-04 12:50:32159 SkTileMode mode,
Florin Malita07866982017-08-07 21:11:50160 SkScalar start_degrees,
161 SkScalar end_degrees,
Adrienne Walker8d85c9d72017-07-07 23:16:46162 uint32_t flags,
163 const SkMatrix* local_matrix,
164 SkColor fallback_color) {
Vladimir Levin7440d462017-07-21 23:53:51165 sk_sp<PaintShader> shader(new PaintShader(Type::kSweepGradient));
Vladimir Levin4ca1c842017-07-10 22:09:31166
167 shader->center_ = SkPoint::Make(cx, cy);
Florin Malita07866982017-08-07 21:11:50168 shader->start_degrees_ = start_degrees;
169 shader->end_degrees_ = end_degrees;
Vladimir Levin4ca1c842017-07-10 22:09:31170 shader->SetColorsAndPositions(colors, pos, color_count);
Florin Malita07866982017-08-07 21:11:50171 shader->SetMatrixAndTiling(local_matrix, mode, mode);
Vladimir Levin4ca1c842017-07-10 22:09:31172 shader->SetFlagsAndFallback(flags, fallback_color);
173
Khushala866a802017-10-05 18:21:00174 shader->CreateSkShader();
Vladimir Levin4ca1c842017-07-10 22:09:31175 return shader;
vmpstr7b99c9582017-06-08 21:39:45176}
177
Vladimir Levin7440d462017-07-21 23:53:51178sk_sp<PaintShader> PaintShader::MakeImage(const PaintImage& image,
Mike Reed500aabf2019-04-04 12:50:32179 SkTileMode tx,
180 SkTileMode ty,
Xida Chen0481c522019-08-07 00:54:46181 const SkMatrix* local_matrix,
182 const SkRect* tile_rect) {
Vladimir Levin7440d462017-07-21 23:53:51183 sk_sp<PaintShader> shader(new PaintShader(Type::kImage));
Vladimir Levin4ca1c842017-07-10 22:09:31184
Vladimir Levin7440d462017-07-21 23:53:51185 shader->image_ = image;
Vladimir Levin4ca1c842017-07-10 22:09:31186 shader->SetMatrixAndTiling(local_matrix, tx, ty);
Xida Chen0481c522019-08-07 00:54:46187 if (tile_rect) {
188 DCHECK(image.IsPaintWorklet());
189 shader->tile_ = *tile_rect;
190 }
Vladimir Levin4ca1c842017-07-10 22:09:31191
Khushala866a802017-10-05 18:21:00192 shader->CreateSkShader();
Vladimir Levin4ca1c842017-07-10 22:09:31193 return shader;
vmpstr7b99c9582017-06-08 21:39:45194}
195
Vladimir Levin7440d462017-07-21 23:53:51196sk_sp<PaintShader> PaintShader::MakePaintRecord(
197 sk_sp<PaintRecord> record,
198 const SkRect& tile,
Mike Reed500aabf2019-04-04 12:50:32199 SkTileMode tx,
200 SkTileMode ty,
Vladimir Levin7440d462017-07-21 23:53:51201 const SkMatrix* local_matrix,
202 ScalingBehavior scaling_behavior) {
203 sk_sp<PaintShader> shader(new PaintShader(Type::kPaintRecord));
Vladimir Levin4ca1c842017-07-10 22:09:31204
205 shader->record_ = std::move(record);
Lei Zhang868717c2018-05-09 04:33:56206 shader->id_ = g_next_shader_id.GetNext();
Vladimir Levin4ca1c842017-07-10 22:09:31207 shader->tile_ = tile;
Vladimir Levin7440d462017-07-21 23:53:51208 shader->scaling_behavior_ = scaling_behavior;
Vladimir Levin4ca1c842017-07-10 22:09:31209 shader->SetMatrixAndTiling(local_matrix, tx, ty);
210
Khushala866a802017-10-05 18:21:00211 shader->CreateSkShader();
Vladimir Levin4ca1c842017-07-10 22:09:31212 return shader;
vmpstr7b99c9582017-06-08 21:39:45213}
214
Khushal252af332018-02-14 05:03:09215// static
216size_t PaintShader::GetSerializedSize(const PaintShader* shader) {
217 size_t bool_size = sizeof(bool);
218 if (!shader)
219 return bool_size;
220
221 return bool_size + sizeof(shader->shader_type_) + sizeof(shader->flags_) +
222 sizeof(shader->end_radius_) + sizeof(shader->start_radius_) +
223 sizeof(shader->tx_) + sizeof(shader->ty_) +
224 sizeof(shader->fallback_color_) + sizeof(shader->scaling_behavior_) +
225 bool_size + sizeof(*shader->local_matrix_) + sizeof(shader->center_) +
226 sizeof(shader->tile_) + sizeof(shader->start_point_) +
227 sizeof(shader->end_point_) + sizeof(shader->start_degrees_) +
228 sizeof(shader->end_degrees_) +
229 PaintOpWriter::GetImageSize(shader->image_) +
230 PaintOpWriter::GetImageSize(shader->image_) + bool_size +
Adrienne Walker90b79a22018-05-08 21:40:42231 sizeof(shader->id_) +
Khushal252af332018-02-14 05:03:09232 PaintOpWriter::GetRecordSize(shader->record_.get()) +
233 sizeof(shader->colors_.size()) +
234 shader->colors_.size() * sizeof(SkColor) +
235 sizeof(shader->positions_.size()) +
236 shader->positions_.size() * sizeof(SkScalar);
237}
238
Vladimir Levin4ca1c842017-07-10 22:09:31239PaintShader::PaintShader(Type type) : shader_type_(type) {}
Adrienne Walker8d85c9d72017-07-07 23:16:46240PaintShader::~PaintShader() = default;
vmpstr7b99c9582017-06-08 21:39:45241
Khushal0c568dc2018-03-21 01:46:07242bool PaintShader::has_discardable_images() const {
Khushalbd34e882018-10-22 20:46:08243 return (image_ && !image_.IsTextureBacked()) ||
Khushal0c568dc2018-03-21 01:46:07244 (record_ && record_->HasDiscardableImages());
245}
246
Khushal7ae9c792017-10-05 22:26:32247bool PaintShader::GetRasterizationTileRect(const SkMatrix& ctm,
248 SkRect* tile_rect) const {
249 DCHECK_EQ(shader_type_, Type::kPaintRecord);
250
251 // If we are using a fixed scale, the record is rasterized with the original
252 // tile size and scaling is applied to the generated output.
253 if (scaling_behavior_ == ScalingBehavior::kFixedScale) {
254 *tile_rect = tile_;
255 return true;
256 }
257
258 SkMatrix matrix = ctm;
259 if (local_matrix_.has_value())
260 matrix.preConcat(local_matrix_.value());
261
262 SkSize scale;
263 if (!matrix.decomposeScale(&scale)) {
264 // Decomposition failed, use an approximation.
265 scale.set(SkScalarSqrt(matrix.getScaleX() * matrix.getScaleX() +
266 matrix.getSkewX() * matrix.getSkewX()),
267 SkScalarSqrt(matrix.getScaleY() * matrix.getScaleY() +
268 matrix.getSkewY() * matrix.getSkewY()));
269 }
Adrienne Walkerc4bdc13e2018-06-27 00:56:30270
271 SkScalar tile_area =
272 tile_.width() * tile_.height() * scale.width() * scale.height();
Khushal7ae9c792017-10-05 22:26:32273
274 // Clamp the tile size to about 4M pixels.
275 // TODO(khushalsagar): We need to consider the max texture size as well.
276 static const SkScalar kMaxTileArea = 2048 * 2048;
Khushal7ae9c792017-10-05 22:26:32277 if (tile_area > kMaxTileArea) {
278 SkScalar clamp_scale = SkScalarSqrt(kMaxTileArea / tile_area);
Adrienne Walkerc4bdc13e2018-06-27 00:56:30279 scale.set(clamp_scale, clamp_scale);
Khushal7ae9c792017-10-05 22:26:32280 }
281
Adrienne Walkerc4bdc13e2018-06-27 00:56:30282 *tile_rect = SkRect::MakeXYWH(
283 tile_.fLeft * scale.width(), tile_.fTop * scale.height(),
284 SkScalarCeilToInt(SkScalarAbs(scale.width() * tile_.width())),
285 SkScalarCeilToInt(SkScalarAbs(scale.height() * tile_.height())));
286
287 if (tile_rect->isEmpty())
Khushal7ae9c792017-10-05 22:26:32288 return false;
289
Khushal7ae9c792017-10-05 22:26:32290 return true;
291}
292
Khushal67c8c742018-05-16 18:05:05293sk_sp<PaintShader> PaintShader::CreateScaledPaintRecord(
Khushal7ae9c792017-10-05 22:26:32294 const SkMatrix& ctm,
Khushal515436e22019-04-05 05:03:51295 int max_texture_size,
Khushal67c8c742018-05-16 18:05:05296 gfx::SizeF* raster_scale) const {
Khushal7ae9c792017-10-05 22:26:32297 DCHECK_EQ(shader_type_, Type::kPaintRecord);
298
Adrienne Walker13de7e32018-10-23 17:46:58299 // If this is already fixed scale, then this is already good to go.
300 if (scaling_behavior_ == ScalingBehavior::kFixedScale) {
301 *raster_scale = gfx::SizeF(1.f, 1.f);
302 return sk_ref_sp<PaintShader>(this);
303 }
304
Khushal7ae9c792017-10-05 22:26:32305 // For creating a decoded PaintRecord shader, we need to do the following:
306 // 1) Figure out the scale at which the record should be rasterization given
307 // the ctm and local_matrix on the shader.
308 // 2) Transform this record to an SkPicture with this scale and replace
309 // encoded images in this record with decodes from the ImageProvider. This
310 // is done by setting the raster_matrix_ for this shader to be used
311 // in GetSkShader.
312 // 3) Since the SkShader will use a scaled SkPicture, we use a kFixedScale for
313 // the decoded shader which creates an SkPicture backed SkImage for
314 // creating the decoded SkShader.
315 // Note that the scaling logic here is replicated from
316 // SkPictureShader::refBitmapShader.
317 SkRect tile_rect;
318 if (!GetRasterizationTileRect(ctm, &tile_rect))
319 return nullptr;
Khushal515436e22019-04-05 05:03:51320 tile_rect = AdjustForMaxTextureSize(tile_rect, max_texture_size);
Khushal7ae9c792017-10-05 22:26:32321
322 sk_sp<PaintShader> shader(new PaintShader(Type::kPaintRecord));
323 shader->record_ = record_;
Adrienne Walker90b79a22018-05-08 21:40:42324 shader->id_ = id_;
Khushal7ae9c792017-10-05 22:26:32325 shader->tile_ = tile_rect;
326 // Use a fixed scale since we have already scaled the tile rect and fixed the
327 // raster scale.
328 shader->scaling_behavior_ = ScalingBehavior::kFixedScale;
329 shader->tx_ = tx_;
330 shader->ty_ = ty_;
331
Khushal67c8c742018-05-16 18:05:05332 *raster_scale =
Khushal9fd411f2018-01-20 02:09:51333 gfx::SizeF(SkIntToScalar(tile_rect.width()) / tile_.width(),
334 SkIntToScalar(tile_rect.height()) / tile_.height());
Khushal7ae9c792017-10-05 22:26:32335 shader->local_matrix_ = GetLocalMatrix();
Khushal67c8c742018-05-16 18:05:05336 shader->local_matrix_->preScale(1 / raster_scale->width(),
337 1 / raster_scale->height());
Khushal7ae9c792017-10-05 22:26:32338
Khushal7ae9c792017-10-05 22:26:32339 return shader;
340}
341
Xida Chen044ad8a2019-12-17 16:41:22342sk_sp<PaintShader> PaintShader::CreatePaintWorkletRecord(
343 ImageProvider* image_provider) const {
344 DCHECK_EQ(shader_type_, Type::kImage);
345 DCHECK(image_ && image_.IsPaintWorklet());
346
347 ImageProvider::ScopedResult result =
348 image_provider->GetRasterContent(DrawImage(image_));
349 if (!result || !result.paint_record())
350 return nullptr;
351 SkMatrix local_matrix = GetLocalMatrix();
352 return PaintShader::MakePaintRecord(
353 sk_ref_sp<PaintRecord>(result.paint_record()), tile_, tx_, ty_,
354 &local_matrix);
355}
356
Khushal67c8c742018-05-16 18:05:05357sk_sp<PaintShader> PaintShader::CreateDecodedImage(
358 const SkMatrix& ctm,
359 SkFilterQuality quality,
360 ImageProvider* image_provider,
361 uint32_t* transfer_cache_entry_id,
Eric Karl4c5bf9d2018-07-13 08:26:44362 SkFilterQuality* raster_quality,
363 bool* needs_mips) const {
Khushal67c8c742018-05-16 18:05:05364 DCHECK_EQ(shader_type_, Type::kImage);
365 if (!image_)
366 return nullptr;
367
368 SkMatrix total_image_matrix = GetLocalMatrix();
369 total_image_matrix.preConcat(ctm);
370 SkRect src_rect = SkRect::MakeIWH(image_.width(), image_.height());
371 SkIRect int_src_rect;
372 src_rect.roundOut(&int_src_rect);
373 DrawImage draw_image(image_, int_src_rect, quality, total_image_matrix);
Xida Chen2d4a1182019-02-08 15:48:49374 auto decoded_draw_image = image_provider->GetRasterContent(draw_image);
Khushal67c8c742018-05-16 18:05:05375 if (!decoded_draw_image)
376 return nullptr;
377
378 auto decoded_image = decoded_draw_image.decoded_image();
379 SkMatrix final_matrix = GetLocalMatrix();
380 bool need_scale = !decoded_image.is_scale_adjustment_identity();
381 if (need_scale) {
382 final_matrix.preScale(1.f / decoded_image.scale_adjustment().width(),
383 1.f / decoded_image.scale_adjustment().height());
384 }
385
386 PaintImage decoded_paint_image;
387 if (decoded_image.transfer_cache_entry_id()) {
388 decoded_paint_image = image_;
389 *transfer_cache_entry_id = *decoded_image.transfer_cache_entry_id();
390 } else {
391 DCHECK(decoded_image.image());
392
393 sk_sp<SkImage> sk_image =
394 sk_ref_sp<SkImage>(const_cast<SkImage*>(decoded_image.image().get()));
395 decoded_paint_image =
396 PaintImageBuilder::WithDefault()
397 .set_id(image_.stable_id())
398 .set_image(std::move(sk_image), image_.content_id())
399 .TakePaintImage();
400 }
401
402 // TODO(khushalsagar): Remove filter quality from DecodedDrawImage. All we
403 // want to do is cap the filter quality used, but Gpu and Sw cache have
404 // different behaviour. D:
405 *raster_quality = decoded_image.filter_quality();
Eric Karl4c5bf9d2018-07-13 08:26:44406 *needs_mips = decoded_image.transfer_cache_entry_needs_mips();
Khushal67c8c742018-05-16 18:05:05407 return PaintShader::MakeImage(decoded_paint_image, tx_, ty_, &final_matrix);
408}
409
Vladimir Levin4ca1c842017-07-10 22:09:31410sk_sp<SkShader> PaintShader::GetSkShader() const {
Khushala866a802017-10-05 18:21:00411 return cached_shader_;
412}
413
Khushal67c8c742018-05-16 18:05:05414void PaintShader::CreateSkShader(const gfx::SizeF* raster_scale,
415 ImageProvider* image_provider) {
Khushala866a802017-10-05 18:21:00416 DCHECK(!cached_shader_);
Vladimir Levin4ca1c842017-07-10 22:09:31417
418 switch (shader_type_) {
Florin Malitac677eac2018-11-08 18:51:18419 case Type::kEmpty:
Mike Reeda1a4e0b2019-04-10 17:54:16420 cached_shader_ = SkShaders::Empty();
Florin Malitac677eac2018-11-08 18:51:18421 break;
Vladimir Levin7440d462017-07-21 23:53:51422 case Type::kColor:
Vladimir Levin4ca1c842017-07-10 22:09:31423 // This will be handled by the fallback check below.
424 break;
Vladimir Levin7440d462017-07-21 23:53:51425 case Type::kLinearGradient: {
Vladimir Levin4ca1c842017-07-10 22:09:31426 SkPoint points[2] = {start_point_, end_point_};
427 cached_shader_ = SkGradientShader::MakeLinear(
428 points, colors_.data(),
429 positions_.empty() ? nullptr : positions_.data(),
430 static_cast<int>(colors_.size()), tx_, flags_,
Philip Rogers3f67719f2018-03-09 02:16:44431 base::OptionalOrNullptr(local_matrix_));
Vladimir Levin4ca1c842017-07-10 22:09:31432 break;
433 }
Vladimir Levin7440d462017-07-21 23:53:51434 case Type::kRadialGradient:
Vladimir Levin4ca1c842017-07-10 22:09:31435 cached_shader_ = SkGradientShader::MakeRadial(
436 center_, start_radius_, colors_.data(),
437 positions_.empty() ? nullptr : positions_.data(),
438 static_cast<int>(colors_.size()), tx_, flags_,
Philip Rogers3f67719f2018-03-09 02:16:44439 base::OptionalOrNullptr(local_matrix_));
Vladimir Levin4ca1c842017-07-10 22:09:31440 break;
Vladimir Levin7440d462017-07-21 23:53:51441 case Type::kTwoPointConicalGradient:
Vladimir Levin4ca1c842017-07-10 22:09:31442 cached_shader_ = SkGradientShader::MakeTwoPointConical(
443 start_point_, start_radius_, end_point_, end_radius_, colors_.data(),
444 positions_.empty() ? nullptr : positions_.data(),
445 static_cast<int>(colors_.size()), tx_, flags_,
Philip Rogers3f67719f2018-03-09 02:16:44446 base::OptionalOrNullptr(local_matrix_));
Vladimir Levin4ca1c842017-07-10 22:09:31447 break;
Vladimir Levin7440d462017-07-21 23:53:51448 case Type::kSweepGradient:
Vladimir Levin4ca1c842017-07-10 22:09:31449 cached_shader_ = SkGradientShader::MakeSweep(
450 center_.x(), center_.y(), colors_.data(),
451 positions_.empty() ? nullptr : positions_.data(),
Florin Malita07866982017-08-07 21:11:50452 static_cast<int>(colors_.size()), tx_, start_degrees_, end_degrees_,
Philip Rogers3f67719f2018-03-09 02:16:44453 flags_, base::OptionalOrNullptr(local_matrix_));
Vladimir Levin4ca1c842017-07-10 22:09:31454 break;
Vladimir Levin7440d462017-07-21 23:53:51455 case Type::kImage:
Xida Chen0481c522019-08-07 00:54:46456 if (image_ && !image_.IsPaintWorklet()) {
Vladimir Levindd4145d2018-01-13 04:25:30457 cached_shader_ = image_.GetSkImage()->makeShader(
Philip Rogers3f67719f2018-03-09 02:16:44458 tx_, ty_, base::OptionalOrNullptr(local_matrix_));
Vladimir Levindd4145d2018-01-13 04:25:30459 }
Vladimir Levin4ca1c842017-07-10 22:09:31460 break;
Vladimir Levin7440d462017-07-21 23:53:51461 case Type::kPaintRecord: {
Khushal7ae9c792017-10-05 22:26:32462 // Create a recording at the desired scale if this record has images which
463 // have been decoded before raster.
Khushal67c8c742018-05-16 18:05:05464 auto picture = ToSkPicture(record_, tile_, raster_scale, image_provider);
Vladimir Levin7440d462017-07-21 23:53:51465
466 switch (scaling_behavior_) {
467 // For raster scale, we create a picture shader directly.
468 case ScalingBehavior::kRasterAtScale:
Mike Reed500aabf2019-04-04 12:50:32469 cached_shader_ = picture->makeShader(
470 tx_, ty_, base::OptionalOrNullptr(local_matrix_), nullptr);
Vladimir Levin7440d462017-07-21 23:53:51471 break;
Khushal7ae9c792017-10-05 22:26:32472 // For fixed scale, we create an image shader with an image backed by
Vladimir Levin7440d462017-07-21 23:53:51473 // the picture.
474 case ScalingBehavior::kFixedScale: {
475 auto image = SkImage::MakeFromPicture(
476 std::move(picture), SkISize::Make(tile_.width(), tile_.height()),
477 nullptr, nullptr, SkImage::BitDepth::kU8,
478 SkColorSpace::MakeSRGB());
479 cached_shader_ = image->makeShader(
Philip Rogers3f67719f2018-03-09 02:16:44480 tx_, ty_, base::OptionalOrNullptr(local_matrix_));
Vladimir Levin7440d462017-07-21 23:53:51481 break;
482 }
483 }
Vladimir Levin4ca1c842017-07-10 22:09:31484 break;
Vladimir Levin7440d462017-07-21 23:53:51485 }
486 case Type::kShaderCount:
Vladimir Levin4ca1c842017-07-10 22:09:31487 NOTREACHED();
488 break;
489 }
490
491 // If we didn't create a shader for whatever reason, create a fallback color
492 // one.
493 if (!cached_shader_)
Mike Reeda1a4e0b2019-04-10 17:54:16494 cached_shader_ = SkShaders::Color(fallback_color_);
Vladimir Levin4ca1c842017-07-10 22:09:31495}
496
497void PaintShader::SetColorsAndPositions(const SkColor* colors,
498 const SkScalar* positions,
499 int count) {
Vladimir Levin1ec7cdb62017-08-30 02:21:48500#if DCHECK_IS_ON()
501 static const int kMaxShaderColorsSupported = 10000;
Vladimir Levin4ca1c842017-07-10 22:09:31502 DCHECK_GE(count, 2);
Vladimir Levin1ec7cdb62017-08-30 02:21:48503 DCHECK_LE(count, kMaxShaderColorsSupported);
504#endif
Vladimir Levin4ca1c842017-07-10 22:09:31505 colors_.assign(colors, colors + count);
506 if (positions)
507 positions_.assign(positions, positions + count);
508}
509
510void PaintShader::SetMatrixAndTiling(const SkMatrix* matrix,
Mike Reed500aabf2019-04-04 12:50:32511 SkTileMode tx,
512 SkTileMode ty) {
Vladimir Levin4ca1c842017-07-10 22:09:31513 if (matrix)
514 local_matrix_ = *matrix;
515 tx_ = tx;
516 ty_ = ty;
517}
518
519void PaintShader::SetFlagsAndFallback(uint32_t flags, SkColor fallback_color) {
520 flags_ = flags;
521 fallback_color_ = fallback_color;
522}
523
Adrienne Walkerdab49622017-07-21 00:07:44524bool PaintShader::IsOpaque() const {
525 // TODO(enne): don't create a shader to answer this.
526 return GetSkShader()->isOpaque();
527}
528
Vladimir Levin2f5940a2017-08-11 18:01:05529bool PaintShader::IsValid() const {
530 // If we managed to create a shader already, then we should be valid.
531 if (cached_shader_)
532 return true;
533
534 switch (shader_type_) {
Florin Malitac677eac2018-11-08 18:51:18535 case Type::kEmpty:
Vladimir Levin2f5940a2017-08-11 18:01:05536 case Type::kColor:
537 return true;
Vladimir Levin3b052192017-09-08 01:51:00538 case Type::kSweepGradient:
539 if (!std::isfinite(start_degrees_) || !std::isfinite(end_degrees_) ||
540 start_degrees_ >= end_degrees_) {
541 return false;
542 }
Nico Weber38a941952018-01-26 17:56:35543 FALLTHROUGH;
Vladimir Levin2f5940a2017-08-11 18:01:05544 case Type::kLinearGradient:
545 case Type::kRadialGradient:
546 case Type::kTwoPointConicalGradient:
Vladimir Levin2f5940a2017-08-11 18:01:05547 return colors_.size() >= 2 &&
548 (positions_.empty() || positions_.size() == colors_.size());
549 case Type::kImage:
Vladimir Levindd4145d2018-01-13 04:25:30550 // We may not be able to decode the image, in which case it would be
551 // false, but that would still make a valid shader.
552 return true;
Vladimir Levin2f5940a2017-08-11 18:01:05553 case Type::kPaintRecord:
554 return !!record_;
555 case Type::kShaderCount:
556 return false;
557 }
558 return false;
559}
560
Adrienne Walker6ac30632017-11-18 01:52:07561bool PaintShader::operator==(const PaintShader& other) const {
562 if (shader_type_ != other.shader_type_)
563 return false;
Adrienne Walkere1bef6c2017-11-30 00:46:35564
Khushal67c8c742018-05-16 18:05:05565 // Record and image shaders are scaled during serialization.
566 const bool ignore_scaling_differences =
567 shader_type_ == PaintShader::Type::kPaintRecord ||
568 shader_type_ == PaintShader::Type::kImage;
569
Adrienne Walkere1bef6c2017-11-30 00:46:35570 // Variables that all shaders use.
Khushal67c8c742018-05-16 18:05:05571 const SkMatrix& local_matrix = local_matrix_ ? *local_matrix_ : SkMatrix::I();
572 const SkMatrix& other_local_matrix =
573 other.local_matrix_ ? *other.local_matrix_ : SkMatrix::I();
574 if (!CompareMatrices(local_matrix, other_local_matrix,
575 ignore_scaling_differences)) {
576 return false;
Adrienne Walker6ac30632017-11-18 01:52:07577 }
Khushal67c8c742018-05-16 18:05:05578
Adrienne Walkere1bef6c2017-11-30 00:46:35579 if (fallback_color_ != other.fallback_color_)
Adrienne Walker6ac30632017-11-18 01:52:07580 return false;
Adrienne Walkere1bef6c2017-11-30 00:46:35581 if (flags_ != other.flags_)
Adrienne Walker6ac30632017-11-18 01:52:07582 return false;
Adrienne Walkere1bef6c2017-11-30 00:46:35583 if (tx_ != other.tx_)
Adrienne Walker6ac30632017-11-18 01:52:07584 return false;
Adrienne Walkere1bef6c2017-11-30 00:46:35585 if (ty_ != other.ty_)
Adrienne Walker6ac30632017-11-18 01:52:07586 return false;
Khushal67c8c742018-05-16 18:05:05587
588 if (!ignore_scaling_differences &&
589 scaling_behavior_ != other.scaling_behavior_)
Adrienne Walker6ac30632017-11-18 01:52:07590 return false;
591
Adrienne Walkere1bef6c2017-11-30 00:46:35592 // Variables that only some shaders use.
593 switch (shader_type_) {
Florin Malitac677eac2018-11-08 18:51:18594 case Type::kEmpty:
Adrienne Walkere1bef6c2017-11-30 00:46:35595 case Type::kColor:
596 break;
597 case Type::kSweepGradient:
598 if (!PaintOp::AreEqualEvenIfNaN(start_degrees_, other.start_degrees_))
599 return false;
600 if (!PaintOp::AreEqualEvenIfNaN(end_degrees_, other.end_degrees_))
601 return false;
Nico Weber38a941952018-01-26 17:56:35602 FALLTHROUGH;
Adrienne Walkere1bef6c2017-11-30 00:46:35603 case Type::kLinearGradient:
604 case Type::kRadialGradient:
605 case Type::kTwoPointConicalGradient:
606 if (!PaintOp::AreEqualEvenIfNaN(start_radius_, other.start_radius_))
607 return false;
608 if (!PaintOp::AreEqualEvenIfNaN(end_radius_, other.end_radius_))
609 return false;
610 if (!PaintOp::AreSkPointsEqual(center_, other.center_))
611 return false;
612 if (!PaintOp::AreSkPointsEqual(start_point_, other.start_point_))
613 return false;
614 if (!PaintOp::AreSkPointsEqual(end_point_, other.end_point_))
615 return false;
616 if (colors_ != other.colors_)
617 return false;
618 if (positions_.size() != other.positions_.size())
619 return false;
620 for (size_t i = 0; i < positions_.size(); ++i) {
621 if (!PaintOp::AreEqualEvenIfNaN(positions_[i], other.positions_[i]))
622 return false;
623 }
624 break;
625 case Type::kImage:
626 // TODO(enne): add comparison of images once those are serialized.
627 break;
628 case Type::kPaintRecord:
Vladimir Levinbd083f782018-01-12 23:26:09629 // If we have a record but not other.record, or vice versa, then shaders
630 // aren't the same.
631 if (!record_ != !other.record_)
632 return false;
Khushal67c8c742018-05-16 18:05:05633 // tile_ and record_ intentionally omitted since they are modified on the
634 // serialized shader based on the ctm.
Adrienne Walkere1bef6c2017-11-30 00:46:35635 break;
636 case Type::kShaderCount:
637 break;
638 }
Adrienne Walker6ac30632017-11-18 01:52:07639
Adrienne Walker6ac30632017-11-18 01:52:07640 return true;
641}
642
vmpstr7b99c9582017-06-08 21:39:45643} // namespace cc