paint_shader.cc 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667
  1. // 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. #include "cc/paint/paint_shader.h"
  5. #include <utility>
  6. #include "base/atomic_sequence_num.h"
  7. #include "base/notreached.h"
  8. #include "base/stl_util.h"
  9. #include "cc/paint/image_provider.h"
  10. #include "cc/paint/paint_image_builder.h"
  11. #include "cc/paint/paint_op_writer.h"
  12. #include "cc/paint/paint_record.h"
  13. #include "third_party/skia/include/core/SkColorSpace.h"
  14. #include "third_party/skia/include/core/SkPictureRecorder.h"
  15. #include "third_party/skia/include/effects/SkGradientShader.h"
  16. namespace cc {
  17. namespace {
  18. base::AtomicSequenceNumber g_next_shader_id;
  19. sk_sp<SkPicture> ToSkPicture(sk_sp<PaintRecord> record,
  20. const SkRect& bounds,
  21. const gfx::SizeF* raster_scale,
  22. ImageProvider* image_provider) {
  23. SkPictureRecorder recorder;
  24. SkCanvas* canvas =
  25. recorder.beginRecording(SkRect::MakeWH(bounds.width(), bounds.height()));
  26. canvas->translate(-bounds.fLeft, -bounds.fTop);
  27. if (raster_scale)
  28. canvas->scale(raster_scale->width(), raster_scale->height());
  29. record->Playback(canvas, PlaybackParams(image_provider));
  30. return recorder.finishRecordingAsPicture();
  31. }
  32. bool 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. SkSize scale;
  38. SkMatrix a_without_scale;
  39. SkMatrix b_without_scale;
  40. const bool decomposes = a.decomposeScale(&scale, &a_without_scale);
  41. if (decomposes != b.decomposeScale(&scale, &b_without_scale))
  42. return false;
  43. if (!decomposes)
  44. return true;
  45. return PaintOp::AreSkMatricesEqual(a_without_scale, b_without_scale);
  46. }
  47. } // namespace
  48. const PaintShader::RecordShaderId PaintShader::kInvalidRecordShaderId = -1;
  49. sk_sp<PaintShader> PaintShader::MakeEmpty() {
  50. sk_sp<PaintShader> shader(new PaintShader(Type::kEmpty));
  51. shader->ResolveSkObjects();
  52. return shader;
  53. }
  54. sk_sp<PaintShader> PaintShader::MakeColor(SkColor4f color) {
  55. sk_sp<PaintShader> shader(new PaintShader(Type::kColor));
  56. // Just one color. Store it in the fallback color. Easy.
  57. shader->fallback_color_ = color;
  58. shader->ResolveSkObjects();
  59. return shader;
  60. }
  61. sk_sp<PaintShader> PaintShader::MakeLinearGradient(const SkPoint points[],
  62. const SkColor4f colors[],
  63. const SkScalar pos[],
  64. int count,
  65. SkTileMode mode,
  66. uint32_t flags,
  67. const SkMatrix* local_matrix,
  68. SkColor4f fallback_color) {
  69. sk_sp<PaintShader> shader(new PaintShader(Type::kLinearGradient));
  70. // There are always two points, the start and the end.
  71. shader->start_point_ = points[0];
  72. shader->end_point_ = points[1];
  73. shader->SetColorsAndPositions(colors, pos, count);
  74. shader->SetMatrixAndTiling(local_matrix, mode, mode);
  75. shader->SetFlagsAndFallback(flags, fallback_color);
  76. shader->ResolveSkObjects();
  77. return shader;
  78. }
  79. sk_sp<PaintShader> PaintShader::MakeRadialGradient(const SkPoint& center,
  80. SkScalar radius,
  81. const SkColor4f colors[],
  82. const SkScalar pos[],
  83. int count,
  84. SkTileMode mode,
  85. uint32_t flags,
  86. const SkMatrix* local_matrix,
  87. SkColor4f fallback_color) {
  88. sk_sp<PaintShader> shader(new PaintShader(Type::kRadialGradient));
  89. shader->center_ = center;
  90. shader->start_radius_ = shader->end_radius_ = radius;
  91. shader->SetColorsAndPositions(colors, pos, count);
  92. shader->SetMatrixAndTiling(local_matrix, mode, mode);
  93. shader->SetFlagsAndFallback(flags, fallback_color);
  94. shader->ResolveSkObjects();
  95. return shader;
  96. }
  97. sk_sp<PaintShader> PaintShader::MakeTwoPointConicalGradient(
  98. const SkPoint& start,
  99. SkScalar start_radius,
  100. const SkPoint& end,
  101. SkScalar end_radius,
  102. const SkColor4f colors[],
  103. const SkScalar pos[],
  104. int count,
  105. SkTileMode mode,
  106. uint32_t flags,
  107. const SkMatrix* local_matrix,
  108. SkColor4f fallback_color) {
  109. sk_sp<PaintShader> shader(new PaintShader(Type::kTwoPointConicalGradient));
  110. shader->start_point_ = start;
  111. shader->end_point_ = end;
  112. shader->start_radius_ = start_radius;
  113. shader->end_radius_ = end_radius;
  114. shader->SetColorsAndPositions(colors, pos, count);
  115. shader->SetMatrixAndTiling(local_matrix, mode, mode);
  116. shader->SetFlagsAndFallback(flags, fallback_color);
  117. shader->ResolveSkObjects();
  118. return shader;
  119. }
  120. sk_sp<PaintShader> PaintShader::MakeSweepGradient(SkScalar cx,
  121. SkScalar cy,
  122. const SkColor4f colors[],
  123. const SkScalar pos[],
  124. int color_count,
  125. SkTileMode mode,
  126. SkScalar start_degrees,
  127. SkScalar end_degrees,
  128. uint32_t flags,
  129. const SkMatrix* local_matrix,
  130. SkColor4f fallback_color) {
  131. sk_sp<PaintShader> shader(new PaintShader(Type::kSweepGradient));
  132. shader->center_ = SkPoint::Make(cx, cy);
  133. shader->start_degrees_ = start_degrees;
  134. shader->end_degrees_ = end_degrees;
  135. shader->SetColorsAndPositions(colors, pos, color_count);
  136. shader->SetMatrixAndTiling(local_matrix, mode, mode);
  137. shader->SetFlagsAndFallback(flags, fallback_color);
  138. shader->ResolveSkObjects();
  139. return shader;
  140. }
  141. sk_sp<PaintShader> PaintShader::MakeImage(const PaintImage& image,
  142. SkTileMode tx,
  143. SkTileMode ty,
  144. const SkMatrix* local_matrix,
  145. const SkRect* tile_rect) {
  146. sk_sp<PaintShader> shader(new PaintShader(Type::kImage));
  147. shader->image_ = image;
  148. shader->SetMatrixAndTiling(local_matrix, tx, ty);
  149. if (tile_rect) {
  150. DCHECK(image.IsPaintWorklet());
  151. shader->tile_ = *tile_rect;
  152. }
  153. shader->ResolveSkObjects();
  154. return shader;
  155. }
  156. sk_sp<PaintShader> PaintShader::MakePaintRecord(
  157. sk_sp<PaintRecord> record,
  158. const SkRect& tile,
  159. SkTileMode tx,
  160. SkTileMode ty,
  161. const SkMatrix* local_matrix,
  162. ScalingBehavior scaling_behavior) {
  163. sk_sp<PaintShader> shader(new PaintShader(Type::kPaintRecord));
  164. shader->record_ = std::move(record);
  165. shader->id_ = g_next_shader_id.GetNext();
  166. shader->tile_ = tile;
  167. shader->scaling_behavior_ = scaling_behavior;
  168. shader->SetMatrixAndTiling(local_matrix, tx, ty);
  169. shader->ResolveSkObjects();
  170. return shader;
  171. }
  172. // static
  173. size_t PaintShader::GetSerializedSize(const PaintShader* shader) {
  174. size_t bool_size = sizeof(bool);
  175. if (!shader)
  176. return bool_size;
  177. return bool_size + sizeof(shader->shader_type_) + sizeof(shader->flags_) +
  178. sizeof(shader->end_radius_) + sizeof(shader->start_radius_) +
  179. sizeof(shader->tx_) + sizeof(shader->ty_) +
  180. sizeof(shader->fallback_color_) + sizeof(shader->scaling_behavior_) +
  181. bool_size + sizeof(*shader->local_matrix_) + sizeof(shader->center_) +
  182. sizeof(shader->tile_) + sizeof(shader->start_point_) +
  183. sizeof(shader->end_point_) + sizeof(shader->start_degrees_) +
  184. sizeof(shader->end_degrees_) +
  185. PaintOpWriter::GetImageSize(shader->image_) +
  186. PaintOpWriter::GetImageSize(shader->image_) + bool_size +
  187. sizeof(shader->id_) +
  188. PaintOpWriter::GetRecordSize(shader->record_.get()) +
  189. sizeof(shader->colors_.size()) +
  190. shader->colors_.size() * sizeof(SkColor4f) +
  191. sizeof(shader->positions_.size()) +
  192. shader->positions_.size() * sizeof(SkScalar);
  193. }
  194. PaintShader::PaintShader(Type type) : shader_type_(type) {}
  195. PaintShader::~PaintShader() = default;
  196. bool PaintShader::has_discardable_images() const {
  197. return (image_ && !image_.IsTextureBacked()) ||
  198. (record_ && record_->HasDiscardableImages());
  199. }
  200. bool PaintShader::GetClampedRasterizationTileRect(const SkMatrix& ctm,
  201. int max_texture_size,
  202. SkRect* tile_rect) const {
  203. DCHECK_EQ(shader_type_, Type::kPaintRecord);
  204. // If we are using a fixed scale, the record is rasterized with the original
  205. // tile size and scaling is applied to the generated output.
  206. if (scaling_behavior_ == ScalingBehavior::kFixedScale) {
  207. *tile_rect = tile_;
  208. return true;
  209. }
  210. SkMatrix matrix = ctm;
  211. if (local_matrix_.has_value())
  212. matrix.preConcat(local_matrix_.value());
  213. *tile_rect =
  214. PaintRecord::GetFixedScaleBounds(matrix, tile_, max_texture_size);
  215. if (tile_rect->isEmpty())
  216. return false;
  217. return true;
  218. }
  219. sk_sp<PaintShader> PaintShader::CreateScaledPaintRecord(
  220. const SkMatrix& ctm,
  221. int max_texture_size,
  222. gfx::SizeF* raster_scale) const {
  223. DCHECK_EQ(shader_type_, Type::kPaintRecord);
  224. // If this is already fixed scale, then this is already good to go.
  225. if (scaling_behavior_ == ScalingBehavior::kFixedScale) {
  226. *raster_scale = gfx::SizeF(1.f, 1.f);
  227. return sk_ref_sp<PaintShader>(this);
  228. }
  229. // For creating a decoded PaintRecord shader, we need to do the following:
  230. // 1) Figure out the scale at which the record should be rasterization given
  231. // the ctm and local_matrix on the shader.
  232. // 2) Transform this record to an SkPicture with this scale and replace
  233. // encoded images in this record with decodes from the ImageProvider. This
  234. // is done by setting the raster_matrix_ for this shader to be used
  235. // in GetSkShader.
  236. // 3) Since the SkShader will use a scaled SkPicture, we use a kFixedScale for
  237. // the decoded shader which creates an SkPicture backed SkImage for
  238. // creating the decoded SkShader.
  239. // Note that the scaling logic here is replicated from
  240. // SkPictureShader::refBitmapShader.
  241. SkRect tile_rect;
  242. if (!GetClampedRasterizationTileRect(ctm, max_texture_size, &tile_rect))
  243. return nullptr;
  244. sk_sp<PaintShader> shader(new PaintShader(Type::kPaintRecord));
  245. shader->record_ = record_;
  246. shader->id_ = id_;
  247. shader->tile_ = tile_rect;
  248. // Use a fixed scale since we have already scaled the tile rect and fixed the
  249. // raster scale.
  250. shader->scaling_behavior_ = ScalingBehavior::kFixedScale;
  251. shader->tx_ = tx_;
  252. shader->ty_ = ty_;
  253. *raster_scale =
  254. gfx::SizeF(SkIntToScalar(tile_rect.width()) / tile_.width(),
  255. SkIntToScalar(tile_rect.height()) / tile_.height());
  256. shader->local_matrix_ = GetLocalMatrix();
  257. shader->local_matrix_->preScale(1 / raster_scale->width(),
  258. 1 / raster_scale->height());
  259. return shader;
  260. }
  261. sk_sp<PaintShader> PaintShader::CreatePaintWorkletRecord(
  262. ImageProvider* image_provider) const {
  263. DCHECK_EQ(shader_type_, Type::kImage);
  264. DCHECK(image_ && image_.IsPaintWorklet());
  265. ImageProvider::ScopedResult result =
  266. image_provider->GetRasterContent(DrawImage(image_));
  267. if (!result || !result.paint_record())
  268. return nullptr;
  269. SkMatrix local_matrix = GetLocalMatrix();
  270. return PaintShader::MakePaintRecord(
  271. sk_ref_sp<PaintRecord>(result.paint_record()), tile_, tx_, ty_,
  272. &local_matrix);
  273. }
  274. sk_sp<PaintShader> PaintShader::CreateDecodedImage(
  275. const SkMatrix& ctm,
  276. PaintFlags::FilterQuality quality,
  277. ImageProvider* image_provider,
  278. uint32_t* transfer_cache_entry_id,
  279. PaintFlags::FilterQuality* raster_quality,
  280. bool* needs_mips,
  281. gpu::Mailbox* mailbox) const {
  282. DCHECK_EQ(shader_type_, Type::kImage);
  283. if (!image_)
  284. return nullptr;
  285. SkMatrix total_image_matrix = GetLocalMatrix();
  286. total_image_matrix.preConcat(ctm);
  287. SkRect src_rect = SkRect::MakeIWH(image_.width(), image_.height());
  288. SkIRect int_src_rect;
  289. src_rect.roundOut(&int_src_rect);
  290. DrawImage draw_image(image_, false, int_src_rect, quality,
  291. SkM44(total_image_matrix));
  292. auto decoded_draw_image = image_provider->GetRasterContent(draw_image);
  293. if (!decoded_draw_image)
  294. return nullptr;
  295. auto decoded_image = decoded_draw_image.decoded_image();
  296. SkMatrix final_matrix = GetLocalMatrix();
  297. bool need_scale = !decoded_image.is_scale_adjustment_identity();
  298. if (need_scale) {
  299. final_matrix.preScale(1.f / decoded_image.scale_adjustment().width(),
  300. 1.f / decoded_image.scale_adjustment().height());
  301. }
  302. PaintImage decoded_paint_image;
  303. if (decoded_image.transfer_cache_entry_id()) {
  304. decoded_paint_image = image_;
  305. *transfer_cache_entry_id = *decoded_image.transfer_cache_entry_id();
  306. } else if (!decoded_image.mailbox().IsZero()) {
  307. decoded_paint_image = image_;
  308. *mailbox = decoded_image.mailbox();
  309. } else {
  310. DCHECK(decoded_image.image());
  311. sk_sp<SkImage> sk_image =
  312. sk_ref_sp<SkImage>(const_cast<SkImage*>(decoded_image.image().get()));
  313. decoded_paint_image =
  314. PaintImageBuilder::WithDefault()
  315. .set_id(image_.stable_id())
  316. .set_texture_image(std::move(sk_image),
  317. image_.GetContentIdForFrame(0u))
  318. .TakePaintImage();
  319. }
  320. // TODO(khushalsagar): Remove filter quality from DecodedDrawImage. All we
  321. // want to do is cap the filter quality used, but Gpu and Sw cache have
  322. // different behaviour. D:
  323. *raster_quality = decoded_image.filter_quality();
  324. *needs_mips = decoded_image.transfer_cache_entry_needs_mips();
  325. return PaintShader::MakeImage(decoded_paint_image, tx_, ty_, &final_matrix);
  326. }
  327. sk_sp<SkShader> PaintShader::GetSkShader(
  328. PaintFlags::FilterQuality quality) const {
  329. SkSamplingOptions sampling(
  330. PaintFlags::FilterQualityToSkSamplingOptions(quality));
  331. // TODO(crbug/1308932): Remove this helper vector colors and make all
  332. // SkColor4f.
  333. std::vector<SkColor> colors;
  334. colors.reserve(colors.size());
  335. for (auto& c : colors_)
  336. colors.push_back(c.toSkColor());
  337. switch (shader_type_) {
  338. case Type::kEmpty:
  339. return SkShaders::Empty();
  340. case Type::kColor:
  341. // This will be handled by the fallback check below.
  342. break;
  343. case Type::kLinearGradient: {
  344. SkPoint points[2] = {start_point_, end_point_};
  345. // TODO(crbug/1308932): Remove this helper vector colors and make all
  346. // SkColor4f.
  347. return SkGradientShader::MakeLinear(
  348. points, colors.data(),
  349. positions_.empty() ? nullptr : positions_.data(),
  350. static_cast<int>(colors.size()), tx_, flags_,
  351. base::OptionalOrNullptr(local_matrix_));
  352. }
  353. case Type::kRadialGradient:
  354. return SkGradientShader::MakeRadial(
  355. center_, start_radius_, colors_.data(),
  356. nullptr /*sk_sp<SkColorSpace>*/,
  357. positions_.empty() ? nullptr : positions_.data(),
  358. static_cast<int>(colors_.size()), tx_, flags_,
  359. base::OptionalOrNullptr(local_matrix_));
  360. case Type::kTwoPointConicalGradient:
  361. return SkGradientShader::MakeTwoPointConical(
  362. start_point_, start_radius_, end_point_, end_radius_, colors_.data(),
  363. nullptr /*sk_sp<SkColorSpace>*/,
  364. positions_.empty() ? nullptr : positions_.data(),
  365. static_cast<int>(colors_.size()), tx_, flags_,
  366. base::OptionalOrNullptr(local_matrix_));
  367. case Type::kSweepGradient:
  368. return SkGradientShader::MakeSweep(
  369. center_.x(), center_.y(), colors_.data(),
  370. nullptr /*sk_sp<SkColorSpace>*/,
  371. positions_.empty() ? nullptr : positions_.data(),
  372. static_cast<int>(colors_.size()), tx_, start_degrees_, end_degrees_,
  373. flags_, base::OptionalOrNullptr(local_matrix_));
  374. case Type::kImage:
  375. if (sk_cached_image_) {
  376. return sk_cached_image_->makeShader(
  377. tx_, ty_, sampling, base::OptionalOrNullptr(local_matrix_));
  378. }
  379. break;
  380. case Type::kPaintRecord:
  381. if (sk_cached_picture_) {
  382. switch (scaling_behavior_) {
  383. // For raster scale, we create a picture shader directly.
  384. case ScalingBehavior::kRasterAtScale:
  385. return sk_cached_picture_->makeShader(
  386. tx_, ty_, sampling.filter,
  387. base::OptionalOrNullptr(local_matrix_), nullptr);
  388. // For fixed scale, we create an image shader with an image backed by
  389. // the picture.
  390. case ScalingBehavior::kFixedScale: {
  391. auto image = SkImage::MakeFromPicture(
  392. sk_cached_picture_,
  393. SkISize::Make(tile_.width(), tile_.height()), nullptr, nullptr,
  394. SkImage::BitDepth::kU8, SkColorSpace::MakeSRGB());
  395. return image->makeShader(tx_, ty_, sampling,
  396. base::OptionalOrNullptr(local_matrix_));
  397. }
  398. }
  399. break;
  400. }
  401. break;
  402. case Type::kShaderCount:
  403. NOTREACHED();
  404. break;
  405. }
  406. // If we didn't create a shader for whatever reason, create a fallback
  407. // color one.
  408. return SkShaders::Color(fallback_color_.toSkColor());
  409. }
  410. void PaintShader::ResolveSkObjects(const gfx::SizeF* raster_scale,
  411. ImageProvider* image_provider) {
  412. switch (shader_type_) {
  413. case Type::kImage:
  414. if (image_ && !image_.IsPaintWorklet()) {
  415. sk_cached_image_ = image_.GetSkImage();
  416. }
  417. break;
  418. case Type::kPaintRecord: {
  419. // Create a recording at the desired scale if this record has images
  420. // which have been decoded before raster.
  421. sk_cached_picture_ =
  422. ToSkPicture(record_, tile_, raster_scale, image_provider);
  423. break;
  424. }
  425. default:
  426. break;
  427. }
  428. }
  429. void PaintShader::SetColorsAndPositions(const SkColor4f* colors,
  430. const SkScalar* positions,
  431. int count) {
  432. #if DCHECK_IS_ON()
  433. static const int kMaxShaderColorsSupported = 10000;
  434. DCHECK_GE(count, 2);
  435. DCHECK_LE(count, kMaxShaderColorsSupported);
  436. #endif
  437. colors_.assign(colors, colors + count);
  438. if (positions)
  439. positions_.assign(positions, positions + count);
  440. }
  441. void PaintShader::SetMatrixAndTiling(const SkMatrix* matrix,
  442. SkTileMode tx,
  443. SkTileMode ty) {
  444. if (matrix)
  445. local_matrix_ = *matrix;
  446. tx_ = tx;
  447. ty_ = ty;
  448. }
  449. void PaintShader::SetFlagsAndFallback(uint32_t flags,
  450. SkColor4f fallback_color) {
  451. flags_ = flags;
  452. fallback_color_ = fallback_color;
  453. }
  454. bool PaintShader::IsOpaque() const {
  455. switch (shader_type_) {
  456. case Type::kEmpty:
  457. return false;
  458. case Type::kColor:
  459. // This will be handled by the fallback check below.
  460. break;
  461. case Type::kLinearGradient: // fall-through
  462. case Type::kRadialGradient: // fall-through
  463. case Type::kSweepGradient:
  464. if (tx_ == SkTileMode::kDecal)
  465. return false;
  466. for (const auto& c : colors_)
  467. if (!c.isOpaque())
  468. return false;
  469. return true;
  470. case Type::kTwoPointConicalGradient:
  471. // Because two-point-conical can sometimes ignore its tiling and not draw
  472. // everywhere, we conservatively return false here. If we measure
  473. // performance reasons to be more aggressive here, we can ask Skia to
  474. // expose private functionality to compute this with having to actually
  475. // instantiate a sk_shader object.
  476. return false;
  477. case Type::kImage:
  478. if (tx_ == SkTileMode::kDecal || ty_ == SkTileMode::kDecal)
  479. return false;
  480. if (sk_cached_image_)
  481. return sk_cached_image_->isOpaque();
  482. return false;
  483. case Type::kPaintRecord:
  484. return false;
  485. case Type::kShaderCount:
  486. NOTREACHED();
  487. break;
  488. }
  489. return fallback_color_.isOpaque();
  490. }
  491. bool PaintShader::IsValid() const {
  492. switch (shader_type_) {
  493. case Type::kEmpty:
  494. case Type::kColor:
  495. return true;
  496. case Type::kSweepGradient:
  497. if (!std::isfinite(start_degrees_) || !std::isfinite(end_degrees_) ||
  498. start_degrees_ >= end_degrees_) {
  499. return false;
  500. }
  501. [[fallthrough]];
  502. case Type::kLinearGradient:
  503. case Type::kRadialGradient:
  504. case Type::kTwoPointConicalGradient:
  505. return colors_.size() >= 2 &&
  506. (positions_.empty() || positions_.size() == colors_.size());
  507. case Type::kImage:
  508. // We may not be able to decode the image, in which case it would be
  509. // false, but that would still make a valid shader.
  510. return true;
  511. case Type::kPaintRecord:
  512. return !!record_;
  513. case Type::kShaderCount:
  514. return false;
  515. }
  516. return false;
  517. }
  518. bool PaintShader::operator==(const PaintShader& other) const {
  519. if (shader_type_ != other.shader_type_)
  520. return false;
  521. // Record and image shaders are scaled during serialization.
  522. const bool ignore_scaling_differences =
  523. shader_type_ == PaintShader::Type::kPaintRecord ||
  524. shader_type_ == PaintShader::Type::kImage;
  525. // Variables that all shaders use.
  526. const SkMatrix& local_matrix = local_matrix_ ? *local_matrix_ : SkMatrix::I();
  527. const SkMatrix& other_local_matrix =
  528. other.local_matrix_ ? *other.local_matrix_ : SkMatrix::I();
  529. if (!CompareMatrices(local_matrix, other_local_matrix,
  530. ignore_scaling_differences)) {
  531. return false;
  532. }
  533. if (fallback_color_ != other.fallback_color_)
  534. return false;
  535. if (flags_ != other.flags_)
  536. return false;
  537. if (tx_ != other.tx_)
  538. return false;
  539. if (ty_ != other.ty_)
  540. return false;
  541. if (!ignore_scaling_differences &&
  542. scaling_behavior_ != other.scaling_behavior_)
  543. return false;
  544. // Variables that only some shaders use.
  545. switch (shader_type_) {
  546. case Type::kEmpty:
  547. case Type::kColor:
  548. break;
  549. case Type::kSweepGradient:
  550. if (!PaintOp::AreEqualEvenIfNaN(start_degrees_, other.start_degrees_))
  551. return false;
  552. if (!PaintOp::AreEqualEvenIfNaN(end_degrees_, other.end_degrees_))
  553. return false;
  554. [[fallthrough]];
  555. case Type::kLinearGradient:
  556. case Type::kRadialGradient:
  557. case Type::kTwoPointConicalGradient:
  558. if (!PaintOp::AreEqualEvenIfNaN(start_radius_, other.start_radius_))
  559. return false;
  560. if (!PaintOp::AreEqualEvenIfNaN(end_radius_, other.end_radius_))
  561. return false;
  562. if (!PaintOp::AreSkPointsEqual(center_, other.center_))
  563. return false;
  564. if (!PaintOp::AreSkPointsEqual(start_point_, other.start_point_))
  565. return false;
  566. if (!PaintOp::AreSkPointsEqual(end_point_, other.end_point_))
  567. return false;
  568. if (colors_ != other.colors_)
  569. return false;
  570. if (positions_.size() != other.positions_.size())
  571. return false;
  572. for (size_t i = 0; i < positions_.size(); ++i) {
  573. if (!PaintOp::AreEqualEvenIfNaN(positions_[i], other.positions_[i]))
  574. return false;
  575. }
  576. break;
  577. case Type::kImage:
  578. // TODO(enne): add comparison of images once those are serialized.
  579. break;
  580. case Type::kPaintRecord:
  581. // If we have a record but not other.record, or vice versa, then shaders
  582. // aren't the same.
  583. if (!record_ != !other.record_)
  584. return false;
  585. // tile_ and record_ intentionally omitted since they are modified on the
  586. // serialized shader based on the ctm.
  587. break;
  588. case Type::kShaderCount:
  589. break;
  590. }
  591. return true;
  592. }
  593. } // namespace cc