michael@0: michael@0: /* michael@0: * Copyright 2010 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 SkDevice_DEFINED michael@0: #define SkDevice_DEFINED michael@0: michael@0: #include "SkRefCnt.h" michael@0: #include "SkBitmap.h" michael@0: #include "SkCanvas.h" michael@0: #include "SkColor.h" michael@0: #include "SkDeviceProperties.h" michael@0: #include "SkImageFilter.h" michael@0: michael@0: // getDeviceCapabilities() is not called by skia, but this flag keeps it around michael@0: // for clients that have "override" annotations on their subclass. These overrides michael@0: // should be deleted. michael@0: //#define SK_SUPPORT_LEGACY_GETDEVICECAPABILITIES michael@0: michael@0: //#define SK_SUPPORT_LEGACY_COMPATIBLEDEVICE_CONFIG michael@0: michael@0: class SkClipStack; michael@0: class SkDraw; michael@0: struct SkIRect; michael@0: class SkMatrix; michael@0: class SkMetaData; michael@0: class SkRegion; michael@0: michael@0: class GrRenderTarget; michael@0: michael@0: class SK_API SkBaseDevice : public SkRefCnt { michael@0: public: michael@0: SK_DECLARE_INST_COUNT(SkBaseDevice) michael@0: michael@0: /** michael@0: * Construct a new device. michael@0: */ michael@0: SkBaseDevice(); michael@0: michael@0: /** michael@0: * Construct a new device. michael@0: */ michael@0: SkBaseDevice(const SkDeviceProperties& deviceProperties); michael@0: michael@0: virtual ~SkBaseDevice(); michael@0: michael@0: #ifdef SK_SUPPORT_LEGACY_COMPATIBLEDEVICE_CONFIG michael@0: /** michael@0: * Creates a device that is of the same type as this device (e.g. SW-raster, michael@0: * GPU, or PDF). The backing store for this device is created automatically michael@0: * (e.g. offscreen pixels or FBO or whatever is appropriate). michael@0: * michael@0: * @param width width of the device to create michael@0: * @param height height of the device to create michael@0: * @param isOpaque performance hint, set to true if you know that you will michael@0: * draw into this device such that all of the pixels will michael@0: * be opaque. michael@0: */ michael@0: SkBaseDevice* createCompatibleDevice(SkBitmap::Config config, michael@0: int width, int height, michael@0: bool isOpaque); michael@0: #endif michael@0: SkBaseDevice* createCompatibleDevice(const SkImageInfo&); michael@0: michael@0: SkMetaData& getMetaData(); michael@0: michael@0: #ifdef SK_SUPPORT_LEGACY_GETDEVICECAPABILITIES michael@0: enum Capabilities { michael@0: kVector_Capability = 0x1, michael@0: }; michael@0: virtual uint32_t getDeviceCapabilities() { return 0; } michael@0: #endif michael@0: michael@0: /** Return the width of the device (in pixels). michael@0: */ michael@0: virtual int width() const = 0; michael@0: /** Return the height of the device (in pixels). michael@0: */ michael@0: virtual int height() const = 0; michael@0: michael@0: /** Return the image properties of the device. */ michael@0: virtual const SkDeviceProperties& getDeviceProperties() const { michael@0: //Currently, all the properties are leaky. michael@0: return fLeakyProperties; michael@0: } michael@0: michael@0: /** michael@0: * Return ImageInfo for this device. If the canvas is not backed by pixels michael@0: * (cpu or gpu), then the info's ColorType will be kUnknown_SkColorType. michael@0: */ michael@0: virtual SkImageInfo imageInfo() const; michael@0: michael@0: /** michael@0: * Return the bounds of the device in the coordinate space of the root michael@0: * canvas. The root device will have its top-left at 0,0, but other devices michael@0: * such as those associated with saveLayer may have a non-zero origin. michael@0: */ michael@0: void getGlobalBounds(SkIRect* bounds) const { michael@0: SkASSERT(bounds); michael@0: const SkIPoint& origin = this->getOrigin(); michael@0: bounds->setXYWH(origin.x(), origin.y(), this->width(), this->height()); michael@0: } michael@0: michael@0: michael@0: /** Returns true if the device's bitmap's config treats every pixel as michael@0: implicitly opaque. michael@0: */ michael@0: virtual bool isOpaque() const = 0; michael@0: michael@0: /** Return the bitmap config of the device's pixels michael@0: */ michael@0: virtual SkBitmap::Config config() const = 0; michael@0: michael@0: /** Return the bitmap associated with this device. Call this each time you need michael@0: to access the bitmap, as it notifies the subclass to perform any flushing michael@0: etc. before you examine the pixels. michael@0: @param changePixels set to true if the caller plans to change the pixels michael@0: @return the device's bitmap michael@0: */ michael@0: const SkBitmap& accessBitmap(bool changePixels); michael@0: michael@0: #ifdef SK_SUPPORT_LEGACY_WRITEPIXELSCONFIG michael@0: /** michael@0: * DEPRECATED: This will be made protected once WebKit stops using it. michael@0: * Instead use Canvas' writePixels method. michael@0: * michael@0: * Similar to draw sprite, this method will copy the pixels in bitmap onto michael@0: * the device, with the top/left corner specified by (x, y). The pixel michael@0: * values in the device are completely replaced: there is no blending. michael@0: * michael@0: * Currently if bitmap is backed by a texture this is a no-op. This may be michael@0: * relaxed in the future. michael@0: * michael@0: * If the bitmap has config kARGB_8888_Config then the config8888 param michael@0: * will determines how the pixel valuess are intepreted. If the bitmap is michael@0: * not kARGB_8888_Config then this parameter is ignored. michael@0: */ michael@0: virtual void writePixels(const SkBitmap& bitmap, int x, int y, michael@0: SkCanvas::Config8888 config8888 = SkCanvas::kNative_Premul_Config8888); michael@0: #endif michael@0: michael@0: bool writePixelsDirect(const SkImageInfo&, const void*, size_t rowBytes, int x, int y); michael@0: michael@0: void* accessPixels(SkImageInfo* info, size_t* rowBytes); michael@0: michael@0: /** michael@0: * Return the device's associated gpu render target, or NULL. michael@0: */ michael@0: virtual GrRenderTarget* accessRenderTarget() = 0; michael@0: michael@0: michael@0: /** michael@0: * Return the device's origin: its offset in device coordinates from michael@0: * the default origin in its canvas' matrix/clip michael@0: */ michael@0: const SkIPoint& getOrigin() const { return fOrigin; } michael@0: michael@0: /** michael@0: * onAttachToCanvas is invoked whenever a device is installed in a canvas michael@0: * (i.e., setDevice, saveLayer (for the new device created by the save), michael@0: * and SkCanvas' SkBaseDevice & SkBitmap -taking ctors). It allows the michael@0: * devices to prepare for drawing (e.g., locking their pixels, etc.) michael@0: */ michael@0: virtual void onAttachToCanvas(SkCanvas*) { michael@0: SkASSERT(!fAttachedToCanvas); michael@0: this->lockPixels(); michael@0: #ifdef SK_DEBUG michael@0: fAttachedToCanvas = true; michael@0: #endif michael@0: }; michael@0: michael@0: /** michael@0: * onDetachFromCanvas notifies a device that it will no longer be drawn to. michael@0: * It gives the device a chance to clean up (e.g., unlock its pixels). It michael@0: * is invoked from setDevice (for the displaced device), restore and michael@0: * possibly from SkCanvas' dtor. michael@0: */ michael@0: virtual void onDetachFromCanvas() { michael@0: SkASSERT(fAttachedToCanvas); michael@0: this->unlockPixels(); michael@0: #ifdef SK_DEBUG michael@0: fAttachedToCanvas = false; michael@0: #endif michael@0: }; michael@0: michael@0: protected: michael@0: enum Usage { michael@0: kGeneral_Usage, michael@0: kSaveLayer_Usage // clear(eraseColor); } michael@0: michael@0: /** These are called inside the per-device-layer loop for each draw call. michael@0: When these are called, we have already applied any saveLayer operations, michael@0: and are handling any looping from the paint, and any effects from the michael@0: DrawFilter. michael@0: */ michael@0: virtual void drawPaint(const SkDraw&, const SkPaint& paint) = 0; michael@0: virtual void drawPoints(const SkDraw&, SkCanvas::PointMode mode, size_t count, michael@0: const SkPoint[], const SkPaint& paint) = 0; michael@0: virtual void drawRect(const SkDraw&, const SkRect& r, michael@0: const SkPaint& paint) = 0; michael@0: virtual void drawOval(const SkDraw&, const SkRect& oval, michael@0: const SkPaint& paint) = 0; michael@0: virtual void drawRRect(const SkDraw&, const SkRRect& rr, michael@0: const SkPaint& paint) = 0; michael@0: michael@0: // Default impl calls drawPath() michael@0: virtual void drawDRRect(const SkDraw&, const SkRRect& outer, michael@0: const SkRRect& inner, const SkPaint&); michael@0: michael@0: /** michael@0: * If pathIsMutable, then the implementation is allowed to cast path to a michael@0: * non-const pointer and modify it in place (as an optimization). Canvas michael@0: * may do this to implement helpers such as drawOval, by placing a temp michael@0: * path on the stack to hold the representation of the oval. michael@0: * michael@0: * If prePathMatrix is not null, it should logically be applied before any michael@0: * stroking or other effects. If there are no effects on the paint that michael@0: * affect the geometry/rasterization, then the pre matrix can just be michael@0: * pre-concated with the current matrix. michael@0: */ michael@0: virtual void drawPath(const SkDraw&, const SkPath& path, michael@0: const SkPaint& paint, michael@0: const SkMatrix* prePathMatrix = NULL, michael@0: bool pathIsMutable = false) = 0; michael@0: virtual void drawBitmap(const SkDraw&, const SkBitmap& bitmap, michael@0: const SkMatrix& matrix, const SkPaint& paint) = 0; michael@0: virtual void drawSprite(const SkDraw&, const SkBitmap& bitmap, michael@0: int x, int y, const SkPaint& paint) = 0; michael@0: michael@0: /** michael@0: * The default impl. will create a bitmap-shader from the bitmap, michael@0: * and call drawRect with it. michael@0: */ michael@0: virtual void drawBitmapRect(const SkDraw&, const SkBitmap&, michael@0: const SkRect* srcOrNull, const SkRect& dst, michael@0: const SkPaint& paint, michael@0: SkCanvas::DrawBitmapRectFlags flags) = 0; michael@0: michael@0: /** michael@0: * Does not handle text decoration. michael@0: * Decorations (underline and stike-thru) will be handled by SkCanvas. michael@0: */ michael@0: virtual void drawText(const SkDraw&, const void* text, size_t len, michael@0: SkScalar x, SkScalar y, const SkPaint& paint) = 0; michael@0: virtual void drawPosText(const SkDraw&, const void* text, size_t len, michael@0: const SkScalar pos[], SkScalar constY, michael@0: int scalarsPerPos, const SkPaint& paint) = 0; michael@0: virtual void drawTextOnPath(const SkDraw&, const void* text, size_t len, michael@0: const SkPath& path, const SkMatrix* matrix, michael@0: const SkPaint& paint) = 0; michael@0: virtual void drawVertices(const SkDraw&, SkCanvas::VertexMode, int vertexCount, michael@0: const SkPoint verts[], const SkPoint texs[], michael@0: const SkColor colors[], SkXfermode* xmode, michael@0: const uint16_t indices[], int indexCount, michael@0: const SkPaint& paint) = 0; michael@0: /** The SkDevice passed will be an SkDevice which was returned by a call to michael@0: onCreateDevice on this device with kSaveLayer_Usage. michael@0: */ michael@0: virtual void drawDevice(const SkDraw&, SkBaseDevice*, int x, int y, michael@0: const SkPaint&) = 0; michael@0: michael@0: /** michael@0: * On success (returns true), copy the device pixels into the bitmap. michael@0: * On failure, the bitmap parameter is left unchanged and false is michael@0: * returned. michael@0: * michael@0: * The device's pixels are converted to the bitmap's config. The only michael@0: * supported config is kARGB_8888_Config, though this is likely to be michael@0: * relaxed in the future. The meaning of config kARGB_8888_Config is michael@0: * modified by the enum param config8888. The default value interprets michael@0: * kARGB_8888_Config as SkPMColor michael@0: * michael@0: * If the bitmap has pixels already allocated, the device pixels will be michael@0: * written there. If not, bitmap->allocPixels() will be called michael@0: * automatically. If the bitmap is backed by a texture readPixels will michael@0: * fail. michael@0: * michael@0: * The actual pixels written is the intersection of the device's bounds, michael@0: * and the rectangle formed by the bitmap's width,height and the specified michael@0: * x,y. If bitmap pixels extend outside of that intersection, they will not michael@0: * be modified. michael@0: * michael@0: * Other failure conditions: michael@0: * * If the device is not a raster device (e.g. PDF) then readPixels will michael@0: * fail. michael@0: * * If bitmap is texture-backed then readPixels will fail. (This may be michael@0: * relaxed in the future.) michael@0: */ michael@0: bool readPixels(SkBitmap* bitmap, michael@0: int x, int y, michael@0: SkCanvas::Config8888 config8888); michael@0: michael@0: /////////////////////////////////////////////////////////////////////////// michael@0: michael@0: /** Update as needed the pixel value in the bitmap, so that the caller can michael@0: access the pixels directly. michael@0: @return The device contents as a bitmap michael@0: */ michael@0: virtual const SkBitmap& onAccessBitmap() = 0; michael@0: michael@0: /** Called when this device is installed into a Canvas. Balanced by a call michael@0: to unlockPixels() when the device is removed from a Canvas. michael@0: */ michael@0: virtual void lockPixels() = 0; michael@0: virtual void unlockPixels() = 0; michael@0: michael@0: /** michael@0: * Returns true if the device allows processing of this imagefilter. If michael@0: * false is returned, then the filter is ignored. This may happen for michael@0: * some subclasses that do not support pixel manipulations after drawing michael@0: * has occurred (e.g. printing). The default implementation returns true. michael@0: */ michael@0: virtual bool allowImageFilter(const SkImageFilter*) = 0; michael@0: michael@0: /** michael@0: * Override and return true for filters that the device can handle michael@0: * intrinsically. Doing so means that SkCanvas will pass-through this michael@0: * filter to drawSprite and drawDevice (and potentially filterImage). michael@0: * Returning false means the SkCanvas will have apply the filter itself, michael@0: * and just pass the resulting image to the device. michael@0: */ michael@0: virtual bool canHandleImageFilter(const SkImageFilter*) = 0; michael@0: michael@0: /** michael@0: * Related (but not required) to canHandleImageFilter, this method returns michael@0: * true if the device could apply the filter to the src bitmap and return michael@0: * the result (and updates offset as needed). michael@0: * If the device does not recognize or support this filter, michael@0: * it just returns false and leaves result and offset unchanged. michael@0: */ michael@0: virtual bool filterImage(const SkImageFilter*, const SkBitmap&, michael@0: const SkImageFilter::Context& ctx, michael@0: SkBitmap* result, SkIPoint* offset) = 0; michael@0: michael@0: // This is equal kBGRA_Premul_Config8888 or kRGBA_Premul_Config8888 if michael@0: // either is identical to kNative_Premul_Config8888. Otherwise, -1. michael@0: static const SkCanvas::Config8888 kPMColorAlias; michael@0: michael@0: protected: michael@0: // default impl returns NULL michael@0: virtual SkSurface* newSurface(const SkImageInfo&); michael@0: michael@0: // default impl returns NULL michael@0: virtual const void* peekPixels(SkImageInfo*, size_t* rowBytes); michael@0: michael@0: /** michael@0: * Implements readPixels API. The caller will ensure that: michael@0: * 1. bitmap has pixel config kARGB_8888_Config. michael@0: * 2. bitmap has pixels. michael@0: * 3. The rectangle (x, y, x + bitmap->width(), y + bitmap->height()) is michael@0: * contained in the device bounds. michael@0: */ michael@0: virtual bool onReadPixels(const SkBitmap& bitmap, michael@0: int x, int y, michael@0: SkCanvas::Config8888 config8888); michael@0: michael@0: /** michael@0: * The caller is responsible for "pre-clipping" the src. The impl can assume that the src michael@0: * image at the specified x,y offset will fit within the device's bounds. michael@0: * michael@0: * This is explicitly asserted in writePixelsDirect(), the public way to call this. michael@0: */ michael@0: virtual bool onWritePixels(const SkImageInfo&, const void*, size_t, int x, int y); michael@0: michael@0: /** michael@0: * Default impl returns NULL. michael@0: */ michael@0: virtual void* onAccessPixels(SkImageInfo* info, size_t* rowBytes); michael@0: michael@0: /** michael@0: * Leaky properties are those which the device should be applying but it isn't. michael@0: * These properties will be applied by the draw, when and as it can. michael@0: * If the device does handle a property, that property should be set to the identity value michael@0: * for that property, effectively making it non-leaky. michael@0: */ michael@0: SkDeviceProperties fLeakyProperties; michael@0: michael@0: /** michael@0: * PRIVATE / EXPERIMENTAL -- do not call michael@0: * Construct an acceleration object and attach it to 'picture' michael@0: */ michael@0: virtual void EXPERIMENTAL_optimize(SkPicture* picture); michael@0: michael@0: /** michael@0: * PRIVATE / EXPERIMENTAL -- do not call michael@0: * This entry point gives the backend an opportunity to take over the rendering michael@0: * of 'picture'. If optimization data is available (due to an earlier michael@0: * 'optimize' call) this entry point should make use of it and return true michael@0: * if all rendering has been done. If false is returned, SkCanvas will michael@0: * perform its own rendering pass. It is acceptable for the backend michael@0: * to perform some device-specific warm up tasks and then let SkCanvas michael@0: * perform the main rendering loop (by return false from here). michael@0: */ michael@0: virtual bool EXPERIMENTAL_drawPicture(const SkPicture& picture); michael@0: michael@0: private: michael@0: friend class SkCanvas; michael@0: friend struct DeviceCM; //for setMatrixClip michael@0: friend class SkDraw; michael@0: friend class SkDrawIter; michael@0: friend class SkDeviceFilteredPaint; michael@0: friend class SkDeviceImageFilterProxy; michael@0: friend class SkDeferredDevice; // for newSurface michael@0: michael@0: friend class SkSurface_Raster; michael@0: michael@0: // used to change the backend's pixels (and possibly config/rowbytes) michael@0: // but cannot change the width/height, so there should be no change to michael@0: // any clip information. michael@0: // TODO: move to SkBitmapDevice michael@0: virtual void replaceBitmapBackendForRasterSurface(const SkBitmap&) = 0; michael@0: michael@0: // just called by SkCanvas when built as a layer michael@0: void setOrigin(int x, int y) { fOrigin.set(x, y); } michael@0: // just called by SkCanvas for saveLayer michael@0: SkBaseDevice* createCompatibleDeviceForSaveLayer(const SkImageInfo&); michael@0: michael@0: #ifdef SK_SUPPORT_LEGACY_COMPATIBLEDEVICE_CONFIG michael@0: /** michael@0: * Justs exists during the period where clients still "override" this michael@0: * signature. They are supported by our base-impl calling this old michael@0: * signature from the new one (using ImageInfo). michael@0: */ michael@0: virtual SkBaseDevice* onCreateCompatibleDevice(SkBitmap::Config config, michael@0: int width, int height, michael@0: bool isOpaque, Usage) { michael@0: return NULL; michael@0: } michael@0: #endif michael@0: virtual SkBaseDevice* onCreateDevice(const SkImageInfo&, Usage) { michael@0: return NULL; michael@0: } michael@0: michael@0: /** Causes any deferred drawing to the device to be completed. michael@0: */ michael@0: virtual void flush() = 0; michael@0: michael@0: SkIPoint fOrigin; michael@0: SkMetaData* fMetaData; michael@0: michael@0: #ifdef SK_DEBUG michael@0: bool fAttachedToCanvas; michael@0: #endif michael@0: michael@0: typedef SkRefCnt INHERITED; michael@0: }; michael@0: michael@0: #endif