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 "SkPictureUtils.h"
      9 #include "SkCanvas.h"
     10 #include "SkData.h"
     11 #include "SkDevice.h"
     12 #include "SkPixelRef.h"
     13 #include "SkShader.h"
     14 #include "SkRRect.h"
     15 
     16 class PixelRefSet {
     17 public:
     18     PixelRefSet(SkTDArray<SkPixelRef*>* array) : fArray(array) {}
     19 
     20     // This does a linear search on existing pixelrefs, so if this list gets big
     21     // we should use a more complex sorted/hashy thing.
     22     //
     23     void add(SkPixelRef* pr) {
     24         uint32_t genID = pr->getGenerationID();
     25         if (fGenID.find(genID) < 0) {
     26             *fArray->append() = pr;
     27             *fGenID.append() = genID;
     28 //            SkDebugf("--- adding [%d] %x %d\n", fArray->count() - 1, pr, genID);
     29         } else {
     30 //            SkDebugf("--- already have %x %d\n", pr, genID);
     31         }
     32     }
     33 
     34 private:
     35     SkTDArray<SkPixelRef*>* fArray;
     36     SkTDArray<uint32_t>     fGenID;
     37 };
     38 
     39 static void not_supported() {
     40     SkASSERT(!"this method should never be called");
     41 }
     42 
     43 static void nothing_to_do() {}
     44 
     45 /**
     46  *  This device will route all bitmaps (primitives and in shaders) to its PRSet.
     47  *  It should never actually draw anything, so there need not be any pixels
     48  *  behind its device-bitmap.
     49  */
     50 class GatherPixelRefDevice : public SkDevice {
     51 private:
     52     PixelRefSet*  fPRSet;
     53 
     54     void addBitmap(const SkBitmap& bm) {
     55         fPRSet->add(bm.pixelRef());
     56     }
     57 
     58     void addBitmapFromPaint(const SkPaint& paint) {
     59         SkShader* shader = paint.getShader();
     60         if (shader) {
     61             SkBitmap bm;
     62             // Check whether the shader is a gradient in order to short-circuit
     63             // call to asABitmap to prevent generation of bitmaps from
     64             // gradient shaders, which implement asABitmap.
     65             if (SkShader::kNone_GradientType == shader->asAGradient(NULL) &&
     66                 shader->asABitmap(&bm, NULL, NULL)) {
     67                 fPRSet->add(bm.pixelRef());
     68             }
     69         }
     70     }
     71 
     72 public:
     73     GatherPixelRefDevice(const SkBitmap& bm, PixelRefSet* prset) : SkDevice(bm) {
     74         fPRSet = prset;
     75     }
     76 
     77     virtual void clear(SkColor color) SK_OVERRIDE {
     78         nothing_to_do();
     79     }
     80     virtual void writePixels(const SkBitmap& bitmap, int x, int y,
     81                              SkCanvas::Config8888 config8888) SK_OVERRIDE {
     82         not_supported();
     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 drawOval(const SkDraw&, const SkRect&,
     97                           const SkPaint& paint) SK_OVERRIDE {
     98         this->addBitmapFromPaint(paint);
     99     }
    100     virtual void drawPath(const SkDraw&, const SkPath& path,
    101                           const SkPaint& paint, const SkMatrix* prePathMatrix,
    102                           bool pathIsMutable) SK_OVERRIDE {
    103         this->addBitmapFromPaint(paint);
    104     }
    105     virtual void drawBitmap(const SkDraw&, const SkBitmap& bitmap,
    106                             const SkMatrix&, const SkPaint&) SK_OVERRIDE {
    107         this->addBitmap(bitmap);
    108     }
    109     virtual void drawBitmapRect(const SkDraw&, const SkBitmap& bitmap,
    110                                 const SkRect* srcOrNull, const SkRect& dst,
    111                                 const SkPaint&) SK_OVERRIDE {
    112         this->addBitmap(bitmap);
    113     }
    114     virtual void drawSprite(const SkDraw&, const SkBitmap& bitmap,
    115                             int x, int y, const SkPaint& paint) SK_OVERRIDE {
    116         this->addBitmap(bitmap);
    117     }
    118     virtual void drawText(const SkDraw&, const void* text, size_t len,
    119                           SkScalar x, SkScalar y,
    120                           const SkPaint& paint) SK_OVERRIDE {
    121         this->addBitmapFromPaint(paint);
    122     }
    123     virtual void drawPosText(const SkDraw&, const void* text, size_t len,
    124                              const SkScalar pos[], SkScalar constY,
    125                              int, const SkPaint& paint) SK_OVERRIDE {
    126         this->addBitmapFromPaint(paint);
    127     }
    128     virtual void drawTextOnPath(const SkDraw&, const void* text, size_t len,
    129                                 const SkPath& path, const SkMatrix* matrix,
    130                                 const SkPaint& paint) SK_OVERRIDE {
    131         this->addBitmapFromPaint(paint);
    132     }
    133     virtual void drawVertices(const SkDraw&, SkCanvas::VertexMode, int vertexCount,
    134                               const SkPoint verts[], const SkPoint texs[],
    135                               const SkColor colors[], SkXfermode* xmode,
    136                               const uint16_t indices[], int indexCount,
    137                               const SkPaint& paint) SK_OVERRIDE {
    138         this->addBitmapFromPaint(paint);
    139     }
    140     virtual void drawDevice(const SkDraw&, SkDevice*, int x, int y,
    141                             const SkPaint&) SK_OVERRIDE {
    142         nothing_to_do();
    143     }
    144 
    145 protected:
    146     virtual bool onReadPixels(const SkBitmap& bitmap,
    147                               int x, int y,
    148                               SkCanvas::Config8888 config8888) SK_OVERRIDE {
    149         not_supported();
    150         return false;
    151     }
    152 };
    153 
    154 class NoSaveLayerCanvas : public SkCanvas {
    155 public:
    156     NoSaveLayerCanvas(SkDevice* device) : INHERITED(device) {}
    157 
    158     // turn saveLayer() into save() for speed, should not affect correctness.
    159     virtual int saveLayer(const SkRect* bounds, const SkPaint* paint,
    160                           SaveFlags flags) SK_OVERRIDE {
    161 
    162         // Like SkPictureRecord, we don't want to create layers, but we do need
    163         // to respect the save and (possibly) its rect-clip.
    164 
    165         int count = this->INHERITED::save(flags);
    166         if (bounds) {
    167             this->INHERITED::clipRectBounds(bounds, flags, NULL);
    168         }
    169         return count;
    170     }
    171 
    172     // disable aa for speed
    173     virtual bool clipRect(const SkRect& rect, SkRegion::Op op,
    174                           bool doAA) SK_OVERRIDE {
    175         return this->INHERITED::clipRect(rect, op, false);
    176     }
    177 
    178     // for speed, just respect the bounds, and disable AA. May give us a few
    179     // false positives and negatives.
    180     virtual bool clipPath(const SkPath& path, SkRegion::Op op,
    181                           bool doAA) SK_OVERRIDE {
    182         return this->updateClipConservativelyUsingBounds(path.getBounds(), op, path.isInverseFillType());
    183     }
    184     virtual bool clipRRect(const SkRRect& rrect, SkRegion::Op op,
    185                            bool doAA) SK_OVERRIDE {
    186         return this->updateClipConservativelyUsingBounds(rrect.getBounds(), op, false);
    187     }
    188 
    189 private:
    190     typedef SkCanvas INHERITED;
    191 };
    192 
    193 SkData* SkPictureUtils::GatherPixelRefs(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,
    200                             SkRect::MakeWH(SkIntToScalar(pict->width()),
    201                                            SkIntToScalar(pict->height())))) {
    202         return NULL;
    203     }
    204 
    205     SkTDArray<SkPixelRef*> array;
    206     PixelRefSet prset(&array);
    207 
    208     SkBitmap emptyBitmap;
    209     emptyBitmap.setConfig(SkBitmap::kARGB_8888_Config, pict->width(), pict->height());
    210     // note: we do not set any pixels (shouldn't need to)
    211 
    212     GatherPixelRefDevice device(emptyBitmap, &prset);
    213     NoSaveLayerCanvas canvas(&device);
    214 
    215     canvas.clipRect(area, SkRegion::kIntersect_Op, false);
    216     canvas.drawPicture(*pict);
    217 
    218     SkData* data = NULL;
    219     int count = array.count();
    220     if (count > 0) {
    221         data = SkData::NewFromMalloc(array.detach(), count * sizeof(SkPixelRef*));
    222     }
    223     return data;
    224 }
    225