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