• 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 "SkBitmapDevice.h"
9 #include "SkDraw.h"
10 #include "SkImageFilter.h"
11 #include "SkImageFilterCache.h"
12 #include "SkMallocPixelRef.h"
13 #include "SkMatrix.h"
14 #include "SkPaint.h"
15 #include "SkPath.h"
16 #include "SkPixelRef.h"
17 #include "SkPixmap.h"
18 #include "SkRasterClip.h"
19 #include "SkRasterHandleAllocator.h"
20 #include "SkShader.h"
21 #include "SkSpecialImage.h"
22 #include "SkSurface.h"
23 #include "SkVertices.h"
24 
25 class SkColorTable;
26 
valid_for_bitmap_device(const SkImageInfo & info,SkAlphaType * newAlphaType)27 static bool valid_for_bitmap_device(const SkImageInfo& info,
28                                     SkAlphaType* newAlphaType) {
29     if (info.width() < 0 || info.height() < 0) {
30         return false;
31     }
32 
33     // TODO: can we stop supporting kUnknown in SkBitmkapDevice?
34     if (kUnknown_SkColorType == info.colorType()) {
35         if (newAlphaType) {
36             *newAlphaType = kUnknown_SkAlphaType;
37         }
38         return true;
39     }
40 
41     switch (info.alphaType()) {
42         case kPremul_SkAlphaType:
43         case kOpaque_SkAlphaType:
44             break;
45         default:
46             return false;
47     }
48 
49     SkAlphaType canonicalAlphaType = info.alphaType();
50 
51     switch (info.colorType()) {
52         case kAlpha_8_SkColorType:
53             break;
54         case kRGB_565_SkColorType:
55             canonicalAlphaType = kOpaque_SkAlphaType;
56             break;
57         case kN32_SkColorType:
58             break;
59         case kRGBA_F16_SkColorType:
60             break;
61         default:
62             return false;
63     }
64 
65     if (newAlphaType) {
66         *newAlphaType = canonicalAlphaType;
67     }
68     return true;
69 }
70 
SkBitmapDevice(const SkBitmap & bitmap)71 SkBitmapDevice::SkBitmapDevice(const SkBitmap& bitmap)
72     : INHERITED(bitmap.info(), SkSurfaceProps(SkSurfaceProps::kLegacyFontHost_InitType))
73     , fBitmap(bitmap)
74     , fRCStack(bitmap.width(), bitmap.height())
75 {
76     SkASSERT(valid_for_bitmap_device(bitmap.info(), nullptr));
77     fBitmap.lockPixels();
78 }
79 
Create(const SkImageInfo & info)80 SkBitmapDevice* SkBitmapDevice::Create(const SkImageInfo& info) {
81     return Create(info, SkSurfaceProps(SkSurfaceProps::kLegacyFontHost_InitType));
82 }
83 
SkBitmapDevice(const SkBitmap & bitmap,const SkSurfaceProps & surfaceProps,SkRasterHandleAllocator::Handle hndl)84 SkBitmapDevice::SkBitmapDevice(const SkBitmap& bitmap, const SkSurfaceProps& surfaceProps,
85                                SkRasterHandleAllocator::Handle hndl)
86     : INHERITED(bitmap.info(), surfaceProps)
87     , fBitmap(bitmap)
88     , fRasterHandle(hndl)
89     , fRCStack(bitmap.width(), bitmap.height())
90 {
91     SkASSERT(valid_for_bitmap_device(bitmap.info(), nullptr));
92     fBitmap.lockPixels();
93 }
94 
Create(const SkImageInfo & origInfo,const SkSurfaceProps & surfaceProps,SkRasterHandleAllocator * allocator)95 SkBitmapDevice* SkBitmapDevice::Create(const SkImageInfo& origInfo,
96                                        const SkSurfaceProps& surfaceProps,
97                                        SkRasterHandleAllocator* allocator) {
98     SkAlphaType newAT = origInfo.alphaType();
99     if (!valid_for_bitmap_device(origInfo, &newAT)) {
100         return nullptr;
101     }
102 
103     SkRasterHandleAllocator::Handle hndl = nullptr;
104     const SkImageInfo info = origInfo.makeAlphaType(newAT);
105     SkBitmap bitmap;
106 
107     if (kUnknown_SkColorType == info.colorType()) {
108         if (!bitmap.setInfo(info)) {
109             return nullptr;
110         }
111     } else if (allocator) {
112         hndl = allocator->allocBitmap(info, &bitmap);
113         if (!hndl) {
114             return nullptr;
115         }
116     } else if (info.isOpaque()) {
117         // If this bitmap is opaque, we don't have any sensible default color,
118         // so we just return uninitialized pixels.
119         if (!bitmap.tryAllocPixels(info)) {
120             return nullptr;
121         }
122     } else {
123         // This bitmap has transparency, so we'll zero the pixels (to transparent).
124         // We use a ZeroedPRFactory as a faster alloc-then-eraseColor(SK_ColorTRANSPARENT).
125         SkMallocPixelRef::ZeroedPRFactory factory;
126         if (!bitmap.tryAllocPixels(info, &factory, nullptr/*color table*/)) {
127             return nullptr;
128         }
129     }
130 
131     return new SkBitmapDevice(bitmap, surfaceProps, hndl);
132 }
133 
replaceBitmapBackendForRasterSurface(const SkBitmap & bm)134 void SkBitmapDevice::replaceBitmapBackendForRasterSurface(const SkBitmap& bm) {
135     SkASSERT(bm.width() == fBitmap.width());
136     SkASSERT(bm.height() == fBitmap.height());
137     fBitmap = bm;   // intent is to use bm's pixelRef (and rowbytes/config)
138     fBitmap.lockPixels();
139     this->privateResize(fBitmap.info().width(), fBitmap.info().height());
140 }
141 
onCreateDevice(const CreateInfo & cinfo,const SkPaint *)142 SkBaseDevice* SkBitmapDevice::onCreateDevice(const CreateInfo& cinfo, const SkPaint*) {
143     const SkSurfaceProps surfaceProps(this->surfaceProps().flags(), cinfo.fPixelGeometry);
144     return SkBitmapDevice::Create(cinfo.fInfo, surfaceProps, cinfo.fAllocator);
145 }
146 
onAccessPixels(SkPixmap * pmap)147 bool SkBitmapDevice::onAccessPixels(SkPixmap* pmap) {
148     if (this->onPeekPixels(pmap)) {
149         fBitmap.notifyPixelsChanged();
150         return true;
151     }
152     return false;
153 }
154 
onPeekPixels(SkPixmap * pmap)155 bool SkBitmapDevice::onPeekPixels(SkPixmap* pmap) {
156     const SkImageInfo info = fBitmap.info();
157     if (fBitmap.getPixels() && (kUnknown_SkColorType != info.colorType())) {
158         SkColorTable* ctable = nullptr;
159         pmap->reset(fBitmap.info(), fBitmap.getPixels(), fBitmap.rowBytes(), ctable);
160         return true;
161     }
162     return false;
163 }
164 
onWritePixels(const SkImageInfo & srcInfo,const void * srcPixels,size_t srcRowBytes,int x,int y)165 bool SkBitmapDevice::onWritePixels(const SkImageInfo& srcInfo, const void* srcPixels,
166                                    size_t srcRowBytes, int x, int y) {
167     // since we don't stop creating un-pixeled devices yet, check for no pixels here
168     if (nullptr == fBitmap.getPixels()) {
169         return false;
170     }
171 
172     if (fBitmap.writePixels(SkPixmap(srcInfo, srcPixels, srcRowBytes), x, y)) {
173         fBitmap.notifyPixelsChanged();
174         return true;
175     }
176     return false;
177 }
178 
onReadPixels(const SkImageInfo & dstInfo,void * dstPixels,size_t dstRowBytes,int x,int y)179 bool SkBitmapDevice::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
180                                   int x, int y) {
181     return fBitmap.readPixels(dstInfo, dstPixels, dstRowBytes, x, y);
182 }
183 
184 ///////////////////////////////////////////////////////////////////////////////
185 
186 class SkBitmapDevice::BDDraw : public SkDraw {
187 public:
BDDraw(SkBitmapDevice * dev)188     BDDraw(SkBitmapDevice* dev) {
189         // we need fDst to be set, and if we're actually drawing, to dirty the genID
190         if (!dev->accessPixels(&fDst)) {
191             // NoDrawDevice uses us (why?) so we have to catch this case w/ no pixels
192             fDst.reset(dev->imageInfo(), nullptr, 0);
193         }
194         fMatrix = &dev->ctm();
195         fRC = &dev->fRCStack.rc();
196     }
197 };
198 
drawPaint(const SkPaint & paint)199 void SkBitmapDevice::drawPaint(const SkPaint& paint) {
200     BDDraw(this).drawPaint(paint);
201 }
202 
drawPoints(SkCanvas::PointMode mode,size_t count,const SkPoint pts[],const SkPaint & paint)203 void SkBitmapDevice::drawPoints(SkCanvas::PointMode mode, size_t count,
204                                 const SkPoint pts[], const SkPaint& paint) {
205     BDDraw(this).drawPoints(mode, count, pts, paint, nullptr);
206 }
207 
drawRect(const SkRect & r,const SkPaint & paint)208 void SkBitmapDevice::drawRect(const SkRect& r, const SkPaint& paint) {
209     BDDraw(this).drawRect(r, paint);
210 }
211 
drawOval(const SkRect & oval,const SkPaint & paint)212 void SkBitmapDevice::drawOval(const SkRect& oval, const SkPaint& paint) {
213     SkPath path;
214     path.addOval(oval);
215     // call the VIRTUAL version, so any subclasses who do handle drawPath aren't
216     // required to override drawOval.
217     this->drawPath(path, paint, nullptr, true);
218 }
219 
drawRRect(const SkRRect & rrect,const SkPaint & paint)220 void SkBitmapDevice::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
221 #ifdef SK_IGNORE_BLURRED_RRECT_OPT
222     SkPath  path;
223 
224     path.addRRect(rrect);
225     // call the VIRTUAL version, so any subclasses who do handle drawPath aren't
226     // required to override drawRRect.
227     this->drawPath(path, paint, nullptr, true);
228 #else
229     BDDraw(this).drawRRect(rrect, paint);
230 #endif
231 }
232 
drawPath(const SkPath & path,const SkPaint & paint,const SkMatrix * prePathMatrix,bool pathIsMutable)233 void SkBitmapDevice::drawPath(const SkPath& path,
234                               const SkPaint& paint, const SkMatrix* prePathMatrix,
235                               bool pathIsMutable) {
236     BDDraw(this).drawPath(path, paint, prePathMatrix, pathIsMutable);
237 }
238 
drawBitmap(const SkBitmap & bitmap,const SkMatrix & matrix,const SkPaint & paint)239 void SkBitmapDevice::drawBitmap(const SkBitmap& bitmap,
240                                 const SkMatrix& matrix, const SkPaint& paint) {
241     LogDrawScaleFactor(SkMatrix::Concat(this->ctm(), matrix), paint.getFilterQuality());
242     BDDraw(this).drawBitmap(bitmap, matrix, nullptr, paint);
243 }
244 
CanApplyDstMatrixAsCTM(const SkMatrix & m,const SkPaint & paint)245 static inline bool CanApplyDstMatrixAsCTM(const SkMatrix& m, const SkPaint& paint) {
246     if (!paint.getMaskFilter()) {
247         return true;
248     }
249 
250     // Some mask filters parameters (sigma) depend on the CTM/scale.
251     return m.getType() <= SkMatrix::kTranslate_Mask;
252 }
253 
drawBitmapRect(const SkBitmap & bitmap,const SkRect * src,const SkRect & dst,const SkPaint & paint,SkCanvas::SrcRectConstraint constraint)254 void SkBitmapDevice::drawBitmapRect(const SkBitmap& bitmap,
255                                     const SkRect* src, const SkRect& dst,
256                                     const SkPaint& paint, SkCanvas::SrcRectConstraint constraint) {
257     SkMatrix    matrix;
258     SkRect      bitmapBounds, tmpSrc, tmpDst;
259     SkBitmap    tmpBitmap;
260 
261     bitmapBounds.isetWH(bitmap.width(), bitmap.height());
262 
263     // Compute matrix from the two rectangles
264     if (src) {
265         tmpSrc = *src;
266     } else {
267         tmpSrc = bitmapBounds;
268     }
269     matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit);
270 
271     LogDrawScaleFactor(SkMatrix::Concat(this->ctm(), matrix), paint.getFilterQuality());
272 
273     const SkRect* dstPtr = &dst;
274     const SkBitmap* bitmapPtr = &bitmap;
275 
276     // clip the tmpSrc to the bounds of the bitmap, and recompute dstRect if
277     // needed (if the src was clipped). No check needed if src==null.
278     if (src) {
279         if (!bitmapBounds.contains(*src)) {
280             if (!tmpSrc.intersect(bitmapBounds)) {
281                 return; // nothing to draw
282             }
283             // recompute dst, based on the smaller tmpSrc
284             matrix.mapRect(&tmpDst, tmpSrc);
285             dstPtr = &tmpDst;
286         }
287     }
288 
289     if (src && !src->contains(bitmapBounds) &&
290         SkCanvas::kFast_SrcRectConstraint == constraint &&
291         paint.getFilterQuality() != kNone_SkFilterQuality) {
292         // src is smaller than the bounds of the bitmap, and we are filtering, so we don't know
293         // how much more of the bitmap we need, so we can't use extractSubset or drawBitmap,
294         // but we must use a shader w/ dst bounds (which can access all of the bitmap needed).
295         goto USE_SHADER;
296     }
297 
298     if (src) {
299         // since we may need to clamp to the borders of the src rect within
300         // the bitmap, we extract a subset.
301         const SkIRect srcIR = tmpSrc.roundOut();
302         if (!bitmap.extractSubset(&tmpBitmap, srcIR)) {
303             return;
304         }
305         bitmapPtr = &tmpBitmap;
306 
307         // Since we did an extract, we need to adjust the matrix accordingly
308         SkScalar dx = 0, dy = 0;
309         if (srcIR.fLeft > 0) {
310             dx = SkIntToScalar(srcIR.fLeft);
311         }
312         if (srcIR.fTop > 0) {
313             dy = SkIntToScalar(srcIR.fTop);
314         }
315         if (dx || dy) {
316             matrix.preTranslate(dx, dy);
317         }
318 
319         SkRect extractedBitmapBounds;
320         extractedBitmapBounds.isetWH(bitmapPtr->width(), bitmapPtr->height());
321         if (extractedBitmapBounds == tmpSrc) {
322             // no fractional part in src, we can just call drawBitmap
323             goto USE_DRAWBITMAP;
324         }
325     } else {
326         USE_DRAWBITMAP:
327         // We can go faster by just calling drawBitmap, which will concat the
328         // matrix with the CTM, and try to call drawSprite if it can. If not,
329         // it will make a shader and call drawRect, as we do below.
330         if (CanApplyDstMatrixAsCTM(matrix, paint)) {
331             BDDraw(this).drawBitmap(*bitmapPtr, matrix, dstPtr, paint);
332             return;
333         }
334     }
335 
336     USE_SHADER:
337 
338     // TODO(herb): Move this over to SkArenaAlloc when arena alloc has a facility to return sk_sps.
339     // Since the shader need only live for our stack-frame, pass in a custom allocator. This
340     // can save malloc calls, and signals to SkMakeBitmapShader to not try to copy the bitmap
341     // if its mutable, since that precaution is not needed (give the short lifetime of the shader).
342 
343     // construct a shader, so we can call drawRect with the dst
344     auto s = SkMakeBitmapShader(*bitmapPtr, SkShader::kClamp_TileMode, SkShader::kClamp_TileMode,
345                                 &matrix, kNever_SkCopyPixelsMode);
346     if (!s) {
347         return;
348     }
349 
350     SkPaint paintWithShader(paint);
351     paintWithShader.setStyle(SkPaint::kFill_Style);
352     paintWithShader.setShader(s);
353 
354     // Call ourself, in case the subclass wanted to share this setup code
355     // but handle the drawRect code themselves.
356     this->drawRect(*dstPtr, paintWithShader);
357 }
358 
drawSprite(const SkBitmap & bitmap,int x,int y,const SkPaint & paint)359 void SkBitmapDevice::drawSprite(const SkBitmap& bitmap, int x, int y, const SkPaint& paint) {
360     BDDraw(this).drawSprite(bitmap, x, y, paint);
361 }
362 
drawText(const void * text,size_t len,SkScalar x,SkScalar y,const SkPaint & paint)363 void SkBitmapDevice::drawText(const void* text, size_t len,
364                               SkScalar x, SkScalar y, const SkPaint& paint) {
365     BDDraw(this).drawText((const char*)text, len, x, y, paint, &fSurfaceProps);
366 }
367 
drawPosText(const void * text,size_t len,const SkScalar xpos[],int scalarsPerPos,const SkPoint & offset,const SkPaint & paint)368 void SkBitmapDevice::drawPosText(const void* text, size_t len, const SkScalar xpos[],
369                                  int scalarsPerPos, const SkPoint& offset, const SkPaint& paint) {
370     BDDraw(this).drawPosText((const char*)text, len, xpos, scalarsPerPos, offset, paint,
371                              &fSurfaceProps);
372 }
373 
drawVertices(const SkVertices * vertices,SkBlendMode bmode,const SkPaint & paint)374 void SkBitmapDevice::drawVertices(const SkVertices* vertices, SkBlendMode bmode,
375                                   const SkPaint& paint) {
376     BDDraw(this).drawVertices(vertices->mode(), vertices->vertexCount(), vertices->positions(),
377                               vertices->texCoords(), vertices->colors(), bmode,
378                               vertices->indices(), vertices->indexCount(), paint);
379 }
380 
drawDevice(SkBaseDevice * device,int x,int y,const SkPaint & paint)381 void SkBitmapDevice::drawDevice(SkBaseDevice* device, int x, int y, const SkPaint& paint) {
382     SkASSERT(!paint.getImageFilter());
383     BDDraw(this).drawSprite(static_cast<SkBitmapDevice*>(device)->fBitmap, x, y, paint);
384 }
385 
386 ///////////////////////////////////////////////////////////////////////////////
387 
drawSpecial(SkSpecialImage * srcImg,int x,int y,const SkPaint & paint)388 void SkBitmapDevice::drawSpecial(SkSpecialImage* srcImg, int x, int y,
389                                  const SkPaint& paint) {
390     SkASSERT(!srcImg->isTextureBacked());
391 
392     SkBitmap resultBM;
393 
394     SkImageFilter* filter = paint.getImageFilter();
395     if (filter) {
396         SkIPoint offset = SkIPoint::Make(0, 0);
397         SkMatrix matrix = this->ctm();
398         matrix.postTranslate(SkIntToScalar(-x), SkIntToScalar(-y));
399         const SkIRect clipBounds = fRCStack.rc().getBounds().makeOffset(-x, -y);
400         sk_sp<SkImageFilterCache> cache(this->getImageFilterCache());
401         SkImageFilter::OutputProperties outputProperties(fBitmap.colorSpace());
402         SkImageFilter::Context ctx(matrix, clipBounds, cache.get(), outputProperties);
403 
404         sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg, ctx, &offset));
405         if (resultImg) {
406             SkPaint tmpUnfiltered(paint);
407             tmpUnfiltered.setImageFilter(nullptr);
408             if (resultImg->getROPixels(&resultBM)) {
409                 this->drawSprite(resultBM, x + offset.x(), y + offset.y(), tmpUnfiltered);
410             }
411         }
412     } else {
413         if (srcImg->getROPixels(&resultBM)) {
414             this->drawSprite(resultBM, x, y, paint);
415         }
416     }
417 }
418 
makeSpecial(const SkBitmap & bitmap)419 sk_sp<SkSpecialImage> SkBitmapDevice::makeSpecial(const SkBitmap& bitmap) {
420     return SkSpecialImage::MakeFromRaster(bitmap.bounds(), bitmap);
421 }
422 
makeSpecial(const SkImage * image)423 sk_sp<SkSpecialImage> SkBitmapDevice::makeSpecial(const SkImage* image) {
424     return SkSpecialImage::MakeFromImage(SkIRect::MakeWH(image->width(), image->height()),
425                                          image->makeNonTextureImage(), fBitmap.colorSpace());
426 }
427 
snapSpecial()428 sk_sp<SkSpecialImage> SkBitmapDevice::snapSpecial() {
429     return this->makeSpecial(fBitmap);
430 }
431 
432 ///////////////////////////////////////////////////////////////////////////////
433 
makeSurface(const SkImageInfo & info,const SkSurfaceProps & props)434 sk_sp<SkSurface> SkBitmapDevice::makeSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
435     return SkSurface::MakeRaster(info, &props);
436 }
437 
getImageFilterCache()438 SkImageFilterCache* SkBitmapDevice::getImageFilterCache() {
439     SkImageFilterCache* cache = SkImageFilterCache::Get();
440     cache->ref();
441     return cache;
442 }
443 
444 ///////////////////////////////////////////////////////////////////////////////////////////////////
445 
onShouldDisableLCD(const SkPaint & paint) const446 bool SkBitmapDevice::onShouldDisableLCD(const SkPaint& paint) const {
447     if (kN32_SkColorType != fBitmap.colorType() ||
448         paint.getRasterizer() ||
449         paint.getPathEffect() ||
450         paint.isFakeBoldText() ||
451         paint.getStyle() != SkPaint::kFill_Style ||
452         !paint.isSrcOver())
453     {
454         return true;
455     }
456     return false;
457 }
458 
459 ///////////////////////////////////////////////////////////////////////////////////////////////////
460 
onSave()461 void SkBitmapDevice::onSave() {
462     fRCStack.save();
463 }
464 
onRestore()465 void SkBitmapDevice::onRestore() {
466     fRCStack.restore();
467 }
468 
onClipRect(const SkRect & rect,SkClipOp op,bool aa)469 void SkBitmapDevice::onClipRect(const SkRect& rect, SkClipOp op, bool aa) {
470     fRCStack.clipRect(this->ctm(), rect, op, aa);
471 }
472 
onClipRRect(const SkRRect & rrect,SkClipOp op,bool aa)473 void SkBitmapDevice::onClipRRect(const SkRRect& rrect, SkClipOp op, bool aa) {
474     fRCStack.clipRRect(this->ctm(), rrect, op, aa);
475 }
476 
onClipPath(const SkPath & path,SkClipOp op,bool aa)477 void SkBitmapDevice::onClipPath(const SkPath& path, SkClipOp op, bool aa) {
478     fRCStack.clipPath(this->ctm(), path, op, aa);
479 }
480 
onClipRegion(const SkRegion & rgn,SkClipOp op)481 void SkBitmapDevice::onClipRegion(const SkRegion& rgn, SkClipOp op) {
482     SkIPoint origin = this->getOrigin();
483     SkRegion tmp;
484     const SkRegion* ptr = &rgn;
485     if (origin.fX | origin.fY) {
486         // translate from "global/canvas" coordinates to relative to this device
487         rgn.translate(-origin.fX, -origin.fY, &tmp);
488         ptr = &tmp;
489     }
490     fRCStack.clipRegion(*ptr, op);
491 }
492 
onSetDeviceClipRestriction(SkIRect * mutableClipRestriction)493 void SkBitmapDevice::onSetDeviceClipRestriction(SkIRect* mutableClipRestriction) {
494     fRCStack.setDeviceClipRestriction(mutableClipRestriction);
495     if (!mutableClipRestriction->isEmpty()) {
496         SkRegion rgn(*mutableClipRestriction);
497         fRCStack.clipRegion(rgn, SkClipOp::kIntersect);
498     }
499 }
500 
onClipIsAA() const501 bool SkBitmapDevice::onClipIsAA() const {
502     const SkRasterClip& rc = fRCStack.rc();
503     return !rc.isEmpty() && rc.isAA();
504 }
505 
onAsRgnClip(SkRegion * rgn) const506 void SkBitmapDevice::onAsRgnClip(SkRegion* rgn) const {
507     const SkRasterClip& rc = fRCStack.rc();
508     if (rc.isAA()) {
509         rgn->setRect(rc.getBounds());
510     } else {
511         *rgn = rc.bwRgn();
512     }
513 }
514 
validateDevBounds(const SkIRect & drawClipBounds)515 void SkBitmapDevice::validateDevBounds(const SkIRect& drawClipBounds) {
516 #ifdef SK_DEBUG
517     const SkIRect& stackBounds = fRCStack.rc().getBounds();
518     SkASSERT(drawClipBounds == stackBounds);
519 #endif
520 }
521 
onGetClipType() const522 SkBaseDevice::ClipType SkBitmapDevice::onGetClipType() const {
523     const SkRasterClip& rc = fRCStack.rc();
524     if (rc.isEmpty()) {
525         return kEmpty_ClipType;
526     } else if (rc.isRect()) {
527         return kRect_ClipType;
528     } else {
529         return kComplex_ClipType;
530     }
531 }
532