1 /*
2  * Copyright 2014 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "include/core/SkCanvas.h"
9 #include "include/core/SkRSXform.h"
10 #include "include/core/SkTextBlob.h"
11 #include "include/core/SkTypes.h"
12 #include "include/private/SkTDArray.h"
13 #include "src/core/SkCanvasPriv.h"
14 #include "src/core/SkDrawShadowInfo.h"
15 #include "src/core/SkFontPriv.h"
16 #include "src/core/SkPaintPriv.h"
17 #include "src/core/SkPictureData.h"
18 #include "src/core/SkPicturePlayback.h"
19 #include "src/core/SkPictureRecord.h"
20 #include "src/core/SkReadBuffer.h"
21 #include "src/core/SkSafeMath.h"
22 #include "src/utils/SkPatchUtils.h"
23 
24 // matches old SkCanvas::SaveFlags
25 enum LegacySaveFlags {
26     kClipToLayer_LegacySaveFlags      = 0x10,
27 };
28 
LegacySaveFlagsToSaveLayerFlags(uint32_t flags)29 SkCanvas::SaveLayerFlags SkCanvasPriv::LegacySaveFlagsToSaveLayerFlags(uint32_t flags) {
30     uint32_t layerFlags = 0;
31 
32     if (0 == (flags & kClipToLayer_LegacySaveFlags)) {
33         layerFlags |= kDontClipToLayer_SaveLayerFlag;
34     }
35     return layerFlags;
36 }
37 
38 /*
39  * Read the next op code and chunk size from 'reader'. The returned size
40  * is the entire size of the chunk (including the opcode). Thus, the
41  * offset just prior to calling ReadOpAndSize + 'size' is the offset
42  * to the next chunk's op code. This also means that the size of a chunk
43  * with no arguments (just an opcode) will be 4.
44  */
ReadOpAndSize(SkReadBuffer * reader,uint32_t * size)45 DrawType SkPicturePlayback::ReadOpAndSize(SkReadBuffer* reader, uint32_t* size) {
46     uint32_t temp = reader->readInt();
47     uint32_t op;
48     if ((temp & 0xFF) == temp) {
49         // old skp file - no size information
50         op = temp;
51         *size = 0;
52     } else {
53         UNPACK_8_24(temp, op, *size);
54         if (MASK_24 == *size) {
55             *size = reader->readInt();
56         }
57     }
58     return (DrawType)op;
59 }
60 
61 
get_rect_ptr(SkReadBuffer * reader,SkRect * storage)62 static const SkRect* get_rect_ptr(SkReadBuffer* reader, SkRect* storage) {
63     if (reader->readBool()) {
64         reader->readRect(storage);
65         return storage;
66     } else {
67         return nullptr;
68     }
69 }
70 
draw(SkCanvas * canvas,SkPicture::AbortCallback * callback,SkReadBuffer * buffer)71 void SkPicturePlayback::draw(SkCanvas* canvas,
72                              SkPicture::AbortCallback* callback,
73                              SkReadBuffer* buffer) {
74     AutoResetOpID aroi(this);
75     SkASSERT(0 == fCurOffset);
76 
77     SkReadBuffer reader(fPictureData->opData()->bytes(),
78                         fPictureData->opData()->size());
79 
80     // Record this, so we can concat w/ it if we encounter a setMatrix()
81     SkMatrix initialMatrix = canvas->getTotalMatrix();
82 
83     SkAutoCanvasRestore acr(canvas, false);
84 
85     while (!reader.eof()) {
86         if (callback && callback->abort()) {
87             return;
88         }
89 
90         fCurOffset = reader.offset();
91         uint32_t size;
92         DrawType op = ReadOpAndSize(&reader, &size);
93         if (!reader.validate(op > UNUSED && op <= LAST_DRAWTYPE_ENUM)) {
94             return;
95         }
96 
97         this->handleOp(&reader, op, size, canvas, initialMatrix);
98     }
99 
100     // need to propagate invalid state to the parent reader
101     if (buffer) {
102         buffer->validate(reader.isValid());
103     }
104 }
105 
validate_offsetToRestore(SkReadBuffer * reader,size_t offsetToRestore)106 static void validate_offsetToRestore(SkReadBuffer* reader, size_t offsetToRestore) {
107     if (offsetToRestore) {
108         reader->validate(SkIsAlign4(offsetToRestore) && offsetToRestore >= reader->offset());
109     }
110 }
111 
handleOp(SkReadBuffer * reader,DrawType op,uint32_t size,SkCanvas * canvas,const SkMatrix & initialMatrix)112 void SkPicturePlayback::handleOp(SkReadBuffer* reader,
113                                  DrawType op,
114                                  uint32_t size,
115                                  SkCanvas* canvas,
116                                  const SkMatrix& initialMatrix) {
117 #define BREAK_ON_READ_ERROR(r) if (!r->isValid()) break
118 
119     switch (op) {
120         case NOOP: {
121             SkASSERT(size >= 4);
122             reader->skip(size - 4);
123         } break;
124         case FLUSH:
125             canvas->flush();
126             break;
127         case CLIP_PATH: {
128             const SkPath& path = fPictureData->getPath(reader);
129             uint32_t packed = reader->readInt();
130             SkClipOp clipOp = ClipParams_unpackRegionOp(reader, packed);
131             bool doAA = ClipParams_unpackDoAA(packed);
132             size_t offsetToRestore = reader->readInt();
133             validate_offsetToRestore(reader, offsetToRestore);
134             BREAK_ON_READ_ERROR(reader);
135 
136             canvas->clipPath(path, clipOp, doAA);
137             if (canvas->isClipEmpty() && offsetToRestore) {
138                 reader->skip(offsetToRestore - reader->offset());
139             }
140         } break;
141         case CLIP_REGION: {
142             SkRegion region;
143             reader->readRegion(&region);
144             uint32_t packed = reader->readInt();
145             SkClipOp clipOp = ClipParams_unpackRegionOp(reader, packed);
146             size_t offsetToRestore = reader->readInt();
147             validate_offsetToRestore(reader, offsetToRestore);
148             BREAK_ON_READ_ERROR(reader);
149 
150             canvas->clipRegion(region, clipOp);
151             if (canvas->isClipEmpty() && offsetToRestore) {
152                 reader->skip(offsetToRestore - reader->offset());
153             }
154         } break;
155         case CLIP_RECT: {
156             SkRect rect;
157             reader->readRect(&rect);
158             uint32_t packed = reader->readInt();
159             SkClipOp clipOp = ClipParams_unpackRegionOp(reader, packed);
160             bool doAA = ClipParams_unpackDoAA(packed);
161             size_t offsetToRestore = reader->readInt();
162             validate_offsetToRestore(reader, offsetToRestore);
163             BREAK_ON_READ_ERROR(reader);
164 
165             canvas->clipRect(rect, clipOp, doAA);
166             if (canvas->isClipEmpty() && offsetToRestore) {
167                 reader->skip(offsetToRestore - reader->offset());
168             }
169         } break;
170         case CLIP_RRECT: {
171             SkRRect rrect;
172             reader->readRRect(&rrect);
173             uint32_t packed = reader->readInt();
174             SkClipOp clipOp = ClipParams_unpackRegionOp(reader, packed);
175             bool doAA = ClipParams_unpackDoAA(packed);
176             size_t offsetToRestore = reader->readInt();
177             validate_offsetToRestore(reader, offsetToRestore);
178             BREAK_ON_READ_ERROR(reader);
179 
180             canvas->clipRRect(rrect, clipOp, doAA);
181             if (canvas->isClipEmpty() && offsetToRestore) {
182                 reader->skip(offsetToRestore - reader->offset());
183             }
184         } break;
185         case PUSH_CULL: break;  // Deprecated, safe to ignore both push and pop.
186         case POP_CULL:  break;
187         case CONCAT: {
188             SkMatrix matrix;
189             reader->readMatrix(&matrix);
190             BREAK_ON_READ_ERROR(reader);
191 
192             canvas->concat(matrix);
193             break;
194         }
195         case DRAW_ANNOTATION: {
196             SkRect rect;
197             reader->readRect(&rect);
198             SkString key;
199             reader->readString(&key);
200             sk_sp<SkData> data = reader->readByteArrayAsData();
201             BREAK_ON_READ_ERROR(reader);
202             SkASSERT(data);
203 
204             canvas->drawAnnotation(rect, key.c_str(), data.get());
205         } break;
206         case DRAW_ARC: {
207             const SkPaint* paint = fPictureData->getPaint(reader);
208             SkRect rect;
209             reader->readRect(&rect);
210             SkScalar startAngle = reader->readScalar();
211             SkScalar sweepAngle = reader->readScalar();
212             int useCenter = reader->readInt();
213             BREAK_ON_READ_ERROR(reader);
214 
215             if (paint) {
216                 canvas->drawArc(rect, startAngle, sweepAngle, SkToBool(useCenter), *paint);
217             }
218         } break;
219         case DRAW_ATLAS: {
220             const SkPaint* paint = fPictureData->getPaint(reader);
221             const SkImage* atlas = fPictureData->getImage(reader);
222             const uint32_t flags = reader->readUInt();
223             const int count = reader->readUInt();
224             const SkRSXform* xform = (const SkRSXform*)reader->skip(count, sizeof(SkRSXform));
225             const SkRect* tex = (const SkRect*)reader->skip(count, sizeof(SkRect));
226             const SkColor* colors = nullptr;
227             SkBlendMode mode = SkBlendMode::kDst;
228             if (flags & DRAW_ATLAS_HAS_COLORS) {
229                 colors = (const SkColor*)reader->skip(count, sizeof(SkColor));
230                 mode = (SkBlendMode)reader->readUInt();
231             }
232             const SkRect* cull = nullptr;
233             if (flags & DRAW_ATLAS_HAS_CULL) {
234                 cull = (const SkRect*)reader->skip(sizeof(SkRect));
235             }
236             BREAK_ON_READ_ERROR(reader);
237 
238             canvas->drawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
239         } break;
240         case DRAW_CLEAR: {
241             auto c = reader->readInt();
242             BREAK_ON_READ_ERROR(reader);
243 
244             canvas->clear(c);
245         } break;
246         case DRAW_DATA: {
247             // This opcode is now dead, just need to skip it for backwards compatibility
248             size_t length = reader->readInt();
249             (void)reader->skip(length);
250             // skip handles padding the read out to a multiple of 4
251         } break;
252         case DRAW_DRAWABLE: {
253             auto* d = fPictureData->getDrawable(reader);
254             BREAK_ON_READ_ERROR(reader);
255 
256             canvas->drawDrawable(d);
257         } break;
258         case DRAW_DRAWABLE_MATRIX: {
259             SkMatrix matrix;
260             reader->readMatrix(&matrix);
261             SkDrawable* drawable = fPictureData->getDrawable(reader);
262             BREAK_ON_READ_ERROR(reader);
263 
264             canvas->drawDrawable(drawable, &matrix);
265         } break;
266         case DRAW_DRRECT: {
267             const SkPaint* paint = fPictureData->getPaint(reader);
268             SkRRect outer, inner;
269             reader->readRRect(&outer);
270             reader->readRRect(&inner);
271             BREAK_ON_READ_ERROR(reader);
272 
273             if (paint) {
274                 canvas->drawDRRect(outer, inner, *paint);
275             }
276         } break;
277         case DRAW_EDGEAA_QUAD: {
278             SkRect rect;
279             reader->readRect(&rect);
280             SkCanvas::QuadAAFlags aaFlags = static_cast<SkCanvas::QuadAAFlags>(reader->read32());
281             SkColor4f color;
282             if (reader->isVersionLT(SkPicturePriv::kEdgeAAQuadColor4f_Version)) {
283                 // Old version stored color as 8888
284                 color = SkColor4f::FromColor(reader->read32());
285             } else {
286                 reader->readColor4f(&color);
287             }
288             SkBlendMode blend = static_cast<SkBlendMode>(reader->read32());
289             bool hasClip = reader->readInt();
290             SkPoint* clip = nullptr;
291             if (hasClip) {
292                 clip = (SkPoint*) reader->skip(4, sizeof(SkPoint));
293             }
294             BREAK_ON_READ_ERROR(reader);
295             canvas->experimental_DrawEdgeAAQuad(rect, clip, aaFlags, color, blend);
296         } break;
297         case DRAW_EDGEAA_IMAGE_SET: {
298             static const size_t kEntryReadSize =
299                     4 * sizeof(uint32_t) + 2 * sizeof(SkRect) + sizeof(SkScalar);
300             static const size_t kMatrixSize = 9 * sizeof(SkScalar); // != sizeof(SkMatrix)
301 
302             int cnt = reader->readInt();
303             if (!reader->validate(cnt >= 0)) {
304                 break;
305             }
306             const SkPaint* paint = fPictureData->getPaint(reader);
307             SkCanvas::SrcRectConstraint constraint =
308                     static_cast<SkCanvas::SrcRectConstraint>(reader->readInt());
309 
310             if (!reader->validate(SkSafeMath::Mul(cnt, kEntryReadSize) <= reader->available())) {
311                 break;
312             }
313 
314             // Track minimum necessary clip points and matrices that must be provided to satisfy
315             // the entries.
316             int expectedClips = 0;
317             int maxMatrixIndex = -1;
318             SkAutoTArray<SkCanvas::ImageSetEntry> set(cnt);
319             for (int i = 0; i < cnt && reader->isValid(); ++i) {
320                 set[i].fImage = sk_ref_sp(fPictureData->getImage(reader));
321                 reader->readRect(&set[i].fSrcRect);
322                 reader->readRect(&set[i].fDstRect);
323                 set[i].fMatrixIndex = reader->readInt();
324                 set[i].fAlpha = reader->readScalar();
325                 set[i].fAAFlags = reader->readUInt();
326                 set[i].fHasClip = reader->readInt();
327 
328                 expectedClips += set[i].fHasClip ? 1 : 0;
329                 if (set[i].fMatrixIndex > maxMatrixIndex) {
330                     maxMatrixIndex = set[i].fMatrixIndex;
331                 }
332             }
333 
334             int dstClipCount = reader->readInt();
335             SkPoint* dstClips = nullptr;
336             if (!reader->validate(expectedClips <= dstClipCount)) {
337                 // Entries request more dstClip points than are provided in the buffer
338                 break;
339             } else if (dstClipCount > 0) {
340                 dstClips = (SkPoint*) reader->skip(dstClipCount, sizeof(SkPoint));
341                 if (dstClips == nullptr) {
342                     // Not enough bytes remaining so the reader has been invalidated
343                     break;
344                 }
345             }
346             int matrixCount = reader->readInt();
347             if (!reader->validate((maxMatrixIndex + 1) <= matrixCount) ||
348                 !reader->validate(
349                     SkSafeMath::Mul(matrixCount, kMatrixSize) <= reader->available())) {
350                 // Entries access out-of-bound matrix indices, given provided matrices or
351                 // there aren't enough bytes to provide that many matrices
352                 break;
353             }
354             SkTArray<SkMatrix> matrices(matrixCount);
355             for (int i = 0; i < matrixCount && reader->isValid(); ++i) {
356                 reader->readMatrix(&matrices.push_back());
357             }
358             BREAK_ON_READ_ERROR(reader);
359 
360             canvas->experimental_DrawEdgeAAImageSet(set.get(), cnt, dstClips, matrices.begin(),
361                                                     paint, constraint);
362         } break;
363         case DRAW_IMAGE: {
364             const SkPaint* paint = fPictureData->getPaint(reader);
365             const SkImage* image = fPictureData->getImage(reader);
366             SkPoint loc;
367             reader->readPoint(&loc);
368             BREAK_ON_READ_ERROR(reader);
369 
370             canvas->drawImage(image, loc.fX, loc.fY, paint);
371         } break;
372         case DRAW_IMAGE_LATTICE: {
373             const SkPaint* paint = fPictureData->getPaint(reader);
374             const SkImage* image = fPictureData->getImage(reader);
375             SkCanvas::Lattice lattice;
376             (void)SkCanvasPriv::ReadLattice(*reader, &lattice);
377             const SkRect* dst = reader->skipT<SkRect>();
378             BREAK_ON_READ_ERROR(reader);
379 
380             canvas->drawImageLattice(image, lattice, *dst, paint);
381         } break;
382         case DRAW_IMAGE_NINE: {
383             const SkPaint* paint = fPictureData->getPaint(reader);
384             const SkImage* image = fPictureData->getImage(reader);
385             SkIRect center;
386             reader->readIRect(&center);
387             SkRect dst;
388             reader->readRect(&dst);
389             BREAK_ON_READ_ERROR(reader);
390 
391             canvas->drawImageNine(image, center, dst, paint);
392         } break;
393         case DRAW_IMAGE_RECT: {
394             const SkPaint* paint = fPictureData->getPaint(reader);
395             const SkImage* image = fPictureData->getImage(reader);
396             SkRect storage;
397             const SkRect* src = get_rect_ptr(reader, &storage);   // may be null
398             SkRect dst;
399             reader->readRect(&dst);     // required
400             // DRAW_IMAGE_RECT_STRICT assumes this constraint, and doesn't store it
401             SkCanvas::SrcRectConstraint constraint = SkCanvas::kStrict_SrcRectConstraint;
402             if (DRAW_IMAGE_RECT == op) {
403                 // newer op-code stores the constraint explicitly
404                 constraint = (SkCanvas::SrcRectConstraint)reader->readInt();
405             }
406             BREAK_ON_READ_ERROR(reader);
407 
408             canvas->legacy_drawImageRect(image, src, dst, paint, constraint);
409         } break;
410         case DRAW_OVAL: {
411             const SkPaint* paint = fPictureData->getPaint(reader);
412             SkRect rect;
413             reader->readRect(&rect);
414             BREAK_ON_READ_ERROR(reader);
415 
416             if (paint) {
417                 canvas->drawOval(rect, *paint);
418             }
419         } break;
420         case DRAW_PAINT: {
421             const SkPaint* paint = fPictureData->getPaint(reader);
422             BREAK_ON_READ_ERROR(reader);
423 
424             if (paint) {
425                 canvas->drawPaint(*paint);
426             }
427         } break;
428         case DRAW_BEHIND_PAINT: {
429             const SkPaint* paint = fPictureData->getPaint(reader);
430             BREAK_ON_READ_ERROR(reader);
431 
432             if (paint) {
433                 SkCanvasPriv::DrawBehind(canvas, *paint);
434             }
435         } break;
436         case DRAW_PATCH: {
437             const SkPaint* paint = fPictureData->getPaint(reader);
438 
439             const SkPoint* cubics = (const SkPoint*)reader->skip(SkPatchUtils::kNumCtrlPts,
440                                                                  sizeof(SkPoint));
441             uint32_t flag = reader->readInt();
442             const SkColor* colors = nullptr;
443             if (flag & DRAW_VERTICES_HAS_COLORS) {
444                 colors = (const SkColor*)reader->skip(SkPatchUtils::kNumCorners, sizeof(SkColor));
445             }
446             const SkPoint* texCoords = nullptr;
447             if (flag & DRAW_VERTICES_HAS_TEXS) {
448                 texCoords = (const SkPoint*)reader->skip(SkPatchUtils::kNumCorners,
449                                                          sizeof(SkPoint));
450             }
451             SkBlendMode bmode = SkBlendMode::kModulate;
452             if (flag & DRAW_VERTICES_HAS_XFER) {
453                 unsigned mode = reader->readInt();
454                 if (mode <= (unsigned)SkBlendMode::kLastMode) {
455                     bmode = (SkBlendMode)mode;
456                 }
457             }
458             BREAK_ON_READ_ERROR(reader);
459 
460             if (paint) {
461                 canvas->drawPatch(cubics, colors, texCoords, bmode, *paint);
462             }
463         } break;
464         case DRAW_PATH: {
465             const SkPaint* paint = fPictureData->getPaint(reader);
466             const auto& path = fPictureData->getPath(reader);
467             BREAK_ON_READ_ERROR(reader);
468 
469             if (paint) {
470                 canvas->drawPath(path, *paint);
471             }
472         } break;
473         case DRAW_PICTURE: {
474             const auto* pic = fPictureData->getPicture(reader);
475             BREAK_ON_READ_ERROR(reader);
476 
477             canvas->drawPicture(pic);
478         } break;
479         case DRAW_PICTURE_MATRIX_PAINT: {
480             const SkPaint* paint = fPictureData->getPaint(reader);
481             SkMatrix matrix;
482             reader->readMatrix(&matrix);
483             const SkPicture* pic = fPictureData->getPicture(reader);
484             BREAK_ON_READ_ERROR(reader);
485 
486             canvas->drawPicture(pic, &matrix, paint);
487         } break;
488         case DRAW_POINTS: {
489             const SkPaint* paint = fPictureData->getPaint(reader);
490             SkCanvas::PointMode mode = (SkCanvas::PointMode)reader->readInt();
491             size_t count = reader->readInt();
492             const SkPoint* pts = (const SkPoint*)reader->skip(count, sizeof(SkPoint));
493             BREAK_ON_READ_ERROR(reader);
494 
495             if (paint) {
496                 canvas->drawPoints(mode, count, pts, *paint);
497             }
498         } break;
499         case DRAW_RECT: {
500             const SkPaint* paint = fPictureData->getPaint(reader);
501             SkRect rect;
502             reader->readRect(&rect);
503             BREAK_ON_READ_ERROR(reader);
504 
505             if (paint) {
506                 canvas->drawRect(rect, *paint);
507             }
508         } break;
509         case DRAW_REGION: {
510             const SkPaint* paint = fPictureData->getPaint(reader);
511             SkRegion region;
512             reader->readRegion(&region);
513             BREAK_ON_READ_ERROR(reader);
514 
515             if (paint) {
516                 canvas->drawRegion(region, *paint);
517             }
518         } break;
519         case DRAW_RRECT: {
520             const SkPaint* paint = fPictureData->getPaint(reader);
521             SkRRect rrect;
522             reader->readRRect(&rrect);
523             BREAK_ON_READ_ERROR(reader);
524 
525             if (paint) {
526                 canvas->drawRRect(rrect, *paint);
527             }
528         } break;
529         case DRAW_SHADOW_REC: {
530             const auto& path = fPictureData->getPath(reader);
531             SkDrawShadowRec rec;
532             reader->readPoint3(&rec.fZPlaneParams);
533             reader->readPoint3(&rec.fLightPos);
534             rec.fLightRadius = reader->readScalar();
535             if (reader->isVersionLT(SkPicturePriv::kTwoColorDrawShadow_Version)) {
536                 SkScalar ambientAlpha = reader->readScalar();
537                 SkScalar spotAlpha = reader->readScalar();
538                 SkColor color = reader->read32();
539                 rec.fAmbientColor = SkColorSetA(color, SkColorGetA(color)*ambientAlpha);
540                 rec.fSpotColor = SkColorSetA(color, SkColorGetA(color)*spotAlpha);
541             } else {
542                 rec.fAmbientColor = reader->read32();
543                 rec.fSpotColor = reader->read32();
544             }
545             rec.fFlags = reader->read32();
546             BREAK_ON_READ_ERROR(reader);
547 
548             canvas->private_draw_shadow_rec(path, rec);
549         } break;
550         case DRAW_TEXT_BLOB: {
551             const SkPaint* paint = fPictureData->getPaint(reader);
552             const SkTextBlob* blob = fPictureData->getTextBlob(reader);
553             SkScalar x = reader->readScalar();
554             SkScalar y = reader->readScalar();
555             BREAK_ON_READ_ERROR(reader);
556 
557             if (paint) {
558                 canvas->drawTextBlob(blob, x, y, *paint);
559             }
560         } break;
561         case DRAW_VERTICES_OBJECT: {
562             const SkPaint* paint = fPictureData->getPaint(reader);
563             const SkVertices* vertices = fPictureData->getVertices(reader);
564             const int boneCount = reader->readInt();
565             const SkVertices::Bone* bones = boneCount ?
566                     (const SkVertices::Bone*) reader->skip(boneCount, sizeof(SkVertices::Bone)) :
567                     nullptr;
568             SkBlendMode bmode = reader->read32LE(SkBlendMode::kLastMode);
569             BREAK_ON_READ_ERROR(reader);
570 
571             if (paint && vertices) {
572                 canvas->drawVertices(vertices, bones, boneCount, bmode, *paint);
573             }
574         } break;
575         case RESTORE:
576             canvas->restore();
577             break;
578         case ROTATE: {
579             auto deg = reader->readScalar();
580             canvas->rotate(deg);
581         } break;
582         case SAVE:
583             canvas->save();
584             break;
585         case SAVE_BEHIND: {
586             uint32_t flags = reader->readInt();
587             const SkRect* subset = nullptr;
588             SkRect storage;
589             if (flags & SAVEBEHIND_HAS_SUBSET) {
590                 reader->readRect(&storage);
591                 subset = &storage;
592             }
593             SkCanvasPriv::SaveBehind(canvas, subset);
594         } break;
595         case SAVE_LAYER_SAVEFLAGS_DEPRECATED: {
596             SkRect storage;
597             const SkRect* boundsPtr = get_rect_ptr(reader, &storage);
598             const SkPaint* paint = fPictureData->getPaint(reader);
599             auto flags = SkCanvasPriv::LegacySaveFlagsToSaveLayerFlags(reader->readInt());
600             BREAK_ON_READ_ERROR(reader);
601 
602             canvas->saveLayer(SkCanvas::SaveLayerRec(boundsPtr, paint, flags));
603         } break;
604         case SAVE_LAYER_SAVELAYERREC: {
605             SkCanvas::SaveLayerRec rec(nullptr, nullptr, nullptr, nullptr, nullptr, 0);
606             SkMatrix clipMatrix;
607             const uint32_t flatFlags = reader->readInt();
608             SkRect bounds;
609             if (flatFlags & SAVELAYERREC_HAS_BOUNDS) {
610                 reader->readRect(&bounds);
611                 rec.fBounds = &bounds;
612             }
613             if (flatFlags & SAVELAYERREC_HAS_PAINT) {
614                 rec.fPaint = fPictureData->getPaint(reader);
615             }
616             if (flatFlags & SAVELAYERREC_HAS_BACKDROP) {
617                 if (const auto* paint = fPictureData->getPaint(reader)) {
618                     rec.fBackdrop = paint->getImageFilter();
619                 }
620             }
621             if (flatFlags & SAVELAYERREC_HAS_FLAGS) {
622                 rec.fSaveLayerFlags = reader->readInt();
623             }
624             if (flatFlags & SAVELAYERREC_HAS_CLIPMASK) {
625                 rec.fClipMask = fPictureData->getImage(reader);
626             }
627             if (flatFlags & SAVELAYERREC_HAS_CLIPMATRIX) {
628                 reader->readMatrix(&clipMatrix);
629                 rec.fClipMatrix = &clipMatrix;
630             }
631             BREAK_ON_READ_ERROR(reader);
632 
633             canvas->saveLayer(rec);
634         } break;
635         case SCALE: {
636             SkScalar sx = reader->readScalar();
637             SkScalar sy = reader->readScalar();
638             canvas->scale(sx, sy);
639         } break;
640         case SET_MATRIX: {
641             SkMatrix matrix;
642             reader->readMatrix(&matrix);
643             matrix.postConcat(initialMatrix);
644             canvas->setMatrix(matrix);
645         } break;
646         case SKEW: {
647             SkScalar sx = reader->readScalar();
648             SkScalar sy = reader->readScalar();
649             canvas->skew(sx, sy);
650         } break;
651         case TRANSLATE: {
652             SkScalar dx = reader->readScalar();
653             SkScalar dy = reader->readScalar();
654             canvas->translate(dx, dy);
655         } break;
656         default:
657             reader->validate(false);    // unknown op
658             break;
659     }
660 
661 #undef BREAK_ON_READ_ERROR
662 }
663