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 #if 0
     65 SkBitmapDevice::SkBitmapDevice(const SkBitmap& bitmap, const SkDeviceProperties& deviceProperties)
     66     : SkBaseDevice(deviceProperties)
     67     , fBitmap(bitmap)
     68 {
     69     SkASSERT(valid_for_bitmap_device(bitmap.info(), NULL));
     70 }
     71 #endif
     72 
     73 SkBitmapDevice* SkBitmapDevice::Create(const SkImageInfo& origInfo,
     74                                        const SkDeviceProperties* props) {
     75     SkAlphaType newAT = origInfo.alphaType();
     76     if (!valid_for_bitmap_device(origInfo, &newAT)) {
     77         return NULL;
     78     }
     79 
     80     const SkImageInfo info = origInfo.makeAlphaType(newAT);
     81     SkBitmap bitmap;
     82 
     83     if (kUnknown_SkColorType == info.colorType()) {
     84         if (!bitmap.setInfo(info)) {
     85             return NULL;
     86         }
     87     } else {
     88         if (!bitmap.tryAllocPixels(info)) {
     89             return NULL;
     90         }
     91         if (!bitmap.info().isOpaque()) {
     92             bitmap.eraseColor(SK_ColorTRANSPARENT);
     93         }
     94     }
     95 
     96     if (props && false) {
     97 //        return SkNEW_ARGS(SkBitmapDevice, (bitmap, *props));
     98     } else {
     99         return SkNEW_ARGS(SkBitmapDevice, (bitmap));
    100     }
    101 }
    102 
    103 SkImageInfo SkBitmapDevice::imageInfo() const {
    104     return fBitmap.info();
    105 }
    106 
    107 void SkBitmapDevice::replaceBitmapBackendForRasterSurface(const SkBitmap& bm) {
    108     SkASSERT(bm.width() == fBitmap.width());
    109     SkASSERT(bm.height() == fBitmap.height());
    110     fBitmap = bm;   // intent is to use bm's pixelRef (and rowbytes/config)
    111     fBitmap.lockPixels();
    112 }
    113 
    114 SkBaseDevice* SkBitmapDevice::onCreateDevice(const SkImageInfo& info, Usage usage) {
    115     return SkBitmapDevice::Create(info);// &this->getDeviceProperties());
    116 }
    117 
    118 void SkBitmapDevice::lockPixels() {
    119     if (fBitmap.lockPixelsAreWritable()) {
    120         fBitmap.lockPixels();
    121     }
    122 }
    123 
    124 void SkBitmapDevice::unlockPixels() {
    125     if (fBitmap.lockPixelsAreWritable()) {
    126         fBitmap.unlockPixels();
    127     }
    128 }
    129 
    130 void SkBitmapDevice::clear(SkColor color) {
    131     fBitmap.eraseColor(color);
    132 }
    133 
    134 const SkBitmap& SkBitmapDevice::onAccessBitmap() {
    135     return fBitmap;
    136 }
    137 
    138 void* SkBitmapDevice::onAccessPixels(SkImageInfo* info, size_t* rowBytes) {
    139     if (fBitmap.getPixels()) {
    140         *info = fBitmap.info();
    141         *rowBytes = fBitmap.rowBytes();
    142         return fBitmap.getPixels();
    143     }
    144     return NULL;
    145 }
    146 
    147 #include "SkConfig8888.h"
    148 #include "SkPixelRef.h"
    149 
    150 bool SkBitmapDevice::onWritePixels(const SkImageInfo& srcInfo, const void* srcPixels,
    151                                    size_t srcRowBytes, int x, int y) {
    152     // since we don't stop creating un-pixeled devices yet, check for no pixels here
    153     if (NULL == fBitmap.getPixels()) {
    154         return false;
    155     }
    156 
    157     const SkImageInfo dstInfo = fBitmap.info().makeWH(srcInfo.width(), srcInfo.height());
    158 
    159     void* dstPixels = fBitmap.getAddr(x, y);
    160     size_t dstRowBytes = fBitmap.rowBytes();
    161 
    162     if (SkPixelInfo::CopyPixels(dstInfo, dstPixels, dstRowBytes, srcInfo, srcPixels, srcRowBytes)) {
    163         fBitmap.notifyPixelsChanged();
    164         return true;
    165     }
    166     return false;
    167 }
    168 
    169 bool SkBitmapDevice::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
    170                                   int x, int y) {
    171     return fBitmap.readPixels(dstInfo, dstPixels, dstRowBytes, x, y);
    172 }
    173 
    174 ///////////////////////////////////////////////////////////////////////////////
    175 
    176 void SkBitmapDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
    177     draw.drawPaint(paint);
    178 }
    179 
    180 void SkBitmapDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, size_t count,
    181                                 const SkPoint pts[], const SkPaint& paint) {
    182     CHECK_FOR_ANNOTATION(paint);
    183     draw.drawPoints(mode, count, pts, paint);
    184 }
    185 
    186 void SkBitmapDevice::drawRect(const SkDraw& draw, const SkRect& r, const SkPaint& paint) {
    187     CHECK_FOR_ANNOTATION(paint);
    188     draw.drawRect(r, paint);
    189 }
    190 
    191 void SkBitmapDevice::drawOval(const SkDraw& draw, const SkRect& oval, const SkPaint& paint) {
    192     CHECK_FOR_ANNOTATION(paint);
    193 
    194     SkPath path;
    195     path.addOval(oval);
    196     // call the VIRTUAL version, so any subclasses who do handle drawPath aren't
    197     // required to override drawOval.
    198     this->drawPath(draw, path, paint, NULL, true);
    199 }
    200 
    201 void SkBitmapDevice::drawRRect(const SkDraw& draw, const SkRRect& rrect, const SkPaint& paint) {
    202     CHECK_FOR_ANNOTATION(paint);
    203 
    204 #ifdef SK_IGNORE_BLURRED_RRECT_OPT
    205     SkPath  path;
    206 
    207     path.addRRect(rrect);
    208     // call the VIRTUAL version, so any subclasses who do handle drawPath aren't
    209     // required to override drawRRect.
    210     this->drawPath(draw, path, paint, NULL, true);
    211 #else
    212     draw.drawRRect(rrect, paint);
    213 #endif
    214 }
    215 
    216 void SkBitmapDevice::drawPath(const SkDraw& draw, const SkPath& path,
    217                               const SkPaint& paint, const SkMatrix* prePathMatrix,
    218                               bool pathIsMutable) {
    219     CHECK_FOR_ANNOTATION(paint);
    220     draw.drawPath(path, paint, prePathMatrix, pathIsMutable);
    221 }
    222 
    223 void SkBitmapDevice::drawBitmap(const SkDraw& draw, const SkBitmap& bitmap,
    224                                 const SkMatrix& matrix, const SkPaint& paint) {
    225     draw.drawBitmap(bitmap, matrix, paint);
    226 }
    227 
    228 void SkBitmapDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap,
    229                                     const SkRect* src, const SkRect& dst,
    230                                     const SkPaint& paint,
    231                                     SkCanvas::DrawBitmapRectFlags flags) {
    232     SkMatrix    matrix;
    233     SkRect      bitmapBounds, tmpSrc, tmpDst;
    234     SkBitmap    tmpBitmap;
    235 
    236     bitmapBounds.isetWH(bitmap.width(), bitmap.height());
    237 
    238     // Compute matrix from the two rectangles
    239     if (src) {
    240         tmpSrc = *src;
    241     } else {
    242         tmpSrc = bitmapBounds;
    243     }
    244     matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit);
    245 
    246     const SkRect* dstPtr = &dst;
    247     const SkBitmap* bitmapPtr = &bitmap;
    248 
    249     // clip the tmpSrc to the bounds of the bitmap, and recompute dstRect if
    250     // needed (if the src was clipped). No check needed if src==null.
    251     if (src) {
    252         if (!bitmapBounds.contains(*src)) {
    253             if (!tmpSrc.intersect(bitmapBounds)) {
    254                 return; // nothing to draw
    255             }
    256             // recompute dst, based on the smaller tmpSrc
    257             matrix.mapRect(&tmpDst, tmpSrc);
    258             dstPtr = &tmpDst;
    259         }
    260 
    261         // since we may need to clamp to the borders of the src rect within
    262         // the bitmap, we extract a subset.
    263         SkIRect srcIR;
    264         tmpSrc.roundOut(&srcIR);
    265         if(bitmap.pixelRef()->getTexture()) {
    266             // Accelerated source canvas, don't use extractSubset but readPixels to get the subset.
    267             // This way, the pixels are copied in CPU memory instead of GPU memory.
    268             bitmap.pixelRef()->readPixels(&tmpBitmap, &srcIR);
    269         } else {
    270             if (!bitmap.extractSubset(&tmpBitmap, srcIR)) {
    271                 return;
    272             }
    273         }
    274         bitmapPtr = &tmpBitmap;
    275 
    276         // Since we did an extract, we need to adjust the matrix accordingly
    277         SkScalar dx = 0, dy = 0;
    278         if (srcIR.fLeft > 0) {
    279             dx = SkIntToScalar(srcIR.fLeft);
    280         }
    281         if (srcIR.fTop > 0) {
    282             dy = SkIntToScalar(srcIR.fTop);
    283         }
    284         if (dx || dy) {
    285             matrix.preTranslate(dx, dy);
    286         }
    287 
    288         SkRect extractedBitmapBounds;
    289         extractedBitmapBounds.isetWH(bitmapPtr->width(), bitmapPtr->height());
    290         if (extractedBitmapBounds == tmpSrc) {
    291             // no fractional part in src, we can just call drawBitmap
    292             goto USE_DRAWBITMAP;
    293         }
    294     } else {
    295         USE_DRAWBITMAP:
    296         // We can go faster by just calling drawBitmap, which will concat the
    297         // matrix with the CTM, and try to call drawSprite if it can. If not,
    298         // it will make a shader and call drawRect, as we do below.
    299         this->drawBitmap(draw, *bitmapPtr, matrix, paint);
    300         return;
    301     }
    302 
    303     // construct a shader, so we can call drawRect with the dst
    304     SkShader* s = SkShader::CreateBitmapShader(*bitmapPtr,
    305                                                SkShader::kClamp_TileMode,
    306                                                SkShader::kClamp_TileMode,
    307                                                &matrix);
    308     if (NULL == s) {
    309         return;
    310     }
    311 
    312     SkPaint paintWithShader(paint);
    313     paintWithShader.setStyle(SkPaint::kFill_Style);
    314     paintWithShader.setShader(s)->unref();
    315 
    316     // Call ourself, in case the subclass wanted to share this setup code
    317     // but handle the drawRect code themselves.
    318     this->drawRect(draw, *dstPtr, paintWithShader);
    319 }
    320 
    321 void SkBitmapDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
    322                                 int x, int y, const SkPaint& paint) {
    323     draw.drawSprite(bitmap, x, y, paint);
    324 }
    325 
    326 void SkBitmapDevice::drawText(const SkDraw& draw, const void* text, size_t len,
    327                               SkScalar x, SkScalar y, const SkPaint& paint) {
    328     draw.drawText((const char*)text, len, x, y, paint);
    329 }
    330 
    331 void SkBitmapDevice::drawPosText(const SkDraw& draw, const void* text, size_t len,
    332                                  const SkScalar xpos[], SkScalar y,
    333                                  int scalarsPerPos, const SkPaint& paint) {
    334     draw.drawPosText((const char*)text, len, xpos, y, scalarsPerPos, paint);
    335 }
    336 
    337 void SkBitmapDevice::drawTextOnPath(const SkDraw& draw, const void* text,
    338                                     size_t len, const SkPath& path,
    339                                     const SkMatrix* matrix,
    340                                     const SkPaint& paint) {
    341     draw.drawTextOnPath((const char*)text, len, path, matrix, paint);
    342 }
    343 
    344 void SkBitmapDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
    345                                   int vertexCount,
    346                                   const SkPoint verts[], const SkPoint textures[],
    347                                   const SkColor colors[], SkXfermode* xmode,
    348                                   const uint16_t indices[], int indexCount,
    349                                   const SkPaint& paint) {
    350     draw.drawVertices(vmode, vertexCount, verts, textures, colors, xmode,
    351                       indices, indexCount, paint);
    352 }
    353 
    354 void SkBitmapDevice::drawDevice(const SkDraw& draw, SkBaseDevice* device,
    355                                 int x, int y, const SkPaint& paint) {
    356     const SkBitmap& src = device->accessBitmap(false);
    357     draw.drawSprite(src, x, y, paint);
    358 }
    359 
    360 SkSurface* SkBitmapDevice::newSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
    361     return SkSurface::NewRaster(info, &props);
    362 }
    363 
    364 const void* SkBitmapDevice::peekPixels(SkImageInfo* info, size_t* rowBytes) {
    365     const SkImageInfo bmInfo = fBitmap.info();
    366     if (fBitmap.getPixels() && (kUnknown_SkColorType != bmInfo.colorType())) {
    367         if (info) {
    368             *info = bmInfo;
    369         }
    370         if (rowBytes) {
    371             *rowBytes = fBitmap.rowBytes();
    372         }
    373         return fBitmap.getPixels();
    374     }
    375     return NULL;
    376 }
    377 
    378 SkImageFilter::Cache* SkBitmapDevice::getImageFilterCache() {
    379     SkImageFilter::Cache* cache = SkImageFilter::Cache::Get();
    380     cache->ref();
    381     return cache;
    382 }
    383 
    384 ///////////////////////////////////////////////////////////////////////////////
    385 
    386 bool SkBitmapDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) {
    387     if (!paint.isLCDRenderText() || !paint.isAntiAlias()) {
    388         // we're cool with the paint as is
    389         return false;
    390     }
    391 
    392     if (kN32_SkColorType != fBitmap.colorType() ||
    393         paint.getRasterizer() ||
    394         paint.getPathEffect() ||
    395         paint.isFakeBoldText() ||
    396         paint.getStyle() != SkPaint::kFill_Style ||
    397         !SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrcOver_Mode)) {
    398         // turn off lcd, but turn on kGenA8
    399         flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag;
    400         flags->fFlags |= SkPaint::kGenA8FromLCD_Flag;
    401         return true;
    402     }
    403     // we're cool with the paint as is
    404     return false;
    405 }
    406