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 "SkDraw.h"
     10 #include "SkImageFilter.h"
     11 #include "SkMetaData.h"
     12 #include "SkRect.h"
     13 
     14 ///////////////////////////////////////////////////////////////////////////////
     15 
     16 SkDevice::SkDevice(const SkBitmap& bitmap) : fBitmap(bitmap) {
     17     fOrigin.setZero();
     18     fMetaData = NULL;
     19 }
     20 
     21 SkDevice::SkDevice(SkBitmap::Config config, int width, int height, bool isOpaque) {
     22     fOrigin.setZero();
     23     fMetaData = NULL;
     24 
     25     fBitmap.setConfig(config, width, height);
     26     fBitmap.allocPixels();
     27     fBitmap.setIsOpaque(isOpaque);
     28     if (!isOpaque) {
     29         fBitmap.eraseColor(0);
     30     }
     31 }
     32 
     33 SkDevice::~SkDevice() {
     34     delete fMetaData;
     35 }
     36 
     37 SkDevice* SkDevice::createCompatibleDevice(SkBitmap::Config config,
     38                                            int width, int height,
     39                                            bool isOpaque) {
     40     return this->onCreateCompatibleDevice(config, width, height,
     41                                           isOpaque, kGeneral_Usage);
     42 }
     43 
     44 SkDevice* SkDevice::createCompatibleDeviceForSaveLayer(SkBitmap::Config config,
     45                                                        int width, int height,
     46                                                        bool isOpaque) {
     47     return this->onCreateCompatibleDevice(config, width, height,
     48                                           isOpaque, kSaveLayer_Usage);
     49 }
     50 
     51 SkDevice* SkDevice::onCreateCompatibleDevice(SkBitmap::Config config,
     52                                              int width, int height,
     53                                              bool isOpaque,
     54                                              Usage usage) {
     55     return SkNEW_ARGS(SkDevice,(config, width, height, isOpaque));
     56 }
     57 
     58 SkMetaData& SkDevice::getMetaData() {
     59     // metadata users are rare, so we lazily allocate it. If that changes we
     60     // can decide to just make it a field in the device (rather than a ptr)
     61     if (NULL == fMetaData) {
     62         fMetaData = new SkMetaData;
     63     }
     64     return *fMetaData;
     65 }
     66 
     67 void SkDevice::lockPixels() {
     68     if (fBitmap.lockPixelsAreWritable()) {
     69         fBitmap.lockPixels();
     70     }
     71 }
     72 
     73 void SkDevice::unlockPixels() {
     74     if (fBitmap.lockPixelsAreWritable()) {
     75         fBitmap.unlockPixels();
     76     }
     77 }
     78 
     79 const SkBitmap& SkDevice::accessBitmap(bool changePixels) {
     80     const SkBitmap& bitmap = this->onAccessBitmap(&fBitmap);
     81     if (changePixels) {
     82         bitmap.notifyPixelsChanged();
     83     }
     84     return bitmap;
     85 }
     86 
     87 void SkDevice::getGlobalBounds(SkIRect* bounds) const {
     88     if (bounds) {
     89         bounds->setXYWH(fOrigin.x(), fOrigin.y(),
     90                         fBitmap.width(), fBitmap.height());
     91     }
     92 }
     93 
     94 void SkDevice::clear(SkColor color) {
     95     fBitmap.eraseColor(color);
     96 }
     97 
     98 const SkBitmap& SkDevice::onAccessBitmap(SkBitmap* bitmap) {return *bitmap;}
     99 
    100 void SkDevice::setMatrixClip(const SkMatrix& matrix, const SkRegion& region,
    101                              const SkClipStack& clipStack) {
    102 }
    103 
    104 bool SkDevice::filterImage(SkImageFilter*, const SkBitmap& src,
    105                            const SkMatrix& ctm,
    106                            SkBitmap* result, SkIPoint* offset) {
    107     return false;
    108 }
    109 
    110 bool SkDevice::allowImageFilter(SkImageFilter*) {
    111     return true;
    112 }
    113 
    114 ///////////////////////////////////////////////////////////////////////////////
    115 
    116 bool SkDevice::readPixels(SkBitmap* bitmap, int x, int y,
    117                           SkCanvas::Config8888 config8888) {
    118     if (SkBitmap::kARGB_8888_Config != bitmap->config() ||
    119         NULL != bitmap->getTexture()) {
    120         return false;
    121     }
    122 
    123     const SkBitmap& src = this->accessBitmap(false);
    124 
    125     SkIRect srcRect = SkIRect::MakeXYWH(x, y, bitmap->width(),
    126                                               bitmap->height());
    127     SkIRect devbounds = SkIRect::MakeWH(src.width(), src.height());
    128     if (!srcRect.intersect(devbounds)) {
    129         return false;
    130     }
    131 
    132     SkBitmap tmp;
    133     SkBitmap* bmp;
    134     if (bitmap->isNull()) {
    135         tmp.setConfig(SkBitmap::kARGB_8888_Config, bitmap->width(),
    136                                                    bitmap->height());
    137         if (!tmp.allocPixels()) {
    138             return false;
    139         }
    140         bmp = &tmp;
    141     } else {
    142         bmp = bitmap;
    143     }
    144 
    145     SkIRect subrect = srcRect;
    146     subrect.offset(-x, -y);
    147     SkBitmap bmpSubset;
    148     bmp->extractSubset(&bmpSubset, subrect);
    149 
    150     bool result = this->onReadPixels(bmpSubset,
    151                                      srcRect.fLeft,
    152                                      srcRect.fTop,
    153                                      config8888);
    154     if (result && bmp == &tmp) {
    155         tmp.swap(*bitmap);
    156     }
    157     return result;
    158 }
    159 
    160 #ifdef SK_CPU_LENDIAN
    161     #if   24 == SK_A32_SHIFT && 16 == SK_R32_SHIFT && \
    162            8 == SK_G32_SHIFT &&  0 == SK_B32_SHIFT
    163         const SkCanvas::Config8888 SkDevice::kPMColorAlias =
    164             SkCanvas::kBGRA_Premul_Config8888;
    165     #elif 24 == SK_A32_SHIFT &&  0 == SK_R32_SHIFT && \
    166            8 == SK_G32_SHIFT && 16 == SK_B32_SHIFT
    167         const SkCanvas::Config8888 SkDevice::kPMColorAlias =
    168             SkCanvas::kRGBA_Premul_Config8888;
    169     #else
    170         const SkCanvas::Config8888 SkDevice::kPMColorAlias =
    171             (SkCanvas::Config8888) -1;
    172     #endif
    173 #else
    174     #if    0 == SK_A32_SHIFT &&   8 == SK_R32_SHIFT && \
    175           16 == SK_G32_SHIFT &&  24 == SK_B32_SHIFT
    176         const SkCanvas::Config8888 SkDevice::kPMColorAlias =
    177             SkCanvas::kBGRA_Premul_Config8888;
    178     #elif  0 == SK_A32_SHIFT &&  24 == SK_R32_SHIFT && \
    179           16 == SK_G32_SHIFT &&   8 == SK_B32_SHIFT
    180         const SkCanvas::Config8888 SkDevice::kPMColorAlias =
    181             SkCanvas::kRGBA_Premul_Config8888;
    182     #else
    183         const SkCanvas::Config8888 SkDevice::kPMColorAlias =
    184             (SkCanvas::Config8888) -1;
    185     #endif
    186 #endif
    187 
    188 #include <SkConfig8888.h>
    189 
    190 bool SkDevice::onReadPixels(const SkBitmap& bitmap,
    191                             int x, int y,
    192                             SkCanvas::Config8888 config8888) {
    193     SkASSERT(SkBitmap::kARGB_8888_Config == bitmap.config());
    194     SkASSERT(!bitmap.isNull());
    195     SkASSERT(SkIRect::MakeWH(this->width(), this->height()).contains(SkIRect::MakeXYWH(x, y, bitmap.width(), bitmap.height())));
    196 
    197     SkIRect srcRect = SkIRect::MakeXYWH(x, y, bitmap.width(),
    198                                               bitmap.height());
    199     const SkBitmap& src = this->accessBitmap(false);
    200 
    201     SkBitmap subset;
    202     if (!src.extractSubset(&subset, srcRect)) {
    203         return false;
    204     }
    205     if (SkBitmap::kARGB_8888_Config != subset.config()) {
    206         // It'd be preferable to do this directly to bitmap.
    207         subset.copyTo(&subset, SkBitmap::kARGB_8888_Config);
    208     }
    209     SkAutoLockPixels alp(bitmap);
    210     uint32_t* bmpPixels = reinterpret_cast<uint32_t*>(bitmap.getPixels());
    211     SkCopyBitmapToConfig8888(bmpPixels, bitmap.rowBytes(), config8888, subset);
    212     return true;
    213 }
    214 
    215 void SkDevice::writePixels(const SkBitmap& bitmap,
    216                            int x, int y,
    217                            SkCanvas::Config8888 config8888) {
    218     if (bitmap.isNull() || bitmap.getTexture()) {
    219         return;
    220     }
    221     const SkBitmap* sprite = &bitmap;
    222     // check whether we have to handle a config8888 that doesn't match SkPMColor
    223     if (SkBitmap::kARGB_8888_Config == bitmap.config() &&
    224         SkCanvas::kNative_Premul_Config8888 != config8888 &&
    225         kPMColorAlias != config8888) {
    226 
    227         // We're going to have to convert from a config8888 to the native config
    228         // First we clip to the device bounds.
    229         SkBitmap dstBmp = this->accessBitmap(true);
    230         SkIRect spriteRect = SkIRect::MakeXYWH(x, y,
    231                                                bitmap.width(), bitmap.height());
    232         SkIRect devRect = SkIRect::MakeWH(dstBmp.width(), dstBmp.height());
    233         if (!spriteRect.intersect(devRect)) {
    234             return;
    235         }
    236 
    237         // write directly to the device if it has pixels and is SkPMColor
    238         bool drawSprite;
    239         if (SkBitmap::kARGB_8888_Config == dstBmp.config() && !dstBmp.isNull()) {
    240             // we can write directly to the dst when doing the conversion
    241             dstBmp.extractSubset(&dstBmp, spriteRect);
    242             drawSprite = false;
    243         } else {
    244             // we convert to a temporary bitmap and draw that as a sprite
    245             dstBmp.setConfig(SkBitmap::kARGB_8888_Config,
    246                              spriteRect.width(),
    247                              spriteRect.height());
    248             if (!dstBmp.allocPixels()) {
    249                 return;
    250             }
    251             drawSprite = true;
    252         }
    253 
    254         // copy pixels to dstBmp and convert from config8888 to native config.
    255         SkAutoLockPixels alp(bitmap);
    256         uint32_t* srcPixels = bitmap.getAddr32(spriteRect.fLeft - x,
    257                                                spriteRect.fTop - y);
    258         SkCopyConfig8888ToBitmap(dstBmp,
    259                                  srcPixels,
    260                                  bitmap.rowBytes(),
    261                                  config8888);
    262 
    263         if (drawSprite) {
    264             // we've clipped the sprite when we made a copy
    265             x = spriteRect.fLeft;
    266             y = spriteRect.fTop;
    267             sprite = &dstBmp;
    268         } else {
    269             return;
    270         }
    271     }
    272 
    273     SkPaint paint;
    274     paint.setXfermodeMode(SkXfermode::kSrc_Mode);
    275     SkCanvas canvas(this);
    276     canvas.drawSprite(*sprite, x, y, &paint);
    277 }
    278 
    279 ///////////////////////////////////////////////////////////////////////////////
    280 
    281 void SkDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
    282     draw.drawPaint(paint);
    283 }
    284 
    285 void SkDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, size_t count,
    286                               const SkPoint pts[], const SkPaint& paint) {
    287     draw.drawPoints(mode, count, pts, paint);
    288 }
    289 
    290 void SkDevice::drawRect(const SkDraw& draw, const SkRect& r,
    291                             const SkPaint& paint) {
    292     draw.drawRect(r, paint);
    293 }
    294 
    295 void SkDevice::drawPath(const SkDraw& draw, const SkPath& path,
    296                         const SkPaint& paint, const SkMatrix* prePathMatrix,
    297                         bool pathIsMutable) {
    298     draw.drawPath(path, paint, prePathMatrix, pathIsMutable);
    299 }
    300 
    301 void SkDevice::drawBitmap(const SkDraw& draw, const SkBitmap& bitmap,
    302                           const SkIRect* srcRect,
    303                           const SkMatrix& matrix, const SkPaint& paint) {
    304     SkBitmap        tmp;    // storage if we need a subset of bitmap
    305     const SkBitmap* bitmapPtr = &bitmap;
    306 
    307     if (srcRect) {
    308         if (!bitmap.extractSubset(&tmp, *srcRect)) {
    309             return;     // extraction failed
    310         }
    311         bitmapPtr = &tmp;
    312     }
    313     draw.drawBitmap(*bitmapPtr, matrix, paint);
    314 }
    315 
    316 void SkDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
    317                               int x, int y, const SkPaint& paint) {
    318     draw.drawSprite(bitmap, x, y, paint);
    319 }
    320 
    321 void SkDevice::drawText(const SkDraw& draw, const void* text, size_t len,
    322                             SkScalar x, SkScalar y, const SkPaint& paint) {
    323     draw.drawText((const char*)text, len, x, y, paint);
    324 }
    325 
    326 void SkDevice::drawPosText(const SkDraw& draw, const void* text, size_t len,
    327                                const SkScalar xpos[], SkScalar y,
    328                                int scalarsPerPos, const SkPaint& paint) {
    329     draw.drawPosText((const char*)text, len, xpos, y, scalarsPerPos, paint);
    330 }
    331 
    332 void SkDevice::drawTextOnPath(const SkDraw& draw, const void* text,
    333                                   size_t len, const SkPath& path,
    334                                   const SkMatrix* matrix,
    335                                   const SkPaint& paint) {
    336     draw.drawTextOnPath((const char*)text, len, path, matrix, paint);
    337 }
    338 
    339 #ifdef SK_BUILD_FOR_ANDROID
    340 void SkDevice::drawPosTextOnPath(const SkDraw& draw, const void* text, size_t len,
    341                                      const SkPoint pos[], const SkPaint& paint,
    342                                      const SkPath& path, const SkMatrix* matrix) {
    343     draw.drawPosTextOnPath((const char*)text, len, pos, paint, path, matrix);
    344 }
    345 #endif
    346 
    347 void SkDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
    348                                 int vertexCount,
    349                                 const SkPoint verts[], const SkPoint textures[],
    350                                 const SkColor colors[], SkXfermode* xmode,
    351                                 const uint16_t indices[], int indexCount,
    352                                 const SkPaint& paint) {
    353     draw.drawVertices(vmode, vertexCount, verts, textures, colors, xmode,
    354                       indices, indexCount, paint);
    355 }
    356 
    357 void SkDevice::drawDevice(const SkDraw& draw, SkDevice* device,
    358                               int x, int y, const SkPaint& paint) {
    359     const SkBitmap& src = device->accessBitmap(false);
    360     draw.drawSprite(src, x, y, paint);
    361 }
    362 
    363 ///////////////////////////////////////////////////////////////////////////////
    364 
    365 bool SkDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) {
    366     if (!paint.isLCDRenderText() || !paint.isAntiAlias()) {
    367         // we're cool with the paint as is
    368         return false;
    369     }
    370 
    371     if (SkBitmap::kARGB_8888_Config != fBitmap.config() ||
    372         paint.getRasterizer() ||
    373         paint.getPathEffect() ||
    374         paint.isFakeBoldText() ||
    375         paint.getStyle() != SkPaint::kFill_Style ||
    376         !SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrcOver_Mode)) {
    377         // turn off lcd
    378         flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag;
    379         flags->fHinting = paint.getHinting();
    380         return true;
    381     }
    382     // we're cool with the paint as is
    383     return false;
    384 }
    385 
    386