michael@0: /* michael@0: * Copyright 2012 Google Inc. 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: #ifndef SkDeferredCanvas_DEFINED michael@0: #define SkDeferredCanvas_DEFINED michael@0: michael@0: #include "SkCanvas.h" michael@0: #include "SkPixelRef.h" michael@0: michael@0: class SkDeferredDevice; michael@0: class SkImage; michael@0: class SkSurface; michael@0: michael@0: /** \class SkDeferredCanvas michael@0: Subclass of SkCanvas that encapsulates an SkPicture or SkGPipe for deferred michael@0: drawing. The main difference between this class and SkPictureRecord (the michael@0: canvas provided by SkPicture) is that this is a full drop-in replacement michael@0: for SkCanvas, while SkPictureRecord only supports draw operations. michael@0: SkDeferredCanvas will transparently trigger the flushing of deferred michael@0: draw operations when an attempt is made to access the pixel data. michael@0: */ michael@0: class SK_API SkDeferredCanvas : public SkCanvas { michael@0: public: michael@0: class SK_API NotificationClient; michael@0: michael@0: /** Construct a canvas with the specified surface to draw into. michael@0: This factory must be used for newImageSnapshot to work. michael@0: @param surface Specifies a surface for the canvas to draw into. michael@0: */ michael@0: static SkDeferredCanvas* Create(SkSurface* surface); michael@0: michael@0: // static SkDeferredCanvas* Create(SkBaseDevice* device); michael@0: michael@0: virtual ~SkDeferredCanvas(); michael@0: michael@0: /** michael@0: * Specify the surface to be used by this canvas. Calling setSurface will michael@0: * release the previously set surface or device. Takes a reference on the michael@0: * surface. michael@0: * michael@0: * @param surface The surface that the canvas will raw into michael@0: * @return The surface argument, for convenience. michael@0: */ michael@0: SkSurface* setSurface(SkSurface* surface); michael@0: michael@0: /** michael@0: * Specify a NotificationClient to be used by this canvas. Calling michael@0: * setNotificationClient will release the previously set michael@0: * NotificationClient, if any. SkDeferredCanvas does not take ownership michael@0: * of the notification client. Therefore user code is resposible michael@0: * for its destruction. The notification client must be unregistered michael@0: * by calling setNotificationClient(NULL) if it is destroyed before michael@0: * this canvas. michael@0: * Note: Must be called after the device is set with setDevice. michael@0: * michael@0: * @param notificationClient interface for dispatching notifications michael@0: * @return The notificationClient argument, for convenience. michael@0: */ michael@0: NotificationClient* setNotificationClient(NotificationClient* notificationClient); michael@0: michael@0: /** michael@0: * Enable or disable deferred drawing. When deferral is disabled, michael@0: * pending draw operations are immediately flushed and from then on, michael@0: * the SkDeferredCanvas behaves just like a regular SkCanvas. michael@0: * This method must not be called while the save/restore stack is in use. michael@0: * @param deferred true/false michael@0: */ michael@0: void setDeferredDrawing(bool deferred); michael@0: michael@0: /** michael@0: * Returns true if deferred drawing is currenlty enabled. michael@0: */ michael@0: bool isDeferredDrawing() const; michael@0: michael@0: /** michael@0: * Returns true if the canvas contains a fresh frame. A frame is michael@0: * considered fresh when its content do not depend on the contents michael@0: * of the previous frame. For example, if a canvas is cleared before michael@0: * drawing each frame, the frames will all be considered fresh. michael@0: * A frame is defined as the graphics image produced by as a result michael@0: * of all the canvas draws operation executed between two successive michael@0: * calls to isFreshFrame. The result of isFreshFrame is computed michael@0: * conservatively, so it may report false negatives. michael@0: */ michael@0: bool isFreshFrame() const; michael@0: michael@0: /** michael@0: * Returns true if the canvas has recorded draw commands that have michael@0: * not yet been played back. michael@0: */ michael@0: bool hasPendingCommands() const; michael@0: michael@0: /** michael@0: * Flushes pending draw commands, if any, and returns an image of the michael@0: * current state of the surface pixels up to this point. Subsequent michael@0: * changes to the surface (by drawing into its canvas) will not be michael@0: * reflected in this image. Will return NULL if the deferred canvas michael@0: * was not constructed from an SkSurface. michael@0: */ michael@0: SkImage* newImageSnapshot(); michael@0: michael@0: /** michael@0: * Specify the maximum number of bytes to be allocated for the purpose michael@0: * of recording draw commands to this canvas. The default limit, is michael@0: * 64MB. michael@0: * @param maxStorage The maximum number of bytes to be allocated. michael@0: */ michael@0: void setMaxRecordingStorage(size_t maxStorage); michael@0: michael@0: /** michael@0: * Returns the number of bytes currently allocated for the purpose of michael@0: * recording draw commands. michael@0: */ michael@0: size_t storageAllocatedForRecording() const; michael@0: michael@0: /** michael@0: * Attempt to reduce the storage allocated for recording by evicting michael@0: * cache resources. michael@0: * @param bytesToFree minimum number of bytes that should be attempted to michael@0: * be freed. michael@0: * @return number of bytes actually freed. michael@0: */ michael@0: size_t freeMemoryIfPossible(size_t bytesToFree); michael@0: michael@0: /** michael@0: * Specifies the maximum size (in bytes) allowed for a given image to be michael@0: * rendered using the deferred canvas. michael@0: */ michael@0: void setBitmapSizeThreshold(size_t sizeThreshold); michael@0: michael@0: /** michael@0: * Executes all pending commands without drawing michael@0: */ michael@0: void silentFlush(); michael@0: michael@0: // Overrides of the SkCanvas interface michael@0: virtual bool isDrawingToLayer() const SK_OVERRIDE; michael@0: virtual void clear(SkColor) SK_OVERRIDE; michael@0: virtual void drawPaint(const SkPaint& paint) SK_OVERRIDE; michael@0: virtual void drawPoints(PointMode mode, size_t count, const SkPoint pts[], michael@0: const SkPaint& paint) SK_OVERRIDE; michael@0: virtual void drawOval(const SkRect&, const SkPaint& paint) SK_OVERRIDE; michael@0: virtual void drawRect(const SkRect& rect, const SkPaint& paint) SK_OVERRIDE; michael@0: virtual void drawRRect(const SkRRect&, const SkPaint& paint) SK_OVERRIDE; michael@0: virtual void drawPath(const SkPath& path, const SkPaint& paint) michael@0: SK_OVERRIDE; michael@0: virtual void drawBitmap(const SkBitmap& bitmap, SkScalar left, michael@0: SkScalar top, const SkPaint* paint) michael@0: SK_OVERRIDE; michael@0: virtual void drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src, michael@0: const SkRect& dst, const SkPaint* paint, michael@0: DrawBitmapRectFlags flags) SK_OVERRIDE; michael@0: michael@0: virtual void drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& m, michael@0: const SkPaint* paint) SK_OVERRIDE; michael@0: virtual void drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, michael@0: const SkRect& dst, const SkPaint* paint) michael@0: SK_OVERRIDE; michael@0: virtual void drawSprite(const SkBitmap& bitmap, int left, int top, michael@0: const SkPaint* paint) SK_OVERRIDE; michael@0: virtual void drawText(const void* text, size_t byteLength, SkScalar x, michael@0: SkScalar y, const SkPaint& paint) SK_OVERRIDE; michael@0: virtual void drawPosText(const void* text, size_t byteLength, michael@0: const SkPoint pos[], const SkPaint& paint) michael@0: SK_OVERRIDE; michael@0: virtual void drawPosTextH(const void* text, size_t byteLength, michael@0: const SkScalar xpos[], SkScalar constY, michael@0: const SkPaint& paint) SK_OVERRIDE; michael@0: virtual void drawTextOnPath(const void* text, size_t byteLength, michael@0: const SkPath& path, const SkMatrix* matrix, michael@0: const SkPaint& paint) SK_OVERRIDE; michael@0: virtual void drawPicture(SkPicture& picture) SK_OVERRIDE; michael@0: virtual void drawVertices(VertexMode vmode, int vertexCount, michael@0: const SkPoint vertices[], const SkPoint texs[], michael@0: const SkColor colors[], SkXfermode* xmode, michael@0: const uint16_t indices[], int indexCount, michael@0: const SkPaint& paint) SK_OVERRIDE; michael@0: virtual SkBounder* setBounder(SkBounder* bounder) SK_OVERRIDE; michael@0: virtual SkDrawFilter* setDrawFilter(SkDrawFilter* filter) SK_OVERRIDE; michael@0: michael@0: protected: michael@0: virtual void willSave(SaveFlags) SK_OVERRIDE; michael@0: virtual SaveLayerStrategy willSaveLayer(const SkRect*, const SkPaint*, SaveFlags) SK_OVERRIDE; michael@0: virtual void willRestore() SK_OVERRIDE; michael@0: michael@0: virtual void didTranslate(SkScalar, SkScalar) SK_OVERRIDE; michael@0: virtual void didScale(SkScalar, SkScalar) SK_OVERRIDE; michael@0: virtual void didRotate(SkScalar) SK_OVERRIDE; michael@0: virtual void didSkew(SkScalar, SkScalar) SK_OVERRIDE; michael@0: virtual void didConcat(const SkMatrix&) SK_OVERRIDE; michael@0: virtual void didSetMatrix(const SkMatrix&) SK_OVERRIDE; michael@0: michael@0: virtual void onDrawDRRect(const SkRRect&, const SkRRect&, michael@0: const SkPaint&) SK_OVERRIDE; michael@0: michael@0: virtual void onClipRect(const SkRect&, SkRegion::Op, ClipEdgeStyle) SK_OVERRIDE; michael@0: virtual void onClipRRect(const SkRRect&, SkRegion::Op, ClipEdgeStyle) SK_OVERRIDE; michael@0: virtual void onClipPath(const SkPath&, SkRegion::Op, ClipEdgeStyle) SK_OVERRIDE; michael@0: virtual void onClipRegion(const SkRegion&, SkRegion::Op) SK_OVERRIDE; michael@0: michael@0: public: michael@0: class NotificationClient { michael@0: public: michael@0: virtual ~NotificationClient() {} michael@0: michael@0: /** michael@0: * Called before executing one or several draw commands, which means michael@0: * once per flush when deferred rendering is enabled. michael@0: */ michael@0: virtual void prepareForDraw() {} michael@0: michael@0: /** michael@0: * Called after a recording a draw command if additional memory michael@0: * had to be allocated for recording. michael@0: * @param newAllocatedStorage same value as would be returned by michael@0: * storageAllocatedForRecording(), for convenience. michael@0: */ michael@0: virtual void storageAllocatedForRecordingChanged( michael@0: size_t newAllocatedStorage) {} michael@0: michael@0: /** michael@0: * Called after pending draw commands have been flushed michael@0: */ michael@0: virtual void flushedDrawCommands() {} michael@0: michael@0: /** michael@0: * Called after pending draw commands have been skipped, meaning michael@0: * that they were optimized-out because the canvas is cleared michael@0: * or completely overwritten by the command currently being recorded. michael@0: */ michael@0: virtual void skippedPendingDrawCommands() {} michael@0: }; michael@0: michael@0: protected: michael@0: virtual SkCanvas* canvasForDrawIter(); michael@0: SkDeferredDevice* getDeferredDevice() const; michael@0: michael@0: private: michael@0: SkDeferredCanvas(SkDeferredDevice*); michael@0: michael@0: void recordedDrawCommand(); michael@0: SkCanvas* drawingCanvas() const; michael@0: SkCanvas* immediateCanvas() const; michael@0: bool isFullFrame(const SkRect*, const SkPaint*) const; michael@0: void validate() const; michael@0: void init(); michael@0: bool fDeferredDrawing; michael@0: michael@0: friend class SkDeferredCanvasTester; // for unit testing michael@0: typedef SkCanvas INHERITED; michael@0: }; michael@0: michael@0: michael@0: #endif