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     SkPath  path;
    360     path.addRRect(rrect);
    361     // call the VIRTUAL version, so any subclasses who do handle drawPath aren't
    362     // required to override drawRRect.
    363     this->drawPath(draw, path, paint, NULL, true);
    364 }
    365 
    366 void SkDevice::drawPath(const SkDraw& draw, const SkPath& path,
    367                         const SkPaint& paint, const SkMatrix* prePathMatrix,
    368                         bool pathIsMutable) {
    369     CHECK_FOR_NODRAW_ANNOTATION(paint);
    370     draw.drawPath(path, paint, prePathMatrix, pathIsMutable);
    371 }
    372 
    373 void SkDevice::drawBitmap(const SkDraw& draw, const SkBitmap& bitmap,
    374                           const SkMatrix& matrix, const SkPaint& paint) {
    375     draw.drawBitmap(bitmap, matrix, paint);
    376 }
    377 
    378 void SkDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap,
    379                               const SkRect* src, const SkRect& dst,
    380                               const SkPaint& paint) {
    381     SkMatrix    matrix;
    382     SkRect      bitmapBounds, tmpSrc, tmpDst;
    383     SkBitmap    tmpBitmap;
    384 
    385     bitmapBounds.isetWH(bitmap.width(), bitmap.height());
    386 
    387     // Compute matrix from the two rectangles
    388     if (src) {
    389         tmpSrc = *src;
    390     } else {
    391         tmpSrc = bitmapBounds;
    392     }
    393     matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit);
    394 
    395     const SkRect* dstPtr = &dst;
    396     const SkBitmap* bitmapPtr = &bitmap;
    397 
    398     // clip the tmpSrc to the bounds of the bitmap, and recompute dstRect if
    399     // needed (if the src was clipped). No check needed if src==null.
    400     if (src) {
    401         if (!bitmapBounds.contains(*src)) {
    402             if (!tmpSrc.intersect(bitmapBounds)) {
    403                 return; // nothing to draw
    404             }
    405             // recompute dst, based on the smaller tmpSrc
    406             matrix.mapRect(&tmpDst, tmpSrc);
    407             dstPtr = &tmpDst;
    408         }
    409 
    410         // since we may need to clamp to the borders of the src rect within
    411         // the bitmap, we extract a subset.
    412         SkIRect srcIR;
    413         tmpSrc.roundOut(&srcIR);
    414         if (!bitmap.extractSubset(&tmpBitmap, srcIR)) {
    415             return;
    416         }
    417         bitmapPtr = &tmpBitmap;
    418 
    419         // Since we did an extract, we need to adjust the matrix accordingly
    420         SkScalar dx = 0, dy = 0;
    421         if (srcIR.fLeft > 0) {
    422             dx = SkIntToScalar(srcIR.fLeft);
    423         }
    424         if (srcIR.fTop > 0) {
    425             dy = SkIntToScalar(srcIR.fTop);
    426         }
    427         if (dx || dy) {
    428             matrix.preTranslate(dx, dy);
    429         }
    430 
    431         SkRect extractedBitmapBounds;
    432         extractedBitmapBounds.isetWH(bitmapPtr->width(), bitmapPtr->height());
    433         if (extractedBitmapBounds == tmpSrc) {
    434             // no fractional part in src, we can just call drawBitmap
    435             goto USE_DRAWBITMAP;
    436         }
    437     } else {
    438         USE_DRAWBITMAP:
    439         // We can go faster by just calling drawBitmap, which will concat the
    440         // matrix with the CTM, and try to call drawSprite if it can. If not,
    441         // it will make a shader and call drawRect, as we do below.
    442         this->drawBitmap(draw, *bitmapPtr, matrix, paint);
    443         return;
    444     }
    445 
    446     // construct a shader, so we can call drawRect with the dst
    447     SkShader* s = SkShader::CreateBitmapShader(*bitmapPtr,
    448                                                SkShader::kClamp_TileMode,
    449                                                SkShader::kClamp_TileMode);
    450     if (NULL == s) {
    451         return;
    452     }
    453     s->setLocalMatrix(matrix);
    454 
    455     SkPaint paintWithShader(paint);
    456     paintWithShader.setStyle(SkPaint::kFill_Style);
    457     paintWithShader.setShader(s)->unref();
    458 
    459     // Call ourself, in case the subclass wanted to share this setup code
    460     // but handle the drawRect code themselves.
    461     this->drawRect(draw, *dstPtr, paintWithShader);
    462 }
    463 
    464 void SkDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
    465                               int x, int y, const SkPaint& paint) {
    466     draw.drawSprite(bitmap, x, y, paint);
    467 }
    468 
    469 void SkDevice::drawText(const SkDraw& draw, const void* text, size_t len,
    470                             SkScalar x, SkScalar y, const SkPaint& paint) {
    471     draw.drawText((const char*)text, len, x, y, paint);
    472 }
    473 
    474 void SkDevice::drawPosText(const SkDraw& draw, const void* text, size_t len,
    475                                const SkScalar xpos[], SkScalar y,
    476                                int scalarsPerPos, const SkPaint& paint) {
    477     draw.drawPosText((const char*)text, len, xpos, y, scalarsPerPos, paint);
    478 }
    479 
    480 void SkDevice::drawTextOnPath(const SkDraw& draw, const void* text,
    481                                   size_t len, const SkPath& path,
    482                                   const SkMatrix* matrix,
    483                                   const SkPaint& paint) {
    484     draw.drawTextOnPath((const char*)text, len, path, matrix, paint);
    485 }
    486 
    487 #ifdef SK_BUILD_FOR_ANDROID
    488 void SkDevice::drawPosTextOnPath(const SkDraw& draw, const void* text, size_t len,
    489                                      const SkPoint pos[], const SkPaint& paint,
    490                                      const SkPath& path, const SkMatrix* matrix) {
    491     draw.drawPosTextOnPath((const char*)text, len, pos, paint, path, matrix);
    492 }
    493 #endif
    494 
    495 void SkDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
    496                                 int vertexCount,
    497                                 const SkPoint verts[], const SkPoint textures[],
    498                                 const SkColor colors[], SkXfermode* xmode,
    499                                 const uint16_t indices[], int indexCount,
    500                                 const SkPaint& paint) {
    501     draw.drawVertices(vmode, vertexCount, verts, textures, colors, xmode,
    502                       indices, indexCount, paint);
    503 }
    504 
    505 void SkDevice::drawDevice(const SkDraw& draw, SkDevice* device,
    506                               int x, int y, const SkPaint& paint) {
    507     const SkBitmap& src = device->accessBitmap(false);
    508     draw.drawSprite(src, x, y, paint);
    509 }
    510 
    511 ///////////////////////////////////////////////////////////////////////////////
    512 
    513 bool SkDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) {
    514     if (!paint.isLCDRenderText() || !paint.isAntiAlias()) {
    515         // we're cool with the paint as is
    516         return false;
    517     }
    518 
    519     if (SkBitmap::kARGB_8888_Config != fBitmap.config() ||
    520         paint.getRasterizer() ||
    521         paint.getPathEffect() ||
    522         paint.isFakeBoldText() ||
    523         paint.getStyle() != SkPaint::kFill_Style ||
    524         !SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrcOver_Mode)) {
    525         // turn off lcd
    526         flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag;
    527         flags->fHinting = paint.getHinting();
    528         return true;
    529     }
    530     // we're cool with the paint as is
    531     return false;
    532 }
    533