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