SkPDFDevice.h revision 40a1ae4df28810aa5aa5cf2627d8387b2dfb867a
1
2/*
3 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9
10#ifndef SkPDFDevice_DEFINED
11#define SkPDFDevice_DEFINED
12
13#include "SkCanvas.h"
14#include "SkDevice.h"
15#include "SkPaint.h"
16#include "SkPath.h"
17#include "SkRefCnt.h"
18#include "SkStream.h"
19#include "SkTScopedPtr.h"
20
21class SkPDFArray;
22class SkPDFDevice;
23class SkPDFDict;
24class SkPDFFont;
25class SkPDFFormXObject;
26class SkPDFGlyphSetMap;
27class SkPDFGraphicState;
28class SkPDFObject;
29class SkPDFShader;
30class SkPDFStream;
31
32// Private classes.
33struct ContentEntry;
34struct GraphicStateEntry;
35
36/** \class SkPDFDevice
37
38    The drawing context for the PDF backend.
39*/
40class SkPDFDevice : public SkDevice {
41public:
42    /** Create a PDF drawing context with the given width and height.
43     *  72 points/in means letter paper is 612x792.
44     *  @param pageSize Page size in points.
45     *  @param contentSize The content size of the page in points. This will be
46     *         combined with the initial transform to determine the drawing area
47     *         (as reported by the width and height methods). Anything outside
48     *         of the drawing area will be clipped.
49     *  @param initialTransform The initial transform to apply to the page.
50     *         This may be useful to, for example, move the origin in and
51     *         over a bit to account for a margin, scale the canvas,
52     *         or apply a rotation.  Note1: the SkPDFDevice also applies
53     *         a scale+translate transform to move the origin from the
54     *         bottom left (PDF default) to the top left.  Note2: drawDevice
55     *         (used by layer restore) draws the device after this initial
56     *         transform is applied, so the PDF device does an
57     *         inverse scale+translate to accommodate the one that SkPDFDevice
58     *         always does.
59     */
60    // TODO(vandebo): The sizes should be SkSize and not SkISize.
61    SK_API SkPDFDevice(const SkISize& pageSize, const SkISize& contentSize,
62                       const SkMatrix& initialTransform);
63    SK_API virtual ~SkPDFDevice();
64
65    virtual uint32_t getDeviceCapabilities() SK_OVERRIDE;
66
67    virtual void clear(SkColor color) SK_OVERRIDE;
68
69    /** These are called inside the per-device-layer loop for each draw call.
70     When these are called, we have already applied any saveLayer operations,
71     and are handling any looping from the paint, and any effects from the
72     DrawFilter.
73     */
74    virtual void drawPaint(const SkDraw&, const SkPaint& paint) SK_OVERRIDE;
75    virtual void drawPoints(const SkDraw&, SkCanvas::PointMode mode,
76                            size_t count, const SkPoint[],
77                            const SkPaint& paint) SK_OVERRIDE;
78    virtual void drawRect(const SkDraw&, const SkRect& r, const SkPaint& paint);
79    virtual void drawPath(const SkDraw&, const SkPath& origpath,
80                          const SkPaint& paint, const SkMatrix* prePathMatrix,
81                          bool pathIsMutable) SK_OVERRIDE;
82    virtual void drawBitmap(const SkDraw&, const SkBitmap& bitmap,
83                            const SkIRect* srcRectOrNull,
84                            const SkMatrix& matrix, const SkPaint&) SK_OVERRIDE;
85    virtual void drawSprite(const SkDraw&, const SkBitmap& bitmap, int x, int y,
86                            const SkPaint& paint) SK_OVERRIDE;
87    virtual void drawText(const SkDraw&, const void* text, size_t len,
88                          SkScalar x, SkScalar y, const SkPaint&) SK_OVERRIDE;
89    virtual void drawPosText(const SkDraw&, const void* text, size_t len,
90                             const SkScalar pos[], SkScalar constY,
91                             int scalarsPerPos, const SkPaint&) SK_OVERRIDE;
92    virtual void drawTextOnPath(const SkDraw&, const void* text, size_t len,
93                                const SkPath& path, const SkMatrix* matrix,
94                                const SkPaint& paint) SK_OVERRIDE;
95    virtual void drawVertices(const SkDraw&, SkCanvas::VertexMode,
96                              int vertexCount, const SkPoint verts[],
97                              const SkPoint texs[], const SkColor colors[],
98                              SkXfermode* xmode, const uint16_t indices[],
99                              int indexCount, const SkPaint& paint) SK_OVERRIDE;
100    virtual void drawDevice(const SkDraw&, SkDevice*, int x, int y,
101                            const SkPaint&) SK_OVERRIDE;
102
103    virtual void onAttachToCanvas(SkCanvas* canvas) SK_OVERRIDE;
104    virtual void onDetachFromCanvas() SK_OVERRIDE;
105
106    enum DrawingArea {
107        kContent_DrawingArea,  // Drawing area for the page content.
108        kMargin_DrawingArea,   // Drawing area for the margin content.
109    };
110
111    /** Sets the drawing area for the device. Subsequent draw calls are directed
112     *  to the specific drawing area (margin or content). The default drawing
113     *  area is the content drawing area.
114     *
115     *  Currently if margin content is drawn and then a complex (for PDF) xfer
116     *  mode is used, like SrcIn, Clear, etc, the margin content will get
117     *  clipped. A simple way to avoid the bug is to always draw the margin
118     *  content last.
119     */
120    SK_API void setDrawingArea(DrawingArea drawingArea);
121
122    // PDF specific methods.
123
124    /** Returns the resource dictionary for this device.
125     */
126    SK_API SkPDFDict* getResourceDict();
127
128    /** Get the list of resources (PDF objects) used on this page.
129     *  @param resourceList A list to append the resources to.
130     *  @param recursive    If recursive is true, get the resources of the
131     *                      device's resources recursively. (Useful for adding
132     *                      objects to the catalog.)
133     */
134    SK_API void getResources(SkTDArray<SkPDFObject*>* resourceList,
135                             bool recursive) const;
136
137    /** Get the fonts used on this device.
138     */
139    SK_API const SkTDArray<SkPDFFont*>& getFontResources() const;
140
141    /** Returns the media box for this device.
142     */
143    SK_API SkRefPtr<SkPDFArray> getMediaBox() const;
144
145    /** Returns a SkStream with the page contents.  The caller is responsible
146        for a reference to the returned value.
147        DEPRECATED: use copyContentToData()
148     */
149    SK_API SkStream* content() const;
150
151    /** Returns a SkStream with the page contents.  The caller is responsible
152     *  for calling data->unref() when it is finished.
153     */
154    SK_API SkData* copyContentToData() const;
155
156    SK_API const SkMatrix& initialTransform() const {
157        return fInitialTransform;
158    }
159
160    /** Returns a SkPDFGlyphSetMap which represents glyph usage of every font
161     *  that shows on this device.
162     */
163    const SkPDFGlyphSetMap& getFontGlyphUsage() const {
164        return *(fFontGlyphUsage.get());
165    }
166
167protected:
168    virtual bool onReadPixels(const SkBitmap& bitmap, int x, int y,
169                              SkCanvas::Config8888) SK_OVERRIDE;
170
171    virtual bool allowImageFilter(SkImageFilter*) SK_OVERRIDE;
172
173private:
174    // TODO(vandebo): push most of SkPDFDevice's state into a core object in
175    // order to get the right access levels without using friend.
176    friend class ScopedContentEntry;
177
178    SkISize fPageSize;
179    SkISize fContentSize;
180    SkMatrix fInitialTransform;
181    SkClipStack fExistingClipStack;
182    SkRegion fExistingClipRegion;
183    SkRefPtr<SkPDFDict> fResourceDict;
184
185    SkTDArray<SkPDFGraphicState*> fGraphicStateResources;
186    SkTDArray<SkPDFObject*> fXObjectResources;
187    SkTDArray<SkPDFFont*> fFontResources;
188    SkTDArray<SkPDFObject*> fShaderResources;
189
190    SkTScopedPtr<ContentEntry> fContentEntries;
191    ContentEntry* fLastContentEntry;
192    SkTScopedPtr<ContentEntry> fMarginContentEntries;
193    ContentEntry* fLastMarginContentEntry;
194    DrawingArea fDrawingArea;
195
196    const SkClipStack* fClipStack;
197
198    // Accessor and setter functions based on the current DrawingArea.
199    SkTScopedPtr<ContentEntry>* getContentEntries();
200    ContentEntry* getLastContentEntry();
201    void setLastContentEntry(ContentEntry* contentEntry);
202
203    // Glyph ids used for each font on this device.
204    SkTScopedPtr<SkPDFGlyphSetMap> fFontGlyphUsage;
205
206    SkPDFDevice(const SkISize& layerSize, const SkClipStack& existingClipStack,
207                const SkRegion& existingClipRegion);
208
209    // override from SkDevice
210    virtual SkDevice* onCreateCompatibleDevice(SkBitmap::Config config,
211                                               int width, int height,
212                                               bool isOpaque,
213                                               Usage usage) SK_OVERRIDE;
214
215    void init();
216    void cleanUp(bool clearFontUsage);
217    void createFormXObjectFromDevice(SkRefPtr<SkPDFFormXObject>* xobject);
218
219    // Clear the passed clip from all existing content entries.
220    void clearClipFromContent(const SkClipStack* clipStack,
221                              const SkRegion& clipRegion);
222    void drawFormXObjectWithClip(SkPDFFormXObject* form,
223                                 const SkClipStack* clipStack,
224                                 const SkRegion& clipRegion,
225                                 bool invertClip);
226
227    // If the paint or clip is such that we shouldn't draw anything, this
228    // returns NULL and does not create a content entry.
229    // setUpContentEntry and finishContentEntry can be used directly, but
230    // the preferred method is to use the ScopedContentEntry helper class.
231    ContentEntry* setUpContentEntry(const SkClipStack* clipStack,
232                                    const SkRegion& clipRegion,
233                                    const SkMatrix& matrix,
234                                    const SkPaint& paint,
235                                    bool hasText,
236                                    SkRefPtr<SkPDFFormXObject>* dst);
237    void finishContentEntry(SkXfermode::Mode xfermode,
238                            SkPDFFormXObject* dst);
239    bool isContentEmpty();
240
241    void populateGraphicStateEntryFromPaint(const SkMatrix& matrix,
242                                            const SkClipStack& clipStack,
243                                            const SkRegion& clipRegion,
244                                            const SkPaint& paint,
245                                            bool hasText,
246                                            GraphicStateEntry* entry);
247    int addGraphicStateResource(SkPDFGraphicState* gs);
248
249    void updateFont(const SkPaint& paint, uint16_t glyphID,
250                    ContentEntry* contentEntry);
251    int getFontResourceIndex(SkTypeface* typeface, uint16_t glyphID);
252
253    void internalDrawPaint(const SkPaint& paint, ContentEntry* contentEntry);
254    void internalDrawBitmap(const SkMatrix& matrix,
255                            const SkClipStack* clipStack,
256                            const SkRegion& clipRegion,
257                            const SkBitmap& bitmap,
258                            const SkIRect* srcRect,
259                            const SkPaint& paint);
260
261    /** Helper method for copyContentToData. It is responsible for copying the
262     *  list of content entries |entry| to |data|.
263     */
264    void copyContentEntriesToData(ContentEntry* entry, SkWStream* data) const;
265
266    typedef SkDevice INHERITED;
267};
268
269#endif
270