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      */
getGlobalBounds(SkIRect * bounds)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 
getGlobalBounds()57     SkIRect getGlobalBounds() const {
58         SkIRect bounds;
59         this->getGlobalBounds(&bounds);
60         return bounds;
61     }
62 
width()63     int width() const {
64         return this->imageInfo().width();
65     }
66 
height()67     int height() const {
68         return this->imageInfo().height();
69     }
70 
isOpaque()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      */
accessRenderTarget()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      */
getOrigin()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      */
onAttachToCanvas(SkCanvas *)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      */
onDetachFromCanvas()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 
onShouldDisableLCD(const SkPaint &)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      */
setMatrixClip(const SkMatrix &,const SkRegion &,const SkClipStack &)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     */
lockPixels()257     virtual void lockPixels() {}
unlockPixels()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      */
canHandleImageFilter(const SkImageFilter *)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      */
filterImage(const SkImageFilter *,const SkBitmap &,const SkImageFilter::Context &,SkBitmap *,SkIPoint *)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      */
getLeakyProperties()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)
fInfoCreateInfo341             : 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      */
onCreateDevice(const CreateInfo &,const SkPaint *)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
replaceBitmapBackendForRasterSurface(const SkBitmap &)385     virtual void replaceBitmapBackendForRasterSurface(const SkBitmap&) {}
386 
forceConservativeRasterClip()387     virtual bool forceConservativeRasterClip() const { return false; }
388 
389     // just called by SkCanvas when built as a layer
setOrigin(int x,int y)390     void setOrigin(int x, int y) { fOrigin.set(x, y); }
391 
392     /** Causes any deferred drawing to the device to be completed.
393      */
flush()394     virtual void flush() {}
395 
getImageFilterCache()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