d2d75fe915d404f625680310091e542575cf98ca
[platform/upstream/libSkiaSharp.git] / src / utils / SkDeferredCanvas.cpp
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 "SkDeferredCanvas.h"
9 #include "SkDrawable.h"
10 #include "SkPath.h"
11 #include "SkRRect.h"
12 #include "SkSurface.h"
13 #include "SkTextBlob.h"
14
15 bool SkDeferredCanvas::Rec::isConcat(SkMatrix* m) const {
16     switch (fType) {
17         case kTrans_Type:
18             m->setTranslate(fData.fTranslate.x(), fData.fTranslate.y());
19             return true;
20         case kScaleTrans_Type:
21             m->setScaleTranslate(fData.fScaleTrans.fScale.x(),
22                                  fData.fScaleTrans.fScale.y(),
23                                  fData.fScaleTrans.fTrans.x(),
24                                  fData.fScaleTrans.fTrans.y());
25             return true;
26         default:
27             break;
28     }
29     return false;
30 }
31
32 void SkDeferredCanvas::Rec::setConcat(const SkMatrix& m) {
33     SkASSERT(m.getType() <= (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask));
34
35     if (m.getType() <= SkMatrix::kTranslate_Mask) {
36         fType = kTrans_Type;
37         fData.fTranslate.set(m.getTranslateX(), m.getTranslateY());
38     } else {
39         fType = kScaleTrans_Type;
40         fData.fScaleTrans.fScale.set(m.getScaleX(), m.getScaleY());
41         fData.fScaleTrans.fTrans.set(m.getTranslateX(), m.getTranslateY());
42     }
43 }
44
45 ///////////////////////////////////////////////////////////////////////////////////////////////////
46
47 SkDeferredCanvas::SkDeferredCanvas(SkCanvas* canvas)
48     : SkCanvas({0,0,1,1}, SkCanvas::kConservativeRasterClip_InitFlag) {
49     this->reset(canvas);
50 }
51
52 SkDeferredCanvas::~SkDeferredCanvas() {}
53
54 void SkDeferredCanvas::reset(SkCanvas* canvas) {
55     if (fCanvas) {
56         this->flush();
57         fCanvas = nullptr;
58     }
59     fRecs.reset();
60     if (canvas) {
61         this->resetForNextPicture(SkIRect::MakeSize(canvas->getBaseLayerSize()));
62         fCanvas = canvas;
63     }
64 }
65
66 void SkDeferredCanvas::push_save() {
67     Rec* r = fRecs.append();
68     r->fType = kSave_Type;
69 }
70
71 void SkDeferredCanvas::push_cliprect(const SkRect& bounds) {
72     int index = fRecs.count() - 1;
73     if (index >= 0 && fRecs[index].fType == kClipRect_Type) {
74         if (!fRecs[index].fData.fBounds.intersect(bounds)) {
75             fRecs[index].fData.fBounds.setEmpty();
76         }
77     } else {
78         Rec* r = fRecs.append();
79         r->fType = kClipRect_Type;
80         r->fData.fBounds = bounds;
81     }
82 }
83
84 bool SkDeferredCanvas::push_concat(const SkMatrix& mat) {
85     if (mat.getType() > (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask)) {
86         return false;
87     }
88     // At the moment, we don't know which ops can scale and which can also flip, so
89     // we reject negative scales for now
90     if (mat.getScaleX() < 0 || mat.getScaleY() < 0) {
91         return false;
92     }
93
94     int index = fRecs.count() - 1;
95     SkMatrix m;
96     if (index >= 0 && fRecs[index].isConcat(&m)) {
97         m.preConcat(mat);
98         fRecs[index].setConcat(m);
99     } else {
100         fRecs.append()->setConcat(mat);
101     }
102     return true;
103 }
104
105 void SkDeferredCanvas::emit(const Rec& rec) {
106     switch (rec.fType) {
107         case kSave_Type:
108             fCanvas->save();
109             this->INHERITED::willSave();
110             break;
111         case kClipRect_Type:
112             fCanvas->clipRect(rec.fData.fBounds);
113             this->INHERITED::onClipRect(rec.fData.fBounds,
114                                         kIntersect_Op, kHard_ClipEdgeStyle);
115             break;
116         case kTrans_Type:
117         case kScaleTrans_Type: {
118             SkMatrix mat;
119             rec.getConcat(&mat);
120             fCanvas->concat(mat);
121             this->INHERITED::didConcat(mat);
122         } break;
123     }
124 }
125
126 void SkDeferredCanvas::flush_le(int index) {
127     SkASSERT(index >= -1 && index < fRecs.count());
128
129     int count = index + 1;
130     for (int i = 0; i < count; ++i) {
131         this->emit(fRecs[i]);
132     }
133     fRecs.remove(0, count);
134 }
135
136 void SkDeferredCanvas::flush_all() {
137     this->flush_le(fRecs.count() - 1);
138 }
139
140 void SkDeferredCanvas::flush_before_saves() {
141     int i;
142     for (i = fRecs.count() - 1; i >= 0; --i) {
143         if (kSave_Type != fRecs[i].fType) {
144             break;
145         }
146     }
147     this->flush_le(i);
148 }
149
150 enum Flags {
151     kNoTranslate_Flag   = 1 << 0,
152     kNoClip_Flag        = 1 << 1,
153     kNoCull_Flag        = 1 << 2,
154     kNoScale_Flag       = 1 << 3,
155 };
156
157 void SkDeferredCanvas::flush_check(SkRect* bounds, const SkPaint* paint, unsigned flags) {
158     if (paint) {
159         if (paint->getShader() || paint->getImageFilter()) {
160             flags |= kNoTranslate_Flag | kNoScale_Flag;
161         }
162         // TODO: replace these with code to enlarge the bounds conservatively?
163         if (paint->getStyle() != SkPaint::kFill_Style || paint->getMaskFilter() ||
164             paint->getImageFilter() || paint->getPathEffect())
165         {
166             flags |= kNoCull_Flag | kNoScale_Flag | kNoClip_Flag;
167         }
168         if (paint->getLooper()) {
169             // to be conservative, we disable both, since embedded layers could have shaders
170             // or strokes etc.
171             flags |= kNoTranslate_Flag | kNoCull_Flag | kNoScale_Flag;
172         }
173     }
174     bool canClip = !(flags & kNoClip_Flag);
175     bool canTranslate = !(flags & kNoTranslate_Flag);
176     bool canCull = !(flags & kNoCull_Flag);
177     bool canScale = !(flags & kNoScale_Flag);
178
179     int i;
180     for (i = fRecs.count() - 1; i >= 0; --i) {
181         const Rec& rec = fRecs[i];
182         switch (rec.fType) {
183             case kSave_Type:
184                 // continue to the next rec
185                 break;
186             case kClipRect_Type:
187                 if (!canCull) {
188                     goto STOP;
189                 }
190                 if (canClip) {
191                     if (!bounds->intersect(rec.fData.fBounds)) {
192                         bounds->setEmpty();
193                         return;
194                     }
195                     // continue to the next rec
196                 } else {
197                     if (!rec.fData.fBounds.contains(*bounds)) {
198                         goto STOP;
199                     }
200                     // continue to the next rec
201                 }
202                 break;
203             case kTrans_Type:
204                 if (canTranslate) {
205                     bounds->offset(rec.fData.fTranslate.x(), rec.fData.fTranslate.y());
206                     // continue to the next rec
207                 } else {
208                     goto STOP;
209                 }
210                 break;
211             case kScaleTrans_Type:
212                 if (canScale) {
213                     SkMatrix m;
214                     rec.getConcat(&m);
215                     m.mapRectScaleTranslate(bounds, *bounds);
216                 } else {
217                     goto STOP;
218                 }
219                 break;
220         }
221     }
222 STOP:
223     this->flush_le(i);
224 }
225
226 void SkDeferredCanvas::flush_translate(SkScalar* x, SkScalar* y, const SkRect& bounds,
227                                        const SkPaint* paint) {
228     SkRect tmp = bounds;
229     this->flush_check(&tmp, paint, kNoClip_Flag | kNoScale_Flag);
230     *x += tmp.x() - bounds.x();
231     *y += tmp.y() - bounds.y();
232 }
233
234 void SkDeferredCanvas::flush_translate(SkScalar* x, SkScalar* y, const SkPaint& paint) {
235     SkRect tmp = SkRect::MakeXYWH(*x, *y, 1, 1);
236     this->flush_check(&tmp, &paint, kNoClip_Flag | kNoCull_Flag | kNoScale_Flag);
237     *x = tmp.x();
238     *y = tmp.y();
239 }
240
241 ///////////////////////////////////////////////////////////////////////////////////////////////////
242
243 void SkDeferredCanvas::willSave() {
244     this->push_save();
245 }
246
247 SkCanvas::SaveLayerStrategy SkDeferredCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
248     this->flush_all();
249     fCanvas->saveLayer(rec);
250     this->INHERITED::getSaveLayerStrategy(rec);
251     // No need for a layer.
252     return kNoLayer_SaveLayerStrategy;
253 }
254
255 void SkDeferredCanvas::willRestore() {
256     for (int i = fRecs.count() - 1; i >= 0; --i) {
257         if (kSave_Type == fRecs[i].fType) {
258             fRecs.setCount(i);  // pop off everything here and later
259             return;
260         }
261     }
262     for (int i = 0; i < fRecs.count(); ++i) {
263         SkASSERT(kSave_Type != fRecs[i].fType);
264     }
265     fRecs.setCount(0);
266     fCanvas->restore();
267     this->INHERITED::willRestore();
268 }
269
270 void SkDeferredCanvas::didConcat(const SkMatrix& matrix) {
271     if (matrix.isIdentity()) {
272         return;
273     }
274     if (!this->push_concat(matrix)) {
275         this->flush_all();
276         fCanvas->concat(matrix);
277         this->INHERITED::didConcat(matrix);
278     }
279 }
280
281 void SkDeferredCanvas::didSetMatrix(const SkMatrix& matrix) {
282     this->flush_all();
283     fCanvas->setMatrix(matrix);
284     this->INHERITED::didSetMatrix(matrix);
285 }
286
287 void SkDeferredCanvas::onClipRect(const SkRect& rect, ClipOp op, ClipEdgeStyle edgeStyle) {
288     if (kIntersect_Op == op) {
289         this->push_cliprect(rect);
290     } else {
291         this->flush_all();
292         fCanvas->clipRect(rect, op, kSoft_ClipEdgeStyle == edgeStyle);
293         this->INHERITED::onClipRect(rect, op, edgeStyle);
294     }
295 }
296
297 void SkDeferredCanvas::onClipRRect(const SkRRect& rrect, ClipOp op, ClipEdgeStyle edgeStyle) {
298     this->flush_all();
299     fCanvas->clipRRect(rrect, op, kSoft_ClipEdgeStyle == edgeStyle);
300     this->INHERITED::onClipRRect(rrect, op, edgeStyle);
301 }
302
303 void SkDeferredCanvas::onClipPath(const SkPath& path, ClipOp op, ClipEdgeStyle edgeStyle) {
304     this->flush_all();
305     fCanvas->clipPath(path, op, kSoft_ClipEdgeStyle == edgeStyle);
306     this->INHERITED::onClipPath(path, op, edgeStyle);
307 }
308
309 void SkDeferredCanvas::onClipRegion(const SkRegion& deviceRgn, ClipOp op) {
310     this->flush_all();
311     fCanvas->clipRegion(deviceRgn, op);
312     this->INHERITED::onClipRegion(deviceRgn, op);
313 }
314
315 void SkDeferredCanvas::onDrawPaint(const SkPaint& paint) {
316     // TODO: Can we turn this into drawRect?
317     this->flush_all();
318     fCanvas->drawPaint(paint);
319 }
320
321 void SkDeferredCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
322                                 const SkPaint& paint) {
323     this->flush_all();
324     fCanvas->drawPoints(mode, count, pts, paint);
325 }
326
327 void SkDeferredCanvas::onDrawRect(const SkRect& rect, const SkPaint& paint) {
328     SkRect modRect = rect;
329     this->flush_check(&modRect, &paint);
330     fCanvas->drawRect(modRect, paint);
331 }
332
333 void SkDeferredCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
334     this->flush_all();  // can we do better?
335     fCanvas->drawRegion(region, paint);
336 }
337
338 void SkDeferredCanvas::onDrawOval(const SkRect& rect, const SkPaint& paint) {
339     SkRect modRect = rect;
340     this->flush_check(&modRect, &paint, kNoClip_Flag);
341     fCanvas->drawOval(modRect, paint);
342 }
343
344 void SkDeferredCanvas::onDrawArc(const SkRect& rect, SkScalar startAngle, SkScalar sweepAngle,
345                                  bool useCenter, const SkPaint& paint) {
346     SkRect modRect = rect;
347     this->flush_check(&modRect, &paint, kNoClip_Flag);
348     fCanvas->drawArc(modRect, startAngle, sweepAngle, useCenter, paint);
349 }
350
351 static SkRRect make_offset(const SkRRect& src, SkScalar dx, SkScalar dy) {
352     SkRRect dst = src;
353     dst.offset(dx, dy);
354     return dst;
355 }
356
357 void SkDeferredCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
358     SkRect modRect = rrect.getBounds();
359     this->flush_check(&modRect, &paint, kNoClip_Flag);
360     fCanvas->drawRRect(make_offset(rrect,
361                                    modRect.x() - rrect.getBounds().x(),
362                                    modRect.y() - rrect.getBounds().y()), paint);
363 }
364
365 void SkDeferredCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
366     this->flush_all();
367     fCanvas->drawDRRect(outer, inner, paint);
368 }
369
370 void SkDeferredCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
371     if (path.isInverseFillType()) {
372         this->flush_before_saves();
373     } else {
374         SkRect modRect = path.getBounds();
375         this->flush_check(&modRect, &paint, kNoClip_Flag | kNoTranslate_Flag | kNoScale_Flag);
376     }
377     fCanvas->drawPath(path, paint);
378 }
379
380 void SkDeferredCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y,
381                                 const SkPaint* paint) {
382     const SkScalar w = SkIntToScalar(bitmap.width());
383     const SkScalar h = SkIntToScalar(bitmap.height());
384     SkRect bounds = SkRect::MakeXYWH(x, y, w, h);
385     this->flush_check(&bounds, paint, kNoClip_Flag);
386     if (bounds.width() == w && bounds.height() == h) {
387         fCanvas->drawBitmap(bitmap, bounds.x(), bounds.y(), paint);
388     } else {
389         fCanvas->drawBitmapRect(bitmap, bounds, paint);
390     }
391 }
392
393 void SkDeferredCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
394                                     const SkPaint* paint, SrcRectConstraint constraint) {
395     SkRect modRect = dst;
396     this->flush_check(&modRect, paint, kNoClip_Flag);
397     fCanvas->legacy_drawBitmapRect(bitmap, src, modRect, paint, constraint);
398 }
399
400 void SkDeferredCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
401                                     const SkRect& dst, const SkPaint* paint) {
402     SkRect modRect = dst;
403     this->flush_check(&modRect, paint, kNoClip_Flag);
404     fCanvas->drawBitmapNine(bitmap, center, modRect, paint);
405 }
406
407 void SkDeferredCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
408                                            const SkRect& dst, const SkPaint* paint) {
409     SkRect modRect = dst;
410     this->flush_check(&modRect, paint, kNoClip_Flag);
411     fCanvas->drawBitmapLattice(bitmap, lattice, modRect, paint);
412 }
413
414 void SkDeferredCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center,
415                                        const SkRect& dst, const SkPaint* paint) {
416     SkRect modRect = dst;
417     this->flush_check(&modRect, paint, kNoClip_Flag);
418     fCanvas->drawImageNine(image, center, modRect, paint);
419 }
420
421 void SkDeferredCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y,
422                                    const SkPaint* paint) {
423     const SkScalar w = SkIntToScalar(image->width());
424     const SkScalar h = SkIntToScalar(image->height());
425     SkRect bounds = SkRect::MakeXYWH(x, y, w, h);
426     this->flush_check(&bounds, paint, kNoClip_Flag);
427     if (bounds.width() == w && bounds.height() == h) {
428         fCanvas->drawImage(image, bounds.x(), bounds.y(), paint);
429     } else {
430         fCanvas->drawImageRect(image, bounds, paint);
431     }
432 }
433
434 void SkDeferredCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
435                                    const SkPaint* paint, SrcRectConstraint constraint) {
436     SkRect modRect = dst;
437     this->flush_check(&modRect, paint, kNoClip_Flag);
438     fCanvas->legacy_drawImageRect(image, src, modRect, paint, constraint);
439 }
440
441 void SkDeferredCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice,
442                                           const SkRect& dst, const SkPaint* paint) {
443     SkRect modRect = dst;
444     this->flush_check(&modRect, paint, kNoClip_Flag);
445     fCanvas->drawImageLattice(image, lattice, modRect, paint);
446 }
447
448 void SkDeferredCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
449                                   const SkPaint& paint) {
450     this->flush_translate(&x, &y, paint);
451     fCanvas->drawText(text, byteLength, x, y, paint);
452 }
453
454 void SkDeferredCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
455                                  const SkPaint& paint) {
456     this->flush_before_saves();
457     fCanvas->drawPosText(text, byteLength, pos, paint);
458 }
459
460 void SkDeferredCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
461                                   SkScalar constY, const SkPaint& paint) {
462     this->flush_before_saves();
463     fCanvas->drawPosTextH(text, byteLength, xpos, constY, paint);
464 }
465
466 void SkDeferredCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
467                                     const SkMatrix* matrix, const SkPaint& paint) {
468     this->flush_before_saves();
469     fCanvas->drawTextOnPath(text, byteLength, path, matrix, paint);
470 }
471
472 void SkDeferredCanvas::onDrawTextRSXform(const void* text, size_t byteLength,
473                                          const SkRSXform xform[], const SkRect* cullRect,
474                                          const SkPaint& paint) {
475     if (cullRect) {
476         SkRect modRect = *cullRect;
477         // only allow culling
478         this->flush_check(&modRect, &paint, kNoClip_Flag | kNoScale_Flag | kNoTranslate_Flag);
479     } else {
480         this->flush_before_saves();
481     }
482     fCanvas->drawTextRSXform(text, byteLength, xform, cullRect, paint);
483 }
484
485 void SkDeferredCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
486                                   const SkPaint &paint) {
487     this->flush_translate(&x, &y, blob->bounds(), &paint);
488     fCanvas->drawTextBlob(blob, x, y, paint);
489 }
490
491 #include "SkPicture.h"
492 #include "SkCanvasPriv.h"
493 void SkDeferredCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
494                                  const SkPaint* paint) {
495 #if 0
496     SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
497     picture->playback(this);
498 #else
499     this->flush_before_saves();
500     fCanvas->drawPicture(picture, matrix, paint);
501 #endif
502 }
503
504 void SkDeferredCanvas::onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) {
505     // TODO: investigate culling and applying concat to the matrix
506 #if 0
507     drawable->draw(this, matrix);
508 #else
509     this->flush_before_saves();
510     fCanvas->drawDrawable(drawable, matrix);
511 #endif
512 }
513
514 void SkDeferredCanvas::onDrawAtlas(const SkImage* image, const SkRSXform xform[],
515                                    const SkRect rects[], const SkColor colors[],
516                                    int count, SkXfermode::Mode mode,
517                                    const SkRect* cull, const SkPaint* paint) {
518     this->flush_before_saves();
519     fCanvas->drawAtlas(image, xform, rects, colors, count, mode, cull, paint);
520 }
521
522 void SkDeferredCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
523                                   const SkPoint vertices[], const SkPoint texs[],
524                                   const SkColor colors[], SkXfermode* xmode,
525                                   const uint16_t indices[], int indexCount,
526                                   const SkPaint& paint) {
527     this->flush_before_saves();
528     fCanvas->drawVertices(vmode, vertexCount, vertices, texs, colors, xmode,
529                            indices, indexCount, paint);
530 }
531
532 void SkDeferredCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
533                                const SkPoint texCoords[4], SkXfermode* xmode,
534                                const SkPaint& paint) {
535     this->flush_before_saves();
536     fCanvas->drawPatch(cubics, colors, texCoords, xmode, paint);
537 }
538
539 void SkDeferredCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* data) {
540     SkRect modRect = rect;
541     this->flush_check(&modRect, nullptr, kNoClip_Flag);
542     fCanvas->drawAnnotation(modRect, key, data);
543 }
544
545 #ifdef SK_SUPPORT_LEGACY_DRAWFILTER
546 SkDrawFilter* SkDeferredCanvas::setDrawFilter(SkDrawFilter* filter) {
547     fCanvas->setDrawFilter(filter);
548     return this->INHERITED::setDrawFilter(filter);
549 }
550 #endif
551
552 ///////////////////////////////////////////////////////////////////////////////////////////////////
553
554 sk_sp<SkSurface> SkDeferredCanvas::onNewSurface(const SkImageInfo& info,
555                                                 const SkSurfaceProps& props) {
556     return fCanvas->makeSurface(info, &props);
557 }
558 SkISize SkDeferredCanvas::getBaseLayerSize() const { return fCanvas->getBaseLayerSize(); }
559 bool SkDeferredCanvas::getClipBounds(SkRect* bounds) const {
560     return fCanvas->getClipBounds(bounds);
561 }
562 bool SkDeferredCanvas::getClipDeviceBounds(SkIRect* bounds) const {
563     return fCanvas->getClipDeviceBounds(bounds);
564 }
565 bool SkDeferredCanvas::isClipEmpty() const { return fCanvas->isClipEmpty(); }
566 bool SkDeferredCanvas::isClipRect() const { return fCanvas->isClipRect(); }
567 bool SkDeferredCanvas::onPeekPixels(SkPixmap* pixmap) { return fCanvas->peekPixels(pixmap); }
568 bool SkDeferredCanvas::onAccessTopLayerPixels(SkPixmap* pixmap) {
569     SkImageInfo info;
570     size_t rowBytes;
571     SkIPoint* origin = nullptr;
572     void* addr = fCanvas->accessTopLayerPixels(&info, &rowBytes, origin);
573     if (addr) {
574         *pixmap = SkPixmap(info, addr, rowBytes);
575         return true;
576     }
577     return false;
578 }
579 SkImageInfo SkDeferredCanvas::onImageInfo() const { return fCanvas->imageInfo(); }
580 bool SkDeferredCanvas::onGetProps(SkSurfaceProps* props) const { return fCanvas->getProps(props); }
581 void SkDeferredCanvas::onFlush() {
582     this->flush_all();
583     return fCanvas->flush();
584 }