Line data Source code
1 : /*
2 : * Copyright 2016 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 "SkAutoMalloc.h"
9 : #include "SkColorFilter.h"
10 : #include "SkDrawLooper.h"
11 : #include "SkImageFilter.h"
12 : #include "SkMaskFilter.h"
13 : #include "SkPathEffect.h"
14 : #include "SkPipeCanvas.h"
15 : #include "SkPipeFormat.h"
16 : #include "SkRSXform.h"
17 : #include "SkRasterizer.h"
18 : #include "SkShader.h"
19 : #include "SkStream.h"
20 : #include "SkTextBlob.h"
21 : #include "SkTypeface.h"
22 :
23 0 : template <typename T> void write_rrect(T* writer, const SkRRect& rrect) {
24 : char tmp[SkRRect::kSizeInMemory];
25 0 : rrect.writeToMemory(tmp);
26 0 : writer->write(tmp, SkRRect::kSizeInMemory);
27 0 : }
28 :
29 0 : template <typename T> void write_pad(T* writer, const void* buffer, size_t len) {
30 0 : writer->write(buffer, len & ~3);
31 0 : if (len & 3) {
32 0 : const char* src = (const char*)buffer + (len & ~3);
33 0 : len &= 3;
34 0 : uint32_t tmp = 0;
35 0 : memcpy(&tmp, src, len);
36 0 : writer->write(&tmp, 4);
37 : }
38 0 : }
39 :
40 : ///////////////////////////////////////////////////////////////////////////////////////////////////
41 :
42 0 : static uint16_t compute_nondef(const SkPaint& paint, PaintUsage usage) {
43 : // kRespectsStroke_PaintUsage is only valid if other bits are also set
44 0 : SkASSERT(0 != (usage & ~kRespectsStroke_PaintUsage));
45 :
46 0 : const SkScalar kTextSize_Default = 12;
47 0 : const SkScalar kTextScaleX_Default = 1;
48 0 : const SkScalar kTextSkewX_Default = 0;
49 0 : const SkScalar kStrokeWidth_Default = 0;
50 0 : const SkScalar kStrokeMiter_Default = 4;
51 0 : const SkColor kColor_Default = SK_ColorBLACK;
52 :
53 0 : unsigned bits = (paint.getColor() != kColor_Default) ? kColor_NonDef : 0;
54 :
55 0 : if (usage & kText_PaintUsage) {
56 0 : bits |= (paint.getTextSize() != kTextSize_Default ? kTextSize_NonDef : 0);
57 0 : bits |= (paint.getTextScaleX() != kTextScaleX_Default ? kTextScaleX_NonDef : 0);
58 0 : bits |= (paint.getTextSkewX() != kTextSkewX_Default ? kTextSkewX_NonDef : 0);
59 0 : bits |= (paint.getTypeface() ? kTypeface_NonDef : 0);
60 : }
61 :
62 : // TODO: kImage_PaintUsage only needs the shader/maskfilter IF its colortype is kAlpha_8
63 :
64 0 : if (usage & (kVertices_PaintUsage | kDrawPaint_PaintUsage | kImage_PaintUsage |
65 : kText_PaintUsage | kGeometry_PaintUsage | kTextBlob_PaintUsage)) {
66 0 : bits |= (paint.getShader() ? kShader_NonDef : 0);
67 : }
68 :
69 0 : if (usage & (kText_PaintUsage | kGeometry_PaintUsage | kTextBlob_PaintUsage)) {
70 0 : bits |= (paint.getPathEffect() ? kPathEffect_NonDef : 0);
71 0 : bits |= (paint.getRasterizer() ? kRasterizer_NonDef : 0);
72 :
73 0 : if (paint.getStyle() != SkPaint::kFill_Style || (usage & kRespectsStroke_PaintUsage)) {
74 0 : bits |= (paint.getStrokeWidth() != kStrokeWidth_Default ? kStrokeWidth_NonDef : 0);
75 0 : bits |= (paint.getStrokeMiter() != kStrokeMiter_Default ? kStrokeMiter_NonDef : 0);
76 : }
77 : }
78 :
79 0 : if (usage &
80 : (kText_PaintUsage | kGeometry_PaintUsage | kImage_PaintUsage | kTextBlob_PaintUsage))
81 : {
82 0 : bits |= (paint.getMaskFilter() ? kMaskFilter_NonDef : 0);
83 : }
84 :
85 0 : bits |= (paint.getColorFilter() ? kColorFilter_NonDef : 0);
86 0 : bits |= (paint.getImageFilter() ? kImageFilter_NonDef : 0);
87 0 : bits |= (paint.getDrawLooper() ? kDrawLooper_NonDef : 0);
88 :
89 0 : return SkToU16(bits);
90 : }
91 :
92 0 : static uint32_t pack_paint_flags(unsigned flags, unsigned hint, unsigned align,
93 : unsigned filter, unsigned style, unsigned caps, unsigned joins,
94 : unsigned encoding) {
95 : SkASSERT(kFlags_BPF + kHint_BPF + kAlign_BPF + kFilter_BPF <= 32);
96 :
97 0 : ASSERT_FITS_IN(flags, kFlags_BPF);
98 0 : ASSERT_FITS_IN(filter, kFilter_BPF);
99 0 : ASSERT_FITS_IN(style, kStyle_BPF);
100 0 : ASSERT_FITS_IN(caps, kCaps_BPF);
101 0 : ASSERT_FITS_IN(joins, kJoins_BPF);
102 0 : ASSERT_FITS_IN(hint, kHint_BPF);
103 0 : ASSERT_FITS_IN(align, kAlign_BPF);
104 0 : ASSERT_FITS_IN(encoding, kEncoding_BPF);
105 :
106 : // left-align the fields of "known" size, and right-align the last (flatFlags) so it can easly
107 : // add more bits in the future.
108 :
109 0 : uint32_t packed = 0;
110 0 : int shift = 32;
111 :
112 0 : shift -= kFlags_BPF; packed |= (flags << shift);
113 0 : shift -= kFilter_BPF; packed |= (filter << shift);
114 0 : shift -= kStyle_BPF; packed |= (style << shift);
115 : // these are only needed for stroking (geometry or text)
116 0 : shift -= kCaps_BPF; packed |= (caps << shift);
117 0 : shift -= kJoins_BPF; packed |= (joins << shift);
118 : // these are only needed for text
119 0 : shift -= kHint_BPF; packed |= (hint << shift);
120 0 : shift -= kAlign_BPF; packed |= (align << shift);
121 0 : shift -= kEncoding_BPF; packed |= (encoding << shift);
122 :
123 0 : return packed;
124 : }
125 :
126 : #define CHECK_WRITE_SCALAR(writer, nondef, paint, Field) \
127 : do { if (nondef & (k##Field##_NonDef)) { \
128 : writer.writeScalar(paint.get##Field()); \
129 : }} while (0)
130 :
131 : #define CHECK_WRITE_FLATTENABLE(writer, nondef, paint, Field) \
132 : do { if (nondef & (k##Field##_NonDef)) { \
133 : SkFlattenable* f = paint.get##Field(); \
134 : SkASSERT(f != nullptr); \
135 : writer.writeFlattenable(f); \
136 : } } while (0)
137 :
138 : /*
139 : * Header:
140 : * paint flags : 32
141 : * non_def bits : 16
142 : * xfermode enum : 8
143 : * pad zeros : 8
144 : */
145 0 : static void write_paint(SkWriteBuffer& writer, const SkPaint& paint, unsigned usage) {
146 0 : uint32_t packedFlags = pack_paint_flags(paint.getFlags(), paint.getHinting(),
147 0 : paint.getTextAlign(), paint.getFilterQuality(),
148 0 : paint.getStyle(), paint.getStrokeCap(),
149 0 : paint.getStrokeJoin(), paint.getTextEncoding());
150 0 : writer.write32(packedFlags);
151 :
152 0 : unsigned nondef = compute_nondef(paint, (PaintUsage)usage);
153 0 : const uint8_t pad = 0;
154 0 : writer.write32((nondef << 16) | ((unsigned)paint.getBlendMode() << 8) | pad);
155 :
156 0 : CHECK_WRITE_SCALAR(writer, nondef, paint, TextSize);
157 0 : CHECK_WRITE_SCALAR(writer, nondef, paint, TextScaleX);
158 0 : CHECK_WRITE_SCALAR(writer, nondef, paint, TextSkewX);
159 0 : CHECK_WRITE_SCALAR(writer, nondef, paint, StrokeWidth);
160 0 : CHECK_WRITE_SCALAR(writer, nondef, paint, StrokeMiter);
161 :
162 0 : if (nondef & kColor_NonDef) {
163 0 : writer.write32(paint.getColor());
164 : }
165 0 : if (nondef & kTypeface_NonDef) {
166 : // TODO: explore idea of writing bits indicating "use the prev (or prev N) face"
167 : // e.g. 1-N bits is an index into a ring buffer of typefaces
168 0 : SkTypeface* tf = paint.getTypeface();
169 0 : SkASSERT(tf);
170 0 : writer.writeTypeface(tf);
171 : }
172 :
173 0 : CHECK_WRITE_FLATTENABLE(writer, nondef, paint, PathEffect);
174 0 : CHECK_WRITE_FLATTENABLE(writer, nondef, paint, Shader);
175 0 : CHECK_WRITE_FLATTENABLE(writer, nondef, paint, MaskFilter);
176 0 : CHECK_WRITE_FLATTENABLE(writer, nondef, paint, ColorFilter);
177 0 : CHECK_WRITE_FLATTENABLE(writer, nondef, paint, Rasterizer);
178 0 : CHECK_WRITE_FLATTENABLE(writer, nondef, paint, ImageFilter);
179 0 : CHECK_WRITE_FLATTENABLE(writer, nondef, paint, DrawLooper);
180 0 : }
181 :
182 : class SkPipeWriter : public SkBinaryWriteBuffer {
183 : enum {
184 : N = 1024/4,
185 : };
186 : uint32_t fStorage[N];
187 : SkWStream* fStream;
188 :
189 : public:
190 0 : SkPipeWriter(SkWStream* stream, SkDeduper* deduper)
191 0 : : SkBinaryWriteBuffer(fStorage, sizeof(fStorage))
192 0 : , fStream(stream)
193 : {
194 0 : this->setDeduper(deduper);
195 0 : }
196 :
197 0 : SkPipeWriter(SkPipeCanvas* pc) : SkPipeWriter(pc->fStream, pc->fDeduper) {}
198 :
199 0 : ~SkPipeWriter() override {
200 0 : SkASSERT(SkIsAlign4(fStream->bytesWritten()));
201 0 : this->writeToStream(fStream);
202 0 : }
203 :
204 0 : void writePaint(const SkPaint& paint) override {
205 0 : write_paint(*this, paint, kUnknown_PaintUsage);
206 0 : }
207 : };
208 :
209 : ///////////////////////////////////////////////////////////////////////////////////////////////////
210 :
211 0 : SkPipeCanvas::SkPipeCanvas(const SkRect& cull, SkPipeDeduper* deduper, SkWStream* stream)
212 0 : : INHERITED(cull.roundOut())
213 : , fDeduper(deduper)
214 0 : , fStream(stream)
215 0 : {}
216 :
217 0 : SkPipeCanvas::~SkPipeCanvas() {}
218 :
219 0 : void SkPipeCanvas::willSave() {
220 0 : fStream->write32(pack_verb(SkPipeVerb::kSave));
221 0 : this->INHERITED::willSave();
222 0 : }
223 :
224 0 : SkCanvas::SaveLayerStrategy SkPipeCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
225 0 : SkPipeWriter writer(this);
226 0 : uint32_t extra = rec.fSaveLayerFlags;
227 :
228 : // remap this wacky flag
229 0 : if (extra & (1 << 31)/*SkCanvas::kDontClipToLayer_PrivateSaveLayerFlag*/) {
230 0 : extra &= ~(1 << 31);
231 0 : extra |= kDontClipToLayer_SaveLayerMask;
232 : }
233 :
234 0 : if (rec.fBounds) {
235 0 : extra |= kHasBounds_SaveLayerMask;
236 : }
237 0 : if (rec.fPaint) {
238 0 : extra |= kHasPaint_SaveLayerMask;
239 : }
240 0 : if (rec.fBackdrop) {
241 0 : extra |= kHasBackdrop_SaveLayerMask;
242 : }
243 :
244 0 : writer.write32(pack_verb(SkPipeVerb::kSaveLayer, extra));
245 0 : if (rec.fBounds) {
246 0 : writer.writeRect(*rec.fBounds);
247 : }
248 0 : if (rec.fPaint) {
249 0 : write_paint(writer, *rec.fPaint, kSaveLayer_PaintUsage);
250 : }
251 0 : if (rec.fBackdrop) {
252 0 : writer.writeFlattenable(rec.fBackdrop);
253 : }
254 0 : return kNoLayer_SaveLayerStrategy;
255 : }
256 :
257 0 : void SkPipeCanvas::willRestore() {
258 0 : fStream->write32(pack_verb(SkPipeVerb::kRestore));
259 0 : this->INHERITED::willRestore();
260 0 : }
261 :
262 0 : template <typename T> void write_sparse_matrix(T* writer, const SkMatrix& matrix) {
263 0 : SkMatrix::TypeMask tm = matrix.getType();
264 : SkScalar tmp[9];
265 0 : if (tm & SkMatrix::kPerspective_Mask) {
266 0 : matrix.get9(tmp);
267 0 : writer->write(tmp, 9 * sizeof(SkScalar));
268 0 : } else if (tm & SkMatrix::kAffine_Mask) {
269 0 : tmp[0] = matrix[SkMatrix::kMScaleX];
270 0 : tmp[1] = matrix[SkMatrix::kMSkewX];
271 0 : tmp[2] = matrix[SkMatrix::kMTransX];
272 0 : tmp[3] = matrix[SkMatrix::kMScaleY];
273 0 : tmp[4] = matrix[SkMatrix::kMSkewY];
274 0 : tmp[5] = matrix[SkMatrix::kMTransY];
275 0 : writer->write(tmp, 6 * sizeof(SkScalar));
276 0 : } else if (tm & SkMatrix::kScale_Mask) {
277 0 : tmp[0] = matrix[SkMatrix::kMScaleX];
278 0 : tmp[1] = matrix[SkMatrix::kMTransX];
279 0 : tmp[2] = matrix[SkMatrix::kMScaleY];
280 0 : tmp[3] = matrix[SkMatrix::kMTransY];
281 0 : writer->write(tmp, 4 * sizeof(SkScalar));
282 0 : } else if (tm & SkMatrix::kTranslate_Mask) {
283 0 : tmp[0] = matrix[SkMatrix::kMTransX];
284 0 : tmp[1] = matrix[SkMatrix::kMTransY];
285 0 : writer->write(tmp, 2 * sizeof(SkScalar));
286 : }
287 : // else write nothing for Identity
288 0 : }
289 :
290 0 : static void do_concat(SkWStream* stream, const SkMatrix& matrix, bool isSetMatrix) {
291 0 : unsigned mtype = matrix.getType();
292 0 : SkASSERT(0 == (mtype & ~kTypeMask_ConcatMask));
293 0 : unsigned extra = mtype;
294 0 : if (isSetMatrix) {
295 0 : extra |= kSetMatrix_ConcatMask;
296 : }
297 0 : if (mtype || isSetMatrix) {
298 0 : stream->write32(pack_verb(SkPipeVerb::kConcat, extra));
299 0 : write_sparse_matrix(stream, matrix);
300 : }
301 0 : }
302 :
303 0 : void SkPipeCanvas::didConcat(const SkMatrix& matrix) {
304 0 : do_concat(fStream, matrix, false);
305 0 : this->INHERITED::didConcat(matrix);
306 0 : }
307 :
308 0 : void SkPipeCanvas::didSetMatrix(const SkMatrix& matrix) {
309 0 : do_concat(fStream, matrix, true);
310 0 : this->INHERITED::didSetMatrix(matrix);
311 0 : }
312 :
313 0 : void SkPipeCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
314 0 : fStream->write32(pack_verb(SkPipeVerb::kClipRect, ((unsigned)op << 1) | edgeStyle));
315 0 : fStream->write(&rect, 4 * sizeof(SkScalar));
316 :
317 0 : this->INHERITED::onClipRect(rect, op, edgeStyle);
318 0 : }
319 :
320 0 : void SkPipeCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
321 0 : fStream->write32(pack_verb(SkPipeVerb::kClipRRect, ((unsigned)op << 1) | edgeStyle));
322 0 : write_rrect(fStream, rrect);
323 :
324 0 : this->INHERITED::onClipRRect(rrect, op, edgeStyle);
325 0 : }
326 :
327 0 : void SkPipeCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
328 0 : SkPipeWriter writer(this);
329 0 : writer.write32(pack_verb(SkPipeVerb::kClipPath, ((unsigned)op << 1) | edgeStyle));
330 0 : writer.writePath(path);
331 :
332 0 : this->INHERITED::onClipPath(path, op, edgeStyle);
333 0 : }
334 :
335 0 : void SkPipeCanvas::onClipRegion(const SkRegion& deviceRgn, SkClipOp op) {
336 0 : SkPipeWriter writer(this);
337 0 : writer.write32(pack_verb(SkPipeVerb::kClipRegion, (unsigned)op << 1));
338 0 : writer.writeRegion(deviceRgn);
339 :
340 0 : this->INHERITED::onClipRegion(deviceRgn, op);
341 0 : }
342 :
343 : ///////////////////////////////////////////////////////////////////////////////////////////////////
344 :
345 0 : void SkPipeCanvas::onDrawArc(const SkRect& bounds, SkScalar startAngle, SkScalar sweepAngle,
346 : bool useCenter, const SkPaint& paint) {
347 0 : SkPipeWriter writer(this);
348 0 : writer.write32(pack_verb(SkPipeVerb::kDrawArc, (int)useCenter));
349 0 : writer.writeRect(bounds);
350 0 : writer.writeScalar(startAngle);
351 0 : writer.writeScalar(sweepAngle);
352 0 : write_paint(writer, paint, kGeometry_PaintUsage);
353 0 : }
354 :
355 0 : void SkPipeCanvas::onDrawAtlas(const SkImage* image, const SkRSXform xform[], const SkRect rect[],
356 : const SkColor colors[], int count, SkBlendMode mode,
357 : const SkRect* cull, const SkPaint* paint) {
358 0 : unsigned extra = (unsigned)mode;
359 0 : SkASSERT(0 == (extra & ~kMode_DrawAtlasMask));
360 0 : if (colors) {
361 0 : extra |= kHasColors_DrawAtlasMask;
362 : }
363 0 : if (cull) {
364 0 : extra |= kHasCull_DrawAtlasMask;
365 : }
366 0 : if (paint) {
367 0 : extra |= kHasPaint_DrawAtlasMask;
368 : }
369 :
370 0 : SkPipeWriter writer(this);
371 0 : writer.write32(pack_verb(SkPipeVerb::kDrawAtlas, extra));
372 0 : writer.writeImage(image);
373 0 : writer.write32(count);
374 0 : writer.write(xform, count * sizeof(SkRSXform));
375 0 : writer.write(rect, count * sizeof(SkRect));
376 0 : if (colors) {
377 0 : writer.write(colors, count * sizeof(SkColor));
378 : }
379 0 : if (cull) {
380 0 : writer.writeRect(*cull);
381 : }
382 0 : if (paint) {
383 0 : write_paint(writer, *paint, kImage_PaintUsage);
384 : }
385 0 : }
386 :
387 0 : void SkPipeCanvas::onDrawPaint(const SkPaint& paint) {
388 0 : SkPipeWriter writer(this);
389 0 : writer.write32(pack_verb(SkPipeVerb::kDrawPaint));
390 0 : write_paint(writer, paint, kDrawPaint_PaintUsage);
391 0 : }
392 :
393 0 : void SkPipeCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
394 : const SkPaint& paint) {
395 0 : SkPipeWriter writer(this);
396 0 : writer.write32(pack_verb(SkPipeVerb::kDrawPoints, mode));
397 0 : writer.write32(SkToU32(count));
398 0 : writer.write(pts, count * sizeof(SkPoint));
399 0 : write_paint(writer, paint, kGeometry_PaintUsage | kRespectsStroke_PaintUsage);
400 0 : }
401 :
402 0 : void SkPipeCanvas::onDrawRect(const SkRect& rect, const SkPaint& paint) {
403 0 : SkPipeWriter writer(this);
404 0 : writer.write32(pack_verb(SkPipeVerb::kDrawRect));
405 0 : writer.write(&rect, sizeof(SkRect));
406 0 : write_paint(writer, paint, kGeometry_PaintUsage);
407 0 : }
408 :
409 0 : void SkPipeCanvas::onDrawOval(const SkRect& rect, const SkPaint& paint) {
410 0 : SkPipeWriter writer(this);
411 0 : writer.write32(pack_verb(SkPipeVerb::kDrawOval));
412 0 : writer.write(&rect, sizeof(SkRect));
413 0 : write_paint(writer, paint, kGeometry_PaintUsage);
414 0 : }
415 :
416 0 : void SkPipeCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
417 0 : SkPipeWriter writer(this);
418 0 : writer.write32(pack_verb(SkPipeVerb::kDrawRRect));
419 0 : write_rrect(&writer, rrect);
420 0 : write_paint(writer, paint, kGeometry_PaintUsage);
421 0 : }
422 :
423 0 : void SkPipeCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
424 0 : SkPipeWriter writer(this);
425 0 : writer.write32(pack_verb(SkPipeVerb::kDrawDRRect));
426 0 : write_rrect(&writer, outer);
427 0 : write_rrect(&writer, inner);
428 0 : write_paint(writer, paint, kGeometry_PaintUsage);
429 0 : }
430 :
431 0 : void SkPipeCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
432 0 : SkPipeWriter writer(this);
433 0 : writer.write32(pack_verb(SkPipeVerb::kDrawPath));
434 0 : writer.writePath(path);
435 0 : write_paint(writer, paint, kGeometry_PaintUsage);
436 0 : }
437 :
438 : ///////////////////////////////////////////////////////////////////////////////////////////////////
439 :
440 0 : static sk_sp<SkImage> make_from_bitmap(const SkBitmap& bitmap) {
441 : // If we just "make" an image, it will force a CPU copy (if its mutable), only to have
442 : // us then either find it in our cache, or compress and send it.
443 : //
444 : // Better could be to look it up in our cache first, and only create/compress it if we have to.
445 : //
446 : // But for now, just do the dumb thing...
447 0 : return SkImage::MakeFromBitmap(bitmap);
448 : }
449 :
450 0 : void SkPipeCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y,
451 : const SkPaint* paint) {
452 0 : sk_sp<SkImage> image = make_from_bitmap(bitmap);
453 0 : if (image) {
454 0 : this->onDrawImage(image.get(), x, y, paint);
455 : }
456 0 : }
457 :
458 0 : void SkPipeCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
459 : const SkPaint* paint, SrcRectConstraint constraint) {
460 0 : sk_sp<SkImage> image = make_from_bitmap(bitmap);
461 0 : if (image) {
462 0 : this->onDrawImageRect(image.get(), src, dst, paint, constraint);
463 : }
464 0 : }
465 :
466 0 : void SkPipeCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
467 : const SkRect& dst, const SkPaint* paint) {
468 0 : sk_sp<SkImage> image = make_from_bitmap(bitmap);
469 0 : if (image) {
470 0 : this->onDrawImageNine(image.get(), center, dst, paint);
471 : }
472 0 : }
473 :
474 0 : void SkPipeCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
475 : const SkRect& dst, const SkPaint* paint) {
476 0 : sk_sp<SkImage> image = make_from_bitmap(bitmap);
477 0 : if (image) {
478 0 : this->onDrawImageLattice(image.get(), lattice, dst, paint);
479 : }
480 0 : }
481 :
482 : ///////////////////////////////////////////////////////////////////////////////////////////////////
483 :
484 0 : void SkPipeCanvas::onDrawImage(const SkImage* image, SkScalar left, SkScalar top,
485 : const SkPaint* paint) {
486 0 : unsigned extra = 0;
487 0 : if (paint) {
488 0 : extra |= kHasPaint_DrawImageMask;
489 : }
490 0 : SkPipeWriter writer(this);
491 0 : writer.write32(pack_verb(SkPipeVerb::kDrawImage, extra));
492 0 : writer.writeImage(image);
493 0 : writer.writeScalar(left);
494 0 : writer.writeScalar(top);
495 0 : if (paint) {
496 0 : write_paint(writer, *paint, kImage_PaintUsage);
497 : }
498 0 : }
499 :
500 0 : void SkPipeCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
501 : const SkPaint* paint, SrcRectConstraint constraint) {
502 0 : SkASSERT(0 == ((unsigned)constraint & ~1));
503 0 : unsigned extra = (unsigned)constraint;
504 0 : if (paint) {
505 0 : extra |= kHasPaint_DrawImageRectMask;
506 : }
507 0 : if (src) {
508 0 : extra |= kHasSrcRect_DrawImageRectMask;
509 : }
510 :
511 0 : SkPipeWriter writer(this);
512 0 : writer.write32(pack_verb(SkPipeVerb::kDrawImageRect, extra));
513 0 : writer.writeImage(image);
514 0 : if (src) {
515 0 : writer.write(src, sizeof(*src));
516 : }
517 0 : writer.write(&dst, sizeof(dst));
518 0 : if (paint) {
519 0 : write_paint(writer, *paint, kImage_PaintUsage);
520 : }
521 0 : }
522 :
523 0 : void SkPipeCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
524 : const SkPaint* paint) {
525 0 : unsigned extra = 0;
526 0 : if (paint) {
527 0 : extra |= kHasPaint_DrawImageNineMask;
528 : }
529 0 : SkPipeWriter writer(this);
530 0 : writer.write32(pack_verb(SkPipeVerb::kDrawImageNine, extra));
531 0 : writer.writeImage(image);
532 0 : writer.write(¢er, sizeof(center));
533 0 : writer.write(&dst, sizeof(dst));
534 0 : if (paint) {
535 0 : write_paint(writer, *paint, kImage_PaintUsage);
536 : }
537 0 : }
538 :
539 0 : void SkPipeCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice,
540 : const SkRect& dst, const SkPaint* paint) {
541 0 : unsigned extra = 0;
542 0 : if (paint) {
543 0 : extra |= kHasPaint_DrawImageLatticeMask;
544 : }
545 0 : if (lattice.fFlags) {
546 0 : extra |= kHasFlags_DrawImageLatticeMask;
547 : }
548 0 : if (lattice.fXCount >= kCount_DrawImageLatticeMask) {
549 0 : extra |= kCount_DrawImageLatticeMask << kXCount_DrawImageLatticeShift;
550 : } else {
551 0 : extra |= lattice.fXCount << kXCount_DrawImageLatticeShift;
552 : }
553 0 : if (lattice.fYCount >= kCount_DrawImageLatticeMask) {
554 0 : extra |= kCount_DrawImageLatticeMask << kYCount_DrawImageLatticeShift;
555 : } else {
556 0 : extra |= lattice.fYCount << kYCount_DrawImageLatticeShift;
557 : }
558 :
559 0 : SkPipeWriter writer(this);
560 0 : writer.write32(pack_verb(SkPipeVerb::kDrawImageLattice, extra));
561 0 : writer.writeImage(image);
562 0 : if (lattice.fXCount >= kCount_DrawImageLatticeMask) {
563 0 : writer.write32(lattice.fXCount);
564 : }
565 0 : if (lattice.fYCount >= kCount_DrawImageLatticeMask) {
566 0 : writer.write32(lattice.fYCount);
567 : }
568 : // Often these divs will be small (8 or 16 bits). Consider sniffing that and writing a flag
569 : // so we can store them smaller.
570 0 : writer.write(lattice.fXDivs, lattice.fXCount * sizeof(int32_t));
571 0 : writer.write(lattice.fYDivs, lattice.fYCount * sizeof(int32_t));
572 0 : if (lattice.fFlags) {
573 0 : int32_t count = (lattice.fXCount + 1) * (lattice.fYCount + 1);
574 0 : SkASSERT(count > 0);
575 0 : write_pad(&writer, lattice.fFlags, count);
576 : }
577 0 : SkASSERT(lattice.fBounds);
578 0 : writer.write(&lattice.fBounds, sizeof(*lattice.fBounds));
579 0 : writer.write(&dst, sizeof(dst));
580 0 : if (paint) {
581 0 : write_paint(writer, *paint, kImage_PaintUsage);
582 : }
583 0 : }
584 :
585 : ///////////////////////////////////////////////////////////////////////////////////////////////////
586 :
587 0 : void SkPipeCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
588 : const SkPaint& paint) {
589 0 : SkASSERT(byteLength);
590 :
591 0 : bool compact = fits_in(byteLength, 24);
592 :
593 0 : SkPipeWriter writer(this);
594 0 : writer.write32(pack_verb(SkPipeVerb::kDrawText, compact ? (unsigned)byteLength : 0));
595 0 : if (!compact) {
596 0 : writer.write32(SkToU32(byteLength));
597 : }
598 0 : write_pad(&writer, text, byteLength);
599 0 : writer.writeScalar(x);
600 0 : writer.writeScalar(y);
601 0 : write_paint(writer, paint, kText_PaintUsage);
602 0 : }
603 :
604 0 : void SkPipeCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
605 : const SkPaint& paint) {
606 0 : SkASSERT(byteLength);
607 :
608 0 : bool compact = fits_in(byteLength, 24);
609 :
610 0 : SkPipeWriter writer(this);
611 0 : writer.write32(pack_verb(SkPipeVerb::kDrawPosText, compact ? (unsigned)byteLength : 0));
612 0 : if (!compact) {
613 0 : writer.write32(SkToU32(byteLength));
614 : }
615 0 : write_pad(&writer, text, byteLength);
616 0 : writer.writePointArray(pos, paint.countText(text, byteLength));
617 0 : write_paint(writer, paint, kText_PaintUsage);
618 0 : }
619 :
620 0 : void SkPipeCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
621 : SkScalar constY, const SkPaint& paint) {
622 0 : SkASSERT(byteLength);
623 :
624 0 : bool compact = fits_in(byteLength, 24);
625 :
626 0 : SkPipeWriter writer(this);
627 0 : writer.write32(pack_verb(SkPipeVerb::kDrawPosTextH, compact ? (unsigned)byteLength : 0));
628 0 : if (!compact) {
629 0 : writer.write32(SkToU32(byteLength));
630 : }
631 0 : write_pad(&writer, text, byteLength);
632 0 : writer.writeScalarArray(xpos, paint.countText(text, byteLength));
633 0 : writer.writeScalar(constY);
634 0 : write_paint(writer, paint, kText_PaintUsage);
635 0 : }
636 :
637 0 : void SkPipeCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
638 : const SkMatrix* matrix, const SkPaint& paint) {
639 0 : SkASSERT(byteLength > 0);
640 :
641 0 : unsigned extra = 0;
642 0 : if (byteLength <= kTextLength_DrawTextOnPathMask) {
643 0 : extra |= byteLength;
644 : } // else we will write the length after the packedverb
645 0 : SkMatrix::TypeMask tm = matrix ? matrix->getType() : SkMatrix::kIdentity_Mask;
646 0 : extra |= (unsigned)tm << kMatrixType_DrawTextOnPathShift;
647 :
648 0 : SkPipeWriter writer(this);
649 0 : writer.write32(pack_verb(SkPipeVerb::kDrawTextOnPath, extra));
650 0 : if (byteLength > kTextLength_DrawTextOnPathMask) {
651 0 : writer.write32(byteLength);
652 : }
653 0 : write_pad(&writer, text, byteLength);
654 0 : writer.writePath(path);
655 0 : if (matrix) {
656 0 : write_sparse_matrix(&writer, *matrix);
657 : }
658 0 : write_paint(writer, paint, kText_PaintUsage);
659 0 : }
660 :
661 0 : void SkPipeCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
662 : const SkRect* cull, const SkPaint& paint) {
663 0 : SkASSERT(byteLength);
664 :
665 0 : bool compact = fits_in(byteLength, 23);
666 0 : unsigned extra = compact ? (byteLength << 1) : 0;
667 0 : if (cull) {
668 0 : extra |= 1;
669 : }
670 :
671 0 : SkPipeWriter writer(this);
672 0 : writer.write32(pack_verb(SkPipeVerb::kDrawTextRSXform, extra));
673 0 : if (!compact) {
674 0 : writer.write32(SkToU32(byteLength));
675 : }
676 0 : write_pad(&writer, text, byteLength);
677 :
678 0 : int count = paint.countText(text, byteLength);
679 0 : writer.write32(count); // maybe we can/should store this in extra as well?
680 0 : writer.write(xform, count * sizeof(SkRSXform));
681 0 : if (cull) {
682 0 : writer.writeRect(*cull);
683 : }
684 0 : write_paint(writer, paint, kText_PaintUsage);
685 0 : }
686 :
687 0 : void SkPipeCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
688 : const SkPaint &paint) {
689 0 : SkPipeWriter writer(this);
690 0 : writer.write32(pack_verb(SkPipeVerb::kDrawTextBlob, 0));
691 0 : blob->flatten(writer);
692 0 : writer.writeScalar(x);
693 0 : writer.writeScalar(y);
694 0 : write_paint(writer, paint, kTextBlob_PaintUsage);
695 0 : }
696 :
697 0 : void SkPipeCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
698 : const SkPaint* paint) {
699 0 : unsigned extra = fDeduper->findOrDefinePicture(const_cast<SkPicture*>(picture));
700 0 : if (matrix) {
701 0 : extra |= kHasMatrix_DrawPictureExtra;
702 : }
703 0 : if (paint) {
704 0 : extra |= kHasPaint_DrawPictureExtra;
705 : }
706 0 : SkPipeWriter writer(this);
707 0 : writer.write32(pack_verb(SkPipeVerb::kDrawPicture, extra));
708 0 : if (matrix) {
709 0 : writer.writeMatrix(*matrix);
710 : }
711 0 : if (paint) {
712 0 : write_paint(writer, *paint, kSaveLayer_PaintUsage);
713 : }
714 0 : }
715 :
716 0 : void SkPipeCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
717 0 : size_t size = region.writeToMemory(nullptr);
718 0 : unsigned extra = 0;
719 0 : if (fits_in(size, 24)) {
720 0 : extra = SkToUInt(size);
721 : }
722 :
723 0 : SkPipeWriter writer(this);
724 0 : writer.write32(pack_verb(SkPipeVerb::kDrawRegion, extra));
725 0 : if (0 == extra) {
726 0 : writer.write32(size);
727 : }
728 0 : SkAutoSMalloc<2048> storage(size);
729 0 : region.writeToMemory(storage.get());
730 0 : write_pad(&writer, storage.get(), size);
731 0 : write_paint(writer, paint, kGeometry_PaintUsage);
732 0 : }
733 :
734 0 : void SkPipeCanvas::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode bmode,
735 : const SkPaint& paint) {
736 0 : unsigned extra = static_cast<unsigned>(bmode);
737 :
738 0 : SkPipeWriter writer(this);
739 0 : writer.write32(pack_verb(SkPipeVerb::kDrawVertices, extra));
740 : // TODO: dedup vertices?
741 0 : writer.writeDataAsByteArray(vertices->encode().get());
742 0 : write_paint(writer, paint, kVertices_PaintUsage);
743 0 : }
744 :
745 0 : void SkPipeCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
746 : const SkPoint texCoords[4], SkBlendMode bmode,
747 : const SkPaint& paint) {
748 0 : SkPipeWriter writer(this);
749 0 : unsigned extra = 0;
750 0 : SkASSERT(0 == ((int)bmode & ~kModeEnum_DrawPatchExtraMask));
751 0 : extra = (unsigned)bmode;
752 0 : if (colors) {
753 0 : extra |= kHasColors_DrawPatchExtraMask;
754 : }
755 0 : if (texCoords) {
756 0 : extra |= kHasTexture_DrawPatchExtraMask;
757 : }
758 0 : writer.write32(pack_verb(SkPipeVerb::kDrawPatch, extra));
759 0 : writer.write(cubics, sizeof(SkPoint) * 12);
760 0 : if (colors) {
761 0 : writer.write(colors, sizeof(SkColor) * 4);
762 : }
763 0 : if (texCoords) {
764 0 : writer.write(texCoords, sizeof(SkPoint) * 4);
765 : }
766 0 : write_paint(writer, paint, kGeometry_PaintUsage);
767 0 : }
768 :
769 0 : void SkPipeCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* data) {
770 0 : const size_t len = strlen(key) + 1; // must write the trailing 0
771 0 : bool compact = fits_in(len, 23);
772 0 : uint32_t extra = compact ? (unsigned)len : 0;
773 0 : extra <<= 1; // make room for has_data_sentinel
774 0 : if (data) {
775 0 : extra |= 1;
776 : }
777 :
778 0 : fStream->write32(pack_verb(SkPipeVerb::kDrawAnnotation, extra));
779 0 : fStream->write(&rect, sizeof(SkRect));
780 0 : if (!compact) {
781 0 : fStream->write32(SkToU32(len));
782 : }
783 0 : write_pad(fStream, key, len);
784 0 : if (data) {
785 0 : fStream->write32(SkToU32(data->size()));
786 0 : write_pad(fStream, data->data(), data->size());
787 : }
788 0 : }
789 :
790 : ///////////////////////////////////////////////////////////////////////////////////////////////////
791 :
792 0 : class A8Serializer : public SkPixelSerializer {
793 : protected:
794 0 : bool onUseEncodedData(const void* data, size_t len) {
795 0 : return true;
796 : }
797 :
798 0 : SkData* onEncode(const SkPixmap& pmap) {
799 0 : if (kAlpha_8_SkColorType == pmap.colorType()) {
800 0 : SkDynamicMemoryWStream stream;
801 0 : stream.write("skiaimgf", 8);
802 0 : stream.write32(pmap.width());
803 0 : stream.write32(pmap.height());
804 0 : stream.write16(pmap.colorType());
805 0 : stream.write16(pmap.alphaType());
806 0 : stream.write32(0); // no colorspace for now
807 0 : for (int y = 0; y < pmap.height(); ++y) {
808 0 : stream.write(pmap.addr8(0, y), pmap.width());
809 : }
810 0 : return stream.detachAsData().release();
811 : }
812 0 : return nullptr;
813 : }
814 : };
815 :
816 0 : static sk_sp<SkData> default_image_serializer(SkImage* image) {
817 0 : A8Serializer serial;
818 0 : sk_sp<SkData> data(image->encode(&serial));
819 0 : if (!data) {
820 0 : data.reset(image->encode());
821 : }
822 0 : return data;
823 : }
824 :
825 : static bool show_deduper_traffic = false;
826 :
827 0 : int SkPipeDeduper::findOrDefineImage(SkImage* image) {
828 0 : int index = fImages.find(image->uniqueID());
829 0 : SkASSERT(index >= 0);
830 0 : if (index) {
831 0 : if (show_deduper_traffic) {
832 0 : SkDebugf(" reuseImage(%d)\n", index - 1);
833 : }
834 0 : return index;
835 : }
836 :
837 0 : sk_sp<SkData> data = fIMSerializer ? fIMSerializer->serialize(image)
838 0 : : default_image_serializer(image);
839 0 : if (data) {
840 0 : index = fImages.add(image->uniqueID());
841 0 : SkASSERT(index > 0);
842 0 : SkASSERT(fits_in(index, 24));
843 0 : fStream->write32(pack_verb(SkPipeVerb::kDefineImage, index));
844 :
845 0 : uint32_t len = SkToU32(data->size());
846 0 : fStream->write32(SkAlign4(len));
847 0 : write_pad(fStream, data->data(), len);
848 :
849 0 : if (show_deduper_traffic) {
850 0 : int size = image->width() * image->height() << 2;
851 0 : SkDebugf(" defineImage(%d) %d -> %d\n", index - 1, size, len);
852 : }
853 0 : return index;
854 : }
855 0 : SkDebugf("+++ failed to encode image [%d %d]\n", image->width(), image->height());
856 0 : return 0; // failed to encode
857 : }
858 :
859 0 : int SkPipeDeduper::findOrDefinePicture(SkPicture* picture) {
860 0 : int index = fPictures.find(picture->uniqueID());
861 0 : SkASSERT(index >= 0);
862 0 : if (index) {
863 0 : if (show_deduper_traffic) {
864 0 : SkDebugf(" reusePicture(%d)\n", index - 1);
865 : }
866 0 : return index;
867 : }
868 :
869 0 : size_t prevWritten = fStream->bytesWritten();
870 0 : unsigned extra = 0; // 0 means we're defining a new picture, non-zero means undef_index + 1
871 0 : fStream->write32(pack_verb(SkPipeVerb::kDefinePicture, extra));
872 0 : const SkRect cull = picture->cullRect();
873 0 : fStream->write(&cull, sizeof(cull));
874 0 : picture->playback(fPipeCanvas);
875 : // call fPictures.add *after* we're written the picture, so that any nested pictures will have
876 : // already been defined, and we get the "last" index value.
877 0 : index = fPictures.add(picture->uniqueID());
878 0 : ASSERT_FITS_IN(index, kObjectDefinitionBits);
879 0 : fStream->write32(pack_verb(SkPipeVerb::kEndPicture, index));
880 :
881 0 : if (show_deduper_traffic) {
882 0 : SkDebugf(" definePicture(%d) %d\n",
883 0 : index - 1, SkToU32(fStream->bytesWritten() - prevWritten));
884 : }
885 0 : return index;
886 : }
887 :
888 0 : static sk_sp<SkData> encode(SkTypeface* tf) {
889 0 : SkDynamicMemoryWStream stream;
890 0 : tf->serialize(&stream);
891 0 : return sk_sp<SkData>(stream.detachAsData());
892 : }
893 :
894 0 : int SkPipeDeduper::findOrDefineTypeface(SkTypeface* typeface) {
895 0 : if (!typeface) {
896 0 : return 0; // default
897 : }
898 :
899 0 : int index = fTypefaces.find(typeface->uniqueID());
900 0 : SkASSERT(index >= 0);
901 0 : if (index) {
902 0 : if (show_deduper_traffic) {
903 0 : SkDebugf(" reuseTypeface(%d)\n", index - 1);
904 : }
905 0 : return index;
906 : }
907 :
908 0 : sk_sp<SkData> data = fTFSerializer ? fTFSerializer->serialize(typeface) : encode(typeface);
909 0 : if (data) {
910 0 : index = fTypefaces.add(typeface->uniqueID());
911 0 : SkASSERT(index > 0);
912 0 : SkASSERT(fits_in(index, 24));
913 0 : fStream->write32(pack_verb(SkPipeVerb::kDefineTypeface, index));
914 :
915 0 : uint32_t len = SkToU32(data->size());
916 0 : fStream->write32(SkAlign4(len));
917 0 : write_pad(fStream, data->data(), len);
918 :
919 0 : if (show_deduper_traffic) {
920 0 : SkDebugf(" defineTypeface(%d) %d\n", index - 1, len);
921 : }
922 0 : return index;
923 : }
924 0 : SkDebugf("+++ failed to encode typeface %d\n", typeface->uniqueID());
925 0 : return 0; // failed to encode
926 : }
927 :
928 0 : int SkPipeDeduper::findOrDefineFactory(SkFlattenable* flattenable) {
929 0 : if (!flattenable) {
930 0 : return 0;
931 : }
932 :
933 0 : int index = fFactories.find(flattenable->getFactory());
934 0 : SkASSERT(index >= 0);
935 0 : if (index) {
936 0 : if (show_deduper_traffic) {
937 0 : SkDebugf(" reuseFactory(%d)\n", index - 1);
938 : }
939 0 : return index;
940 : }
941 :
942 0 : index = fFactories.add(flattenable->getFactory());
943 0 : ASSERT_FITS_IN(index, kIndex_DefineFactoryExtraBits);
944 0 : const char* name = flattenable->getTypeName();
945 0 : size_t len = strlen(name);
946 0 : ASSERT_FITS_IN(len, kNameLength_DefineFactoryExtraBits);
947 0 : unsigned extra = (index << kNameLength_DefineFactoryExtraBits) | len;
948 0 : size_t prevWritten = fStream->bytesWritten();
949 0 : fStream->write32(pack_verb(SkPipeVerb::kDefineFactory, extra));
950 0 : write_pad(fStream, name, len + 1);
951 : if (false) {
952 : SkDebugf(" defineFactory(%d) %d %s\n",
953 : index - 1, SkToU32(fStream->bytesWritten() - prevWritten), name);
954 : }
955 0 : return index;
956 : }
957 :
958 : ///////////////////////////////////////////////////////////////////////////////////////////////////
959 : #include "SkPipe.h"
960 :
961 0 : class SkPipeSerializer::Impl {
962 : public:
963 : SkPipeDeduper fDeduper;
964 : std::unique_ptr<SkPipeCanvas> fCanvas;
965 : };
966 :
967 0 : SkPipeSerializer::SkPipeSerializer() : fImpl(new Impl) {}
968 :
969 0 : SkPipeSerializer::~SkPipeSerializer() {
970 0 : if (fImpl->fCanvas) {
971 0 : this->endWrite();
972 : }
973 0 : }
974 :
975 0 : void SkPipeSerializer::setTypefaceSerializer(SkTypefaceSerializer* tfs) {
976 0 : fImpl->fDeduper.setTypefaceSerializer(tfs);
977 0 : }
978 :
979 0 : void SkPipeSerializer::setImageSerializer(SkImageSerializer* ims) {
980 0 : fImpl->fDeduper.setImageSerializer(ims);
981 0 : }
982 :
983 0 : void SkPipeSerializer::resetCache() {
984 0 : fImpl->fDeduper.resetCaches();
985 0 : }
986 :
987 0 : sk_sp<SkData> SkPipeSerializer::writeImage(SkImage* image) {
988 0 : SkDynamicMemoryWStream stream;
989 0 : this->writeImage(image, &stream);
990 0 : return stream.detachAsData();
991 : }
992 :
993 0 : sk_sp<SkData> SkPipeSerializer::writePicture(SkPicture* picture) {
994 0 : SkDynamicMemoryWStream stream;
995 0 : this->writePicture(picture, &stream);
996 0 : return stream.detachAsData();
997 : }
998 :
999 0 : void SkPipeSerializer::writePicture(SkPicture* picture, SkWStream* stream) {
1000 0 : int index = fImpl->fDeduper.findPicture(picture);
1001 0 : if (0 == index) {
1002 : // Try to define the picture
1003 0 : this->beginWrite(picture->cullRect(), stream);
1004 0 : index = fImpl->fDeduper.findOrDefinePicture(picture);
1005 0 : this->endWrite();
1006 : }
1007 0 : stream->write32(pack_verb(SkPipeVerb::kWritePicture, index));
1008 0 : }
1009 :
1010 0 : void SkPipeSerializer::writeImage(SkImage* image, SkWStream* stream) {
1011 0 : int index = fImpl->fDeduper.findImage(image);
1012 0 : if (0 == index) {
1013 : // Try to define the image
1014 0 : fImpl->fDeduper.setStream(stream);
1015 0 : index = fImpl->fDeduper.findOrDefineImage(image);
1016 : }
1017 0 : stream->write32(pack_verb(SkPipeVerb::kWriteImage, index));
1018 0 : }
1019 :
1020 0 : SkCanvas* SkPipeSerializer::beginWrite(const SkRect& cull, SkWStream* stream) {
1021 0 : SkASSERT(nullptr == fImpl->fCanvas);
1022 0 : fImpl->fCanvas.reset(new SkPipeCanvas(cull, &fImpl->fDeduper, stream));
1023 0 : fImpl->fDeduper.setStream(stream);
1024 0 : fImpl->fDeduper.setCanvas(fImpl->fCanvas.get());
1025 0 : return fImpl->fCanvas.get();
1026 : }
1027 :
1028 0 : void SkPipeSerializer::endWrite() {
1029 0 : fImpl->fCanvas->restoreToCount(1);
1030 0 : fImpl->fCanvas.reset(nullptr);
1031 0 : fImpl->fDeduper.setCanvas(nullptr);
1032 0 : }
|