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 SkIRect* srcRectOrNull,
    107                             const SkMatrix&, const SkPaint&) SK_OVERRIDE {
    108         this->addBitmap(bitmap);
    109     }
    110     virtual void drawBitmapRect(const SkDraw&, const SkBitmap& bitmap,
    111                                 const SkRect* srcOrNull, const SkRect& dst,
    112                                 const SkPaint&) SK_OVERRIDE {
    113         this->addBitmap(bitmap);
    114     }
    115     virtual void drawSprite(const SkDraw&, const SkBitmap& bitmap,
    116                             int x, int y, const SkPaint& paint) SK_OVERRIDE {
    117         this->addBitmap(bitmap);
    118     }
    119     virtual void drawText(const SkDraw&, const void* text, size_t len,
    120                           SkScalar x, SkScalar y,
    121                           const SkPaint& paint) SK_OVERRIDE {
    122         this->addBitmapFromPaint(paint);
    123     }
    124     virtual void drawPosText(const SkDraw&, const void* text, size_t len,
    125                              const SkScalar pos[], SkScalar constY,
    126                              int, const SkPaint& paint) SK_OVERRIDE {
    127         this->addBitmapFromPaint(paint);
    128     }
    129     virtual void drawTextOnPath(const SkDraw&, const void* text, size_t len,
    130                                 const SkPath& path, const SkMatrix* matrix,
    131                                 const SkPaint& paint) SK_OVERRIDE {
    132         this->addBitmapFromPaint(paint);
    133     }
    134     virtual void drawVertices(const SkDraw&, SkCanvas::VertexMode, int vertexCount,
    135                               const SkPoint verts[], const SkPoint texs[],
    136                               const SkColor colors[], SkXfermode* xmode,
    137                               const uint16_t indices[], int indexCount,
    138                               const SkPaint& paint) SK_OVERRIDE {
    139         this->addBitmapFromPaint(paint);
    140     }
    141     virtual void drawDevice(const SkDraw&, SkDevice*, int x, int y,
    142                             const SkPaint&) SK_OVERRIDE {
    143         nothing_to_do();
    144     }
    145 
    146 protected:
    147     virtual bool onReadPixels(const SkBitmap& bitmap,
    148                               int x, int y,
    149                               SkCanvas::Config8888 config8888) SK_OVERRIDE {
    150         not_supported();
    151         return false;
    152     }
    153 };
    154 
    155 class NoSaveLayerCanvas : public SkCanvas {
    156 public:
    157     NoSaveLayerCanvas(SkDevice* device) : INHERITED(device) {}
    158 
    159     // turn saveLayer() into save() for speed, should not affect correctness.
    160     virtual int saveLayer(const SkRect* bounds, const SkPaint* paint,
    161                           SaveFlags flags) SK_OVERRIDE {
    162 
    163         // Like SkPictureRecord, we don't want to create layers, but we do need
    164         // to respect the save and (possibly) its rect-clip.
    165 
    166         int count = this->INHERITED::save(flags);
    167         if (bounds) {
    168             this->INHERITED::clipRectBounds(bounds, flags, NULL);
    169         }
    170         return count;
    171     }
    172 
    173     // disable aa for speed
    174     virtual bool clipRect(const SkRect& rect, SkRegion::Op op,
    175                           bool doAA) SK_OVERRIDE {
    176         return this->INHERITED::clipRect(rect, op, false);
    177     }
    178 
    179     // for speed, just respect the bounds, and disable AA. May give us a few
    180     // false positives and negatives.
    181     virtual bool clipPath(const SkPath& path, SkRegion::Op op,
    182                           bool doAA) SK_OVERRIDE {
    183         return this->INHERITED::clipRect(path.getBounds(), op, false);
    184     }
    185     virtual bool clipRRect(const SkRRect& rrect, SkRegion::Op op,
    186                            bool doAA) SK_OVERRIDE {
    187         return this->INHERITED::clipRect(rrect.getBounds(), op, false);
    188     }
    189 
    190 private:
    191     typedef SkCanvas INHERITED;
    192 };
    193 
    194 SkData* SkPictureUtils::GatherPixelRefs(SkPicture* pict, const SkRect& area) {
    195     if (NULL == pict) {
    196         return NULL;
    197     }
    198 
    199     // this test also handles if either area or pict's width/height are empty
    200     if (!SkRect::Intersects(area,
    201                             SkRect::MakeWH(SkIntToScalar(pict->width()),
    202                                            SkIntToScalar(pict->height())))) {
    203         return NULL;
    204     }
    205 
    206     SkTDArray<SkPixelRef*> array;
    207     PixelRefSet prset(&array);
    208 
    209     SkBitmap emptyBitmap;
    210     emptyBitmap.setConfig(SkBitmap::kARGB_8888_Config, pict->width(), pict->height());
    211     // note: we do not set any pixels (shouldn't need to)
    212 
    213     GatherPixelRefDevice device(emptyBitmap, &prset);
    214     NoSaveLayerCanvas canvas(&device);
    215 
    216     canvas.clipRect(area, SkRegion::kIntersect_Op, false);
    217     canvas.drawPicture(*pict);
    218 
    219     SkData* data = NULL;
    220     int count = array.count();
    221     if (count > 0) {
    222         data = SkData::NewFromMalloc(array.detach(), count * sizeof(SkPixelRef*));
    223     }
    224     return data;
    225 }
    226