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