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