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 "SkConfig8888.h"
     10 #include "SkDraw.h"
     11 #include "SkRasterClip.h"
     12 #include "SkShader.h"
     13 
     14 #define CHECK_FOR_ANNOTATION(paint) \
     15     do { if (paint.getAnnotation()) { return; } } while (0)
     16 
     17 SkBitmapDevice::SkBitmapDevice(const SkBitmap& bitmap)
     18     : fBitmap(bitmap) {
     19     SkASSERT(SkBitmap::kARGB_4444_Config != bitmap.config());
     20 }
     21 
     22 SkBitmapDevice::SkBitmapDevice(const SkBitmap& bitmap, const SkDeviceProperties& deviceProperties)
     23     : SkBaseDevice(deviceProperties)
     24     , fBitmap(bitmap) {
     25 }
     26 
     27 SkBitmapDevice::SkBitmapDevice(SkBitmap::Config config, int width, int height, bool isOpaque) {
     28     fBitmap.setConfig(config, width, height, 0, isOpaque ?
     29                       kOpaque_SkAlphaType : kPremul_SkAlphaType);
     30     if (!fBitmap.allocPixels()) {
     31         fBitmap.setConfig(config, 0, 0, 0, isOpaque ?
     32                           kOpaque_SkAlphaType : kPremul_SkAlphaType);
     33     }
     34     if (!isOpaque) {
     35         fBitmap.eraseColor(SK_ColorTRANSPARENT);
     36     }
     37 }
     38 
     39 SkBitmapDevice::SkBitmapDevice(SkBitmap::Config config, int width, int height, bool isOpaque,
     40                                const SkDeviceProperties& deviceProperties)
     41     : SkBaseDevice(deviceProperties) {
     42 
     43     fBitmap.setConfig(config, width, height, 0, isOpaque ?
     44                       kOpaque_SkAlphaType : kPremul_SkAlphaType);
     45     if (!fBitmap.allocPixels()) {
     46         fBitmap.setConfig(config, 0, 0, 0, isOpaque ?
     47                           kOpaque_SkAlphaType : kPremul_SkAlphaType);
     48     }
     49     if (!isOpaque) {
     50         fBitmap.eraseColor(SK_ColorTRANSPARENT);
     51     }
     52 }
     53 
     54 SkBitmapDevice::~SkBitmapDevice() {
     55 }
     56 
     57 void SkBitmapDevice::replaceBitmapBackendForRasterSurface(const SkBitmap& bm) {
     58     SkASSERT(bm.width() == fBitmap.width());
     59     SkASSERT(bm.height() == fBitmap.height());
     60     fBitmap = bm;   // intent is to use bm's pixelRef (and rowbytes/config)
     61     fBitmap.lockPixels();
     62 }
     63 
     64 SkBaseDevice* SkBitmapDevice::onCreateCompatibleDevice(SkBitmap::Config config,
     65                                                        int width, int height,
     66                                                        bool isOpaque,
     67                                                        Usage usage) {
     68     SkBitmapDevice* device = SkNEW_ARGS(SkBitmapDevice,(config, width, height,
     69                                         isOpaque, this->getDeviceProperties()));
     70     // Check if allocation failed and delete device if it did fail
     71     if ((device->width() != width) || (device->height() != height)) {
     72         SkDELETE(device);
     73         device = NULL;
     74     }
     75     return device;
     76 }
     77 
     78 void SkBitmapDevice::lockPixels() {
     79     if (fBitmap.lockPixelsAreWritable()) {
     80         fBitmap.lockPixels();
     81     }
     82 }
     83 
     84 void SkBitmapDevice::unlockPixels() {
     85     if (fBitmap.lockPixelsAreWritable()) {
     86         fBitmap.unlockPixels();
     87     }
     88 }
     89 
     90 void SkBitmapDevice::clear(SkColor color) {
     91     fBitmap.eraseColor(color);
     92 }
     93 
     94 const SkBitmap& SkBitmapDevice::onAccessBitmap() {
     95     return fBitmap;
     96 }
     97 
     98 bool SkBitmapDevice::canHandleImageFilter(SkImageFilter*) {
     99     return false;
    100 }
    101 
    102 bool SkBitmapDevice::filterImage(SkImageFilter* filter, const SkBitmap& src,
    103                                  const SkMatrix& ctm, SkBitmap* result,
    104                                  SkIPoint* offset) {
    105     return false;
    106 }
    107 
    108 bool SkBitmapDevice::allowImageFilter(SkImageFilter*) {
    109     return true;
    110 }
    111 
    112 bool SkBitmapDevice::onReadPixels(const SkBitmap& bitmap,
    113                                   int x, int y,
    114                                   SkCanvas::Config8888 config8888) {
    115     SkASSERT(SkBitmap::kARGB_8888_Config == bitmap.config());
    116     SkASSERT(!bitmap.isNull());
    117     SkASSERT(SkIRect::MakeWH(this->width(), this->height()).contains(SkIRect::MakeXYWH(x, y,
    118                                                                           bitmap.width(),
    119                                                                           bitmap.height())));
    120 
    121     SkIRect srcRect = SkIRect::MakeXYWH(x, y, bitmap.width(), bitmap.height());
    122     const SkBitmap& src = this->accessBitmap(false);
    123 
    124     SkBitmap subset;
    125     if (!src.extractSubset(&subset, srcRect)) {
    126         return false;
    127     }
    128     if (SkBitmap::kARGB_8888_Config != subset.config()) {
    129         // It'd be preferable to do this directly to bitmap.
    130         subset.copyTo(&subset, SkBitmap::kARGB_8888_Config);
    131     }
    132     SkAutoLockPixels alp(bitmap);
    133     uint32_t* bmpPixels = reinterpret_cast<uint32_t*>(bitmap.getPixels());
    134     SkCopyBitmapToConfig8888(bmpPixels, bitmap.rowBytes(), config8888, subset);
    135     return true;
    136 }
    137 
    138 void SkBitmapDevice::writePixels(const SkBitmap& bitmap,
    139                                  int x, int y,
    140                                  SkCanvas::Config8888 config8888) {
    141     if (bitmap.isNull() || bitmap.getTexture()) {
    142         return;
    143     }
    144     const SkBitmap* sprite = &bitmap;
    145     // check whether we have to handle a config8888 that doesn't match SkPMColor
    146     if (SkBitmap::kARGB_8888_Config == bitmap.config() &&
    147         SkCanvas::kNative_Premul_Config8888 != config8888 &&
    148         kPMColorAlias != config8888) {
    149 
    150         // We're going to have to convert from a config8888 to the native config
    151         // First we clip to the device bounds.
    152         SkBitmap dstBmp = this->accessBitmap(true);
    153         SkIRect spriteRect = SkIRect::MakeXYWH(x, y,
    154                                                bitmap.width(), bitmap.height());
    155         SkIRect devRect = SkIRect::MakeWH(dstBmp.width(), dstBmp.height());
    156         if (!spriteRect.intersect(devRect)) {
    157             return;
    158         }
    159 
    160         // write directly to the device if it has pixels and is SkPMColor
    161         bool drawSprite;
    162         if (SkBitmap::kARGB_8888_Config == dstBmp.config() && !dstBmp.isNull()) {
    163             // we can write directly to the dst when doing the conversion
    164             dstBmp.extractSubset(&dstBmp, spriteRect);
    165             drawSprite = false;
    166         } else {
    167             // we convert to a temporary bitmap and draw that as a sprite
    168             dstBmp.setConfig(SkBitmap::kARGB_8888_Config,
    169                              spriteRect.width(),
    170                              spriteRect.height());
    171             if (!dstBmp.allocPixels()) {
    172                 return;
    173             }
    174             drawSprite = true;
    175         }
    176 
    177         // copy pixels to dstBmp and convert from config8888 to native config.
    178         SkAutoLockPixels alp(bitmap);
    179         uint32_t* srcPixels = bitmap.getAddr32(spriteRect.fLeft - x,
    180                                                spriteRect.fTop - y);
    181         SkCopyConfig8888ToBitmap(dstBmp,
    182                                  srcPixels,
    183                                  bitmap.rowBytes(),
    184                                  config8888);
    185 
    186         if (drawSprite) {
    187             // we've clipped the sprite when we made a copy
    188             x = spriteRect.fLeft;
    189             y = spriteRect.fTop;
    190             sprite = &dstBmp;
    191         } else {
    192             return;
    193         }
    194     }
    195 
    196     SkPaint paint;
    197     paint.setXfermodeMode(SkXfermode::kSrc_Mode);
    198     SkRasterClip clip(SkIRect::MakeWH(fBitmap.width(), fBitmap.height()));
    199     SkDraw  draw;
    200     draw.fRC = &clip;
    201     draw.fClip = &clip.bwRgn();
    202     draw.fBitmap = &fBitmap; // canvas should have already called accessBitmap
    203     draw.fMatrix = &SkMatrix::I();
    204     this->drawSprite(draw, *sprite, x, y, paint);
    205 }
    206 
    207 ///////////////////////////////////////////////////////////////////////////////
    208 
    209 void SkBitmapDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
    210     draw.drawPaint(paint);
    211 }
    212 
    213 void SkBitmapDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, size_t count,
    214                                 const SkPoint pts[], const SkPaint& paint) {
    215     CHECK_FOR_ANNOTATION(paint);
    216     draw.drawPoints(mode, count, pts, paint);
    217 }
    218 
    219 void SkBitmapDevice::drawRect(const SkDraw& draw, const SkRect& r, const SkPaint& paint) {
    220     CHECK_FOR_ANNOTATION(paint);
    221     draw.drawRect(r, paint);
    222 }
    223 
    224 void SkBitmapDevice::drawOval(const SkDraw& draw, const SkRect& oval, const SkPaint& paint) {
    225     CHECK_FOR_ANNOTATION(paint);
    226 
    227     SkPath path;
    228     path.addOval(oval);
    229     // call the VIRTUAL version, so any subclasses who do handle drawPath aren't
    230     // required to override drawOval.
    231     this->drawPath(draw, path, paint, NULL, true);
    232 }
    233 
    234 void SkBitmapDevice::drawRRect(const SkDraw& draw, const SkRRect& rrect, const SkPaint& paint) {
    235     CHECK_FOR_ANNOTATION(paint);
    236 
    237 #ifdef SK_IGNORE_BLURRED_RRECT_OPT
    238     SkPath  path;
    239 
    240     path.addRRect(rrect);
    241     // call the VIRTUAL version, so any subclasses who do handle drawPath aren't
    242     // required to override drawRRect.
    243     this->drawPath(draw, path, paint, NULL, true);
    244 #else
    245     draw.drawRRect(rrect, paint);
    246 #endif
    247 }
    248 
    249 void SkBitmapDevice::drawPath(const SkDraw& draw, const SkPath& path,
    250                               const SkPaint& paint, const SkMatrix* prePathMatrix,
    251                               bool pathIsMutable) {
    252     CHECK_FOR_ANNOTATION(paint);
    253     draw.drawPath(path, paint, prePathMatrix, pathIsMutable);
    254 }
    255 
    256 void SkBitmapDevice::drawBitmap(const SkDraw& draw, const SkBitmap& bitmap,
    257                                 const SkMatrix& matrix, const SkPaint& paint) {
    258     draw.drawBitmap(bitmap, matrix, paint);
    259 }
    260 
    261 void SkBitmapDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap,
    262                                     const SkRect* src, const SkRect& dst,
    263                                     const SkPaint& paint,
    264                                     SkCanvas::DrawBitmapRectFlags flags) {
    265     SkMatrix    matrix;
    266     SkRect      bitmapBounds, tmpSrc, tmpDst;
    267     SkBitmap    tmpBitmap;
    268 
    269     bitmapBounds.isetWH(bitmap.width(), bitmap.height());
    270 
    271     // Compute matrix from the two rectangles
    272     if (src) {
    273         tmpSrc = *src;
    274     } else {
    275         tmpSrc = bitmapBounds;
    276     }
    277     matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit);
    278 
    279     const SkRect* dstPtr = &dst;
    280     const SkBitmap* bitmapPtr = &bitmap;
    281 
    282     // clip the tmpSrc to the bounds of the bitmap, and recompute dstRect if
    283     // needed (if the src was clipped). No check needed if src==null.
    284     if (src) {
    285         if (!bitmapBounds.contains(*src)) {
    286             if (!tmpSrc.intersect(bitmapBounds)) {
    287                 return; // nothing to draw
    288             }
    289             // recompute dst, based on the smaller tmpSrc
    290             matrix.mapRect(&tmpDst, tmpSrc);
    291             dstPtr = &tmpDst;
    292         }
    293 
    294         // since we may need to clamp to the borders of the src rect within
    295         // the bitmap, we extract a subset.
    296         SkIRect srcIR;
    297         tmpSrc.roundOut(&srcIR);
    298         if (!bitmap.extractSubset(&tmpBitmap, srcIR)) {
    299             return;
    300         }
    301         bitmapPtr = &tmpBitmap;
    302 
    303         // Since we did an extract, we need to adjust the matrix accordingly
    304         SkScalar dx = 0, dy = 0;
    305         if (srcIR.fLeft > 0) {
    306             dx = SkIntToScalar(srcIR.fLeft);
    307         }
    308         if (srcIR.fTop > 0) {
    309             dy = SkIntToScalar(srcIR.fTop);
    310         }
    311         if (dx || dy) {
    312             matrix.preTranslate(dx, dy);
    313         }
    314 
    315         SkRect extractedBitmapBounds;
    316         extractedBitmapBounds.isetWH(bitmapPtr->width(), bitmapPtr->height());
    317         if (extractedBitmapBounds == tmpSrc) {
    318             // no fractional part in src, we can just call drawBitmap
    319             goto USE_DRAWBITMAP;
    320         }
    321     } else {
    322         USE_DRAWBITMAP:
    323         // We can go faster by just calling drawBitmap, which will concat the
    324         // matrix with the CTM, and try to call drawSprite if it can. If not,
    325         // it will make a shader and call drawRect, as we do below.
    326         this->drawBitmap(draw, *bitmapPtr, matrix, paint);
    327         return;
    328     }
    329 
    330     // construct a shader, so we can call drawRect with the dst
    331     SkShader* s = SkShader::CreateBitmapShader(*bitmapPtr,
    332                                                SkShader::kClamp_TileMode,
    333                                                SkShader::kClamp_TileMode);
    334     if (NULL == s) {
    335         return;
    336     }
    337     s->setLocalMatrix(matrix);
    338 
    339     SkPaint paintWithShader(paint);
    340     paintWithShader.setStyle(SkPaint::kFill_Style);
    341     paintWithShader.setShader(s)->unref();
    342 
    343     // Call ourself, in case the subclass wanted to share this setup code
    344     // but handle the drawRect code themselves.
    345     this->drawRect(draw, *dstPtr, paintWithShader);
    346 }
    347 
    348 void SkBitmapDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
    349                                 int x, int y, const SkPaint& paint) {
    350     draw.drawSprite(bitmap, x, y, paint);
    351 }
    352 
    353 void SkBitmapDevice::drawText(const SkDraw& draw, const void* text, size_t len,
    354                               SkScalar x, SkScalar y, const SkPaint& paint) {
    355     draw.drawText((const char*)text, len, x, y, paint);
    356 }
    357 
    358 void SkBitmapDevice::drawPosText(const SkDraw& draw, const void* text, size_t len,
    359                                  const SkScalar xpos[], SkScalar y,
    360                                  int scalarsPerPos, const SkPaint& paint) {
    361     draw.drawPosText((const char*)text, len, xpos, y, scalarsPerPos, paint);
    362 }
    363 
    364 void SkBitmapDevice::drawTextOnPath(const SkDraw& draw, const void* text,
    365                                     size_t len, const SkPath& path,
    366                                     const SkMatrix* matrix,
    367                                     const SkPaint& paint) {
    368     draw.drawTextOnPath((const char*)text, len, path, matrix, paint);
    369 }
    370 
    371 void SkBitmapDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
    372                                   int vertexCount,
    373                                   const SkPoint verts[], const SkPoint textures[],
    374                                   const SkColor colors[], SkXfermode* xmode,
    375                                   const uint16_t indices[], int indexCount,
    376                                   const SkPaint& paint) {
    377     draw.drawVertices(vmode, vertexCount, verts, textures, colors, xmode,
    378                       indices, indexCount, paint);
    379 }
    380 
    381 void SkBitmapDevice::drawDevice(const SkDraw& draw, SkBaseDevice* device,
    382                                 int x, int y, const SkPaint& paint) {
    383     const SkBitmap& src = device->accessBitmap(false);
    384     draw.drawSprite(src, x, y, paint);
    385 }
    386 
    387 ///////////////////////////////////////////////////////////////////////////////
    388 
    389 bool SkBitmapDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) {
    390     if (!paint.isLCDRenderText() || !paint.isAntiAlias()) {
    391         // we're cool with the paint as is
    392         return false;
    393     }
    394 
    395     if (SkBitmap::kARGB_8888_Config != fBitmap.config() ||
    396         paint.getRasterizer() ||
    397         paint.getPathEffect() ||
    398         paint.isFakeBoldText() ||
    399         paint.getStyle() != SkPaint::kFill_Style ||
    400         !SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrcOver_Mode)) {
    401         // turn off lcd
    402         flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag;
    403         flags->fHinting = paint.getHinting();
    404         return true;
    405     }
    406     // we're cool with the paint as is
    407     return false;
    408 }
    409