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 #include "SkSurface.h"
     14 
     15 #define CHECK_FOR_ANNOTATION(paint) \
     16     do { if (paint.getAnnotation()) { return; } } while (0)
     17 
     18 static bool valid_for_bitmap_device(const SkImageInfo& info,
     19                                     SkAlphaType* newAlphaType) {
     20     if (info.width() < 0 || info.height() < 0) {
     21         return false;
     22     }
     23 
     24     // TODO: can we stop supporting kUnknown in SkBitmkapDevice?
     25     if (kUnknown_SkColorType == info.colorType()) {
     26         if (newAlphaType) {
     27             *newAlphaType = kIgnore_SkAlphaType;
     28         }
     29         return true;
     30     }
     31 
     32     switch (info.alphaType()) {
     33         case kPremul_SkAlphaType:
     34         case kOpaque_SkAlphaType:
     35             break;
     36         default:
     37             return false;
     38     }
     39 
     40     SkAlphaType canonicalAlphaType = info.alphaType();
     41 
     42     switch (info.colorType()) {
     43         case kAlpha_8_SkColorType:
     44             break;
     45         case kRGB_565_SkColorType:
     46             canonicalAlphaType = kOpaque_SkAlphaType;
     47             break;
     48         case kN32_SkColorType:
     49             break;
     50         default:
     51             return false;
     52     }
     53 
     54     if (newAlphaType) {
     55         *newAlphaType = canonicalAlphaType;
     56     }
     57     return true;
     58 }
     59 
     60 SkBitmapDevice::SkBitmapDevice(const SkBitmap& bitmap) : fBitmap(bitmap) {
     61     SkASSERT(valid_for_bitmap_device(bitmap.info(), NULL));
     62 }
     63 
     64 SkBitmapDevice::SkBitmapDevice(const SkBitmap& bitmap, const SkDeviceProperties& deviceProperties)
     65     : SkBaseDevice(deviceProperties)
     66     , fBitmap(bitmap)
     67 {
     68     SkASSERT(valid_for_bitmap_device(bitmap.info(), NULL));
     69 }
     70 
     71 SkBitmapDevice* SkBitmapDevice::Create(const SkImageInfo& origInfo,
     72                                        const SkDeviceProperties* props) {
     73     SkImageInfo info = origInfo;
     74     if (!valid_for_bitmap_device(info, &info.fAlphaType)) {
     75         return NULL;
     76     }
     77 
     78     SkBitmap bitmap;
     79 
     80     if (kUnknown_SkColorType == info.colorType()) {
     81         if (!bitmap.setInfo(info)) {
     82             return NULL;
     83         }
     84     } else {
     85         if (!bitmap.allocPixels(info)) {
     86             return NULL;
     87         }
     88         if (!bitmap.info().isOpaque()) {
     89             bitmap.eraseColor(SK_ColorTRANSPARENT);
     90         }
     91     }
     92 
     93     if (props) {
     94         return SkNEW_ARGS(SkBitmapDevice, (bitmap, *props));
     95     } else {
     96         return SkNEW_ARGS(SkBitmapDevice, (bitmap));
     97     }
     98 }
     99 
    100 SkImageInfo SkBitmapDevice::imageInfo() const {
    101     return fBitmap.info();
    102 }
    103 
    104 void SkBitmapDevice::replaceBitmapBackendForRasterSurface(const SkBitmap& bm) {
    105     SkASSERT(bm.width() == fBitmap.width());
    106     SkASSERT(bm.height() == fBitmap.height());
    107     fBitmap = bm;   // intent is to use bm's pixelRef (and rowbytes/config)
    108     fBitmap.lockPixels();
    109 }
    110 
    111 SkBaseDevice* SkBitmapDevice::onCreateDevice(const SkImageInfo& info, Usage usage) {
    112     return SkBitmapDevice::Create(info, &this->getDeviceProperties());
    113 }
    114 
    115 void SkBitmapDevice::lockPixels() {
    116     if (fBitmap.lockPixelsAreWritable()) {
    117         fBitmap.lockPixels();
    118     }
    119 }
    120 
    121 void SkBitmapDevice::unlockPixels() {
    122     if (fBitmap.lockPixelsAreWritable()) {
    123         fBitmap.unlockPixels();
    124     }
    125 }
    126 
    127 void SkBitmapDevice::clear(SkColor color) {
    128     fBitmap.eraseColor(color);
    129 }
    130 
    131 const SkBitmap& SkBitmapDevice::onAccessBitmap() {
    132     return fBitmap;
    133 }
    134 
    135 bool SkBitmapDevice::canHandleImageFilter(const SkImageFilter*) {
    136     return false;
    137 }
    138 
    139 bool SkBitmapDevice::filterImage(const SkImageFilter* filter, const SkBitmap& src,
    140                                  const SkImageFilter::Context& ctx, SkBitmap* result,
    141                                  SkIPoint* offset) {
    142     return false;
    143 }
    144 
    145 bool SkBitmapDevice::allowImageFilter(const SkImageFilter*) {
    146     return true;
    147 }
    148 
    149 void* SkBitmapDevice::onAccessPixels(SkImageInfo* info, size_t* rowBytes) {
    150     if (fBitmap.getPixels()) {
    151         *info = fBitmap.info();
    152         *rowBytes = fBitmap.rowBytes();
    153         return fBitmap.getPixels();
    154     }
    155     return NULL;
    156 }
    157 
    158 static void rect_memcpy(void* dst, size_t dstRB, const void* src, size_t srcRB, size_t bytesPerRow,
    159                         int rowCount) {
    160     SkASSERT(bytesPerRow <= srcRB);
    161     SkASSERT(bytesPerRow <= dstRB);
    162     for (int i = 0; i < rowCount; ++i) {
    163         memcpy(dst, src, bytesPerRow);
    164         dst = (char*)dst + dstRB;
    165         src = (const char*)src + srcRB;
    166     }
    167 }
    168 
    169 #include "SkConfig8888.h"
    170 
    171 static bool copy_pixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
    172                         const SkImageInfo& srcInfo, const void* srcPixels, size_t srcRowBytes) {
    173     if (srcInfo.dimensions() != dstInfo.dimensions()) {
    174         return false;
    175     }
    176     if (4 == srcInfo.bytesPerPixel() && 4 == dstInfo.bytesPerPixel()) {
    177         SkDstPixelInfo dstPI;
    178         dstPI.fColorType = dstInfo.colorType();
    179         dstPI.fAlphaType = dstInfo.alphaType();
    180         dstPI.fPixels = dstPixels;
    181         dstPI.fRowBytes = dstRowBytes;
    182 
    183         SkSrcPixelInfo srcPI;
    184         srcPI.fColorType = srcInfo.colorType();
    185         srcPI.fAlphaType = srcInfo.alphaType();
    186         srcPI.fPixels = srcPixels;
    187         srcPI.fRowBytes = srcRowBytes;
    188 
    189         return srcPI.convertPixelsTo(&dstPI, srcInfo.width(), srcInfo.height());
    190     }
    191     if (srcInfo.colorType() == dstInfo.colorType()) {
    192         switch (srcInfo.colorType()) {
    193             case kRGB_565_SkColorType:
    194             case kAlpha_8_SkColorType:
    195                 break;
    196             case kARGB_4444_SkColorType:
    197                 if (srcInfo.alphaType() != dstInfo.alphaType()) {
    198                     return false;
    199                 }
    200                 break;
    201             default:
    202                 return false;
    203         }
    204         rect_memcpy(dstPixels, dstRowBytes, srcPixels, srcRowBytes,
    205                     srcInfo.width() * srcInfo.bytesPerPixel(), srcInfo.height());
    206     }
    207     // TODO: add support for more conversions as needed
    208     return false;
    209 }
    210 
    211 bool SkBitmapDevice::onWritePixels(const SkImageInfo& srcInfo, const void* srcPixels,
    212                                    size_t srcRowBytes, int x, int y) {
    213     // since we don't stop creating un-pixeled devices yet, check for no pixels here
    214     if (NULL == fBitmap.getPixels()) {
    215         return false;
    216     }
    217 
    218     SkImageInfo dstInfo = fBitmap.info();
    219     dstInfo.fWidth = srcInfo.width();
    220     dstInfo.fHeight = srcInfo.height();
    221 
    222     void* dstPixels = fBitmap.getAddr(x, y);
    223     size_t dstRowBytes = fBitmap.rowBytes();
    224 
    225     if (copy_pixels(dstInfo, dstPixels, dstRowBytes, srcInfo, srcPixels, srcRowBytes)) {
    226         fBitmap.notifyPixelsChanged();
    227         return true;
    228     }
    229     return false;
    230 }
    231 
    232 bool SkBitmapDevice::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
    233                                   int x, int y) {
    234     // since we don't stop creating un-pixeled devices yet, check for no pixels here
    235     if (NULL == fBitmap.getPixels()) {
    236         return false;
    237     }
    238 
    239     SkImageInfo srcInfo = fBitmap.info();
    240 
    241     // perhaps can relax these in the future
    242     if (4 != dstInfo.bytesPerPixel()) {
    243         return false;
    244     }
    245     if (4 != srcInfo.bytesPerPixel()) {
    246         return false;
    247     }
    248 
    249     srcInfo.fWidth = dstInfo.width();
    250     srcInfo.fHeight = dstInfo.height();
    251 
    252     const void* srcPixels = fBitmap.getAddr(x, y);
    253     const size_t srcRowBytes = fBitmap.rowBytes();
    254 
    255     return copy_pixels(dstInfo, dstPixels, dstRowBytes, srcInfo, srcPixels, srcRowBytes);
    256 }
    257 
    258 ///////////////////////////////////////////////////////////////////////////////
    259 
    260 void SkBitmapDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
    261     draw.drawPaint(paint);
    262 }
    263 
    264 void SkBitmapDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, size_t count,
    265                                 const SkPoint pts[], const SkPaint& paint) {
    266     CHECK_FOR_ANNOTATION(paint);
    267     draw.drawPoints(mode, count, pts, paint);
    268 }
    269 
    270 void SkBitmapDevice::drawRect(const SkDraw& draw, const SkRect& r, const SkPaint& paint) {
    271     CHECK_FOR_ANNOTATION(paint);
    272     draw.drawRect(r, paint);
    273 }
    274 
    275 void SkBitmapDevice::drawOval(const SkDraw& draw, const SkRect& oval, const SkPaint& paint) {
    276     CHECK_FOR_ANNOTATION(paint);
    277 
    278     SkPath path;
    279     path.addOval(oval);
    280     // call the VIRTUAL version, so any subclasses who do handle drawPath aren't
    281     // required to override drawOval.
    282     this->drawPath(draw, path, paint, NULL, true);
    283 }
    284 
    285 void SkBitmapDevice::drawRRect(const SkDraw& draw, const SkRRect& rrect, const SkPaint& paint) {
    286     CHECK_FOR_ANNOTATION(paint);
    287 
    288 #ifdef SK_IGNORE_BLURRED_RRECT_OPT
    289     SkPath  path;
    290 
    291     path.addRRect(rrect);
    292     // call the VIRTUAL version, so any subclasses who do handle drawPath aren't
    293     // required to override drawRRect.
    294     this->drawPath(draw, path, paint, NULL, true);
    295 #else
    296     draw.drawRRect(rrect, paint);
    297 #endif
    298 }
    299 
    300 void SkBitmapDevice::drawPath(const SkDraw& draw, const SkPath& path,
    301                               const SkPaint& paint, const SkMatrix* prePathMatrix,
    302                               bool pathIsMutable) {
    303     CHECK_FOR_ANNOTATION(paint);
    304     draw.drawPath(path, paint, prePathMatrix, pathIsMutable);
    305 }
    306 
    307 void SkBitmapDevice::drawBitmap(const SkDraw& draw, const SkBitmap& bitmap,
    308                                 const SkMatrix& matrix, const SkPaint& paint) {
    309     draw.drawBitmap(bitmap, matrix, paint);
    310 }
    311 
    312 void SkBitmapDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap,
    313                                     const SkRect* src, const SkRect& dst,
    314                                     const SkPaint& paint,
    315                                     SkCanvas::DrawBitmapRectFlags flags) {
    316     SkMatrix    matrix;
    317     SkRect      bitmapBounds, tmpSrc, tmpDst;
    318     SkBitmap    tmpBitmap;
    319 
    320     bitmapBounds.isetWH(bitmap.width(), bitmap.height());
    321 
    322     // Compute matrix from the two rectangles
    323     if (src) {
    324         tmpSrc = *src;
    325     } else {
    326         tmpSrc = bitmapBounds;
    327     }
    328     matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit);
    329 
    330     const SkRect* dstPtr = &dst;
    331     const SkBitmap* bitmapPtr = &bitmap;
    332 
    333     // clip the tmpSrc to the bounds of the bitmap, and recompute dstRect if
    334     // needed (if the src was clipped). No check needed if src==null.
    335     if (src) {
    336         if (!bitmapBounds.contains(*src)) {
    337             if (!tmpSrc.intersect(bitmapBounds)) {
    338                 return; // nothing to draw
    339             }
    340             // recompute dst, based on the smaller tmpSrc
    341             matrix.mapRect(&tmpDst, tmpSrc);
    342             dstPtr = &tmpDst;
    343         }
    344 
    345         // since we may need to clamp to the borders of the src rect within
    346         // the bitmap, we extract a subset.
    347         SkIRect srcIR;
    348         tmpSrc.roundOut(&srcIR);
    349         if (!bitmap.extractSubset(&tmpBitmap, srcIR)) {
    350             return;
    351         }
    352         bitmapPtr = &tmpBitmap;
    353 
    354         // Since we did an extract, we need to adjust the matrix accordingly
    355         SkScalar dx = 0, dy = 0;
    356         if (srcIR.fLeft > 0) {
    357             dx = SkIntToScalar(srcIR.fLeft);
    358         }
    359         if (srcIR.fTop > 0) {
    360             dy = SkIntToScalar(srcIR.fTop);
    361         }
    362         if (dx || dy) {
    363             matrix.preTranslate(dx, dy);
    364         }
    365 
    366         SkRect extractedBitmapBounds;
    367         extractedBitmapBounds.isetWH(bitmapPtr->width(), bitmapPtr->height());
    368         if (extractedBitmapBounds == tmpSrc) {
    369             // no fractional part in src, we can just call drawBitmap
    370             goto USE_DRAWBITMAP;
    371         }
    372     } else {
    373         USE_DRAWBITMAP:
    374         // We can go faster by just calling drawBitmap, which will concat the
    375         // matrix with the CTM, and try to call drawSprite if it can. If not,
    376         // it will make a shader and call drawRect, as we do below.
    377         this->drawBitmap(draw, *bitmapPtr, matrix, paint);
    378         return;
    379     }
    380 
    381     // construct a shader, so we can call drawRect with the dst
    382     SkShader* s = SkShader::CreateBitmapShader(*bitmapPtr,
    383                                                SkShader::kClamp_TileMode,
    384                                                SkShader::kClamp_TileMode,
    385                                                &matrix);
    386     if (NULL == s) {
    387         return;
    388     }
    389 
    390     SkPaint paintWithShader(paint);
    391     paintWithShader.setStyle(SkPaint::kFill_Style);
    392     paintWithShader.setShader(s)->unref();
    393 
    394     // Call ourself, in case the subclass wanted to share this setup code
    395     // but handle the drawRect code themselves.
    396     this->drawRect(draw, *dstPtr, paintWithShader);
    397 }
    398 
    399 void SkBitmapDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
    400                                 int x, int y, const SkPaint& paint) {
    401     draw.drawSprite(bitmap, x, y, paint);
    402 }
    403 
    404 void SkBitmapDevice::drawText(const SkDraw& draw, const void* text, size_t len,
    405                               SkScalar x, SkScalar y, const SkPaint& paint) {
    406     draw.drawText((const char*)text, len, x, y, paint);
    407 }
    408 
    409 void SkBitmapDevice::drawPosText(const SkDraw& draw, const void* text, size_t len,
    410                                  const SkScalar xpos[], SkScalar y,
    411                                  int scalarsPerPos, const SkPaint& paint) {
    412     draw.drawPosText((const char*)text, len, xpos, y, scalarsPerPos, paint);
    413 }
    414 
    415 void SkBitmapDevice::drawTextOnPath(const SkDraw& draw, const void* text,
    416                                     size_t len, const SkPath& path,
    417                                     const SkMatrix* matrix,
    418                                     const SkPaint& paint) {
    419     draw.drawTextOnPath((const char*)text, len, path, matrix, paint);
    420 }
    421 
    422 void SkBitmapDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
    423                                   int vertexCount,
    424                                   const SkPoint verts[], const SkPoint textures[],
    425                                   const SkColor colors[], SkXfermode* xmode,
    426                                   const uint16_t indices[], int indexCount,
    427                                   const SkPaint& paint) {
    428     draw.drawVertices(vmode, vertexCount, verts, textures, colors, xmode,
    429                       indices, indexCount, paint);
    430 }
    431 
    432 void SkBitmapDevice::drawDevice(const SkDraw& draw, SkBaseDevice* device,
    433                                 int x, int y, const SkPaint& paint) {
    434     const SkBitmap& src = device->accessBitmap(false);
    435     draw.drawSprite(src, x, y, paint);
    436 }
    437 
    438 SkSurface* SkBitmapDevice::newSurface(const SkImageInfo& info) {
    439     return SkSurface::NewRaster(info);
    440 }
    441 
    442 const void* SkBitmapDevice::peekPixels(SkImageInfo* info, size_t* rowBytes) {
    443     const SkImageInfo bmInfo = fBitmap.info();
    444     if (fBitmap.getPixels() && (kUnknown_SkColorType != bmInfo.colorType())) {
    445         if (info) {
    446             *info = bmInfo;
    447         }
    448         if (rowBytes) {
    449             *rowBytes = fBitmap.rowBytes();
    450         }
    451         return fBitmap.getPixels();
    452     }
    453     return NULL;
    454 }
    455 
    456 ///////////////////////////////////////////////////////////////////////////////
    457 
    458 bool SkBitmapDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) {
    459     if (!paint.isLCDRenderText() || !paint.isAntiAlias()) {
    460         // we're cool with the paint as is
    461         return false;
    462     }
    463 
    464     if (kN32_SkColorType != fBitmap.colorType() ||
    465         paint.getRasterizer() ||
    466         paint.getPathEffect() ||
    467         paint.isFakeBoldText() ||
    468         paint.getStyle() != SkPaint::kFill_Style ||
    469         !SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrcOver_Mode)) {
    470         // turn off lcd
    471         flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag;
    472         flags->fHinting = paint.getHinting();
    473         return true;
    474     }
    475     // we're cool with the paint as is
    476     return false;
    477 }
    478