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