Home | History | Annotate | Download | only in core
      1 /*
      2  * Copyright 2010 The Android Open Source Project
      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 SkDevice_DEFINED
      9 #define SkDevice_DEFINED
     10 
     11 #include "SkRefCnt.h"
     12 #include "SkBitmap.h"
     13 #include "SkCanvas.h"
     14 #include "SkColor.h"
     15 #include "SkImageFilter.h"
     16 
     17 class SkClipStack;
     18 class SkDraw;
     19 class SkDrawFilter;
     20 struct SkIRect;
     21 class SkMatrix;
     22 class SkMetaData;
     23 class SkRegion;
     24 struct SkDeviceProperties;
     25 class GrRenderTarget;
     26 
     27 class SK_API SkBaseDevice : public SkRefCnt {
     28 public:
     29     SK_DECLARE_INST_COUNT(SkBaseDevice)
     30 
     31     /**
     32      *  Construct a new device.
     33     */
     34     SkBaseDevice();
     35     explicit SkBaseDevice(const SkDeviceProperties&);
     36     virtual ~SkBaseDevice();
     37 
     38     SkMetaData& getMetaData();
     39 
     40     /**
     41      *  Return ImageInfo for this device. If the canvas is not backed by pixels
     42      *  (cpu or gpu), then the info's ColorType will be kUnknown_SkColorType.
     43      */
     44     virtual SkImageInfo imageInfo() const;
     45 
     46     /**
     47      *  Return the bounds of the device in the coordinate space of the root
     48      *  canvas. The root device will have its top-left at 0,0, but other devices
     49      *  such as those associated with saveLayer may have a non-zero origin.
     50      */
     51     void getGlobalBounds(SkIRect* bounds) const {
     52         SkASSERT(bounds);
     53         const SkIPoint& origin = this->getOrigin();
     54         bounds->setXYWH(origin.x(), origin.y(), this->width(), this->height());
     55     }
     56 
     57     SkIRect getGlobalBounds() const {
     58         SkIRect bounds;
     59         this->getGlobalBounds(&bounds);
     60         return bounds;
     61     }
     62 
     63     int width() const {
     64         return this->imageInfo().width();
     65     }
     66 
     67     int height() const {
     68         return this->imageInfo().height();
     69     }
     70 
     71     bool isOpaque() const {
     72         return this->imageInfo().isOpaque();
     73     }
     74 
     75     /** Return the bitmap associated with this device. Call this each time you need
     76         to access the bitmap, as it notifies the subclass to perform any flushing
     77         etc. before you examine the pixels.
     78         @param changePixels set to true if the caller plans to change the pixels
     79         @return the device's bitmap
     80     */
     81     const SkBitmap& accessBitmap(bool changePixels);
     82 
     83     bool writePixels(const SkImageInfo&, const void*, size_t rowBytes, int x, int y);
     84 
     85     void* accessPixels(SkImageInfo* info, size_t* rowBytes);
     86 
     87     /**
     88      * Return the device's associated gpu render target, or NULL.
     89      */
     90     virtual GrRenderTarget* accessRenderTarget() { return NULL; }
     91 
     92 
     93     /**
     94      *  Return the device's origin: its offset in device coordinates from
     95      *  the default origin in its canvas' matrix/clip
     96      */
     97     const SkIPoint& getOrigin() const { return fOrigin; }
     98 
     99     /**
    100      * onAttachToCanvas is invoked whenever a device is installed in a canvas
    101      * (i.e., setDevice, saveLayer (for the new device created by the save),
    102      * and SkCanvas' SkBaseDevice & SkBitmap -taking ctors). It allows the
    103      * devices to prepare for drawing (e.g., locking their pixels, etc.)
    104      */
    105     virtual void onAttachToCanvas(SkCanvas*) {
    106         SkASSERT(!fAttachedToCanvas);
    107         this->lockPixels();
    108 #ifdef SK_DEBUG
    109         fAttachedToCanvas = true;
    110 #endif
    111     };
    112 
    113     /**
    114      * onDetachFromCanvas notifies a device that it will no longer be drawn to.
    115      * It gives the device a chance to clean up (e.g., unlock its pixels). It
    116      * is invoked from setDevice (for the displaced device), restore and
    117      * possibly from SkCanvas' dtor.
    118      */
    119     virtual void onDetachFromCanvas() {
    120         SkASSERT(fAttachedToCanvas);
    121         this->unlockPixels();
    122 #ifdef SK_DEBUG
    123         fAttachedToCanvas = false;
    124 #endif
    125     };
    126 
    127 protected:
    128     enum TileUsage {
    129         kPossible_TileUsage,    //!< the created device may be drawn tiled
    130         kNever_TileUsage,       //!< the created device will never be drawn tiled
    131     };
    132 
    133     struct TextFlags {
    134         uint32_t    fFlags;     // SkPaint::getFlags()
    135     };
    136 
    137     /**
    138      * Returns the text-related flags, possibly modified based on the state of the
    139      * device (e.g. support for LCD).
    140      */
    141     uint32_t filterTextFlags(const SkPaint&) const;
    142 
    143     virtual bool onShouldDisableLCD(const SkPaint&) const { return false; }
    144 
    145     /**
    146      *
    147      *  DEPRECATED: This will be removed in a future change. Device subclasses
    148      *  should use the matrix and clip from the SkDraw passed to draw functions.
    149      *
    150      *  Called with the correct matrix and clip before this device is drawn
    151      *  to using those settings. If your subclass overrides this, be sure to
    152      *  call through to the base class as well.
    153      *
    154      *  The clipstack is another view of the clip. It records the actual
    155      *  geometry that went into building the region. It is present for devices
    156      *  that want to parse it, but is not required: the region is a complete
    157      *  picture of the current clip. (i.e. if you regionize all of the geometry
    158      *  in the clipstack, you will arrive at an equivalent region to the one
    159      *  passed in).
    160      */
    161      virtual void setMatrixClip(const SkMatrix&, const SkRegion&,
    162                                 const SkClipStack&) {};
    163 
    164     /** These are called inside the per-device-layer loop for each draw call.
    165      When these are called, we have already applied any saveLayer operations,
    166      and are handling any looping from the paint, and any effects from the
    167      DrawFilter.
    168      */
    169     virtual void drawPaint(const SkDraw&, const SkPaint& paint) = 0;
    170     virtual void drawPoints(const SkDraw&, SkCanvas::PointMode mode, size_t count,
    171                             const SkPoint[], const SkPaint& paint) = 0;
    172     virtual void drawRect(const SkDraw&, const SkRect& r,
    173                           const SkPaint& paint) = 0;
    174     virtual void drawOval(const SkDraw&, const SkRect& oval,
    175                           const SkPaint& paint) = 0;
    176     virtual void drawRRect(const SkDraw&, const SkRRect& rr,
    177                            const SkPaint& paint) = 0;
    178 
    179     // Default impl calls drawPath()
    180     virtual void drawDRRect(const SkDraw&, const SkRRect& outer,
    181                             const SkRRect& inner, const SkPaint&);
    182 
    183     /**
    184      *  If pathIsMutable, then the implementation is allowed to cast path to a
    185      *  non-const pointer and modify it in place (as an optimization). Canvas
    186      *  may do this to implement helpers such as drawOval, by placing a temp
    187      *  path on the stack to hold the representation of the oval.
    188      *
    189      *  If prePathMatrix is not null, it should logically be applied before any
    190      *  stroking or other effects. If there are no effects on the paint that
    191      *  affect the geometry/rasterization, then the pre matrix can just be
    192      *  pre-concated with the current matrix.
    193      */
    194     virtual void drawPath(const SkDraw&, const SkPath& path,
    195                           const SkPaint& paint,
    196                           const SkMatrix* prePathMatrix = NULL,
    197                           bool pathIsMutable = false) = 0;
    198     virtual void drawBitmap(const SkDraw&, const SkBitmap& bitmap,
    199                             const SkMatrix& matrix, const SkPaint& paint) = 0;
    200     virtual void drawSprite(const SkDraw&, const SkBitmap& bitmap,
    201                             int x, int y, const SkPaint& paint) = 0;
    202 
    203     /**
    204      *  The default impl. will create a bitmap-shader from the bitmap,
    205      *  and call drawRect with it.
    206      */
    207     virtual void drawBitmapRect(const SkDraw&, const SkBitmap&,
    208                                 const SkRect* srcOrNull, const SkRect& dst,
    209                                 const SkPaint& paint,
    210                                 SkCanvas::DrawBitmapRectFlags flags) = 0;
    211 
    212     virtual void drawImage(const SkDraw&, const SkImage*, SkScalar x, SkScalar y, const SkPaint&);
    213     virtual void drawImageRect(const SkDraw&, const SkImage*, const SkRect* src, const SkRect& dst,
    214                                const SkPaint&);
    215 
    216     /**
    217      *  Does not handle text decoration.
    218      *  Decorations (underline and stike-thru) will be handled by SkCanvas.
    219      */
    220     virtual void drawText(const SkDraw&, const void* text, size_t len,
    221                           SkScalar x, SkScalar y, const SkPaint& paint) = 0;
    222     virtual void drawPosText(const SkDraw&, const void* text, size_t len,
    223                              const SkScalar pos[], int scalarsPerPos,
    224                              const SkPoint& offset, const SkPaint& paint) = 0;
    225     virtual void drawVertices(const SkDraw&, SkCanvas::VertexMode, int vertexCount,
    226                               const SkPoint verts[], const SkPoint texs[],
    227                               const SkColor colors[], SkXfermode* xmode,
    228                               const uint16_t indices[], int indexCount,
    229                               const SkPaint& paint) = 0;
    230     // default implementation unrolls the blob runs.
    231     virtual void drawTextBlob(const SkDraw&, const SkTextBlob*, SkScalar x, SkScalar y,
    232                               const SkPaint& paint, SkDrawFilter* drawFilter);
    233     // default implementation calls drawVertices
    234     virtual void drawPatch(const SkDraw&, const SkPoint cubics[12], const SkColor colors[4],
    235                            const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint);
    236     /** The SkDevice passed will be an SkDevice which was returned by a call to
    237         onCreateDevice on this device with kNeverTile_TileExpectation.
    238      */
    239     virtual void drawDevice(const SkDraw&, SkBaseDevice*, int x, int y,
    240                             const SkPaint&) = 0;
    241 
    242     virtual void drawTextOnPath(const SkDraw&, const void* text, size_t len, const SkPath&,
    243                                 const SkMatrix*, const SkPaint&);
    244     bool readPixels(const SkImageInfo&, void* dst, size_t rowBytes, int x, int y);
    245 
    246     ///////////////////////////////////////////////////////////////////////////
    247 
    248     /** Update as needed the pixel value in the bitmap, so that the caller can
    249         access the pixels directly.
    250         @return The device contents as a bitmap
    251     */
    252     virtual const SkBitmap& onAccessBitmap() = 0;
    253 
    254     /** Called when this device is installed into a Canvas. Balanced by a call
    255         to unlockPixels() when the device is removed from a Canvas.
    256     */
    257     virtual void lockPixels() {}
    258     virtual void unlockPixels() {}
    259 
    260     /**
    261      *  Override and return true for filters that the device can handle
    262      *  intrinsically. Doing so means that SkCanvas will pass-through this
    263      *  filter to drawSprite and drawDevice (and potentially filterImage).
    264      *  Returning false means the SkCanvas will have apply the filter itself,
    265      *  and just pass the resulting image to the device.
    266      */
    267     virtual bool canHandleImageFilter(const SkImageFilter*) { return false; }
    268 
    269     /**
    270      *  Related (but not required) to canHandleImageFilter, this method returns
    271      *  true if the device could apply the filter to the src bitmap and return
    272      *  the result (and updates offset as needed).
    273      *  If the device does not recognize or support this filter,
    274      *  it just returns false and leaves result and offset unchanged.
    275      */
    276     virtual bool filterImage(const SkImageFilter*, const SkBitmap&,
    277                              const SkImageFilter::Context&,
    278                              SkBitmap* /*result*/, SkIPoint* /*offset*/) {
    279         return false;
    280     }
    281 
    282 protected:
    283     // default impl returns NULL
    284     virtual SkSurface* newSurface(const SkImageInfo&, const SkSurfaceProps&);
    285 
    286     // default impl returns NULL
    287     virtual const void* peekPixels(SkImageInfo*, size_t* rowBytes);
    288 
    289     /**
    290      *  The caller is responsible for "pre-clipping" the dst. The impl can assume that the dst
    291      *  image at the specified x,y offset will fit within the device's bounds.
    292      *
    293      *  This is explicitly asserted in readPixels(), the public way to call this.
    294      */
    295     virtual bool onReadPixels(const SkImageInfo&, void*, size_t, int x, int y);
    296 
    297     /**
    298      *  The caller is responsible for "pre-clipping" the src. The impl can assume that the src
    299      *  image at the specified x,y offset will fit within the device's bounds.
    300      *
    301      *  This is explicitly asserted in writePixelsDirect(), the public way to call this.
    302      */
    303     virtual bool onWritePixels(const SkImageInfo&, const void*, size_t, int x, int y);
    304 
    305     /**
    306      *  Default impl returns NULL.
    307      */
    308     virtual void* onAccessPixels(SkImageInfo* info, size_t* rowBytes);
    309 
    310     /**
    311      *  Leaky properties are those which the device should be applying but it isn't.
    312      *  These properties will be applied by the draw, when and as it can.
    313      *  If the device does handle a property, that property should be set to the identity value
    314      *  for that property, effectively making it non-leaky.
    315      */
    316     const SkDeviceProperties& getLeakyProperties() const {
    317         return *fLeakyProperties;
    318     }
    319 
    320     /**
    321      *  PRIVATE / EXPERIMENTAL -- do not call
    322      *  This entry point gives the backend an opportunity to take over the rendering
    323      *  of 'picture'. If optimization data is available (due to an earlier
    324      *  'optimize' call) this entry point should make use of it and return true
    325      *  if all rendering has been done. If false is returned, SkCanvas will
    326      *  perform its own rendering pass. It is acceptable for the backend
    327      *  to perform some device-specific warm up tasks and then let SkCanvas
    328      *  perform the main rendering loop (by return false from here).
    329      */
    330     virtual bool EXPERIMENTAL_drawPicture(SkCanvas*, const SkPicture*, const SkMatrix*,
    331                                           const SkPaint*);
    332 
    333     struct CreateInfo {
    334         static SkPixelGeometry AdjustGeometry(const SkImageInfo&, TileUsage, SkPixelGeometry);
    335 
    336         // The constructor may change the pixel geometry based on other parameters.
    337         CreateInfo(const SkImageInfo& info,
    338                    TileUsage tileUsage,
    339                    SkPixelGeometry geo,
    340                    bool forImageFilter = false)
    341             : fInfo(info)
    342             , fTileUsage(tileUsage)
    343             , fPixelGeometry(AdjustGeometry(info, tileUsage, geo))
    344             , fForImageFilter(forImageFilter) {}
    345 
    346         const SkImageInfo       fInfo;
    347         const TileUsage         fTileUsage;
    348         const SkPixelGeometry   fPixelGeometry;
    349         const bool              fForImageFilter;
    350     };
    351 
    352     /**
    353      *  Create a new device based on CreateInfo. If the paint is not null, then it represents a
    354      *  preview of how the new device will be composed with its creator device (this).
    355      *
    356      *  The subclass may be handed this device in drawDevice(), so it must always return
    357      *  a device that it knows how to draw, and that it knows how to identify if it is not of the
    358      *  same subclass (since drawDevice is passed a SkBaseDevice*). If the subclass cannot fulfill
    359      *  that contract (e.g. PDF cannot support some settings on the paint) it should return NULL,
    360      *  and the caller may then decide to explicitly create a bitmapdevice, knowing that later
    361      *  it could not call drawDevice with it (but it could call drawSprite or drawBitmap).
    362      */
    363     virtual SkBaseDevice* onCreateDevice(const CreateInfo&, const SkPaint*) {
    364         return NULL;
    365     }
    366 
    367     virtual void initForRootLayer(SkPixelGeometry geo);
    368 
    369 private:
    370     friend class SkCanvas;
    371     friend struct DeviceCM; //for setMatrixClip
    372     friend class SkDraw;
    373     friend class SkDrawIter;
    374     friend class SkDeviceFilteredPaint;
    375     friend class SkDeviceImageFilterProxy;
    376     friend class SkDeferredDevice;    // for newSurface
    377     friend class SkNoPixelsBitmapDevice;
    378 
    379     friend class SkSurface_Raster;
    380 
    381     // used to change the backend's pixels (and possibly config/rowbytes)
    382     // but cannot change the width/height, so there should be no change to
    383     // any clip information.
    384     // TODO: move to SkBitmapDevice
    385     virtual void replaceBitmapBackendForRasterSurface(const SkBitmap&) {}
    386 
    387     virtual bool forceConservativeRasterClip() const { return false; }
    388 
    389     // just called by SkCanvas when built as a layer
    390     void setOrigin(int x, int y) { fOrigin.set(x, y); }
    391 
    392     /** Causes any deferred drawing to the device to be completed.
    393      */
    394     virtual void flush() {}
    395 
    396     virtual SkImageFilter::Cache* getImageFilterCache() { return NULL; }
    397 
    398     SkIPoint    fOrigin;
    399     SkMetaData* fMetaData;
    400     SkDeviceProperties* fLeakyProperties;   // will always exist.
    401 
    402 #ifdef SK_DEBUG
    403     bool        fAttachedToCanvas;
    404 #endif
    405 
    406     typedef SkRefCnt INHERITED;
    407 };
    408 
    409 #endif
    410