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 5 #ifndef CC_PAINT_PAINT_OP_BUFFER_H_ 6 #define CC_PAINT_PAINT_OP_BUFFER_H_ 7 8 #include <stdint.h> 9 10 #include <limits> 11 #include <string> 12 #include <type_traits> 13 14 #include "base/callback.h" 15 #include "base/containers/stack_container.h" 16 #include "base/debug/alias.h" 17 #include "base/logging.h" 18 #include "base/memory/aligned_memory.h" 19 #include "base/optional.h" 20 #include "cc/base/math_util.h" 21 #include "cc/paint/node_id.h" 22 #include "cc/paint/paint_canvas.h" 23 #include "cc/paint/paint_export.h" 24 #include "cc/paint/paint_flags.h" 25 #include "cc/paint/skottie_wrapper.h" 26 #include "cc/paint/transfer_cache_deserialize_helper.h" 27 #include "cc/paint/transfer_cache_serialize_helper.h" 28 #include "third_party/skia/include/core/SkColor.h" 29 #include "third_party/skia/include/core/SkPicture.h" 30 #include "third_party/skia/include/core/SkRect.h" 31 #include "third_party/skia/include/core/SkScalar.h" 32 #include "third_party/skia/include/core/SkTextBlob.h" 33 #include "ui/gfx/color_space.h" 34 35 class SkColorSpace; 36 class SkStrikeClient; 37 class SkStrikeServer; 38 39 // PaintOpBuffer is a reimplementation of SkLiteDL. 40 // See: third_party/skia/src/core/SkLiteDL.h. 41 namespace cc { 42 class ClientPaintCache; 43 class ImageProvider; 44 class ServicePaintCache; 45 46 class CC_PAINT_EXPORT ThreadsafeMatrix : public SkMatrix { 47 public: ThreadsafeMatrix(const SkMatrix & matrix)48 explicit ThreadsafeMatrix(const SkMatrix& matrix) : SkMatrix(matrix) { 49 (void)getType(); 50 } ThreadsafeMatrix()51 ThreadsafeMatrix() { (void)getType(); } 52 }; 53 54 class CC_PAINT_EXPORT ThreadsafePath : public SkPath { 55 public: ThreadsafePath(const SkPath & path)56 explicit ThreadsafePath(const SkPath& path) : SkPath(path) { 57 updateBoundsCache(); 58 } ThreadsafePath()59 ThreadsafePath() { updateBoundsCache(); } 60 }; 61 62 // See PaintOp::Serialize/Deserialize for comments. Derived Serialize types 63 // don't write the 4 byte type/skip header because they don't know how much 64 // data they will need to write. PaintOp::Serialize itself must update it. 65 #define HAS_SERIALIZATION_FUNCTIONS() \ 66 static size_t Serialize(const PaintOp* op, void* memory, size_t size, \ 67 const SerializeOptions& options); \ 68 static PaintOp* Deserialize(const volatile void* input, size_t input_size, \ 69 void* output, size_t output_size, \ 70 const DeserializeOptions& options) 71 72 enum class PaintOpType : uint8_t { 73 Annotate, 74 ClipPath, 75 ClipRect, 76 ClipRRect, 77 Concat, 78 CustomData, 79 DrawColor, 80 DrawDRRect, 81 DrawImage, 82 DrawImageRect, 83 DrawIRect, 84 DrawLine, 85 DrawOval, 86 DrawPath, 87 DrawRecord, 88 DrawRect, 89 DrawRRect, 90 DrawSkottie, 91 DrawTextBlob, 92 Noop, 93 Restore, 94 Rotate, 95 Save, 96 SaveLayer, 97 SaveLayerAlpha, 98 Scale, 99 SetMatrix, 100 SetNodeId, 101 Translate, 102 LastPaintOpType = Translate, 103 }; 104 105 CC_PAINT_EXPORT std::string PaintOpTypeToString(PaintOpType type); 106 CC_PAINT_EXPORT std::ostream& operator<<(std::ostream&, PaintOpType); 107 108 struct CC_PAINT_EXPORT PlaybackParams { 109 using CustomDataRasterCallback = 110 base::RepeatingCallback<void(SkCanvas* canvas, uint32_t id)>; 111 using DidDrawOpCallback = base::RepeatingCallback<void()>; 112 113 explicit PlaybackParams(ImageProvider* image_provider); 114 PlaybackParams( 115 ImageProvider* image_provider, 116 const SkMatrix& original_ctm, 117 CustomDataRasterCallback custom_callback = CustomDataRasterCallback(), 118 DidDrawOpCallback did_draw_op_callback = DidDrawOpCallback()); 119 ~PlaybackParams(); 120 121 PlaybackParams(const PlaybackParams& other); 122 PlaybackParams& operator=(const PlaybackParams& other); 123 124 ImageProvider* image_provider; 125 SkMatrix original_ctm; 126 CustomDataRasterCallback custom_callback; 127 DidDrawOpCallback did_draw_op_callback; 128 }; 129 130 class CC_PAINT_EXPORT PaintOp { 131 public: 132 uint32_t type : 8; 133 uint32_t skip : 24; 134 PaintOp(PaintOpType type)135 explicit PaintOp(PaintOpType type) : type(static_cast<uint8_t>(type)) {} 136 GetType()137 PaintOpType GetType() const { return static_cast<PaintOpType>(type); } 138 139 // Subclasses should provide a static Raster() method which is called from 140 // here. The Raster method should take a const PaintOp* parameter. It is 141 // static with a pointer to the base type so that we can use it as a function 142 // pointer. 143 void Raster(SkCanvas* canvas, const PlaybackParams& params) const; 144 bool IsDrawOp() const; 145 bool IsPaintOpWithFlags() const; 146 147 bool operator==(const PaintOp& other) const; 148 bool operator!=(const PaintOp& other) const { return !(*this == other); } 149 150 struct CC_PAINT_EXPORT SerializeOptions { 151 SerializeOptions(ImageProvider* image_provider, 152 TransferCacheSerializeHelper* transfer_cache, 153 ClientPaintCache* paint_cache, 154 SkCanvas* canvas, 155 SkStrikeServer* strike_server, 156 sk_sp<SkColorSpace> color_space, 157 bool can_use_lcd_text, 158 bool context_supports_distance_field_text, 159 int max_texture_size, 160 const SkMatrix& original_ctm); 161 SerializeOptions(const SerializeOptions&); 162 SerializeOptions& operator=(const SerializeOptions&); 163 ~SerializeOptions(); 164 165 // Required. 166 ImageProvider* image_provider = nullptr; 167 TransferCacheSerializeHelper* transfer_cache = nullptr; 168 ClientPaintCache* paint_cache = nullptr; 169 SkCanvas* canvas = nullptr; 170 SkStrikeServer* strike_server = nullptr; 171 sk_sp<SkColorSpace> color_space = nullptr; 172 bool can_use_lcd_text = false; 173 bool context_supports_distance_field_text = true; 174 int max_texture_size = 0; 175 SkMatrix original_ctm = SkMatrix::I(); 176 177 // Optional. 178 // The flags to use when serializing this op. This can be used to override 179 // the flags serialized with the op. Valid only for PaintOpWithFlags. 180 const PaintFlags* flags_to_serialize = nullptr; 181 }; 182 183 struct CC_PAINT_EXPORT DeserializeOptions { 184 DeserializeOptions(TransferCacheDeserializeHelper* transfer_cache, 185 ServicePaintCache* paint_cache, 186 SkStrikeClient* strike_client, 187 std::vector<uint8_t>* scratch_buffer, 188 bool is_privileged); 189 TransferCacheDeserializeHelper* transfer_cache = nullptr; 190 ServicePaintCache* paint_cache = nullptr; 191 SkStrikeClient* strike_client = nullptr; 192 // Do a DumpWithoutCrashing when serialization fails. 193 bool crash_dump_on_failure = false; 194 // Used to memcpy Skia flattenables into to avoid TOCTOU issues. 195 std::vector<uint8_t>* scratch_buffer = nullptr; 196 // True if the deserialization is happening on a privileged gpu channel. 197 // e.g. in the case of UI. 198 bool is_privileged = false; 199 }; 200 201 // Indicates how PaintImages are serialized. 202 enum class SerializedImageType : uint8_t { 203 kNoImage, 204 kImageData, 205 kTransferCacheEntry, 206 kLastType = kTransferCacheEntry 207 }; 208 209 // Subclasses should provide a static Serialize() method called from here. 210 // If the op can be serialized to |memory| in no more than |size| bytes, 211 // then return the number of bytes written. If it won't fit, return 0. 212 size_t Serialize(void* memory, 213 size_t size, 214 const SerializeOptions& options) const; 215 216 // Deserializes a PaintOp of this type from a given buffer |input| of 217 // at most |input_size| bytes. Returns null on any errors. 218 // The PaintOp is deserialized into the |output| buffer and returned 219 // if valid. nullptr is returned if the deserialization fails. 220 // |output_size| must be at least LargestPaintOp + serialized->skip, 221 // to fit all ops. The caller is responsible for destroying these ops. 222 // After reading, it returns the number of bytes read in |read_bytes|. 223 static PaintOp* Deserialize(const volatile void* input, 224 size_t input_size, 225 void* output, 226 size_t output_size, 227 size_t* read_bytes, 228 const DeserializeOptions& options); 229 230 // For draw ops, returns true if a conservative bounding rect can be provided 231 // for the op. 232 static bool GetBounds(const PaintOp* op, SkRect* rect); 233 234 // Returns the minimum conservative bounding rect that |op| draws to on a 235 // canvas. |clip_rect| and |ctm| are the current clip rect and transform on 236 // this canvas. 237 static gfx::Rect ComputePaintRect(const PaintOp* op, 238 const SkRect& clip_rect, 239 const SkMatrix& ctm); 240 241 // Returns true if the op lies outside the current clip and should be skipped. 242 // Should only be used with draw ops. 243 static bool QuickRejectDraw(const PaintOp* op, const SkCanvas* canvas); 244 245 // Returns true if executing this op will require decoding of any lazy 246 // generated images. 247 static bool OpHasDiscardableImages(const PaintOp* op); 248 249 // Returns true if the given op type has PaintFlags. 250 static bool TypeHasFlags(PaintOpType type); 251 CountSlowPaths()252 int CountSlowPaths() const { return 0; } CountSlowPathsFromFlags()253 int CountSlowPathsFromFlags() const { return 0; } 254 HasNonAAPaint()255 bool HasNonAAPaint() const { return false; } 256 HasDiscardableImages()257 bool HasDiscardableImages() const { return false; } HasDiscardableImagesFromFlags()258 bool HasDiscardableImagesFromFlags() const { return false; } 259 260 // Returns the number of bytes used by this op in referenced sub records 261 // and display lists. This doesn't count other objects like paths or blobs. AdditionalBytesUsed()262 size_t AdditionalBytesUsed() const { return 0; } 263 264 // Returns the number of ops in referenced sub records and display lists. AdditionalOpCount()265 size_t AdditionalOpCount() const { return 0; } 266 267 // Run the destructor for the derived op type. Ops are usually contained in 268 // memory buffers and so don't have their destructors run automatically. 269 void DestroyThis(); 270 271 // DrawColor is more restrictive on the blend modes that can be used. IsValidDrawColorSkBlendMode(SkBlendMode mode)272 static bool IsValidDrawColorSkBlendMode(SkBlendMode mode) { 273 return static_cast<uint32_t>(mode) <= 274 static_cast<uint32_t>(SkBlendMode::kLastCoeffMode); 275 } 276 277 // PaintFlags can have more complex blend modes than DrawColor. IsValidPaintFlagsSkBlendMode(SkBlendMode mode)278 static bool IsValidPaintFlagsSkBlendMode(SkBlendMode mode) { 279 return static_cast<uint32_t>(mode) <= 280 static_cast<uint32_t>(SkBlendMode::kLastMode); 281 } 282 IsValidSkClipOp(SkClipOp op)283 static bool IsValidSkClipOp(SkClipOp op) { 284 return static_cast<uint32_t>(op) <= 285 static_cast<uint32_t>(SkClipOp::kMax_EnumValue); 286 } 287 IsValidPath(const SkPath & path)288 static bool IsValidPath(const SkPath& path) { return path.isValid(); } 289 IsUnsetRect(const SkRect & rect)290 static bool IsUnsetRect(const SkRect& rect) { 291 return rect.fLeft == SK_ScalarInfinity; 292 } 293 IsValidOrUnsetRect(const SkRect & rect)294 static bool IsValidOrUnsetRect(const SkRect& rect) { 295 return IsUnsetRect(rect) || rect.isFinite(); 296 } 297 298 // PaintOp supports having nans, but some tests want to make sure 299 // that operator== is true on two objects. These helpers compare 300 // various types in a way where nan == nan is true. AreEqualEvenIfNaN(float left,float right)301 static bool AreEqualEvenIfNaN(float left, float right) { 302 if (std::isnan(left) && std::isnan(right)) 303 return true; 304 return left == right; 305 } 306 static bool AreSkPointsEqual(const SkPoint& left, const SkPoint& right); 307 static bool AreSkPoint3sEqual(const SkPoint3& left, const SkPoint3& right); 308 static bool AreSkRectsEqual(const SkRect& left, const SkRect& right); 309 static bool AreSkRRectsEqual(const SkRRect& left, const SkRRect& right); 310 static bool AreSkMatricesEqual(const SkMatrix& left, const SkMatrix& right); 311 static bool AreSkFlattenablesEqual(SkFlattenable* left, SkFlattenable* right); 312 313 static constexpr bool kIsDrawOp = false; 314 static constexpr bool kHasPaintFlags = false; 315 // Since skip and type fit in a uint32_t, this is the max size of skip. 316 static constexpr size_t kMaxSkip = static_cast<size_t>(1 << 24); 317 static const SkRect kUnsetRect; 318 }; 319 320 class CC_PAINT_EXPORT PaintOpWithFlags : public PaintOp { 321 public: 322 static constexpr bool kHasPaintFlags = true; PaintOpWithFlags(PaintOpType type,const PaintFlags & flags)323 PaintOpWithFlags(PaintOpType type, const PaintFlags& flags) 324 : PaintOp(type), flags(flags) {} 325 CountSlowPathsFromFlags()326 int CountSlowPathsFromFlags() const { return flags.getPathEffect() ? 1 : 0; } HasNonAAPaint()327 bool HasNonAAPaint() const { return !flags.isAntiAlias(); } 328 bool HasDiscardableImagesFromFlags() const; 329 330 void RasterWithFlags(SkCanvas* canvas, 331 const PaintFlags* flags, 332 const PlaybackParams& params) const; 333 334 // Subclasses should provide a static RasterWithFlags() method which is called 335 // from the Raster() method. The RasterWithFlags() should use the SkPaint 336 // passed to it, instead of the |flags| member directly, as some callers may 337 // provide a modified PaintFlags. The RasterWithFlags() method is static with 338 // a const PaintOpWithFlags* parameter so that it can be used as a function 339 // pointer. 340 PaintFlags flags; 341 342 protected: PaintOpWithFlags(PaintOpType type)343 explicit PaintOpWithFlags(PaintOpType type) : PaintOp(type) {} 344 }; 345 346 class CC_PAINT_EXPORT AnnotateOp final : public PaintOp { 347 public: 348 static constexpr PaintOpType kType = PaintOpType::Annotate; 349 AnnotateOp(PaintCanvas::AnnotationType annotation_type, 350 const SkRect& rect, 351 sk_sp<SkData> data); 352 ~AnnotateOp(); 353 static void Raster(const AnnotateOp* op, 354 SkCanvas* canvas, 355 const PlaybackParams& params); IsValid()356 bool IsValid() const { return rect.isFinite(); } 357 static bool AreEqual(const PaintOp* left, const PaintOp* right); 358 HAS_SERIALIZATION_FUNCTIONS(); 359 360 PaintCanvas::AnnotationType annotation_type; 361 SkRect rect; 362 sk_sp<SkData> data; 363 364 private: 365 AnnotateOp(); 366 }; 367 368 class CC_PAINT_EXPORT ClipPathOp final : public PaintOp { 369 public: 370 static constexpr PaintOpType kType = PaintOpType::ClipPath; ClipPathOp(SkPath path,SkClipOp op,bool antialias)371 ClipPathOp(SkPath path, SkClipOp op, bool antialias) 372 : PaintOp(kType), path(path), op(op), antialias(antialias) {} 373 static void Raster(const ClipPathOp* op, 374 SkCanvas* canvas, 375 const PlaybackParams& params); IsValid()376 bool IsValid() const { return IsValidSkClipOp(op) && IsValidPath(path); } 377 static bool AreEqual(const PaintOp* left, const PaintOp* right); 378 int CountSlowPaths() const; HasNonAAPaint()379 bool HasNonAAPaint() const { return !antialias; } 380 HAS_SERIALIZATION_FUNCTIONS(); 381 382 ThreadsafePath path; 383 SkClipOp op; 384 bool antialias; 385 386 private: ClipPathOp()387 ClipPathOp() : PaintOp(kType) {} 388 }; 389 390 class CC_PAINT_EXPORT ClipRectOp final : public PaintOp { 391 public: 392 static constexpr PaintOpType kType = PaintOpType::ClipRect; ClipRectOp(const SkRect & rect,SkClipOp op,bool antialias)393 ClipRectOp(const SkRect& rect, SkClipOp op, bool antialias) 394 : PaintOp(kType), rect(rect), op(op), antialias(antialias) {} 395 static void Raster(const ClipRectOp* op, 396 SkCanvas* canvas, 397 const PlaybackParams& params); IsValid()398 bool IsValid() const { return IsValidSkClipOp(op) && rect.isFinite(); } 399 static bool AreEqual(const PaintOp* left, const PaintOp* right); 400 HAS_SERIALIZATION_FUNCTIONS(); 401 402 SkRect rect; 403 SkClipOp op; 404 bool antialias; 405 406 private: ClipRectOp()407 ClipRectOp() : PaintOp(kType) {} 408 }; 409 410 class CC_PAINT_EXPORT ClipRRectOp final : public PaintOp { 411 public: 412 static constexpr PaintOpType kType = PaintOpType::ClipRRect; ClipRRectOp(const SkRRect & rrect,SkClipOp op,bool antialias)413 ClipRRectOp(const SkRRect& rrect, SkClipOp op, bool antialias) 414 : PaintOp(kType), rrect(rrect), op(op), antialias(antialias) {} 415 static void Raster(const ClipRRectOp* op, 416 SkCanvas* canvas, 417 const PlaybackParams& params); IsValid()418 bool IsValid() const { return IsValidSkClipOp(op) && rrect.isValid(); } 419 static bool AreEqual(const PaintOp* left, const PaintOp* right); HasNonAAPaint()420 bool HasNonAAPaint() const { return !antialias; } 421 HAS_SERIALIZATION_FUNCTIONS(); 422 423 SkRRect rrect; 424 SkClipOp op; 425 bool antialias; 426 427 private: ClipRRectOp()428 ClipRRectOp() : PaintOp(kType) {} 429 }; 430 431 class CC_PAINT_EXPORT ConcatOp final : public PaintOp { 432 public: 433 static constexpr PaintOpType kType = PaintOpType::Concat; ConcatOp(const SkMatrix & matrix)434 explicit ConcatOp(const SkMatrix& matrix) : PaintOp(kType), matrix(matrix) {} 435 static void Raster(const ConcatOp* op, 436 SkCanvas* canvas, 437 const PlaybackParams& params); IsValid()438 bool IsValid() const { return true; } 439 static bool AreEqual(const PaintOp* left, const PaintOp* right); 440 HAS_SERIALIZATION_FUNCTIONS(); 441 442 ThreadsafeMatrix matrix; 443 444 private: ConcatOp()445 ConcatOp() : PaintOp(kType) {} 446 }; 447 448 class CC_PAINT_EXPORT CustomDataOp final : public PaintOp { 449 public: 450 static constexpr PaintOpType kType = PaintOpType::CustomData; CustomDataOp(uint32_t id)451 explicit CustomDataOp(uint32_t id) : PaintOp(kType), id(id) {} 452 static void Raster(const CustomDataOp* op, 453 SkCanvas* canvas, 454 const PlaybackParams& params); IsValid()455 bool IsValid() const { return true; } 456 static bool AreEqual(const PaintOp* left, const PaintOp* right); 457 HAS_SERIALIZATION_FUNCTIONS(); 458 459 // Stores user defined id as a placeholder op. 460 uint32_t id; 461 462 private: CustomDataOp()463 CustomDataOp() : PaintOp(kType) {} 464 }; 465 466 class CC_PAINT_EXPORT DrawColorOp final : public PaintOp { 467 public: 468 static constexpr PaintOpType kType = PaintOpType::DrawColor; 469 static constexpr bool kIsDrawOp = true; DrawColorOp(SkColor color,SkBlendMode mode)470 DrawColorOp(SkColor color, SkBlendMode mode) 471 : PaintOp(kType), color(color), mode(mode) {} 472 static void Raster(const DrawColorOp* op, 473 SkCanvas* canvas, 474 const PlaybackParams& params); IsValid()475 bool IsValid() const { return IsValidDrawColorSkBlendMode(mode); } 476 static bool AreEqual(const PaintOp* left, const PaintOp* right); 477 HAS_SERIALIZATION_FUNCTIONS(); 478 479 SkColor color; 480 SkBlendMode mode; 481 482 private: DrawColorOp()483 DrawColorOp() : PaintOp(kType) {} 484 }; 485 486 class CC_PAINT_EXPORT DrawDRRectOp final : public PaintOpWithFlags { 487 public: 488 static constexpr PaintOpType kType = PaintOpType::DrawDRRect; 489 static constexpr bool kIsDrawOp = true; DrawDRRectOp(const SkRRect & outer,const SkRRect & inner,const PaintFlags & flags)490 DrawDRRectOp(const SkRRect& outer, 491 const SkRRect& inner, 492 const PaintFlags& flags) 493 : PaintOpWithFlags(kType, flags), outer(outer), inner(inner) {} 494 static void RasterWithFlags(const DrawDRRectOp* op, 495 const PaintFlags* flags, 496 SkCanvas* canvas, 497 const PlaybackParams& params); IsValid()498 bool IsValid() const { 499 return flags.IsValid() && outer.isValid() && inner.isValid(); 500 } 501 static bool AreEqual(const PaintOp* left, const PaintOp* right); 502 HAS_SERIALIZATION_FUNCTIONS(); 503 504 SkRRect outer; 505 SkRRect inner; 506 507 private: DrawDRRectOp()508 DrawDRRectOp() : PaintOpWithFlags(kType) {} 509 }; 510 511 class CC_PAINT_EXPORT DrawImageOp final : public PaintOpWithFlags { 512 public: 513 static constexpr PaintOpType kType = PaintOpType::DrawImage; 514 static constexpr bool kIsDrawOp = true; 515 DrawImageOp(const PaintImage& image, 516 SkScalar left, 517 SkScalar top, 518 const PaintFlags* flags); 519 ~DrawImageOp(); 520 static void RasterWithFlags(const DrawImageOp* op, 521 const PaintFlags* flags, 522 SkCanvas* canvas, 523 const PlaybackParams& params); IsValid()524 bool IsValid() const { 525 return flags.IsValid() && SkScalarIsFinite(scale_adjustment.width()) && 526 SkScalarIsFinite(scale_adjustment.height()); 527 } 528 static bool AreEqual(const PaintOp* left, const PaintOp* right); 529 bool HasDiscardableImages() const; HasNonAAPaint()530 bool HasNonAAPaint() const { return false; } 531 HAS_SERIALIZATION_FUNCTIONS(); 532 533 PaintImage image; 534 SkScalar left; 535 SkScalar top; 536 537 private: 538 DrawImageOp(); 539 540 // Scale that has already been applied to the decoded image during 541 // serialization. Used with OOP raster. 542 SkSize scale_adjustment = SkSize::Make(1.f, 1.f); 543 }; 544 545 class CC_PAINT_EXPORT DrawImageRectOp final : public PaintOpWithFlags { 546 public: 547 static constexpr PaintOpType kType = PaintOpType::DrawImageRect; 548 static constexpr bool kIsDrawOp = true; 549 DrawImageRectOp(const PaintImage& image, 550 const SkRect& src, 551 const SkRect& dst, 552 const PaintFlags* flags, 553 PaintCanvas::SrcRectConstraint constraint); 554 ~DrawImageRectOp(); 555 static void RasterWithFlags(const DrawImageRectOp* op, 556 const PaintFlags* flags, 557 SkCanvas* canvas, 558 const PlaybackParams& params); IsValid()559 bool IsValid() const { 560 return flags.IsValid() && src.isFinite() && dst.isFinite() && 561 SkScalarIsFinite(scale_adjustment.width()) && 562 SkScalarIsFinite(scale_adjustment.height()); 563 } 564 static bool AreEqual(const PaintOp* left, const PaintOp* right); 565 bool HasDiscardableImages() const; 566 HAS_SERIALIZATION_FUNCTIONS(); 567 568 PaintImage image; 569 SkRect src; 570 SkRect dst; 571 PaintCanvas::SrcRectConstraint constraint; 572 573 private: 574 DrawImageRectOp(); 575 576 // Scale that has already been applied to the decoded image during 577 // serialization. Used with OOP raster. 578 SkSize scale_adjustment = SkSize::Make(1.f, 1.f); 579 }; 580 581 class CC_PAINT_EXPORT DrawIRectOp final : public PaintOpWithFlags { 582 public: 583 static constexpr PaintOpType kType = PaintOpType::DrawIRect; 584 static constexpr bool kIsDrawOp = true; DrawIRectOp(const SkIRect & rect,const PaintFlags & flags)585 DrawIRectOp(const SkIRect& rect, const PaintFlags& flags) 586 : PaintOpWithFlags(kType, flags), rect(rect) {} 587 static void RasterWithFlags(const DrawIRectOp* op, 588 const PaintFlags* flags, 589 SkCanvas* canvas, 590 const PlaybackParams& params); IsValid()591 bool IsValid() const { return flags.IsValid(); } 592 static bool AreEqual(const PaintOp* left, const PaintOp* right); HasNonAAPaint()593 bool HasNonAAPaint() const { return false; } 594 HAS_SERIALIZATION_FUNCTIONS(); 595 596 SkIRect rect; 597 598 private: DrawIRectOp()599 DrawIRectOp() : PaintOpWithFlags(kType) {} 600 }; 601 602 class CC_PAINT_EXPORT DrawLineOp final : public PaintOpWithFlags { 603 public: 604 static constexpr PaintOpType kType = PaintOpType::DrawLine; 605 static constexpr bool kIsDrawOp = true; DrawLineOp(SkScalar x0,SkScalar y0,SkScalar x1,SkScalar y1,const PaintFlags & flags)606 DrawLineOp(SkScalar x0, 607 SkScalar y0, 608 SkScalar x1, 609 SkScalar y1, 610 const PaintFlags& flags) 611 : PaintOpWithFlags(kType, flags), x0(x0), y0(y0), x1(x1), y1(y1) {} 612 static void RasterWithFlags(const DrawLineOp* op, 613 const PaintFlags* flags, 614 SkCanvas* canvas, 615 const PlaybackParams& params); IsValid()616 bool IsValid() const { return flags.IsValid(); } 617 static bool AreEqual(const PaintOp* left, const PaintOp* right); 618 HAS_SERIALIZATION_FUNCTIONS(); 619 620 int CountSlowPaths() const; 621 622 SkScalar x0; 623 SkScalar y0; 624 SkScalar x1; 625 SkScalar y1; 626 627 private: DrawLineOp()628 DrawLineOp() : PaintOpWithFlags(kType) {} 629 }; 630 631 class CC_PAINT_EXPORT DrawOvalOp final : public PaintOpWithFlags { 632 public: 633 static constexpr PaintOpType kType = PaintOpType::DrawOval; 634 static constexpr bool kIsDrawOp = true; DrawOvalOp(const SkRect & oval,const PaintFlags & flags)635 DrawOvalOp(const SkRect& oval, const PaintFlags& flags) 636 : PaintOpWithFlags(kType, flags), oval(oval) {} 637 static void RasterWithFlags(const DrawOvalOp* op, 638 const PaintFlags* flags, 639 SkCanvas* canvas, 640 const PlaybackParams& params); IsValid()641 bool IsValid() const { 642 // Reproduce SkRRect::isValid without converting. 643 return flags.IsValid() && oval.isFinite() && oval.isSorted(); 644 } 645 static bool AreEqual(const PaintOp* left, const PaintOp* right); 646 HAS_SERIALIZATION_FUNCTIONS(); 647 648 SkRect oval; 649 650 private: DrawOvalOp()651 DrawOvalOp() : PaintOpWithFlags(kType) {} 652 }; 653 654 class CC_PAINT_EXPORT DrawPathOp final : public PaintOpWithFlags { 655 public: 656 static constexpr PaintOpType kType = PaintOpType::DrawPath; 657 static constexpr bool kIsDrawOp = true; DrawPathOp(const SkPath & path,const PaintFlags & flags)658 DrawPathOp(const SkPath& path, const PaintFlags& flags) 659 : PaintOpWithFlags(kType, flags), path(path) {} 660 static void RasterWithFlags(const DrawPathOp* op, 661 const PaintFlags* flags, 662 SkCanvas* canvas, 663 const PlaybackParams& params); IsValid()664 bool IsValid() const { return flags.IsValid() && IsValidPath(path); } 665 static bool AreEqual(const PaintOp* left, const PaintOp* right); 666 int CountSlowPaths() const; 667 HAS_SERIALIZATION_FUNCTIONS(); 668 669 ThreadsafePath path; 670 671 private: DrawPathOp()672 DrawPathOp() : PaintOpWithFlags(kType) {} 673 }; 674 675 class CC_PAINT_EXPORT DrawRecordOp final : public PaintOp { 676 public: 677 static constexpr PaintOpType kType = PaintOpType::DrawRecord; 678 static constexpr bool kIsDrawOp = true; 679 explicit DrawRecordOp(sk_sp<const PaintRecord> record); 680 ~DrawRecordOp(); 681 static void Raster(const DrawRecordOp* op, 682 SkCanvas* canvas, 683 const PlaybackParams& params); IsValid()684 bool IsValid() const { return true; } 685 static bool AreEqual(const PaintOp* left, const PaintOp* right); 686 size_t AdditionalBytesUsed() const; 687 size_t AdditionalOpCount() const; 688 bool HasDiscardableImages() const; 689 int CountSlowPaths() const; 690 bool HasNonAAPaint() const; 691 HAS_SERIALIZATION_FUNCTIONS(); 692 693 sk_sp<const PaintRecord> record; 694 }; 695 696 class CC_PAINT_EXPORT DrawRectOp final : public PaintOpWithFlags { 697 public: 698 static constexpr PaintOpType kType = PaintOpType::DrawRect; 699 static constexpr bool kIsDrawOp = true; DrawRectOp(const SkRect & rect,const PaintFlags & flags)700 DrawRectOp(const SkRect& rect, const PaintFlags& flags) 701 : PaintOpWithFlags(kType, flags), rect(rect) {} 702 static void RasterWithFlags(const DrawRectOp* op, 703 const PaintFlags* flags, 704 SkCanvas* canvas, 705 const PlaybackParams& params); IsValid()706 bool IsValid() const { return flags.IsValid() && rect.isFinite(); } 707 static bool AreEqual(const PaintOp* left, const PaintOp* right); 708 HAS_SERIALIZATION_FUNCTIONS(); 709 710 SkRect rect; 711 712 private: DrawRectOp()713 DrawRectOp() : PaintOpWithFlags(kType) {} 714 }; 715 716 class CC_PAINT_EXPORT DrawRRectOp final : public PaintOpWithFlags { 717 public: 718 static constexpr PaintOpType kType = PaintOpType::DrawRRect; 719 static constexpr bool kIsDrawOp = true; DrawRRectOp(const SkRRect & rrect,const PaintFlags & flags)720 DrawRRectOp(const SkRRect& rrect, const PaintFlags& flags) 721 : PaintOpWithFlags(kType, flags), rrect(rrect) {} 722 static void RasterWithFlags(const DrawRRectOp* op, 723 const PaintFlags* flags, 724 SkCanvas* canvas, 725 const PlaybackParams& params); IsValid()726 bool IsValid() const { return flags.IsValid() && rrect.isValid(); } 727 static bool AreEqual(const PaintOp* left, const PaintOp* right); 728 HAS_SERIALIZATION_FUNCTIONS(); 729 730 SkRRect rrect; 731 732 private: DrawRRectOp()733 DrawRRectOp() : PaintOpWithFlags(kType) {} 734 }; 735 736 class CC_PAINT_EXPORT DrawSkottieOp final : public PaintOp { 737 public: 738 static constexpr PaintOpType kType = PaintOpType::DrawSkottie; 739 static constexpr bool kIsDrawOp = true; 740 DrawSkottieOp(scoped_refptr<SkottieWrapper> skottie, SkRect dst, float t); 741 ~DrawSkottieOp(); 742 static void Raster(const DrawSkottieOp* op, 743 SkCanvas* canvas, 744 const PlaybackParams& params); IsValid()745 bool IsValid() const { 746 return !!skottie && !dst.isEmpty() && t >= 0 && t <= 1.f; 747 } 748 static bool AreEqual(const PaintOp* left, const PaintOp* right); 749 HAS_SERIALIZATION_FUNCTIONS(); 750 751 scoped_refptr<SkottieWrapper> skottie; 752 SkRect dst; 753 float t; 754 755 private: 756 DrawSkottieOp(); 757 }; 758 759 class CC_PAINT_EXPORT DrawTextBlobOp final : public PaintOpWithFlags { 760 public: 761 static constexpr PaintOpType kType = PaintOpType::DrawTextBlob; 762 static constexpr bool kIsDrawOp = true; 763 DrawTextBlobOp(sk_sp<SkTextBlob> blob, 764 SkScalar x, 765 SkScalar y, 766 const PaintFlags& flags); 767 DrawTextBlobOp(sk_sp<SkTextBlob> blob, 768 SkScalar x, 769 SkScalar y, 770 NodeId node_id, 771 const PaintFlags& flags); 772 ~DrawTextBlobOp(); 773 static void RasterWithFlags(const DrawTextBlobOp* op, 774 const PaintFlags* flags, 775 SkCanvas* canvas, 776 const PlaybackParams& params); IsValid()777 bool IsValid() const { return flags.IsValid(); } 778 static bool AreEqual(const PaintOp* left, const PaintOp* right); 779 HAS_SERIALIZATION_FUNCTIONS(); 780 781 sk_sp<SkTextBlob> blob; 782 SkScalar x; 783 SkScalar y; 784 // This field isn't serialized. 785 NodeId node_id = kInvalidNodeId; 786 787 private: 788 DrawTextBlobOp(); 789 }; 790 791 class CC_PAINT_EXPORT NoopOp final : public PaintOp { 792 public: 793 static constexpr PaintOpType kType = PaintOpType::Noop; NoopOp()794 NoopOp() : PaintOp(kType) {} Raster(const NoopOp * op,SkCanvas * canvas,const PlaybackParams & params)795 static void Raster(const NoopOp* op, 796 SkCanvas* canvas, 797 const PlaybackParams& params) {} IsValid()798 bool IsValid() const { return true; } 799 static bool AreEqual(const PaintOp* left, const PaintOp* right); 800 HAS_SERIALIZATION_FUNCTIONS(); 801 }; 802 803 class CC_PAINT_EXPORT RestoreOp final : public PaintOp { 804 public: 805 static constexpr PaintOpType kType = PaintOpType::Restore; RestoreOp()806 RestoreOp() : PaintOp(kType) {} 807 static void Raster(const RestoreOp* op, 808 SkCanvas* canvas, 809 const PlaybackParams& params); IsValid()810 bool IsValid() const { return true; } 811 static bool AreEqual(const PaintOp* left, const PaintOp* right); 812 HAS_SERIALIZATION_FUNCTIONS(); 813 }; 814 815 class CC_PAINT_EXPORT RotateOp final : public PaintOp { 816 public: 817 static constexpr PaintOpType kType = PaintOpType::Rotate; RotateOp(SkScalar degrees)818 explicit RotateOp(SkScalar degrees) : PaintOp(kType), degrees(degrees) {} 819 static void Raster(const RotateOp* op, 820 SkCanvas* canvas, 821 const PlaybackParams& params); IsValid()822 bool IsValid() const { return true; } 823 static bool AreEqual(const PaintOp* left, const PaintOp* right); 824 HAS_SERIALIZATION_FUNCTIONS(); 825 826 SkScalar degrees; 827 828 private: RotateOp()829 RotateOp() : PaintOp(kType) {} 830 }; 831 832 class CC_PAINT_EXPORT SaveOp final : public PaintOp { 833 public: 834 static constexpr PaintOpType kType = PaintOpType::Save; SaveOp()835 SaveOp() : PaintOp(kType) {} 836 static void Raster(const SaveOp* op, 837 SkCanvas* canvas, 838 const PlaybackParams& params); IsValid()839 bool IsValid() const { return true; } 840 static bool AreEqual(const PaintOp* left, const PaintOp* right); 841 HAS_SERIALIZATION_FUNCTIONS(); 842 }; 843 844 class CC_PAINT_EXPORT SaveLayerOp final : public PaintOpWithFlags { 845 public: 846 static constexpr PaintOpType kType = PaintOpType::SaveLayer; SaveLayerOp(const SkRect * bounds,const PaintFlags * flags)847 SaveLayerOp(const SkRect* bounds, const PaintFlags* flags) 848 : PaintOpWithFlags(kType, flags ? *flags : PaintFlags()), 849 bounds(bounds ? *bounds : kUnsetRect) {} 850 static void RasterWithFlags(const SaveLayerOp* op, 851 const PaintFlags* flags, 852 SkCanvas* canvas, 853 const PlaybackParams& params); IsValid()854 bool IsValid() const { return flags.IsValid() && IsValidOrUnsetRect(bounds); } 855 static bool AreEqual(const PaintOp* left, const PaintOp* right); HasNonAAPaint()856 bool HasNonAAPaint() const { return false; } 857 HAS_SERIALIZATION_FUNCTIONS(); 858 859 SkRect bounds; 860 861 private: SaveLayerOp()862 SaveLayerOp() : PaintOpWithFlags(kType) {} 863 }; 864 865 class CC_PAINT_EXPORT SaveLayerAlphaOp final : public PaintOp { 866 public: 867 static constexpr PaintOpType kType = PaintOpType::SaveLayerAlpha; SaveLayerAlphaOp(const SkRect * bounds,uint8_t alpha)868 SaveLayerAlphaOp(const SkRect* bounds, uint8_t alpha) 869 : PaintOp(kType), bounds(bounds ? *bounds : kUnsetRect), alpha(alpha) {} 870 static void Raster(const SaveLayerAlphaOp* op, 871 SkCanvas* canvas, 872 const PlaybackParams& params); IsValid()873 bool IsValid() const { return IsValidOrUnsetRect(bounds); } 874 static bool AreEqual(const PaintOp* left, const PaintOp* right); 875 HAS_SERIALIZATION_FUNCTIONS(); 876 877 SkRect bounds; 878 uint8_t alpha; 879 880 private: SaveLayerAlphaOp()881 SaveLayerAlphaOp() : PaintOp(kType) {} 882 }; 883 884 class CC_PAINT_EXPORT ScaleOp final : public PaintOp { 885 public: 886 static constexpr PaintOpType kType = PaintOpType::Scale; ScaleOp(SkScalar sx,SkScalar sy)887 ScaleOp(SkScalar sx, SkScalar sy) : PaintOp(kType), sx(sx), sy(sy) {} 888 static void Raster(const ScaleOp* op, 889 SkCanvas* canvas, 890 const PlaybackParams& params); IsValid()891 bool IsValid() const { return true; } 892 static bool AreEqual(const PaintOp* left, const PaintOp* right); 893 HAS_SERIALIZATION_FUNCTIONS(); 894 895 SkScalar sx; 896 SkScalar sy; 897 898 private: ScaleOp()899 ScaleOp() : PaintOp(kType) {} 900 }; 901 902 class CC_PAINT_EXPORT SetMatrixOp final : public PaintOp { 903 public: 904 static constexpr PaintOpType kType = PaintOpType::SetMatrix; SetMatrixOp(const SkMatrix & matrix)905 explicit SetMatrixOp(const SkMatrix& matrix) 906 : PaintOp(kType), matrix(matrix) {} 907 // This is the only op that needs the original ctm of the SkCanvas 908 // used for raster (since SetMatrix is relative to the recording origin and 909 // shouldn't clobber the SkCanvas raster origin). 910 // 911 // TODO(enne): Find some cleaner way to do this, possibly by making 912 // all SetMatrix calls Concat?? 913 static void Raster(const SetMatrixOp* op, 914 SkCanvas* canvas, 915 const PlaybackParams& params); IsValid()916 bool IsValid() const { return true; } 917 static bool AreEqual(const PaintOp* left, const PaintOp* right); 918 HAS_SERIALIZATION_FUNCTIONS(); 919 920 ThreadsafeMatrix matrix; 921 922 private: SetMatrixOp()923 SetMatrixOp() : PaintOp(kType) {} 924 }; 925 926 class CC_PAINT_EXPORT SetNodeIdOp final : public PaintOp { 927 public: 928 static constexpr PaintOpType kType = PaintOpType::SetNodeId; SetNodeIdOp(int node_id)929 explicit SetNodeIdOp(int node_id) : PaintOp(kType), node_id(node_id) {} 930 static void Raster(const SetNodeIdOp* op, 931 SkCanvas* canvas, 932 const PlaybackParams& params); IsValid()933 bool IsValid() const { return true; } 934 static bool AreEqual(const PaintOp* left, const PaintOp* right); 935 HAS_SERIALIZATION_FUNCTIONS(); 936 937 int node_id; 938 939 private: SetNodeIdOp()940 SetNodeIdOp() : PaintOp(kType) {} 941 }; 942 943 class CC_PAINT_EXPORT TranslateOp final : public PaintOp { 944 public: 945 static constexpr PaintOpType kType = PaintOpType::Translate; TranslateOp(SkScalar dx,SkScalar dy)946 TranslateOp(SkScalar dx, SkScalar dy) : PaintOp(kType), dx(dx), dy(dy) {} 947 static void Raster(const TranslateOp* op, 948 SkCanvas* canvas, 949 const PlaybackParams& params); IsValid()950 bool IsValid() const { return true; } 951 static bool AreEqual(const PaintOp* left, const PaintOp* right); 952 HAS_SERIALIZATION_FUNCTIONS(); 953 954 SkScalar dx; 955 SkScalar dy; 956 957 private: TranslateOp()958 TranslateOp() : PaintOp(kType) {} 959 }; 960 961 #undef HAS_SERIALIZATION_FUNCTIONS 962 963 // TODO(vmpstr): Revisit this when sizes of DrawImageRectOp change. 964 using LargestPaintOp = 965 typename std::conditional<(sizeof(DrawImageRectOp) > sizeof(DrawDRRectOp)), 966 DrawImageRectOp, 967 DrawDRRectOp>::type; 968 969 class CC_PAINT_EXPORT PaintOpBuffer : public SkRefCnt { 970 public: 971 enum { kInitialBufferSize = 4096 }; 972 static constexpr size_t PaintOpAlign = 8; ComputeOpSkip(size_t sizeof_op)973 static inline size_t ComputeOpSkip(size_t sizeof_op) { 974 return MathUtil::UncheckedRoundUp(sizeof_op, PaintOpBuffer::PaintOpAlign); 975 } 976 977 PaintOpBuffer(); 978 PaintOpBuffer(const PaintOpBuffer&) = delete; 979 PaintOpBuffer(PaintOpBuffer&& other); 980 ~PaintOpBuffer() override; 981 982 PaintOpBuffer& operator=(const PaintOpBuffer&) = delete; 983 PaintOpBuffer& operator=(PaintOpBuffer&& other); 984 985 void Reset(); 986 987 // Replays the paint op buffer into the canvas. 988 void Playback(SkCanvas* canvas) const; 989 void Playback(SkCanvas* canvas, const PlaybackParams& params) const; 990 991 // Deserialize PaintOps from |input|. The original content will be 992 // overwritten. 993 bool Deserialize(const volatile void* input, 994 size_t input_size, 995 const PaintOp::DeserializeOptions& options); 996 997 static sk_sp<PaintOpBuffer> MakeFromMemory( 998 const volatile void* input, 999 size_t input_size, 1000 const PaintOp::DeserializeOptions& options); 1001 1002 // Returns the size of the paint op buffer. That is, the number of ops 1003 // contained in it. size()1004 size_t size() const { return op_count_; } 1005 // Returns the number of bytes used by the paint op buffer. bytes_used()1006 size_t bytes_used() const { 1007 return sizeof(*this) + reserved_ + subrecord_bytes_used_; 1008 } 1009 // Returns the number of bytes used by paint ops. paint_ops_size()1010 size_t paint_ops_size() const { return used_ + subrecord_bytes_used_; } 1011 // Returns the total number of ops including sub-records. total_op_count()1012 size_t total_op_count() const { return op_count_ + subrecord_op_count_; } 1013 next_op_offset()1014 size_t next_op_offset() const { return used_; } numSlowPaths()1015 int numSlowPaths() const { return num_slow_paths_; } HasNonAAPaint()1016 bool HasNonAAPaint() const { return has_non_aa_paint_; } HasDiscardableImages()1017 bool HasDiscardableImages() const { return has_discardable_images_; } 1018 1019 bool operator==(const PaintOpBuffer& other) const; 1020 bool operator!=(const PaintOpBuffer& other) const { 1021 return !(*this == other); 1022 } 1023 1024 // Resize the PaintOpBuffer to exactly fit the current amount of used space. 1025 void ShrinkToFit(); 1026 GetFirstOp()1027 const PaintOp* GetFirstOp() const { 1028 return reinterpret_cast<const PaintOp*>(data_.get()); 1029 } 1030 1031 template <typename T, typename... Args> push(Args &&...args)1032 const T* push(Args&&... args) { 1033 static_assert(std::is_convertible<T, PaintOp>::value, "T not a PaintOp."); 1034 static_assert(alignof(T) <= PaintOpAlign, ""); 1035 static_assert(sizeof(T) < std::numeric_limits<uint16_t>::max(), 1036 "Cannot fit op code in skip"); 1037 uint16_t skip = static_cast<uint16_t>(ComputeOpSkip(sizeof(T))); 1038 T* op = reinterpret_cast<T*>(AllocatePaintOp(skip)); 1039 1040 new (op) T(std::forward<Args>(args)...); 1041 DCHECK_EQ(op->type, static_cast<uint32_t>(T::kType)); 1042 op->skip = skip; 1043 AnalyzeAddedOp(op); 1044 return op; 1045 } 1046 UpdateSaveLayerBounds(size_t offset,const SkRect & bounds)1047 void UpdateSaveLayerBounds(size_t offset, const SkRect& bounds) { 1048 CHECK_LT(offset, used_); 1049 CHECK_LE(offset + sizeof(PaintOp), used_); 1050 1051 auto* op = reinterpret_cast<PaintOp*>(data_.get() + offset); 1052 switch (op->GetType()) { 1053 case SaveLayerOp::kType: 1054 CHECK_LE(offset + sizeof(SaveLayerOp), used_); 1055 static_cast<SaveLayerOp*>(op)->bounds = bounds; 1056 break; 1057 case SaveLayerAlphaOp::kType: 1058 CHECK_LE(offset + sizeof(SaveLayerAlphaOp), used_); 1059 static_cast<SaveLayerAlphaOp*>(op)->bounds = bounds; 1060 break; 1061 default: 1062 NOTREACHED(); 1063 } 1064 } 1065 1066 template <typename T> AnalyzeAddedOp(const T * op)1067 void AnalyzeAddedOp(const T* op) { 1068 static_assert(!std::is_same<T, PaintOp>::value, 1069 "AnalyzeAddedOp needs a subtype of PaintOp"); 1070 1071 num_slow_paths_ += op->CountSlowPathsFromFlags(); 1072 num_slow_paths_ += op->CountSlowPaths(); 1073 1074 has_non_aa_paint_ |= op->HasNonAAPaint(); 1075 1076 has_discardable_images_ |= op->HasDiscardableImages(); 1077 has_discardable_images_ |= op->HasDiscardableImagesFromFlags(); 1078 1079 subrecord_bytes_used_ += op->AdditionalBytesUsed(); 1080 subrecord_op_count_ += op->AdditionalOpCount(); 1081 } 1082 1083 template <typename T> GetOpAtForTesting(size_t index)1084 const T* GetOpAtForTesting(size_t index) const { 1085 size_t i = 0; 1086 for (PaintOpBuffer::Iterator it(this); it && i <= index; ++it, ++i) { 1087 if (i == index && (*it)->GetType() == T::kType) 1088 return static_cast<const T*>(*it); 1089 } 1090 return nullptr; 1091 } 1092 GetOpOffsetForTracing(const PaintOp * op)1093 size_t GetOpOffsetForTracing(const PaintOp* op) const { 1094 DCHECK_GE(reinterpret_cast<const char*>(op), data_.get()); 1095 size_t result = reinterpret_cast<const char*>(op) - data_.get(); 1096 DCHECK_LT(result, used_); 1097 return result; 1098 } 1099 1100 class CC_PAINT_EXPORT Iterator { 1101 public: Iterator(const PaintOpBuffer * buffer)1102 explicit Iterator(const PaintOpBuffer* buffer) 1103 : Iterator(buffer, buffer->data_.get(), 0u) {} 1104 1105 PaintOp* operator->() const { return reinterpret_cast<PaintOp*>(ptr_); } 1106 PaintOp* operator*() const { return operator->(); } begin()1107 Iterator begin() { return Iterator(buffer_); } end()1108 Iterator end() { 1109 return Iterator(buffer_, buffer_->data_.get() + buffer_->used_, 1110 buffer_->used_); 1111 } 1112 bool operator!=(const Iterator& other) { 1113 // Not valid to compare iterators on different buffers. 1114 DCHECK_EQ(other.buffer_, buffer_); 1115 return other.op_offset_ != op_offset_; 1116 } 1117 Iterator& operator++() { 1118 DCHECK(*this); 1119 const PaintOp* op = **this; 1120 ptr_ += op->skip; 1121 op_offset_ += op->skip; 1122 1123 CHECK_LE(op_offset_, buffer_->used_); 1124 return *this; 1125 } 1126 operator bool() const { return op_offset_ < buffer_->used_; } 1127 1128 private: Iterator(const PaintOpBuffer * buffer,char * ptr,size_t op_offset)1129 Iterator(const PaintOpBuffer* buffer, char* ptr, size_t op_offset) 1130 : buffer_(buffer), ptr_(ptr), op_offset_(op_offset) {} 1131 1132 const PaintOpBuffer* buffer_ = nullptr; 1133 char* ptr_ = nullptr; 1134 size_t op_offset_ = 0; 1135 }; 1136 1137 class CC_PAINT_EXPORT OffsetIterator { 1138 public: 1139 // Offsets and paint op buffer must come from the same DisplayItemList. OffsetIterator(const PaintOpBuffer * buffer,const std::vector<size_t> * offsets)1140 OffsetIterator(const PaintOpBuffer* buffer, 1141 const std::vector<size_t>* offsets) 1142 : buffer_(buffer), ptr_(buffer_->data_.get()), offsets_(offsets) { 1143 if (!offsets || offsets->empty()) { 1144 *this = end(); 1145 return; 1146 } 1147 op_offset_ = (*offsets)[0]; 1148 ptr_ += op_offset_; 1149 } 1150 1151 PaintOp* operator->() const { return reinterpret_cast<PaintOp*>(ptr_); } 1152 PaintOp* operator*() const { return operator->(); } begin()1153 OffsetIterator begin() { return OffsetIterator(buffer_, offsets_); } end()1154 OffsetIterator end() { 1155 return OffsetIterator(buffer_, buffer_->data_.get() + buffer_->used_, 1156 buffer_->used_, offsets_); 1157 } 1158 bool operator!=(const OffsetIterator& other) { 1159 // Not valid to compare iterators on different buffers. 1160 DCHECK_EQ(other.buffer_, buffer_); 1161 return other.op_offset_ != op_offset_; 1162 } 1163 OffsetIterator& operator++() { 1164 if (++offsets_index_ >= offsets_->size()) { 1165 *this = end(); 1166 return *this; 1167 } 1168 1169 size_t target_offset = (*offsets_)[offsets_index_]; 1170 // Sanity checks. 1171 CHECK_GE(target_offset, op_offset_); 1172 // Debugging crbug.com/738182. 1173 base::debug::Alias(&target_offset); 1174 CHECK_LT(target_offset, buffer_->used_); 1175 1176 // Advance the iterator to the target offset. 1177 ptr_ += (target_offset - op_offset_); 1178 op_offset_ = target_offset; 1179 1180 DCHECK(!*this || (*this)->type <= 1181 static_cast<uint32_t>(PaintOpType::LastPaintOpType)); 1182 return *this; 1183 } 1184 1185 operator bool() const { return op_offset_ < buffer_->used_; } 1186 1187 private: OffsetIterator(const PaintOpBuffer * buffer,char * ptr,size_t op_offset,const std::vector<size_t> * offsets)1188 OffsetIterator(const PaintOpBuffer* buffer, 1189 char* ptr, 1190 size_t op_offset, 1191 const std::vector<size_t>* offsets) 1192 : buffer_(buffer), 1193 ptr_(ptr), 1194 offsets_(offsets), 1195 op_offset_(op_offset) {} 1196 1197 const PaintOpBuffer* buffer_ = nullptr; 1198 char* ptr_ = nullptr; 1199 const std::vector<size_t>* offsets_; 1200 size_t op_offset_ = 0; 1201 size_t offsets_index_ = 0; 1202 }; 1203 1204 class CC_PAINT_EXPORT CompositeIterator { 1205 public: 1206 // Offsets and paint op buffer must come from the same DisplayItemList. 1207 CompositeIterator(const PaintOpBuffer* buffer, 1208 const std::vector<size_t>* offsets); 1209 CompositeIterator(const CompositeIterator& other); 1210 CompositeIterator(CompositeIterator&& other); 1211 1212 PaintOp* operator->() const { 1213 return using_offsets_ ? **offset_iter_ : **iter_; 1214 } 1215 PaintOp* operator*() const { 1216 return using_offsets_ ? **offset_iter_ : **iter_; 1217 } 1218 bool operator==(const CompositeIterator& other) { 1219 if (using_offsets_ != other.using_offsets_) 1220 return false; 1221 return using_offsets_ ? (*offset_iter_ == *other.offset_iter_) 1222 : (*iter_ == *other.iter_); 1223 } 1224 bool operator!=(const CompositeIterator& other) { 1225 return !(*this == other); 1226 } 1227 CompositeIterator& operator++() { 1228 if (using_offsets_) 1229 ++*offset_iter_; 1230 else 1231 ++*iter_; 1232 return *this; 1233 } 1234 operator bool() const { 1235 return using_offsets_ ? !!*offset_iter_ : !!*iter_; 1236 } 1237 1238 private: 1239 bool using_offsets_ = false; 1240 base::Optional<OffsetIterator> offset_iter_; 1241 base::Optional<Iterator> iter_; 1242 }; 1243 1244 class PlaybackFoldingIterator { 1245 public: 1246 PlaybackFoldingIterator(const PaintOpBuffer* buffer, 1247 const std::vector<size_t>* offsets); 1248 ~PlaybackFoldingIterator(); 1249 1250 const PaintOp* operator->() const { return current_op_; } 1251 const PaintOp* operator*() const { return current_op_; } 1252 1253 PlaybackFoldingIterator& operator++() { 1254 FindNextOp(); 1255 return *this; 1256 } 1257 1258 operator bool() const { return !!current_op_; } 1259 1260 // Guaranteed to be 255 for all ops without flags. alpha()1261 uint8_t alpha() const { return current_alpha_; } 1262 1263 private: 1264 void FindNextOp(); 1265 const PaintOp* NextUnfoldedOp(); 1266 1267 PaintOpBuffer::CompositeIterator iter_; 1268 1269 // FIFO queue of paint ops that have been peeked at. 1270 base::StackVector<const PaintOp*, 3> stack_; 1271 DrawColorOp folded_draw_color_; 1272 const PaintOp* current_op_ = nullptr; 1273 uint8_t current_alpha_ = 255; 1274 }; 1275 1276 private: 1277 friend class DisplayItemList; 1278 friend class PaintOpBufferOffsetsTest; 1279 friend class SolidColorAnalyzer; 1280 1281 // Replays the paint op buffer into the canvas. If |indices| is specified, it 1282 // contains indices in an increasing order and only the indices specified in 1283 // the vector will be replayed. 1284 void Playback(SkCanvas* canvas, 1285 const PlaybackParams& params, 1286 const std::vector<size_t>* indices) const; 1287 1288 void ReallocBuffer(size_t new_size); 1289 // Returns the allocated op. 1290 void* AllocatePaintOp(size_t skip); 1291 1292 std::unique_ptr<char, base::AlignedFreeDeleter> data_; 1293 size_t used_ = 0; 1294 size_t reserved_ = 0; 1295 size_t op_count_ = 0; 1296 1297 // Record paths for veto-to-msaa for gpu raster. 1298 int num_slow_paths_ = 0; 1299 // Record additional bytes used by referenced sub-records and display lists. 1300 size_t subrecord_bytes_used_ = 0; 1301 // Record total op count of referenced sub-record and display lists. 1302 size_t subrecord_op_count_ = 0; 1303 1304 bool has_non_aa_paint_ : 1; 1305 bool has_discardable_images_ : 1; 1306 }; 1307 1308 } // namespace cc 1309 1310 #endif // CC_PAINT_PAINT_OP_BUFFER_H_ 1311