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