• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2013 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 "src/core/SkBitmapDevice.h"
9 
10 #include "include/core/SkAlphaType.h"
11 #include "include/core/SkBlender.h"
12 #include "include/core/SkClipOp.h"
13 #include "include/core/SkColorType.h"
14 #include "include/core/SkImage.h"
15 #include "include/core/SkImageInfo.h"
16 #include "include/core/SkMatrix.h"
17 #include "include/core/SkPaint.h"
18 #include "include/core/SkPath.h"
19 #include "include/core/SkPixmap.h"
20 #include "include/core/SkPoint.h"
21 #include "include/core/SkRRect.h"
22 #include "include/core/SkRSXform.h"
23 #include "include/core/SkRasterHandleAllocator.h"
24 #include "include/core/SkRegion.h"
25 #include "include/core/SkScalar.h"
26 #include "include/core/SkShader.h"
27 #include "include/core/SkSurface.h"
28 #include "include/core/SkSurfaceProps.h"
29 #include "include/core/SkTileMode.h"
30 #include "include/private/base/SkAssert.h"
31 #include "include/private/base/SkTo.h"
32 #include "src/base/SkTLazy.h"
33 #include "src/core/SkDraw.h"
34 #include "src/core/SkImagePriv.h"
35 #include "src/core/SkMatrixPriv.h"
36 #include "src/core/SkRasterClip.h"
37 #include "src/core/SkSpecialImage.h"
38 #include "src/image/SkImage_Base.h"
39 #include "src/text/GlyphRun.h"
40 
41 #include <utility>
42 
43 class SkVertices;
44 
45 struct Bounder {
46     SkRect  fBounds;
47     bool    fHasBounds;
48 
BounderBounder49     Bounder(const SkRect& r, const SkPaint& paint) {
50         if ((fHasBounds = paint.canComputeFastBounds())) {
51             fBounds = paint.computeFastBounds(r, &fBounds);
52         }
53     }
54 
hasBoundsBounder55     bool hasBounds() const { return fHasBounds; }
boundsBounder56     const SkRect* bounds() const { return fHasBounds ? &fBounds : nullptr; }
operator const SkRect*Bounder57     operator const SkRect* () const { return this->bounds(); }
58 };
59 
60 class SkDrawTiler {
61     enum {
62         // 8K is 1 too big, since 8K << supersample == 32768 which is too big for SkFixed
63         kMaxDim = 8192 - 1
64     };
65 
66     SkBitmapDevice* fDevice;
67     SkPixmap        fRootPixmap;
68     SkIRect         fSrcBounds;
69 
70     // Used for tiling and non-tiling
71     SkDraw          fDraw;
72 
73     // fTileMatrix... are only used if fNeedTiling
74     SkTLazy<SkMatrix> fTileMatrix;
75     SkRasterClip      fTileRC;
76     SkIPoint          fOrigin;
77 
78     bool            fDone, fNeedsTiling;
79 
80 public:
NeedsTiling(SkBitmapDevice * dev)81     static bool NeedsTiling(SkBitmapDevice* dev) {
82         return dev->width() > kMaxDim || dev->height() > kMaxDim;
83     }
84 
SkDrawTiler(SkBitmapDevice * dev,const SkRect * bounds)85     SkDrawTiler(SkBitmapDevice* dev, const SkRect* bounds) : fDevice(dev) {
86         fDone = false;
87 
88         // we need fDst to be set, and if we're actually drawing, to dirty the genID
89         if (!dev->accessPixels(&fRootPixmap)) {
90             // NoDrawDevice uses us (why?) so we have to catch this case w/ no pixels
91             fRootPixmap.reset(dev->imageInfo(), nullptr, 0);
92         }
93 
94         // do a quick check, so we don't even have to process "bounds" if there is no need
95         const SkIRect clipR = dev->fRCStack.rc().getBounds();
96         fNeedsTiling = clipR.right() > kMaxDim || clipR.bottom() > kMaxDim;
97         if (fNeedsTiling) {
98             if (bounds) {
99                 // Make sure we round first, and then intersect. We can't rely on promoting the
100                 // clipR to floats (and then intersecting with devBounds) since promoting
101                 // int --> float can make the float larger than the int.
102                 // rounding(out) first runs the risk of clamping if the float is larger an intmax
103                 // but our roundOut() is saturating, which is fine for this use case
104                 //
105                 // e.g. the older version of this code did this:
106                 //    devBounds = mapRect(bounds);
107                 //    if (devBounds.intersect(SkRect::Make(clipR))) {
108                 //        fSrcBounds = devBounds.roundOut();
109                 // The problem being that the promotion of clipR to SkRect was unreliable
110                 //
111                 fSrcBounds = dev->localToDevice().mapRect(*bounds).roundOut();
112                 if (fSrcBounds.intersect(clipR)) {
113                     // Check again, now that we have computed srcbounds.
114                     fNeedsTiling = fSrcBounds.right() > kMaxDim || fSrcBounds.bottom() > kMaxDim;
115                 } else {
116                     fNeedsTiling = false;
117                     fDone = true;
118                 }
119             } else {
120                 fSrcBounds = clipR;
121             }
122         }
123 
124         if (fNeedsTiling) {
125             // fDraw.fDst and fCTM are reset each time in setupTileDraw()
126             fDraw.fRC = &fTileRC;
127             // we'll step/increase it before using it
128             fOrigin.set(fSrcBounds.fLeft - kMaxDim, fSrcBounds.fTop);
129         } else {
130             // don't reference fSrcBounds, as it may not have been set
131             fDraw.fDst = fRootPixmap;
132             fDraw.fCTM = &dev->localToDevice();
133             fDraw.fRC = &dev->fRCStack.rc();
134             fOrigin.set(0, 0);
135         }
136 
137         fDraw.fProps = &fDevice->surfaceProps();
138     }
139 
needsTiling() const140     bool needsTiling() const { return fNeedsTiling; }
141 
next()142     const SkDraw* next() {
143         if (fDone) {
144             return nullptr;
145         }
146         if (fNeedsTiling) {
147             do {
148                 this->stepAndSetupTileDraw();  // might set the clip to empty and fDone to true
149             } while (!fDone && fTileRC.isEmpty());
150             // if we exit the loop and we're still empty, we're (past) done
151             if (fTileRC.isEmpty()) {
152                 SkASSERT(fDone);
153                 return nullptr;
154             }
155             SkASSERT(!fTileRC.isEmpty());
156         } else {
157             fDone = true;   // only draw untiled once
158         }
159         return &fDraw;
160     }
161 
162 private:
stepAndSetupTileDraw()163     void stepAndSetupTileDraw() {
164         SkASSERT(!fDone);
165         SkASSERT(fNeedsTiling);
166 
167         // We do fRootPixmap.width() - kMaxDim instead of fOrigin.fX + kMaxDim to avoid overflow.
168         if (fOrigin.fX >= fSrcBounds.fRight - kMaxDim) {    // too far
169             fOrigin.fX = fSrcBounds.fLeft;
170             fOrigin.fY += kMaxDim;
171         } else {
172             fOrigin.fX += kMaxDim;
173         }
174         // fDone = next origin will be invalid.
175         fDone = fOrigin.fX >= fSrcBounds.fRight - kMaxDim &&
176                 fOrigin.fY >= fSrcBounds.fBottom - kMaxDim;
177 
178         SkIRect bounds = SkIRect::MakeXYWH(fOrigin.x(), fOrigin.y(), kMaxDim, kMaxDim);
179         SkASSERT(!bounds.isEmpty());
180         bool success = fRootPixmap.extractSubset(&fDraw.fDst, bounds);
181         SkASSERT_RELEASE(success);
182         // now don't use bounds, since fDst has the clipped dimensions.
183 
184         fTileMatrix.init(fDevice->localToDevice());
185         fTileMatrix->postTranslate(-fOrigin.x(), -fOrigin.y());
186         fDraw.fCTM = fTileMatrix.get();
187         fDevice->fRCStack.rc().translate(-fOrigin.x(), -fOrigin.y(), &fTileRC);
188         fTileRC.op(SkIRect::MakeSize(fDraw.fDst.dimensions()), SkClipOp::kIntersect);
189     }
190 };
191 
192 // Passing a bounds allows the tiler to only visit the dst-tiles that might intersect the
193 // drawing. If null is passed, the tiler has to visit everywhere. The bounds is expected to be
194 // in local coordinates, as the tiler itself will transform that into device coordinates.
195 //
196 #define LOOP_TILER(code, boundsPtr)                         \
197     SkDrawTiler priv_tiler(this, boundsPtr);                \
198     while (const SkDraw* priv_draw = priv_tiler.next()) {   \
199         priv_draw->code;                                    \
200     }
201 
202 // Helper to create an SkDraw from a device
203 class SkBitmapDevice::BDDraw : public SkDraw {
204 public:
BDDraw(SkBitmapDevice * dev)205     BDDraw(SkBitmapDevice* dev) {
206         // we need fDst to be set, and if we're actually drawing, to dirty the genID
207         if (!dev->accessPixels(&fDst)) {
208             // NoDrawDevice uses us (why?) so we have to catch this case w/ no pixels
209             fDst.reset(dev->imageInfo(), nullptr, 0);
210         }
211         fCTM = &dev->localToDevice();
212         fRC = &dev->fRCStack.rc();
213     }
214 };
215 
valid_for_bitmap_device(const SkImageInfo & info,SkAlphaType * newAlphaType)216 static bool valid_for_bitmap_device(const SkImageInfo& info,
217                                     SkAlphaType* newAlphaType) {
218     if (info.width() < 0 || info.height() < 0 || kUnknown_SkColorType == info.colorType()) {
219         return false;
220     }
221 
222     if (newAlphaType) {
223         *newAlphaType = SkColorTypeIsAlwaysOpaque(info.colorType()) ? kOpaque_SkAlphaType
224                                                                     : info.alphaType();
225     }
226 
227     return true;
228 }
229 
SkBitmapDevice(const SkBitmap & bitmap)230 SkBitmapDevice::SkBitmapDevice(const SkBitmap& bitmap)
231         : SkDevice(bitmap.info(), SkSurfaceProps())
232         , fBitmap(bitmap)
233         , fRCStack(bitmap.width(), bitmap.height())
234         , fGlyphPainter(this->surfaceProps(), bitmap.colorType(), bitmap.colorSpace()) {
235     SkASSERT(valid_for_bitmap_device(bitmap.info(), nullptr));
236 }
237 
SkBitmapDevice(const SkBitmap & bitmap,const SkSurfaceProps & surfaceProps,SkRasterHandleAllocator::Handle hndl)238 SkBitmapDevice::SkBitmapDevice(const SkBitmap& bitmap, const SkSurfaceProps& surfaceProps,
239                                SkRasterHandleAllocator::Handle hndl)
240         : SkDevice(bitmap.info(), surfaceProps)
241         , fBitmap(bitmap)
242         , fRasterHandle(hndl)
243         , fRCStack(bitmap.width(), bitmap.height())
244         , fGlyphPainter(this->surfaceProps(), bitmap.colorType(), bitmap.colorSpace()) {
245     SkASSERT(valid_for_bitmap_device(bitmap.info(), nullptr));
246 }
247 
Create(const SkImageInfo & origInfo,const SkSurfaceProps & surfaceProps,SkRasterHandleAllocator * allocator)248 sk_sp<SkBitmapDevice> SkBitmapDevice::Create(const SkImageInfo& origInfo,
249                                              const SkSurfaceProps& surfaceProps,
250                                              SkRasterHandleAllocator* allocator) {
251     SkAlphaType newAT = origInfo.alphaType();
252     if (!valid_for_bitmap_device(origInfo, &newAT)) {
253         return nullptr;
254     }
255 
256     SkRasterHandleAllocator::Handle hndl = nullptr;
257     const SkImageInfo info = origInfo.makeAlphaType(newAT);
258     SkBitmap bitmap;
259 
260     if (kUnknown_SkColorType == info.colorType()) {
261         if (!bitmap.setInfo(info)) {
262             return nullptr;
263         }
264     } else if (allocator) {
265         hndl = allocator->allocBitmap(info, &bitmap);
266         if (!hndl) {
267             return nullptr;
268         }
269     } else if (info.isOpaque()) {
270         // If this bitmap is opaque, we don't have any sensible default color,
271         // so we just return uninitialized pixels.
272         if (!bitmap.tryAllocPixels(info)) {
273             return nullptr;
274         }
275     } else {
276         // This bitmap has transparency, so we'll zero the pixels (to transparent).
277         // We use the flag as a faster alloc-then-eraseColor(SK_ColorTRANSPARENT).
278         if (!bitmap.tryAllocPixelsFlags(info, SkBitmap::kZeroPixels_AllocFlag)) {
279             return nullptr;
280         }
281     }
282 
283     return sk_make_sp<SkBitmapDevice>(bitmap, surfaceProps, hndl);
284 }
285 
replaceBitmapBackendForRasterSurface(const SkBitmap & bm)286 void SkBitmapDevice::replaceBitmapBackendForRasterSurface(const SkBitmap& bm) {
287     SkASSERT(bm.width() == fBitmap.width());
288     SkASSERT(bm.height() == fBitmap.height());
289     fBitmap = bm;   // intent is to use bm's pixelRef (and rowbytes/config)
290 }
291 
createDevice(const CreateInfo & cinfo,const SkPaint * layerPaint)292 sk_sp<SkDevice> SkBitmapDevice::createDevice(const CreateInfo& cinfo, const SkPaint* layerPaint) {
293     const SkSurfaceProps surfaceProps =
294         this->surfaceProps().cloneWithPixelGeometry(cinfo.fPixelGeometry);
295 
296     // Need to force L32 for now if we have an image filter.
297     // If filters ever support other colortypes, e.g. F16, we can modify this check.
298     SkImageInfo info = cinfo.fInfo;
299     if (layerPaint && layerPaint->getImageFilter()) {
300         // TODO: can we query the imagefilter, to see if it can handle floats (so we don't always
301         //       use N32 when the layer itself was float)?
302         info = info.makeColorType(kN32_SkColorType);
303     }
304 
305     return SkBitmapDevice::Create(info, surfaceProps, cinfo.fAllocator);
306 }
307 
onAccessPixels(SkPixmap * pmap)308 bool SkBitmapDevice::onAccessPixels(SkPixmap* pmap) {
309     if (this->onPeekPixels(pmap)) {
310         fBitmap.notifyPixelsChanged();
311         return true;
312     }
313     return false;
314 }
315 
onPeekPixels(SkPixmap * pmap)316 bool SkBitmapDevice::onPeekPixels(SkPixmap* pmap) {
317     const SkImageInfo info = fBitmap.info();
318     if (fBitmap.getPixels() && (kUnknown_SkColorType != info.colorType())) {
319         pmap->reset(fBitmap.info(), fBitmap.getPixels(), fBitmap.rowBytes());
320         return true;
321     }
322     return false;
323 }
324 
onWritePixels(const SkPixmap & pm,int x,int y)325 bool SkBitmapDevice::onWritePixels(const SkPixmap& pm, int x, int y) {
326     // since we don't stop creating un-pixeled devices yet, check for no pixels here
327     if (nullptr == fBitmap.getPixels()) {
328         return false;
329     }
330 
331     if (fBitmap.writePixels(pm, x, y)) {
332         fBitmap.notifyPixelsChanged();
333         return true;
334     }
335     return false;
336 }
337 
onReadPixels(const SkPixmap & pm,int x,int y)338 bool SkBitmapDevice::onReadPixels(const SkPixmap& pm, int x, int y) {
339     return fBitmap.readPixels(pm, x, y);
340 }
341 
342 ///////////////////////////////////////////////////////////////////////////////
343 
drawPaint(const SkPaint & paint)344 void SkBitmapDevice::drawPaint(const SkPaint& paint) {
345     BDDraw(this).drawPaint(paint);
346 }
347 
drawPoints(SkCanvas::PointMode mode,size_t count,const SkPoint pts[],const SkPaint & paint)348 void SkBitmapDevice::drawPoints(SkCanvas::PointMode mode, size_t count,
349                                 const SkPoint pts[], const SkPaint& paint) {
350     LOOP_TILER( drawPoints(mode, count, pts, paint, nullptr), nullptr)
351 }
352 
drawRect(const SkRect & r,const SkPaint & paint)353 void SkBitmapDevice::drawRect(const SkRect& r, const SkPaint& paint) {
354     LOOP_TILER( drawRect(r, paint), Bounder(r, paint))
355 }
356 
drawOval(const SkRect & oval,const SkPaint & paint)357 void SkBitmapDevice::drawOval(const SkRect& oval, const SkPaint& paint) {
358     // call the VIRTUAL version, so any subclasses who do handle drawPath aren't
359     // required to override drawOval.
360     this->drawPath(SkPath::Oval(oval), paint, true);
361 }
362 
drawRRect(const SkRRect & rrect,const SkPaint & paint)363 void SkBitmapDevice::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
364 #ifdef SK_IGNORE_BLURRED_RRECT_OPT
365     // call the VIRTUAL version, so any subclasses who do handle drawPath aren't
366     // required to override drawRRect.
367     this->drawPath(SkPath::RRect(rrect), paint, true);
368 #else
369     LOOP_TILER( drawRRect(rrect, paint), Bounder(rrect.getBounds(), paint))
370 #endif
371 }
372 
drawPath(const SkPath & path,const SkPaint & paint,bool pathIsMutable)373 void SkBitmapDevice::drawPath(const SkPath& path,
374                               const SkPaint& paint,
375                               bool pathIsMutable) {
376     const SkRect* bounds = nullptr;
377     if (SkDrawTiler::NeedsTiling(this) && !path.isInverseFillType()) {
378         bounds = &path.getBounds();
379     }
380     SkDrawTiler tiler(this, bounds ? Bounder(*bounds, paint).bounds() : nullptr);
381     if (tiler.needsTiling()) {
382         pathIsMutable = false;
383     }
384     while (const SkDraw* draw = tiler.next()) {
385         draw->drawPath(path, paint, nullptr, pathIsMutable);
386     }
387 }
388 
drawBitmap(const SkBitmap & bitmap,const SkMatrix & matrix,const SkRect * dstOrNull,const SkSamplingOptions & sampling,const SkPaint & paint)389 void SkBitmapDevice::drawBitmap(const SkBitmap& bitmap, const SkMatrix& matrix,
390                                 const SkRect* dstOrNull, const SkSamplingOptions& sampling,
391                                 const SkPaint& paint) {
392     const SkRect* bounds = dstOrNull;
393     SkRect storage;
394     if (!bounds && SkDrawTiler::NeedsTiling(this)) {
395         matrix.mapRect(&storage, SkRect::MakeIWH(bitmap.width(), bitmap.height()));
396         Bounder b(storage, paint);
397         if (b.hasBounds()) {
398             storage = *b.bounds();
399             bounds = &storage;
400         }
401     }
402     LOOP_TILER(drawBitmap(bitmap, matrix, dstOrNull, sampling, paint), bounds)
403 }
404 
CanApplyDstMatrixAsCTM(const SkMatrix & m,const SkPaint & paint)405 static inline bool CanApplyDstMatrixAsCTM(const SkMatrix& m, const SkPaint& paint) {
406     if (!paint.getMaskFilter()) {
407         return true;
408     }
409 
410     // Some mask filters parameters (sigma) depend on the CTM/scale.
411     return m.getType() <= SkMatrix::kTranslate_Mask;
412 }
413 
drawImageRect(const SkImage * image,const SkRect * src,const SkRect & dst,const SkSamplingOptions & sampling,const SkPaint & paint,SkCanvas::SrcRectConstraint constraint)414 void SkBitmapDevice::drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
415                                    const SkSamplingOptions& sampling, const SkPaint& paint,
416                                    SkCanvas::SrcRectConstraint constraint) {
417     SkASSERT(dst.isFinite());
418     SkASSERT(dst.isSorted());
419 
420     SkBitmap bitmap;
421     // TODO: Elevate direct context requirement to public API and remove cheat.
422     auto dContext = as_IB(image)->directContext();
423     if (!as_IB(image)->getROPixels(dContext, &bitmap)) {
424         return;
425     }
426 
427     SkRect      bitmapBounds, tmpSrc, tmpDst;
428     SkBitmap    tmpBitmap;
429 
430     bitmapBounds.setIWH(bitmap.width(), bitmap.height());
431 
432     // Compute matrix from the two rectangles
433     if (src) {
434         tmpSrc = *src;
435     } else {
436         tmpSrc = bitmapBounds;
437     }
438     SkMatrix matrix = SkMatrix::RectToRect(tmpSrc, dst);
439 
440     const SkRect* dstPtr = &dst;
441     const SkBitmap* bitmapPtr = &bitmap;
442 
443     // clip the tmpSrc to the bounds of the bitmap, and recompute dstRect if
444     // needed (if the src was clipped). No check needed if src==null.
445     bool srcIsSubset = false;
446     if (src) {
447         if (!bitmapBounds.contains(*src)) {
448             if (!tmpSrc.intersect(bitmapBounds)) {
449                 return; // nothing to draw
450             }
451             // recompute dst, based on the smaller tmpSrc
452             matrix.mapRect(&tmpDst, tmpSrc);
453             if (!tmpDst.isFinite()) {
454                 return;
455             }
456             dstPtr = &tmpDst;
457         }
458         srcIsSubset = !tmpSrc.contains(bitmapBounds);
459     }
460 
461     if (srcIsSubset &&
462         SkCanvas::kFast_SrcRectConstraint == constraint &&
463         sampling != SkSamplingOptions()) {
464         // src is smaller than the bounds of the bitmap, and we are filtering, so we don't know
465         // how much more of the bitmap we need, so we can't use extractSubset or drawBitmap,
466         // but we must use a shader w/ dst bounds (which can access all of the bitmap needed).
467         goto USE_SHADER;
468     }
469 
470     if (srcIsSubset) {
471         // since we may need to clamp to the borders of the src rect within
472         // the bitmap, we extract a subset.
473         const SkIRect srcIR = tmpSrc.roundOut();
474         if (!bitmap.extractSubset(&tmpBitmap, srcIR)) {
475             return;
476         }
477         bitmapPtr = &tmpBitmap;
478 
479         // Since we did an extract, we need to adjust the matrix accordingly
480         SkScalar dx = 0, dy = 0;
481         if (srcIR.fLeft > 0) {
482             dx = SkIntToScalar(srcIR.fLeft);
483         }
484         if (srcIR.fTop > 0) {
485             dy = SkIntToScalar(srcIR.fTop);
486         }
487         if (dx || dy) {
488             matrix.preTranslate(dx, dy);
489         }
490 
491 #ifdef SK_DRAWBITMAPRECT_FAST_OFFSET
492         SkRect extractedBitmapBounds = SkRect::MakeXYWH(dx, dy,
493                                                         SkIntToScalar(bitmapPtr->width()),
494                                                         SkIntToScalar(bitmapPtr->height()));
495 #else
496         SkRect extractedBitmapBounds;
497         extractedBitmapBounds.setIWH(bitmapPtr->width(), bitmapPtr->height());
498 #endif
499         if (extractedBitmapBounds == tmpSrc) {
500             // no fractional part in src, we can just call drawBitmap
501             goto USE_DRAWBITMAP;
502         }
503     } else {
504         USE_DRAWBITMAP:
505         // We can go faster by just calling drawBitmap, which will concat the
506         // matrix with the CTM, and try to call drawSprite if it can. If not,
507         // it will make a shader and call drawRect, as we do below.
508         if (CanApplyDstMatrixAsCTM(matrix, paint)) {
509             this->drawBitmap(*bitmapPtr, matrix, dstPtr, sampling, paint);
510             return;
511         }
512     }
513 
514     USE_SHADER:
515 
516     // construct a shader, so we can call drawRect with the dst
517     auto s = SkMakeBitmapShaderForPaint(paint, *bitmapPtr, SkTileMode::kClamp, SkTileMode::kClamp,
518                                         sampling, &matrix, kNever_SkCopyPixelsMode);
519     if (!s) {
520         return;
521     }
522 
523     SkPaint paintWithShader(paint);
524     paintWithShader.setStyle(SkPaint::kFill_Style);
525     paintWithShader.setShader(std::move(s));
526 
527     // Call ourself, in case the subclass wanted to share this setup code
528     // but handle the drawRect code themselves.
529     this->drawRect(*dstPtr, paintWithShader);
530 }
531 
onDrawGlyphRunList(SkCanvas * canvas,const sktext::GlyphRunList & glyphRunList,const SkPaint & paint)532 void SkBitmapDevice::onDrawGlyphRunList(SkCanvas* canvas,
533                                         const sktext::GlyphRunList& glyphRunList,
534                                         const SkPaint& paint) {
535     SkASSERT(!glyphRunList.hasRSXForm());
536     LOOP_TILER( drawGlyphRunList(canvas, &fGlyphPainter, glyphRunList, paint), nullptr )
537 }
538 
drawVertices(const SkVertices * vertices,sk_sp<SkBlender> blender,const SkPaint & paint,bool skipColorXform)539 void SkBitmapDevice::drawVertices(const SkVertices* vertices,
540                                   sk_sp<SkBlender> blender,
541                                   const SkPaint& paint,
542                                   bool skipColorXform) {
543 #ifdef SK_LEGACY_IGNORE_DRAW_VERTICES_BLEND_WITH_NO_SHADER
544     if (!paint.getShader()) {
545         blender = SkBlender::Mode(SkBlendMode::kDst);
546     }
547 #endif
548     BDDraw(this).drawVertices(vertices, std::move(blender), paint, skipColorXform);
549 }
550 
drawMesh(const SkMesh &,sk_sp<SkBlender>,const SkPaint &)551 void SkBitmapDevice::drawMesh(const SkMesh&, sk_sp<SkBlender>, const SkPaint&) {
552     // TODO(brianosman): Implement, maybe with a subclass of BitmapDevice that has SkSL support.
553 }
554 
drawAtlas(const SkRSXform xform[],const SkRect tex[],const SkColor colors[],int count,sk_sp<SkBlender> blender,const SkPaint & paint)555 void SkBitmapDevice::drawAtlas(const SkRSXform xform[],
556                                const SkRect tex[],
557                                const SkColor colors[],
558                                int count,
559                                sk_sp<SkBlender> blender,
560                                const SkPaint& paint) {
561     // set this to true for performance comparisons with the old drawVertices way
562     if ((false)) {
563         this->SkDevice::drawAtlas(xform, tex, colors, count, std::move(blender), paint);
564         return;
565     }
566     BDDraw(this).drawAtlas(xform, tex, colors, count, std::move(blender), paint);
567 }
568 
569 ///////////////////////////////////////////////////////////////////////////////
570 
drawSpecial(SkSpecialImage * src,const SkMatrix & localToDevice,const SkSamplingOptions & sampling,const SkPaint & paint,SkCanvas::SrcRectConstraint)571 void SkBitmapDevice::drawSpecial(SkSpecialImage* src,
572                                  const SkMatrix& localToDevice,
573                                  const SkSamplingOptions& sampling,
574                                  const SkPaint& paint,
575                                  SkCanvas::SrcRectConstraint) {
576     SkASSERT(!paint.getImageFilter());
577     SkASSERT(!paint.getMaskFilter());
578     SkASSERT(!src->isGaneshBacked());
579     SkASSERT(!src->isGraphiteBacked());
580 
581     SkBitmap resultBM;
582     if (SkSpecialImages::AsBitmap(src, &resultBM)) {
583         SkDraw draw;
584         if (!this->accessPixels(&draw.fDst)) {
585           return; // no pixels to draw to so skip it
586         }
587         draw.fCTM = &localToDevice;
588         draw.fRC = &fRCStack.rc();
589         draw.drawBitmap(resultBM, SkMatrix::I(), nullptr, sampling, paint);
590     }
591 }
makeSpecial(const SkBitmap & bitmap)592 sk_sp<SkSpecialImage> SkBitmapDevice::makeSpecial(const SkBitmap& bitmap) {
593     return SkSpecialImages::MakeFromRaster(bitmap.bounds(), bitmap, this->surfaceProps());
594 }
595 
makeSpecial(const SkImage * image)596 sk_sp<SkSpecialImage> SkBitmapDevice::makeSpecial(const SkImage* image) {
597     return SkSpecialImages::MakeFromRaster(SkIRect::MakeWH(image->width(), image->height()),
598                                            image->makeNonTextureImage(),
599                                            this->surfaceProps());
600 }
601 
snapSpecial(const SkIRect & bounds,bool forceCopy)602 sk_sp<SkSpecialImage> SkBitmapDevice::snapSpecial(const SkIRect& bounds, bool forceCopy) {
603     if (forceCopy) {
604         return SkSpecialImages::CopyFromRaster(bounds, fBitmap, this->surfaceProps());
605     } else {
606         return SkSpecialImages::MakeFromRaster(bounds, fBitmap, this->surfaceProps());
607     }
608 }
609 
610 ///////////////////////////////////////////////////////////////////////////////
611 
makeSurface(const SkImageInfo & info,const SkSurfaceProps & props)612 sk_sp<SkSurface> SkBitmapDevice::makeSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
613     return SkSurfaces::Raster(info, &props);
614 }
615 
616 ///////////////////////////////////////////////////////////////////////////////////////////////////
617 
pushClipStack()618 void SkBitmapDevice::pushClipStack() {
619     fRCStack.save();
620 }
621 
popClipStack()622 void SkBitmapDevice::popClipStack() {
623     fRCStack.restore();
624 }
625 
clipRect(const SkRect & rect,SkClipOp op,bool aa)626 void SkBitmapDevice::clipRect(const SkRect& rect, SkClipOp op, bool aa) {
627     fRCStack.clipRect(this->localToDevice(), rect, op, aa);
628 }
629 
clipRRect(const SkRRect & rrect,SkClipOp op,bool aa)630 void SkBitmapDevice::clipRRect(const SkRRect& rrect, SkClipOp op, bool aa) {
631     fRCStack.clipRRect(this->localToDevice(), rrect, op, aa);
632 }
633 
clipPath(const SkPath & path,SkClipOp op,bool aa)634 void SkBitmapDevice::clipPath(const SkPath& path, SkClipOp op, bool aa) {
635     fRCStack.clipPath(this->localToDevice(), path, op, aa);
636 }
637 
onClipShader(sk_sp<SkShader> sh)638 void SkBitmapDevice::onClipShader(sk_sp<SkShader> sh) {
639     fRCStack.clipShader(std::move(sh));
640 }
641 
clipRegion(const SkRegion & rgn,SkClipOp op)642 void SkBitmapDevice::clipRegion(const SkRegion& rgn, SkClipOp op) {
643     SkIPoint origin = this->getOrigin();
644     SkRegion tmp;
645     const SkRegion* ptr = &rgn;
646     if (origin.fX | origin.fY) {
647         // translate from "global/canvas" coordinates to relative to this device
648         rgn.translate(-origin.fX, -origin.fY, &tmp);
649         ptr = &tmp;
650     }
651     fRCStack.clipRegion(*ptr, op);
652 }
653 
replaceClip(const SkIRect & rect)654 void SkBitmapDevice::replaceClip(const SkIRect& rect) {
655     // Transform from "global/canvas" coordinates to relative to this device
656     SkRect deviceRect = SkMatrixPriv::MapRect(this->globalToDevice(), SkRect::Make(rect));
657     fRCStack.replaceClip(deviceRect.round());
658 }
659 
isClipWideOpen() const660 bool SkBitmapDevice::isClipWideOpen() const {
661     const SkRasterClip& rc = fRCStack.rc();
662     // If we're AA, we can't be wide-open (we would represent that as BW)
663     return rc.isBW() && rc.bwRgn().isRect() &&
664            rc.bwRgn().getBounds() == SkIRect{0, 0, this->width(), this->height()};
665 }
666 
isClipEmpty() const667 bool SkBitmapDevice::isClipEmpty() const {
668     return fRCStack.rc().isEmpty();
669 }
670 
isClipRect() const671 bool SkBitmapDevice::isClipRect() const {
672     const SkRasterClip& rc = fRCStack.rc();
673     return !rc.isEmpty() && rc.isRect() && !SkToBool(rc.clipShader());
674 }
675 
isClipAntiAliased() const676 bool SkBitmapDevice::isClipAntiAliased() const {
677     const SkRasterClip& rc = fRCStack.rc();
678     return !rc.isEmpty() && rc.isAA();
679 }
680 
android_utils_clipAsRgn(SkRegion * rgn) const681 void SkBitmapDevice::android_utils_clipAsRgn(SkRegion* rgn) const {
682     const SkRasterClip& rc = fRCStack.rc();
683     if (rc.isAA()) {
684         rgn->setRect(   rc.getBounds());
685     } else {
686         *rgn = rc.bwRgn();
687     }
688 }
689 
devClipBounds() const690 SkIRect SkBitmapDevice::devClipBounds() const {
691     return fRCStack.rc().getBounds();
692 }
693