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  *  FIXME: Derive from SkBaseDevice.
     50  */
     51 class GatherPixelRefDevice : public SkDevice {
     52 private:
     53     PixelRefSet*  fPRSet;
     54 
     55     void addBitmap(const SkBitmap& bm) {
     56         fPRSet->add(bm.pixelRef());
     57     }
     58 
     59     void addBitmapFromPaint(const SkPaint& paint) {
     60         SkShader* shader = paint.getShader();
     61         if (shader) {
     62             SkBitmap bm;
     63             // Check whether the shader is a gradient in order to short-circuit
     64             // call to asABitmap to prevent generation of bitmaps from
     65             // gradient shaders, which implement asABitmap.
     66             if (SkShader::kNone_GradientType == shader->asAGradient(NULL) &&
     67                 shader->asABitmap(&bm, NULL, NULL)) {
     68                 fPRSet->add(bm.pixelRef());
     69             }
     70         }
     71     }
     72 
     73 public:
     74     GatherPixelRefDevice(const SkBitmap& bm, PixelRefSet* prset) : SkDevice(bm) {
     75         fPRSet = prset;
     76     }
     77 
     78     virtual void clear(SkColor color) SK_OVERRIDE {
     79         nothing_to_do();
     80     }
     81     virtual void writePixels(const SkBitmap& bitmap, int x, int y,
     82                              SkCanvas::Config8888 config8888) SK_OVERRIDE {
     83         not_supported();
     84     }
     85 
     86     virtual void drawPaint(const SkDraw&, const SkPaint& paint) SK_OVERRIDE {
     87         this->addBitmapFromPaint(paint);
     88     }
     89     virtual void drawPoints(const SkDraw&, SkCanvas::PointMode mode, size_t count,
     90                             const SkPoint[], const SkPaint& paint) SK_OVERRIDE {
     91         this->addBitmapFromPaint(paint);
     92     }
     93     virtual void drawRect(const SkDraw&, const SkRect&,
     94                           const SkPaint& paint) SK_OVERRIDE {
     95         this->addBitmapFromPaint(paint);
     96     }
     97     virtual void drawRRect(const SkDraw&, const SkRRect&,
     98                            const SkPaint& paint) SK_OVERRIDE {
     99         this->addBitmapFromPaint(paint);
    100     }
    101     virtual void drawOval(const SkDraw&, const SkRect&,
    102                           const SkPaint& paint) SK_OVERRIDE {
    103         this->addBitmapFromPaint(paint);
    104     }
    105     virtual void drawPath(const SkDraw&, const SkPath& path,
    106                           const SkPaint& paint, const SkMatrix* prePathMatrix,
    107                           bool pathIsMutable) SK_OVERRIDE {
    108         this->addBitmapFromPaint(paint);
    109     }
    110     virtual void drawBitmap(const SkDraw&, const SkBitmap& bitmap,
    111                             const SkMatrix&, const SkPaint&) SK_OVERRIDE {
    112         this->addBitmap(bitmap);
    113     }
    114     virtual void drawBitmapRect(const SkDraw&, const SkBitmap& bitmap,
    115                                 const SkRect* srcOrNull, const SkRect& dst,
    116                                 const SkPaint&) SK_OVERRIDE {
    117         this->addBitmap(bitmap);
    118     }
    119     virtual void drawSprite(const SkDraw&, const SkBitmap& bitmap,
    120                             int x, int y, const SkPaint& paint) SK_OVERRIDE {
    121         this->addBitmap(bitmap);
    122     }
    123     virtual void drawText(const SkDraw&, const void* text, size_t len,
    124                           SkScalar x, SkScalar y,
    125                           const SkPaint& paint) SK_OVERRIDE {
    126         this->addBitmapFromPaint(paint);
    127     }
    128     virtual void drawPosText(const SkDraw&, const void* text, size_t len,
    129                              const SkScalar pos[], SkScalar constY,
    130                              int, const SkPaint& paint) SK_OVERRIDE {
    131         this->addBitmapFromPaint(paint);
    132     }
    133     virtual void drawTextOnPath(const SkDraw&, const void* text, size_t len,
    134                                 const SkPath& path, const SkMatrix* matrix,
    135                                 const SkPaint& paint) SK_OVERRIDE {
    136         this->addBitmapFromPaint(paint);
    137     }
    138     virtual void drawVertices(const SkDraw&, SkCanvas::VertexMode, int vertexCount,
    139                               const SkPoint verts[], const SkPoint texs[],
    140                               const SkColor colors[], SkXfermode* xmode,
    141                               const uint16_t indices[], int indexCount,
    142                               const SkPaint& paint) SK_OVERRIDE {
    143         this->addBitmapFromPaint(paint);
    144     }
    145     virtual void drawDevice(const SkDraw&, SkDevice*, int x, int y,
    146                             const SkPaint&) SK_OVERRIDE {
    147         nothing_to_do();
    148     }
    149 
    150 protected:
    151     virtual bool onReadPixels(const SkBitmap& bitmap,
    152                               int x, int y,
    153                               SkCanvas::Config8888 config8888) SK_OVERRIDE {
    154         not_supported();
    155         return false;
    156     }
    157 };
    158 
    159 class NoSaveLayerCanvas : public SkCanvas {
    160 public:
    161     NoSaveLayerCanvas(SkDevice* device) : INHERITED(device) {}
    162 
    163     // turn saveLayer() into save() for speed, should not affect correctness.
    164     virtual int saveLayer(const SkRect* bounds, const SkPaint* paint,
    165                           SaveFlags flags) SK_OVERRIDE {
    166 
    167         // Like SkPictureRecord, we don't want to create layers, but we do need
    168         // to respect the save and (possibly) its rect-clip.
    169 
    170         int count = this->INHERITED::save(flags);
    171         if (bounds) {
    172             this->INHERITED::clipRectBounds(bounds, flags, NULL);
    173         }
    174         return count;
    175     }
    176 
    177     // disable aa for speed
    178     virtual bool clipRect(const SkRect& rect, SkRegion::Op op,
    179                           bool doAA) SK_OVERRIDE {
    180         return this->INHERITED::clipRect(rect, op, false);
    181     }
    182 
    183     // for speed, just respect the bounds, and disable AA. May give us a few
    184     // false positives and negatives.
    185     virtual bool clipPath(const SkPath& path, SkRegion::Op op,
    186                           bool doAA) SK_OVERRIDE {
    187         return this->updateClipConservativelyUsingBounds(path.getBounds(), op, path.isInverseFillType());
    188     }
    189     virtual bool clipRRect(const SkRRect& rrect, SkRegion::Op op,
    190                            bool doAA) SK_OVERRIDE {
    191         return this->updateClipConservativelyUsingBounds(rrect.getBounds(), op, false);
    192     }
    193 
    194 private:
    195     typedef SkCanvas INHERITED;
    196 };
    197 
    198 SkData* SkPictureUtils::GatherPixelRefs(SkPicture* pict, const SkRect& area) {
    199     if (NULL == pict) {
    200         return NULL;
    201     }
    202 
    203     // this test also handles if either area or pict's width/height are empty
    204     if (!SkRect::Intersects(area,
    205                             SkRect::MakeWH(SkIntToScalar(pict->width()),
    206                                            SkIntToScalar(pict->height())))) {
    207         return NULL;
    208     }
    209 
    210     SkTDArray<SkPixelRef*> array;
    211     PixelRefSet prset(&array);
    212 
    213     SkBitmap emptyBitmap;
    214     emptyBitmap.setConfig(SkBitmap::kARGB_8888_Config, pict->width(), pict->height());
    215     // note: we do not set any pixels (shouldn't need to)
    216 
    217     GatherPixelRefDevice device(emptyBitmap, &prset);
    218     NoSaveLayerCanvas canvas(&device);
    219 
    220     canvas.clipRect(area, SkRegion::kIntersect_Op, false);
    221     canvas.drawPicture(*pict);
    222 
    223     SkData* data = NULL;
    224     int count = array.count();
    225     if (count > 0) {
    226         data = SkData::NewFromMalloc(array.detach(), count * sizeof(SkPixelRef*));
    227     }
    228     return data;
    229 }
    230