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