Home | History | Annotate | Download | only in utils
      1 /*
      2  * Copyright 2012 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 "SkCanvas.h"
     10 #include "SkData.h"
     11 #include "SkNoSaveLayerCanvas.h"
     12 #include "SkPictureUtils.h"
     13 #include "SkPixelRef.h"
     14 #include "SkRRect.h"
     15 #include "SkShader.h"
     16 
     17 class PixelRefSet {
     18 public:
     19     PixelRefSet(SkTDArray<SkPixelRef*>* array) : fArray(array) {}
     20 
     21     // This does a linear search on existing pixelrefs, so if this list gets big
     22     // we should use a more complex sorted/hashy thing.
     23     //
     24     void add(SkPixelRef* pr) {
     25         uint32_t genID = pr->getGenerationID();
     26         if (fGenID.find(genID) < 0) {
     27             *fArray->append() = pr;
     28             *fGenID.append() = genID;
     29 //            SkDebugf("--- adding [%d] %x %d\n", fArray->count() - 1, pr, genID);
     30         } else {
     31 //            SkDebugf("--- already have %x %d\n", pr, genID);
     32         }
     33     }
     34 
     35 private:
     36     SkTDArray<SkPixelRef*>* fArray;
     37     SkTDArray<uint32_t>     fGenID;
     38 };
     39 
     40 static void not_supported() {
     41     SkDEBUGFAIL("this method should never be called");
     42 }
     43 
     44 static void nothing_to_do() {}
     45 
     46 /**
     47  *  This device will route all bitmaps (primitives and in shaders) to its PRSet.
     48  *  It should never actually draw anything, so there need not be any pixels
     49  *  behind its device.
     50  */
     51 class GatherPixelRefDevice : public SkBaseDevice {
     52 public:
     53     SK_DECLARE_INST_COUNT(GatherPixelRefDevice)
     54 
     55     GatherPixelRefDevice(int width, int height, PixelRefSet* prset) {
     56         fSize.set(width, height);
     57         fEmptyBitmap.setInfo(SkImageInfo::MakeUnknown(width, height));
     58         fPRSet = prset;
     59     }
     60 
     61     virtual SkImageInfo imageInfo() const SK_OVERRIDE {
     62         return SkImageInfo::MakeUnknown(fSize.width(), fSize.height());
     63     }
     64     virtual GrRenderTarget* accessRenderTarget() SK_OVERRIDE { return NULL; }
     65     virtual bool filterTextFlags(const SkPaint& paint, TextFlags*) SK_OVERRIDE {
     66         return false;
     67     }
     68     // TODO: allow this call to return failure, or move to SkBitmapDevice only.
     69     virtual const SkBitmap& onAccessBitmap() SK_OVERRIDE {
     70         return fEmptyBitmap;
     71     }
     72     virtual void lockPixels() SK_OVERRIDE { nothing_to_do(); }
     73     virtual void unlockPixels() SK_OVERRIDE { nothing_to_do(); }
     74     virtual bool allowImageFilter(const SkImageFilter*) SK_OVERRIDE { return false; }
     75     virtual bool canHandleImageFilter(const SkImageFilter*) SK_OVERRIDE { return false; }
     76     virtual bool filterImage(const SkImageFilter*, const SkBitmap&, const SkImageFilter::Context&,
     77                              SkBitmap* result, SkIPoint* offset) SK_OVERRIDE {
     78         return false;
     79     }
     80 
     81     virtual void clear(SkColor color) SK_OVERRIDE {
     82         nothing_to_do();
     83     }
     84 
     85     virtual void drawPaint(const SkDraw&, const SkPaint& paint) SK_OVERRIDE {
     86         this->addBitmapFromPaint(paint);
     87     }
     88     virtual void drawPoints(const SkDraw&, SkCanvas::PointMode mode, size_t count,
     89                             const SkPoint[], const SkPaint& paint) SK_OVERRIDE {
     90         this->addBitmapFromPaint(paint);
     91     }
     92     virtual void drawRect(const SkDraw&, const SkRect&,
     93                           const SkPaint& paint) SK_OVERRIDE {
     94         this->addBitmapFromPaint(paint);
     95     }
     96     virtual void drawRRect(const SkDraw&, const SkRRect&,
     97                            const SkPaint& paint) SK_OVERRIDE {
     98         this->addBitmapFromPaint(paint);
     99     }
    100     virtual void drawOval(const SkDraw&, const SkRect&,
    101                           const SkPaint& paint) SK_OVERRIDE {
    102         this->addBitmapFromPaint(paint);
    103     }
    104     virtual void drawPath(const SkDraw&, const SkPath& path,
    105                           const SkPaint& paint, const SkMatrix* prePathMatrix,
    106                           bool pathIsMutable) SK_OVERRIDE {
    107         this->addBitmapFromPaint(paint);
    108     }
    109     virtual void drawBitmap(const SkDraw&, const SkBitmap& bitmap,
    110                             const SkMatrix&, const SkPaint& paint) SK_OVERRIDE {
    111         this->addBitmap(bitmap);
    112         if (kAlpha_8_SkColorType == bitmap.colorType()) {
    113             this->addBitmapFromPaint(paint);
    114         }
    115     }
    116     virtual void drawBitmapRect(const SkDraw&, const SkBitmap& bitmap,
    117                                 const SkRect* srcOrNull, const SkRect& dst,
    118                                 const SkPaint& paint,
    119                                 SkCanvas::DrawBitmapRectFlags flags) SK_OVERRIDE {
    120         this->addBitmap(bitmap);
    121         if (kAlpha_8_SkColorType == bitmap.colorType()) {
    122             this->addBitmapFromPaint(paint);
    123         }
    124     }
    125     virtual void drawSprite(const SkDraw&, const SkBitmap& bitmap,
    126                             int x, int y, const SkPaint& paint) SK_OVERRIDE {
    127         this->addBitmap(bitmap);
    128     }
    129     virtual void drawText(const SkDraw&, const void* text, size_t len,
    130                           SkScalar x, SkScalar y,
    131                           const SkPaint& paint) SK_OVERRIDE {
    132         this->addBitmapFromPaint(paint);
    133     }
    134     virtual void drawPosText(const SkDraw&, const void* text, size_t len,
    135                              const SkScalar pos[], SkScalar constY,
    136                              int, const SkPaint& paint) SK_OVERRIDE {
    137         this->addBitmapFromPaint(paint);
    138     }
    139     virtual void drawTextOnPath(const SkDraw&, const void* text, size_t len,
    140                                 const SkPath& path, const SkMatrix* matrix,
    141                                 const SkPaint& paint) SK_OVERRIDE {
    142         this->addBitmapFromPaint(paint);
    143     }
    144     virtual void drawVertices(const SkDraw&, SkCanvas::VertexMode, int vertexCount,
    145                               const SkPoint verts[], const SkPoint texs[],
    146                               const SkColor colors[], SkXfermode* xmode,
    147                               const uint16_t indices[], int indexCount,
    148                               const SkPaint& paint) SK_OVERRIDE {
    149         this->addBitmapFromPaint(paint);
    150     }
    151     virtual void drawDevice(const SkDraw&, SkBaseDevice*, int x, int y,
    152                             const SkPaint&) SK_OVERRIDE {
    153         nothing_to_do();
    154     }
    155 
    156 protected:
    157     virtual void replaceBitmapBackendForRasterSurface(const SkBitmap&) SK_OVERRIDE {
    158         not_supported();
    159     }
    160     virtual SkBaseDevice* onCreateDevice(const SkImageInfo& info, Usage usage) SK_OVERRIDE {
    161         // we expect to only get called via savelayer, in which case it is fine.
    162         SkASSERT(kSaveLayer_Usage == usage);
    163         return SkNEW_ARGS(GatherPixelRefDevice, (info.width(), info.height(), fPRSet));
    164     }
    165     virtual void flush() SK_OVERRIDE {}
    166 
    167 private:
    168     PixelRefSet*  fPRSet;
    169     SkBitmap fEmptyBitmap;  // legacy -- need to remove the need for this guy
    170     SkISize fSize;
    171 
    172     void addBitmap(const SkBitmap& bm) {
    173       fPRSet->add(bm.pixelRef());
    174     }
    175 
    176     void addBitmapFromPaint(const SkPaint& paint) {
    177       SkShader* shader = paint.getShader();
    178       if (shader) {
    179           SkBitmap bm;
    180           // Check whether the shader is a gradient in order to short-circuit
    181           // call to asABitmap to prevent generation of bitmaps from
    182           // gradient shaders, which implement asABitmap.
    183           if (SkShader::kNone_GradientType == shader->asAGradient(NULL) &&
    184               shader->asABitmap(&bm, NULL, NULL)) {
    185               fPRSet->add(bm.pixelRef());
    186           }
    187       }
    188     }
    189 
    190     typedef SkBaseDevice INHERITED;
    191 };
    192 
    193 SkData* SkPictureUtils::GatherPixelRefs(const SkPicture* pict, const SkRect& area) {
    194     if (NULL == pict) {
    195         return NULL;
    196     }
    197 
    198     // this test also handles if either area or pict's width/height are empty
    199     if (!SkRect::Intersects(area, pict->cullRect())) {
    200         return NULL;
    201     }
    202 
    203     SkTDArray<SkPixelRef*> array;
    204     PixelRefSet prset(&array);
    205 
    206     GatherPixelRefDevice device(SkScalarCeilToInt(pict->cullRect().width()),
    207                                 SkScalarCeilToInt(pict->cullRect().height()),
    208                                 &prset);
    209     SkNoSaveLayerCanvas canvas(&device);
    210 
    211     canvas.clipRect(area, SkRegion::kIntersect_Op, false);
    212     canvas.drawPicture(pict);
    213 
    214     SkData* data = NULL;
    215     int count = array.count();
    216     if (count > 0) {
    217         data = SkData::NewFromMalloc(array.detach(), count * sizeof(SkPixelRef*));
    218     }
    219     return data;
    220 }
    221