michael@0: michael@0: /* michael@0: * Copyright 2007 The Android Open Source Project michael@0: * michael@0: * Use of this source code is governed by a BSD-style license that can be michael@0: * found in the LICENSE file. michael@0: */ michael@0: michael@0: michael@0: #ifndef SkPicture_DEFINED michael@0: #define SkPicture_DEFINED michael@0: michael@0: #include "SkBitmap.h" michael@0: #include "SkImageDecoder.h" michael@0: #include "SkRefCnt.h" michael@0: michael@0: class SkBBoxHierarchy; michael@0: class SkCanvas; michael@0: class SkDrawPictureCallback; michael@0: class SkData; michael@0: class SkPicturePlayback; michael@0: class SkPictureRecord; michael@0: class SkStream; michael@0: class SkWStream; michael@0: michael@0: struct SkPictInfo; michael@0: michael@0: /** \class SkPicture michael@0: michael@0: The SkPicture class records the drawing commands made to a canvas, to michael@0: be played back at a later time. michael@0: */ michael@0: class SK_API SkPicture : public SkRefCnt { michael@0: public: michael@0: SK_DECLARE_INST_COUNT(SkPicture) michael@0: michael@0: // AccelData provides a base class for device-specific acceleration michael@0: // data. It is added to the picture via a call to a device's optimize michael@0: // method. michael@0: class AccelData : public SkRefCnt { michael@0: public: michael@0: typedef uint8_t Domain; michael@0: typedef uint32_t Key; michael@0: michael@0: AccelData(Key key) : fKey(key) { } michael@0: michael@0: const Key& getKey() const { return fKey; } michael@0: michael@0: // This entry point allows user's to get a unique domain prefix michael@0: // for their keys michael@0: static Domain GenerateDomain(); michael@0: private: michael@0: Key fKey; michael@0: michael@0: typedef SkRefCnt INHERITED; michael@0: }; michael@0: michael@0: /** The constructor prepares the picture to record. michael@0: @param width the width of the virtual device the picture records. michael@0: @param height the height of the virtual device the picture records. michael@0: */ michael@0: SkPicture(); michael@0: /** Make a copy of the contents of src. If src records more drawing after michael@0: this call, those elements will not appear in this picture. michael@0: */ michael@0: SkPicture(const SkPicture& src); michael@0: michael@0: /** PRIVATE / EXPERIMENTAL -- do not call */ michael@0: void EXPERIMENTAL_addAccelData(const AccelData* data) { michael@0: SkRefCnt_SafeAssign(fAccelData, data); michael@0: } michael@0: /** PRIVATE / EXPERIMENTAL -- do not call */ michael@0: const AccelData* EXPERIMENTAL_getAccelData(AccelData::Key key) const { michael@0: if (NULL != fAccelData && fAccelData->getKey() == key) { michael@0: return fAccelData; michael@0: } michael@0: return NULL; michael@0: } michael@0: michael@0: /** michael@0: * Function signature defining a function that sets up an SkBitmap from encoded data. On michael@0: * success, the SkBitmap should have its Config, width, height, rowBytes and pixelref set. michael@0: * If the installed pixelref has decoded the data into pixels, then the src buffer need not be michael@0: * copied. If the pixelref defers the actual decode until its lockPixels() is called, then it michael@0: * must make a copy of the src buffer. michael@0: * @param src Encoded data. michael@0: * @param length Size of the encoded data, in bytes. michael@0: * @param dst SkBitmap to install the pixel ref on. michael@0: * @param bool Whether or not a pixel ref was successfully installed. michael@0: */ michael@0: typedef bool (*InstallPixelRefProc)(const void* src, size_t length, SkBitmap* dst); michael@0: michael@0: /** michael@0: * Recreate a picture that was serialized into a stream. michael@0: * @param SkStream Serialized picture data. michael@0: * @param proc Function pointer for installing pixelrefs on SkBitmaps representing the michael@0: * encoded bitmap data from the stream. michael@0: * @return A new SkPicture representing the serialized data, or NULL if the stream is michael@0: * invalid. michael@0: */ michael@0: static SkPicture* CreateFromStream(SkStream*, michael@0: InstallPixelRefProc proc = &SkImageDecoder::DecodeMemory); michael@0: michael@0: /** michael@0: * Recreate a picture that was serialized into a buffer. If the creation requires bitmap michael@0: * decoding, the decoder must be set on the SkReadBuffer parameter by calling michael@0: * SkReadBuffer::setBitmapDecoder() before calling SkPicture::CreateFromBuffer(). michael@0: * @param SkReadBuffer Serialized picture data. michael@0: * @return A new SkPicture representing the serialized data, or NULL if the buffer is michael@0: * invalid. michael@0: */ michael@0: static SkPicture* CreateFromBuffer(SkReadBuffer&); michael@0: michael@0: virtual ~SkPicture(); michael@0: michael@0: /** michael@0: * Swap the contents of the two pictures. Guaranteed to succeed. michael@0: */ michael@0: void swap(SkPicture& other); michael@0: michael@0: /** michael@0: * Creates a thread-safe clone of the picture that is ready for playback. michael@0: */ michael@0: SkPicture* clone() const; michael@0: michael@0: /** michael@0: * Creates multiple thread-safe clones of this picture that are ready for michael@0: * playback. The resulting clones are stored in the provided array of michael@0: * SkPictures. michael@0: */ michael@0: void clone(SkPicture* pictures, int count) const; michael@0: michael@0: enum RecordingFlags { michael@0: /* This flag specifies that when clipPath() is called, the path will michael@0: be faithfully recorded, but the recording canvas' current clip will michael@0: only see the path's bounds. This speeds up the recording process michael@0: without compromising the fidelity of the playback. The only side- michael@0: effect for recording is that calling getTotalClip() or related michael@0: clip-query calls will reflect the path's bounds, not the actual michael@0: path. michael@0: */ michael@0: kUsePathBoundsForClip_RecordingFlag = 0x01, michael@0: /* This flag causes the picture to compute bounding boxes and build michael@0: up a spatial hierarchy (currently an R-Tree), plus a tree of Canvas' michael@0: usually stack-based clip/etc state. This requires an increase in michael@0: recording time (often ~2x; likely more for very complex pictures), michael@0: but allows us to perform much faster culling at playback time, and michael@0: completely avoid some unnecessary clips and other operations. This michael@0: is ideal for tiled rendering, or any other situation where you're michael@0: drawing a fraction of a large scene into a smaller viewport. michael@0: michael@0: In most cases the record cost is offset by the playback improvement michael@0: after a frame or two of tiled rendering (and complex pictures that michael@0: induce the worst record times will generally get the largest michael@0: speedups at playback time). michael@0: michael@0: Note: Currently this is not serializable, the bounding data will be michael@0: discarded if you serialize into a stream and then deserialize. michael@0: */ michael@0: kOptimizeForClippedPlayback_RecordingFlag = 0x02, michael@0: }; michael@0: michael@0: /** Returns the canvas that records the drawing commands. michael@0: @param width the base width for the picture, as if the recording michael@0: canvas' bitmap had this width. michael@0: @param height the base width for the picture, as if the recording michael@0: canvas' bitmap had this height. michael@0: @param recordFlags optional flags that control recording. michael@0: @return the picture canvas. michael@0: */ michael@0: SkCanvas* beginRecording(int width, int height, uint32_t recordFlags = 0); michael@0: michael@0: /** Returns the recording canvas if one is active, or NULL if recording is michael@0: not active. This does not alter the refcnt on the canvas (if present). michael@0: */ michael@0: SkCanvas* getRecordingCanvas() const; michael@0: /** Signal that the caller is done recording. This invalidates the canvas michael@0: returned by beginRecording/getRecordingCanvas, and prepares the picture michael@0: for drawing. Note: this happens implicitly the first time the picture michael@0: is drawn. michael@0: */ michael@0: void endRecording(); michael@0: michael@0: /** Replays the drawing commands on the specified canvas. This internally michael@0: calls endRecording() if that has not already been called. michael@0: @param canvas the canvas receiving the drawing commands. michael@0: */ michael@0: void draw(SkCanvas* canvas, SkDrawPictureCallback* = NULL); michael@0: michael@0: /** Return the width of the picture's recording canvas. This michael@0: value reflects what was passed to setSize(), and does not necessarily michael@0: reflect the bounds of what has been recorded into the picture. michael@0: @return the width of the picture's recording canvas michael@0: */ michael@0: int width() const { return fWidth; } michael@0: michael@0: /** Return the height of the picture's recording canvas. This michael@0: value reflects what was passed to setSize(), and does not necessarily michael@0: reflect the bounds of what has been recorded into the picture. michael@0: @return the height of the picture's recording canvas michael@0: */ michael@0: int height() const { return fHeight; } michael@0: michael@0: /** michael@0: * Function to encode an SkBitmap to an SkData. A function with this michael@0: * signature can be passed to serialize() and SkWriteBuffer. michael@0: * Returning NULL will tell the SkWriteBuffer to use michael@0: * SkBitmap::flatten() to store the bitmap. michael@0: * michael@0: * @param pixelRefOffset DEPRECATED -- caller assumes it will return 0. michael@0: * @return SkData If non-NULL, holds encoded data representing the passed michael@0: * in bitmap. The caller is responsible for calling unref(). michael@0: */ michael@0: typedef SkData* (*EncodeBitmap)(size_t* pixelRefOffset, const SkBitmap& bm); michael@0: michael@0: /** michael@0: * Serialize to a stream. If non NULL, encoder will be used to encode michael@0: * any bitmaps in the picture. michael@0: * encoder will never be called with a NULL pixelRefOffset. michael@0: */ michael@0: void serialize(SkWStream*, EncodeBitmap encoder = NULL) const; michael@0: michael@0: /** michael@0: * Serialize to a buffer. michael@0: */ michael@0: void flatten(SkWriteBuffer&) const; michael@0: michael@0: /** michael@0: * Returns true if any bitmaps may be produced when this SkPicture michael@0: * is replayed. michael@0: * Returns false if called while still recording. michael@0: */ michael@0: bool willPlayBackBitmaps() const; michael@0: michael@0: #ifdef SK_BUILD_FOR_ANDROID michael@0: /** Signals that the caller is prematurely done replaying the drawing michael@0: commands. This can be called from a canvas virtual while the picture michael@0: is drawing. Has no effect if the picture is not drawing. michael@0: @deprecated preserving for legacy purposes michael@0: */ michael@0: void abortPlayback(); michael@0: #endif michael@0: michael@0: /** Return true if the SkStream/Buffer represents a serialized picture, and michael@0: fills out SkPictInfo. After this function returns, the data source is not michael@0: rewound so it will have to be manually reset before passing to michael@0: CreateFromStream or CreateFromBuffer. Note, CreateFromStream and michael@0: CreateFromBuffer perform this check internally so these entry points are michael@0: intended for stand alone tools. michael@0: If false is returned, SkPictInfo is unmodified. michael@0: */ michael@0: static bool InternalOnly_StreamIsSKP(SkStream*, SkPictInfo*); michael@0: static bool InternalOnly_BufferIsSKP(SkReadBuffer&, SkPictInfo*); michael@0: michael@0: /** Enable/disable all the picture recording optimizations (i.e., michael@0: those in SkPictureRecord). It is mainly intended for testing the michael@0: existing optimizations (i.e., to actually have the pattern michael@0: appear in an .skp we have to disable the optimization). Call right michael@0: after 'beginRecording'. michael@0: */ michael@0: void internalOnly_EnableOpts(bool enableOpts); michael@0: michael@0: protected: michael@0: // V2 : adds SkPixelRef's generation ID. michael@0: // V3 : PictInfo tag at beginning, and EOF tag at the end michael@0: // V4 : move SkPictInfo to be the header michael@0: // V5 : don't read/write FunctionPtr on cross-process (we can detect that) michael@0: // V6 : added serialization of SkPath's bounds (and packed its flags tighter) michael@0: // V7 : changed drawBitmapRect(IRect) to drawBitmapRectToRect(Rect) michael@0: // V8 : Add an option for encoding bitmaps michael@0: // V9 : Allow the reader and writer of an SKP disagree on whether to support michael@0: // SK_SUPPORT_HINTING_SCALE_FACTOR michael@0: // V10: add drawRRect, drawOval, clipRRect michael@0: // V11: modify how readBitmap and writeBitmap store their info. michael@0: // V12: add conics to SkPath, use new SkPathRef flattening michael@0: // V13: add flag to drawBitmapRectToRect michael@0: // parameterize blurs by sigma rather than radius michael@0: // V14: Add flags word to PathRef serialization michael@0: // V15: Remove A1 bitmpa config (and renumber remaining configs) michael@0: // V16: Move SkPath's isOval flag to SkPathRef michael@0: // V17: SkPixelRef now writes SkImageInfo michael@0: // V18: SkBitmap now records x,y for its pixelref origin, instead of offset. michael@0: // V19: encode matrices and regions into the ops stream michael@0: // V20: added bool to SkPictureImageFilter's serialization (to allow SkPicture serialization) michael@0: // V21: add pushCull, popCull michael@0: // V22: SK_PICT_FACTORY_TAG's size is now the chunk size in bytes michael@0: michael@0: // Note: If the picture version needs to be increased then please follow the michael@0: // steps to generate new SKPs in (only accessible to Googlers): http://goo.gl/qATVcw michael@0: michael@0: // Only SKPs within the min/current picture version range (inclusive) can be read. michael@0: static const uint32_t MIN_PICTURE_VERSION = 19; michael@0: static const uint32_t CURRENT_PICTURE_VERSION = 22; michael@0: michael@0: // fPlayback, fRecord, fWidth & fHeight are protected to allow derived classes to michael@0: // install their own SkPicturePlayback-derived players,SkPictureRecord-derived michael@0: // recorders and set the picture size michael@0: SkPicturePlayback* fPlayback; michael@0: SkPictureRecord* fRecord; michael@0: int fWidth, fHeight; michael@0: const AccelData* fAccelData; michael@0: michael@0: // Create a new SkPicture from an existing SkPicturePlayback. Ref count of michael@0: // playback is unchanged. michael@0: SkPicture(SkPicturePlayback*, int width, int height); michael@0: michael@0: // For testing. Derived classes may instantiate an alternate michael@0: // SkBBoxHierarchy implementation michael@0: virtual SkBBoxHierarchy* createBBoxHierarchy() const; michael@0: private: michael@0: void createHeader(SkPictInfo* info) const; michael@0: static bool IsValidPictInfo(const SkPictInfo& info); michael@0: michael@0: friend class SkFlatPicture; michael@0: friend class SkPicturePlayback; michael@0: michael@0: typedef SkRefCnt INHERITED; michael@0: }; michael@0: michael@0: /** michael@0: * Subclasses of this can be passed to canvas.drawPicture. During the drawing michael@0: * of the picture, this callback will periodically be invoked. If its michael@0: * abortDrawing() returns true, then picture playback will be interrupted. michael@0: * michael@0: * The resulting drawing is undefined, as there is no guarantee how often the michael@0: * callback will be invoked. If the abort happens inside some level of nested michael@0: * calls to save(), restore will automatically be called to return the state michael@0: * to the same level it was before the drawPicture call was made. michael@0: */ michael@0: class SK_API SkDrawPictureCallback { michael@0: public: michael@0: SkDrawPictureCallback() {} michael@0: virtual ~SkDrawPictureCallback() {} michael@0: michael@0: virtual bool abortDrawing() = 0; michael@0: }; michael@0: michael@0: #endif