Home | History | Annotate | Download | only in core
      1 
      2 /*
      3  * Copyright 2011 Google Inc.
      4  *
      5  * Use of this source code is governed by a BSD-style license that can be
      6  * found in the LICENSE file.
      7  */
      8 #include "SkDevice.h"
      9 #include "SkDeviceProperties.h"
     10 #include "SkDraw.h"
     11 #include "SkImageFilter.h"
     12 #include "SkMetaData.h"
     13 #include "SkRasterClip.h"
     14 #include "SkRect.h"
     15 #include "SkRRect.h"
     16 #include "SkShader.h"
     17 
     18 SK_DEFINE_INST_COUNT(SkDevice)
     19 
     20 ///////////////////////////////////////////////////////////////////////////////
     21 
     22 #define CHECK_FOR_NODRAW_ANNOTATION(paint) \
     23     do { if (paint.isNoDrawAnnotation()) { return; } } while (0)
     24 
     25 ///////////////////////////////////////////////////////////////////////////////
     26 
     27 SkDevice::SkDevice(const SkBitmap& bitmap)
     28     : fBitmap(bitmap), fLeakyProperties(SkDeviceProperties::MakeDefault())
     29 #ifdef SK_DEBUG
     30     , fAttachedToCanvas(false)
     31 #endif
     32 {
     33     fOrigin.setZero();
     34     fMetaData = NULL;
     35 
     36     SkASSERT(SkBitmap::kARGB_4444_Config != bitmap.config());
     37 }
     38 
     39 SkDevice::SkDevice(const SkBitmap& bitmap, const SkDeviceProperties& deviceProperties)
     40     : fBitmap(bitmap), fLeakyProperties(deviceProperties)
     41 #ifdef SK_DEBUG
     42     , fAttachedToCanvas(false)
     43 #endif
     44 {
     45     fOrigin.setZero();
     46     fMetaData = NULL;
     47 }
     48 
     49 SkDevice::SkDevice(SkBitmap::Config config, int width, int height, bool isOpaque)
     50     : fLeakyProperties(SkDeviceProperties::MakeDefault())
     51 #ifdef SK_DEBUG
     52     , fAttachedToCanvas(false)
     53 #endif
     54 {
     55     fOrigin.setZero();
     56     fMetaData = NULL;
     57 
     58     fBitmap.setConfig(config, width, height);
     59     fBitmap.allocPixels();
     60     fBitmap.setIsOpaque(isOpaque);
     61     if (!isOpaque) {
     62         fBitmap.eraseColor(SK_ColorTRANSPARENT);
     63     }
     64 }
     65 
     66 SkDevice::SkDevice(SkBitmap::Config config, int width, int height, bool isOpaque,
     67                    const SkDeviceProperties& deviceProperties)
     68     : fLeakyProperties(deviceProperties)
     69 #ifdef SK_DEBUG
     70     , fAttachedToCanvas(false)
     71 #endif
     72 {
     73     fOrigin.setZero();
     74     fMetaData = NULL;
     75 
     76     fBitmap.setConfig(config, width, height);
     77     fBitmap.allocPixels();
     78     fBitmap.setIsOpaque(isOpaque);
     79     if (!isOpaque) {
     80         fBitmap.eraseColor(SK_ColorTRANSPARENT);
     81     }
     82 }
     83 
     84 SkDevice::~SkDevice() {
     85     delete fMetaData;
     86 }
     87 
     88 void SkDevice::replaceBitmapBackendForRasterSurface(const SkBitmap& bm) {
     89     SkASSERT(bm.width() == fBitmap.width());
     90     SkASSERT(bm.height() == fBitmap.height());
     91     fBitmap = bm;   // intent is to use bm's pixelRef (and rowbytes/config)
     92     fBitmap.lockPixels();
     93 }
     94 
     95 SkDevice* SkDevice::createCompatibleDevice(SkBitmap::Config config,
     96                                            int width, int height,
     97                                            bool isOpaque) {
     98     return this->onCreateCompatibleDevice(config, width, height,
     99                                           isOpaque, kGeneral_Usage);
    100 }
    101 
    102 SkDevice* SkDevice::createCompatibleDeviceForSaveLayer(SkBitmap::Config config,
    103                                                        int width, int height,
    104                                                        bool isOpaque) {
    105     return this->onCreateCompatibleDevice(config, width, height,
    106                                           isOpaque, kSaveLayer_Usage);
    107 }
    108 
    109 SkDevice* SkDevice::onCreateCompatibleDevice(SkBitmap::Config config,
    110                                              int width, int height,
    111                                              bool isOpaque,
    112                                              Usage usage) {
    113     return SkNEW_ARGS(SkDevice,(config, width, height, isOpaque, fLeakyProperties));
    114 }
    115 
    116 SkMetaData& SkDevice::getMetaData() {
    117     // metadata users are rare, so we lazily allocate it. If that changes we
    118     // can decide to just make it a field in the device (rather than a ptr)
    119     if (NULL == fMetaData) {
    120         fMetaData = new SkMetaData;
    121     }
    122     return *fMetaData;
    123 }
    124 
    125 void SkDevice::lockPixels() {
    126     if (fBitmap.lockPixelsAreWritable()) {
    127         fBitmap.lockPixels();
    128     }
    129 }
    130 
    131 void SkDevice::unlockPixels() {
    132     if (fBitmap.lockPixelsAreWritable()) {
    133         fBitmap.unlockPixels();
    134     }
    135 }
    136 
    137 const SkBitmap& SkDevice::accessBitmap(bool changePixels) {
    138     const SkBitmap& bitmap = this->onAccessBitmap(&fBitmap);
    139     if (changePixels) {
    140         bitmap.notifyPixelsChanged();
    141     }
    142     return bitmap;
    143 }
    144 
    145 void SkDevice::getGlobalBounds(SkIRect* bounds) const {
    146     if (bounds) {
    147         bounds->setXYWH(fOrigin.x(), fOrigin.y(),
    148                         fBitmap.width(), fBitmap.height());
    149     }
    150 }
    151 
    152 void SkDevice::clear(SkColor color) {
    153     fBitmap.eraseColor(color);
    154 }
    155 
    156 const SkBitmap& SkDevice::onAccessBitmap(SkBitmap* bitmap) {return *bitmap;}
    157 
    158 void SkDevice::setMatrixClip(const SkMatrix& matrix, const SkRegion& region,
    159                              const SkClipStack& clipStack) {
    160 }
    161 
    162 bool SkDevice::canHandleImageFilter(SkImageFilter*) {
    163     return false;
    164 }
    165 
    166 bool SkDevice::filterImage(SkImageFilter* filter, const SkBitmap& src,
    167                            const SkMatrix& ctm, SkBitmap* result,
    168                            SkIPoint* offset) {
    169     return false;
    170 }
    171 
    172 bool SkDevice::allowImageFilter(SkImageFilter*) {
    173     return true;
    174 }
    175 
    176 ///////////////////////////////////////////////////////////////////////////////
    177 
    178 bool SkDevice::readPixels(SkBitmap* bitmap, int x, int y,
    179                           SkCanvas::Config8888 config8888) {
    180     if (SkBitmap::kARGB_8888_Config != bitmap->config() ||
    181         NULL != bitmap->getTexture()) {
    182         return false;
    183     }
    184 
    185     const SkBitmap& src = this->accessBitmap(false);
    186 
    187     SkIRect srcRect = SkIRect::MakeXYWH(x, y, bitmap->width(),
    188                                               bitmap->height());
    189     SkIRect devbounds = SkIRect::MakeWH(src.width(), src.height());
    190     if (!srcRect.intersect(devbounds)) {
    191         return false;
    192     }
    193 
    194     SkBitmap tmp;
    195     SkBitmap* bmp;
    196     if (bitmap->isNull()) {
    197         tmp.setConfig(SkBitmap::kARGB_8888_Config, bitmap->width(),
    198                                                    bitmap->height());
    199         if (!tmp.allocPixels()) {
    200             return false;
    201         }
    202         bmp = &tmp;
    203     } else {
    204         bmp = bitmap;
    205     }
    206 
    207     SkIRect subrect = srcRect;
    208     subrect.offset(-x, -y);
    209     SkBitmap bmpSubset;
    210     bmp->extractSubset(&bmpSubset, subrect);
    211 
    212     bool result = this->onReadPixels(bmpSubset,
    213                                      srcRect.fLeft,
    214                                      srcRect.fTop,
    215                                      config8888);
    216     if (result && bmp == &tmp) {
    217         tmp.swap(*bitmap);
    218     }
    219     return result;
    220 }
    221 
    222 #if SK_PMCOLOR_BYTE_ORDER(B,G,R,A)
    223     const SkCanvas::Config8888 SkDevice::kPMColorAlias =
    224         SkCanvas::kBGRA_Premul_Config8888;
    225 #elif SK_PMCOLOR_BYTE_ORDER(R,G,B,A)
    226     const SkCanvas::Config8888 SkDevice::kPMColorAlias =
    227         SkCanvas::kRGBA_Premul_Config8888;
    228 #else
    229     const SkCanvas::Config8888 SkDevice::kPMColorAlias =
    230         (SkCanvas::Config8888) -1;
    231 #endif
    232 
    233 #include <SkConfig8888.h>
    234 
    235 bool SkDevice::onReadPixels(const SkBitmap& bitmap,
    236                             int x, int y,
    237                             SkCanvas::Config8888 config8888) {
    238     SkASSERT(SkBitmap::kARGB_8888_Config == bitmap.config());
    239     SkASSERT(!bitmap.isNull());
    240     SkASSERT(SkIRect::MakeWH(this->width(), this->height()).contains(SkIRect::MakeXYWH(x, y, bitmap.width(), bitmap.height())));
    241 
    242     SkIRect srcRect = SkIRect::MakeXYWH(x, y, bitmap.width(),
    243                                               bitmap.height());
    244     const SkBitmap& src = this->accessBitmap(false);
    245 
    246     SkBitmap subset;
    247     if (!src.extractSubset(&subset, srcRect)) {
    248         return false;
    249     }
    250     if (SkBitmap::kARGB_8888_Config != subset.config()) {
    251         // It'd be preferable to do this directly to bitmap.
    252         subset.copyTo(&subset, SkBitmap::kARGB_8888_Config);
    253     }
    254     SkAutoLockPixels alp(bitmap);
    255     uint32_t* bmpPixels = reinterpret_cast<uint32_t*>(bitmap.getPixels());
    256     SkCopyBitmapToConfig8888(bmpPixels, bitmap.rowBytes(), config8888, subset);
    257     return true;
    258 }
    259 
    260 void SkDevice::writePixels(const SkBitmap& bitmap,
    261                            int x, int y,
    262                            SkCanvas::Config8888 config8888) {
    263     if (bitmap.isNull() || bitmap.getTexture()) {
    264         return;
    265     }
    266     const SkBitmap* sprite = &bitmap;
    267     // check whether we have to handle a config8888 that doesn't match SkPMColor
    268     if (SkBitmap::kARGB_8888_Config == bitmap.config() &&
    269         SkCanvas::kNative_Premul_Config8888 != config8888 &&
    270         kPMColorAlias != config8888) {
    271 
    272         // We're going to have to convert from a config8888 to the native config
    273         // First we clip to the device bounds.
    274         SkBitmap dstBmp = this->accessBitmap(true);
    275         SkIRect spriteRect = SkIRect::MakeXYWH(x, y,
    276                                                bitmap.width(), bitmap.height());
    277         SkIRect devRect = SkIRect::MakeWH(dstBmp.width(), dstBmp.height());
    278         if (!spriteRect.intersect(devRect)) {
    279             return;
    280         }
    281 
    282         // write directly to the device if it has pixels and is SkPMColor
    283         bool drawSprite;
    284         if (SkBitmap::kARGB_8888_Config == dstBmp.config() && !dstBmp.isNull()) {
    285             // we can write directly to the dst when doing the conversion
    286             dstBmp.extractSubset(&dstBmp, spriteRect);
    287             drawSprite = false;
    288         } else {
    289             // we convert to a temporary bitmap and draw that as a sprite
    290             dstBmp.setConfig(SkBitmap::kARGB_8888_Config,
    291                              spriteRect.width(),
    292                              spriteRect.height());
    293             if (!dstBmp.allocPixels()) {
    294                 return;
    295             }
    296             drawSprite = true;
    297         }
    298 
    299         // copy pixels to dstBmp and convert from config8888 to native config.
    300         SkAutoLockPixels alp(bitmap);
    301         uint32_t* srcPixels = bitmap.getAddr32(spriteRect.fLeft - x,
    302                                                spriteRect.fTop - y);
    303         SkCopyConfig8888ToBitmap(dstBmp,
    304                                  srcPixels,
    305                                  bitmap.rowBytes(),
    306                                  config8888);
    307 
    308         if (drawSprite) {
    309             // we've clipped the sprite when we made a copy
    310             x = spriteRect.fLeft;
    311             y = spriteRect.fTop;
    312             sprite = &dstBmp;
    313         } else {
    314             return;
    315         }
    316     }
    317 
    318     SkPaint paint;
    319     paint.setXfermodeMode(SkXfermode::kSrc_Mode);
    320     SkRasterClip clip(SkIRect::MakeWH(fBitmap.width(), fBitmap.height()));
    321     SkDraw  draw;
    322     draw.fRC = &clip;
    323     draw.fClip = &clip.bwRgn();
    324     draw.fBitmap = &fBitmap; // canvas should have already called accessBitmap
    325     draw.fMatrix = &SkMatrix::I();
    326     this->drawSprite(draw, *sprite, x, y, paint);
    327 }
    328 
    329 ///////////////////////////////////////////////////////////////////////////////
    330 
    331 void SkDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
    332     draw.drawPaint(paint);
    333 }
    334 
    335 void SkDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, size_t count,
    336                           const SkPoint pts[], const SkPaint& paint) {
    337     CHECK_FOR_NODRAW_ANNOTATION(paint);
    338     draw.drawPoints(mode, count, pts, paint);
    339 }
    340 
    341 void SkDevice::drawRect(const SkDraw& draw, const SkRect& r, const SkPaint& paint) {
    342     CHECK_FOR_NODRAW_ANNOTATION(paint);
    343     draw.drawRect(r, paint);
    344 }
    345 
    346 void SkDevice::drawOval(const SkDraw& draw, const SkRect& oval, const SkPaint& paint) {
    347     CHECK_FOR_NODRAW_ANNOTATION(paint);
    348 
    349     SkPath path;
    350     path.addOval(oval);
    351     // call the VIRTUAL version, so any subclasses who do handle drawPath aren't
    352     // required to override drawOval.
    353     this->drawPath(draw, path, paint, NULL, true);
    354 }
    355 
    356 void SkDevice::drawRRect(const SkDraw& draw, const SkRRect& rrect, const SkPaint& paint) {
    357     CHECK_FOR_NODRAW_ANNOTATION(paint);
    358 
    359     draw.drawRRect(rrect, paint);
    360 }
    361 
    362 void SkDevice::drawPath(const SkDraw& draw, const SkPath& path,
    363                         const SkPaint& paint, const SkMatrix* prePathMatrix,
    364                         bool pathIsMutable) {
    365     CHECK_FOR_NODRAW_ANNOTATION(paint);
    366     draw.drawPath(path, paint, prePathMatrix, pathIsMutable);
    367 }
    368 
    369 void SkDevice::drawBitmap(const SkDraw& draw, const SkBitmap& bitmap,
    370                           const SkMatrix& matrix, const SkPaint& paint) {
    371     draw.drawBitmap(bitmap, matrix, paint);
    372 }
    373 
    374 void SkDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap,
    375                               const SkRect* src, const SkRect& dst,
    376                               const SkPaint& paint) {
    377     SkMatrix    matrix;
    378     SkRect      bitmapBounds, tmpSrc, tmpDst;
    379     SkBitmap    tmpBitmap;
    380 
    381     bitmapBounds.isetWH(bitmap.width(), bitmap.height());
    382 
    383     // Compute matrix from the two rectangles
    384     if (src) {
    385         tmpSrc = *src;
    386     } else {
    387         tmpSrc = bitmapBounds;
    388     }
    389     matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit);
    390 
    391     const SkRect* dstPtr = &dst;
    392     const SkBitmap* bitmapPtr = &bitmap;
    393 
    394     // clip the tmpSrc to the bounds of the bitmap, and recompute dstRect if
    395     // needed (if the src was clipped). No check needed if src==null.
    396     if (src) {
    397         if (!bitmapBounds.contains(*src)) {
    398             if (!tmpSrc.intersect(bitmapBounds)) {
    399                 return; // nothing to draw
    400             }
    401             // recompute dst, based on the smaller tmpSrc
    402             matrix.mapRect(&tmpDst, tmpSrc);
    403             dstPtr = &tmpDst;
    404         }
    405 
    406         // since we may need to clamp to the borders of the src rect within
    407         // the bitmap, we extract a subset.
    408         SkIRect srcIR;
    409         tmpSrc.roundOut(&srcIR);
    410         if (!bitmap.extractSubset(&tmpBitmap, srcIR)) {
    411             return;
    412         }
    413         bitmapPtr = &tmpBitmap;
    414 
    415         // Since we did an extract, we need to adjust the matrix accordingly
    416         SkScalar dx = 0, dy = 0;
    417         if (srcIR.fLeft > 0) {
    418             dx = SkIntToScalar(srcIR.fLeft);
    419         }
    420         if (srcIR.fTop > 0) {
    421             dy = SkIntToScalar(srcIR.fTop);
    422         }
    423         if (dx || dy) {
    424             matrix.preTranslate(dx, dy);
    425         }
    426 
    427         SkRect extractedBitmapBounds;
    428         extractedBitmapBounds.isetWH(bitmapPtr->width(), bitmapPtr->height());
    429         if (extractedBitmapBounds == tmpSrc) {
    430             // no fractional part in src, we can just call drawBitmap
    431             goto USE_DRAWBITMAP;
    432         }
    433     } else {
    434         USE_DRAWBITMAP:
    435         // We can go faster by just calling drawBitmap, which will concat the
    436         // matrix with the CTM, and try to call drawSprite if it can. If not,
    437         // it will make a shader and call drawRect, as we do below.
    438         this->drawBitmap(draw, *bitmapPtr, matrix, paint);
    439         return;
    440     }
    441 
    442     // construct a shader, so we can call drawRect with the dst
    443     SkShader* s = SkShader::CreateBitmapShader(*bitmapPtr,
    444                                                SkShader::kClamp_TileMode,
    445                                                SkShader::kClamp_TileMode);
    446     if (NULL == s) {
    447         return;
    448     }
    449     s->setLocalMatrix(matrix);
    450 
    451     SkPaint paintWithShader(paint);
    452     paintWithShader.setStyle(SkPaint::kFill_Style);
    453     paintWithShader.setShader(s)->unref();
    454 
    455     // Call ourself, in case the subclass wanted to share this setup code
    456     // but handle the drawRect code themselves.
    457     this->drawRect(draw, *dstPtr, paintWithShader);
    458 }
    459 
    460 void SkDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
    461                               int x, int y, const SkPaint& paint) {
    462     draw.drawSprite(bitmap, x, y, paint);
    463 }
    464 
    465 void SkDevice::drawText(const SkDraw& draw, const void* text, size_t len,
    466                             SkScalar x, SkScalar y, const SkPaint& paint) {
    467     draw.drawText((const char*)text, len, x, y, paint);
    468 }
    469 
    470 void SkDevice::drawPosText(const SkDraw& draw, const void* text, size_t len,
    471                                const SkScalar xpos[], SkScalar y,
    472                                int scalarsPerPos, const SkPaint& paint) {
    473     draw.drawPosText((const char*)text, len, xpos, y, scalarsPerPos, paint);
    474 }
    475 
    476 void SkDevice::drawTextOnPath(const SkDraw& draw, const void* text,
    477                                   size_t len, const SkPath& path,
    478                                   const SkMatrix* matrix,
    479                                   const SkPaint& paint) {
    480     draw.drawTextOnPath((const char*)text, len, path, matrix, paint);
    481 }
    482 
    483 #ifdef SK_BUILD_FOR_ANDROID
    484 void SkDevice::drawPosTextOnPath(const SkDraw& draw, const void* text, size_t len,
    485                                      const SkPoint pos[], const SkPaint& paint,
    486                                      const SkPath& path, const SkMatrix* matrix) {
    487     draw.drawPosTextOnPath((const char*)text, len, pos, paint, path, matrix);
    488 }
    489 #endif
    490 
    491 void SkDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
    492                                 int vertexCount,
    493                                 const SkPoint verts[], const SkPoint textures[],
    494                                 const SkColor colors[], SkXfermode* xmode,
    495                                 const uint16_t indices[], int indexCount,
    496                                 const SkPaint& paint) {
    497     draw.drawVertices(vmode, vertexCount, verts, textures, colors, xmode,
    498                       indices, indexCount, paint);
    499 }
    500 
    501 void SkDevice::drawDevice(const SkDraw& draw, SkDevice* device,
    502                               int x, int y, const SkPaint& paint) {
    503     const SkBitmap& src = device->accessBitmap(false);
    504     draw.drawSprite(src, x, y, paint);
    505 }
    506 
    507 ///////////////////////////////////////////////////////////////////////////////
    508 
    509 bool SkDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) {
    510     if (!paint.isLCDRenderText() || !paint.isAntiAlias()) {
    511         // we're cool with the paint as is
    512         return false;
    513     }
    514 
    515     if (SkBitmap::kARGB_8888_Config != fBitmap.config() ||
    516         paint.getRasterizer() ||
    517         paint.getPathEffect() ||
    518         paint.isFakeBoldText() ||
    519         paint.getStyle() != SkPaint::kFill_Style ||
    520         !SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrcOver_Mode)) {
    521         // turn off lcd
    522         flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag;
    523         flags->fHinting = paint.getHinting();
    524         return true;
    525     }
    526     // we're cool with the paint as is
    527     return false;
    528 }
    529