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