Home | History | Annotate | Download | only in core
      1 /*
      2  * Copyright 2011 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 #ifndef SkPictureRecord_DEFINED
      9 #define SkPictureRecord_DEFINED
     10 
     11 #include "SkCanvas.h"
     12 #include "SkFlattenable.h"
     13 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
     14 #include "SkMatrixClipStateMgr.h"
     15 #endif
     16 #include "SkPathHeap.h"
     17 #include "SkPicture.h"
     18 #include "SkPicturePlayback.h"
     19 #include "SkPictureFlat.h"
     20 #include "SkTemplates.h"
     21 #include "SkWriter32.h"
     22 
     23 class SkBBoxHierarchy;
     24 class SkPictureStateTree;
     25 
     26 // These macros help with packing and unpacking a single byte value and
     27 // a 3 byte value into/out of a uint32_t
     28 #define MASK_24 0x00FFFFFF
     29 #define UNPACK_8_24(combined, small, large)             \
     30     small = (combined >> 24) & 0xFF;                    \
     31     large = combined & MASK_24;
     32 #define PACK_8_24(small, large) ((small << 24) | large)
     33 
     34 
     35 class SkPictureRecord : public SkCanvas {
     36 public:
     37     SkPictureRecord(const SkISize& dimensions, uint32_t recordFlags);
     38     virtual ~SkPictureRecord();
     39 
     40     virtual void clear(SkColor) SK_OVERRIDE;
     41     virtual void drawPaint(const SkPaint& paint) SK_OVERRIDE;
     42     virtual void drawPoints(PointMode, size_t count, const SkPoint pts[],
     43                             const SkPaint&) SK_OVERRIDE;
     44     virtual void drawOval(const SkRect&, const SkPaint&) SK_OVERRIDE;
     45     virtual void drawRect(const SkRect&, const SkPaint&) SK_OVERRIDE;
     46     virtual void drawRRect(const SkRRect&, const SkPaint&) SK_OVERRIDE;
     47     virtual void drawPath(const SkPath& path, const SkPaint&) SK_OVERRIDE;
     48     virtual void drawBitmap(const SkBitmap&, SkScalar left, SkScalar top,
     49                             const SkPaint*) SK_OVERRIDE;
     50     virtual void drawBitmapRectToRect(const SkBitmap&, const SkRect* src,
     51                                       const SkRect& dst, const SkPaint* paint,
     52                                       DrawBitmapRectFlags flags) SK_OVERRIDE;
     53     virtual void drawBitmapMatrix(const SkBitmap&, const SkMatrix&,
     54                                   const SkPaint*) SK_OVERRIDE;
     55     virtual void drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
     56                                 const SkRect& dst, const SkPaint*) SK_OVERRIDE;
     57     virtual void drawSprite(const SkBitmap&, int left, int top,
     58                             const SkPaint*) SK_OVERRIDE;
     59     virtual void drawVertices(VertexMode, int vertexCount,
     60                           const SkPoint vertices[], const SkPoint texs[],
     61                           const SkColor colors[], SkXfermode*,
     62                           const uint16_t indices[], int indexCount,
     63                               const SkPaint&) SK_OVERRIDE;
     64     virtual void drawData(const void*, size_t) SK_OVERRIDE;
     65     virtual void beginCommentGroup(const char* description) SK_OVERRIDE;
     66     virtual void addComment(const char* kywd, const char* value) SK_OVERRIDE;
     67     virtual void endCommentGroup() SK_OVERRIDE;
     68     virtual bool isDrawingToLayer() const SK_OVERRIDE;
     69 
     70     void addFontMetricsTopBottom(const SkPaint& paint, const SkFlatData&,
     71                                  SkScalar minY, SkScalar maxY);
     72 
     73     const SkTDArray<const SkPicture* >& getPictureRefs() const {
     74         return fPictureRefs;
     75     }
     76 
     77     SkData* opData(bool deepCopy) const {
     78         this->validate(fWriter.bytesWritten(), 0);
     79 
     80         if (fWriter.bytesWritten() == 0) {
     81             return SkData::NewEmpty();
     82         }
     83 
     84         if (deepCopy) {
     85             return SkData::NewWithCopy(fWriter.contiguousArray(), fWriter.bytesWritten());
     86         }
     87 
     88         return fWriter.snapshotAsData();
     89     }
     90 
     91     const SkPathHeap* pathHeap() const {
     92         return fPathHeap.get();
     93     }
     94 
     95     const SkPictureContentInfo& contentInfo() const {
     96         return fContentInfo;
     97     }
     98 
     99     void setFlags(uint32_t recordFlags) {
    100         fRecordFlags = recordFlags;
    101     }
    102 
    103     const SkWriter32& writeStream() const {
    104         return fWriter;
    105     }
    106 
    107     void beginRecording();
    108     void endRecording();
    109 
    110     void internalOnly_EnableOpts(bool optsEnabled) {
    111         fOptsEnabled = optsEnabled;
    112     }
    113 
    114 protected:
    115     void addNoOp();
    116 
    117 private:
    118     void handleOptimization(int opt);
    119     size_t recordRestoreOffsetPlaceholder(SkRegion::Op);
    120     void fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset);
    121 
    122 #ifndef SK_COLLAPSE_MATRIX_CLIP_STATE
    123     SkTDArray<int32_t> fRestoreOffsetStack;
    124     int fFirstSavedLayerIndex;
    125     enum {
    126         kNoSavedLayerIndex = -1
    127     };
    128 #endif
    129 
    130     SkTDArray<uint32_t> fCullOffsetStack;
    131 
    132     /*
    133      * Write the 'drawType' operation and chunk size to the skp. 'size'
    134      * can potentially be increased if the chunk size needs its own storage
    135      * location (i.e., it overflows 24 bits).
    136      * Returns the start offset of the chunk. This is the location at which
    137      * the opcode & size are stored.
    138      * TODO: since we are handing the size into here we could call reserve
    139      * and then return a pointer to the memory storage. This could decrease
    140      * allocation overhead but could lead to more wasted space (the tail
    141      * end of blocks could go unused). Possibly add a second addDraw that
    142      * operates in this manner.
    143      */
    144     size_t addDraw(DrawType drawType, size_t* size) {
    145         size_t offset = fWriter.bytesWritten();
    146 
    147         this->predrawNotify();
    148 
    149     #ifdef SK_DEBUG_TRACE
    150         SkDebugf("add %s\n", DrawTypeToString(drawType));
    151     #endif
    152 
    153         SkASSERT(0 != *size);
    154         SkASSERT(((uint8_t) drawType) == drawType);
    155 
    156         if (0 != (*size & ~MASK_24) || *size == MASK_24) {
    157             fWriter.writeInt(PACK_8_24(drawType, MASK_24));
    158             *size += 1;
    159             fWriter.writeInt(SkToU32(*size));
    160         } else {
    161             fWriter.writeInt(PACK_8_24(drawType, SkToU32(*size)));
    162         }
    163 
    164         return offset;
    165     }
    166 
    167     void addInt(int value) {
    168         fWriter.writeInt(value);
    169     }
    170     void addScalar(SkScalar scalar) {
    171         fWriter.writeScalar(scalar);
    172     }
    173 
    174     // The command at 'offset' in the skp uses the specified bitmap
    175     int addBitmap(const SkBitmap& bitmap);
    176     void addMatrix(const SkMatrix& matrix);
    177     const SkFlatData* addPaint(const SkPaint& paint) { return this->addPaintPtr(&paint); }
    178     const SkFlatData* addPaintPtr(const SkPaint* paint);
    179     void addFlatPaint(const SkFlatData* flatPaint);
    180     void addPath(const SkPath& path);
    181     void addPicture(const SkPicture* picture);
    182     void addPoint(const SkPoint& point);
    183     void addPoints(const SkPoint pts[], int count);
    184     void addRect(const SkRect& rect);
    185     void addRectPtr(const SkRect* rect);
    186     void addIRect(const SkIRect& rect);
    187     void addIRectPtr(const SkIRect* rect);
    188     void addRRect(const SkRRect&);
    189     void addRegion(const SkRegion& region);
    190     void addText(const void* text, size_t byteLength);
    191 
    192     int find(const SkBitmap& bitmap);
    193 
    194 #ifdef SK_DEBUG_DUMP
    195 public:
    196     void dumpMatrices();
    197     void dumpPaints();
    198 #endif
    199 
    200 #ifdef SK_DEBUG_SIZE
    201 public:
    202     size_t size() const;
    203     int bitmaps(size_t* size) const;
    204     int matrices(size_t* size) const;
    205     int paints(size_t* size) const;
    206     int paths(size_t* size) const;
    207     int regions(size_t* size) const;
    208     size_t streamlen() const;
    209 
    210     size_t fPointBytes, fRectBytes, fTextBytes;
    211     int fPointWrites, fRectWrites, fTextWrites;
    212 #endif
    213 
    214 #ifdef SK_DEBUG_VALIDATE
    215 public:
    216     void validate(size_t initialOffset, uint32_t size) const;
    217 private:
    218     void validateBitmaps() const;
    219     void validateMatrices() const;
    220     void validatePaints() const;
    221     void validatePaths() const;
    222     void validateRegions() const;
    223 #else
    224 public:
    225     void validate(size_t initialOffset, size_t size) const {
    226         SkASSERT(fWriter.bytesWritten() == initialOffset + size);
    227     }
    228 #endif
    229 
    230 protected:
    231     virtual SkSurface* onNewSurface(const SkImageInfo&) SK_OVERRIDE;
    232     const void* onPeekPixels(SkImageInfo*, size_t*) SK_OVERRIDE {
    233         return NULL;
    234     }
    235 
    236     virtual void willSave(SaveFlags) SK_OVERRIDE;
    237     virtual SaveLayerStrategy willSaveLayer(const SkRect*, const SkPaint*, SaveFlags) SK_OVERRIDE;
    238     virtual void willRestore() SK_OVERRIDE;
    239 
    240     virtual void didConcat(const SkMatrix&) SK_OVERRIDE;
    241     virtual void didSetMatrix(const SkMatrix&) SK_OVERRIDE;
    242 
    243     virtual void onDrawDRRect(const SkRRect&, const SkRRect&, const SkPaint&) SK_OVERRIDE;
    244     virtual void onPushCull(const SkRect&) SK_OVERRIDE;
    245     virtual void onPopCull() SK_OVERRIDE;
    246 
    247     virtual void onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
    248                             const SkPaint&) SK_OVERRIDE;
    249     virtual void onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
    250                                const SkPaint&) SK_OVERRIDE;
    251     virtual void onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
    252                                 SkScalar constY, const SkPaint&) SK_OVERRIDE;
    253     virtual void onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
    254                                   const SkMatrix* matrix, const SkPaint&) SK_OVERRIDE;
    255 
    256     virtual void onClipRect(const SkRect&, SkRegion::Op, ClipEdgeStyle) SK_OVERRIDE;
    257     virtual void onClipRRect(const SkRRect&, SkRegion::Op, ClipEdgeStyle) SK_OVERRIDE;
    258     virtual void onClipPath(const SkPath&, SkRegion::Op, ClipEdgeStyle) SK_OVERRIDE;
    259     virtual void onClipRegion(const SkRegion&, SkRegion::Op) SK_OVERRIDE;
    260 
    261     virtual void onDrawPicture(const SkPicture* picture) SK_OVERRIDE;
    262 
    263     // Return fontmetrics.fTop,fBottom in topbot[0,1], after they have been
    264     // tweaked by paint.computeFastBounds().
    265     static void ComputeFontMetricsTopBottom(const SkPaint& paint, SkScalar topbot[2]);
    266 
    267     // Make sure that flat has fTopBot written.
    268     static void WriteTopBot(const SkPaint& paint, const SkFlatData& flat) {
    269         if (!flat.isTopBotWritten()) {
    270             ComputeFontMetricsTopBottom(paint, flat.writableTopBot());
    271             SkASSERT(flat.isTopBotWritten());
    272         }
    273     }
    274     // Will return a cached version when possible.
    275     const SkFlatData* getFlatPaintData(const SkPaint& paint);
    276     /**
    277      * SkBBoxRecord::drawPosTextH gets a flat paint and uses it,
    278      * then it calls this, using the extra parameter, to avoid duplication.
    279      */
    280     void drawPosTextHImpl(const void* text, size_t byteLength,
    281                           const SkScalar xpos[], SkScalar constY,
    282                           const SkPaint& paint, const SkFlatData* flatPaintData);
    283 
    284     int addPathToHeap(const SkPath& path);  // does not write to ops stream
    285 
    286     // These entry points allow the writing of matrices, clips, saves &
    287     // restores to be deferred (e.g., if the MC state is being collapsed and
    288     // only written out as needed).
    289     void recordConcat(const SkMatrix& matrix);
    290     void recordTranslate(const SkMatrix& matrix);
    291     void recordScale(const SkMatrix& matrix);
    292     size_t recordClipRect(const SkRect& rect, SkRegion::Op op, bool doAA);
    293     size_t recordClipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA);
    294     size_t recordClipPath(int pathID, SkRegion::Op op, bool doAA);
    295     size_t recordClipRegion(const SkRegion& region, SkRegion::Op op);
    296     void recordSave(SaveFlags flags);
    297     void recordSaveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags);
    298     void recordRestore(bool fillInSkips = true);
    299 
    300     // These are set to NULL in our constructor, but may be changed by
    301     // subclasses, in which case they will be SkSafeUnref'd in our destructor.
    302     SkBBoxHierarchy* fBoundingHierarchy;
    303     SkPictureStateTree* fStateTree;
    304 
    305     // Allocated in the constructor and managed by this class.
    306     SkBitmapHeap* fBitmapHeap;
    307 
    308 private:
    309     friend class MatrixClipState; // for access to *Impl methods
    310     friend class SkMatrixClipStateMgr; // for access to *Impl methods
    311 
    312     SkPictureContentInfo fContentInfo;
    313     SkAutoTUnref<SkPathHeap> fPathHeap;
    314 
    315     SkChunkFlatController fFlattenableHeap;
    316 
    317     SkPaintDictionary fPaints;
    318 
    319     SkWriter32 fWriter;
    320 
    321     // we ref each item in these arrays
    322     SkTDArray<const SkPicture*> fPictureRefs;
    323 
    324     uint32_t fRecordFlags;
    325     bool     fOptsEnabled;
    326     int      fInitialSaveCount;
    327 
    328     friend class SkPicturePlayback;
    329     friend class SkPictureTester; // for unit testing
    330 
    331 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
    332     SkMatrixClipStateMgr fMCMgr;
    333 #endif
    334 
    335     typedef SkCanvas INHERITED;
    336 };
    337 
    338 #endif
    339