SkPDFDevice.h revision 0e040f7da2fdfeb49aa60d24117306e3b1e6ea90
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 "SkDevice.h"
14#include "SkBitmap.h"
15#include "SkCanvas.h"
16#include "SkPaint.h"
17#include "SkPath.h"
18#include "SkPicture.h"
19#include "SkRect.h"
20#include "SkRefCnt.h"
21#include "SkStream.h"
22#include "SkTDArray.h"
23#include "SkTemplates.h"
24
25class SkPDFArray;
26class SkPDFCanon;
27class SkPDFDevice;
28class SkPDFDict;
29class SkPDFFont;
30class SkPDFFormXObject;
31class SkPDFGlyphSetMap;
32class SkPDFGraphicState;
33class SkPDFObject;
34class SkPDFResourceDict;
35class SkPDFShader;
36class SkPDFStream;
37class SkRRect;
38template <typename T> class SkTSet;
39
40// Private classes.
41struct ContentEntry;
42struct GraphicStateEntry;
43struct NamedDestination;
44
45/** \class SkPDFDevice
46
47    The drawing context for the PDF backend.
48*/
49class SkPDFDevice : public SkBaseDevice {
50public:
51    /** Create a PDF drawing context.  SkPDFDevice applies a
52     *  scale-and-translate transform to move the origin from the
53     *  bottom left (PDF default) to the top left (Skia default).
54     *  @param pageSize Page size in point units.
55     *         1 point == 127/360 mm == 1/72 inch
56     *  @param rasterDpi the DPI at which features without native PDF
57     *         support will be rasterized (e.g. draw image with
58     *         perspective, draw text with perspective, ...).  A
59     *         larger DPI would create a PDF that reflects the
60     *         original intent with better fidelity, but it can make
61     *         for larger PDF files too, which would use more memory
62     *         while rendering, and it would be slower to be processed
63     *         or sent online or to printer.  A good choice is
64     *         SK_ScalarDefaultRasterDPI(72.0f).
65     *  @param SkPDFCanon.  Should be non-null, and shared by all
66     *         devices in a document.
67     */
68    static SkPDFDevice* Create(SkISize pageSize,
69                               SkScalar rasterDpi,
70                               SkPDFCanon* canon) {
71        return SkNEW_ARGS(SkPDFDevice, (pageSize, rasterDpi, canon, true));
72    }
73
74    /** Create a PDF drawing context without fipping the y-axis. */
75    static SkPDFDevice* CreateUnflipped(SkISize pageSize,
76                                        SkScalar rasterDpi,
77                                        SkPDFCanon* canon) {
78        return SkNEW_ARGS(SkPDFDevice, (pageSize, rasterDpi, canon, false));
79    }
80
81    virtual ~SkPDFDevice();
82
83    /** These are called inside the per-device-layer loop for each draw call.
84     When these are called, we have already applied any saveLayer operations,
85     and are handling any looping from the paint, and any effects from the
86     DrawFilter.
87     */
88    void drawPaint(const SkDraw&, const SkPaint& paint) SK_OVERRIDE;
89    void drawPoints(const SkDraw&, SkCanvas::PointMode mode,
90                    size_t count, const SkPoint[],
91                    const SkPaint& paint) SK_OVERRIDE;
92    void drawRect(const SkDraw&, const SkRect& r, const SkPaint& paint) SK_OVERRIDE;
93    void drawOval(const SkDraw&, const SkRect& oval, const SkPaint& paint) SK_OVERRIDE;
94    void drawRRect(const SkDraw&, const SkRRect& rr, const SkPaint& paint) SK_OVERRIDE;
95    void drawPath(const SkDraw&, const SkPath& origpath,
96                  const SkPaint& paint, const SkMatrix* prePathMatrix,
97                  bool pathIsMutable) SK_OVERRIDE;
98    void drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap,
99                        const SkRect* src, const SkRect& dst,
100                        const SkPaint& paint,
101                        SkCanvas::DrawBitmapRectFlags flags) SK_OVERRIDE;
102    void drawBitmap(const SkDraw&, const SkBitmap& bitmap,
103                    const SkMatrix& matrix, const SkPaint&) SK_OVERRIDE;
104    void drawSprite(const SkDraw&, const SkBitmap& bitmap, int x, int y,
105                    const SkPaint& paint) SK_OVERRIDE;
106    void drawText(const SkDraw&, const void* text, size_t len,
107                  SkScalar x, SkScalar y, const SkPaint&) SK_OVERRIDE;
108    void drawPosText(const SkDraw&, const void* text, size_t len,
109                     const SkScalar pos[], int scalarsPerPos,
110                     const SkPoint& offset, const SkPaint&) SK_OVERRIDE;
111    void drawVertices(const SkDraw&, SkCanvas::VertexMode,
112                      int vertexCount, const SkPoint verts[],
113                      const SkPoint texs[], const SkColor colors[],
114                      SkXfermode* xmode, const uint16_t indices[],
115                      int indexCount, const SkPaint& paint) SK_OVERRIDE;
116    void drawDevice(const SkDraw&, SkBaseDevice*, int x, int y,
117                    const SkPaint&) SK_OVERRIDE;
118
119    void onAttachToCanvas(SkCanvas* canvas) SK_OVERRIDE;
120    void onDetachFromCanvas() SK_OVERRIDE;
121    SkImageInfo imageInfo() const SK_OVERRIDE;
122
123    enum DrawingArea {
124        kContent_DrawingArea,  // Drawing area for the page content.
125        kMargin_DrawingArea,   // Drawing area for the margin content.
126    };
127
128    /** Sets the drawing area for the device. Subsequent draw calls are directed
129     *  to the specific drawing area (margin or content). The default drawing
130     *  area is the content drawing area.
131     *
132     *  Currently if margin content is drawn and then a complex (for PDF) xfer
133     *  mode is used, like SrcIn, Clear, etc, the margin content will get
134     *  clipped. A simple way to avoid the bug is to always draw the margin
135     *  content last.
136     */
137    void setDrawingArea(DrawingArea drawingArea);
138
139    // PDF specific methods.
140
141    /** Returns the resource dictionary for this device.
142     */
143    SkPDFResourceDict* getResourceDict();
144
145    /** Get the fonts used on this device.
146     */
147    const SkTDArray<SkPDFFont*>& getFontResources() const;
148
149    /** Add our named destinations to the supplied dictionary.
150     *  @param dict  Dictionary to add destinations to.
151     *  @param page  The PDF object representing the page for this device.
152     */
153    void appendDestinations(SkPDFDict* dict, SkPDFObject* page);
154
155    /** Returns a copy of the media box for this device. The caller is required
156     *  to unref() this when it is finished.
157     */
158    SkPDFArray* copyMediaBox() const;
159
160    /** Get the annotations from this page, or NULL if there are none.
161     */
162    SkPDFArray* getAnnotations() const { return fAnnotations; }
163
164    /** Returns a SkStream with the page contents.  The caller is responsible
165     *  for a deleting the returned value.
166     */
167    SkStreamAsset* content() const;
168
169    /** Writes the page contents to the stream. */
170    void writeContent(SkWStream*) const;
171
172    const SkMatrix& initialTransform() const {
173        return fInitialTransform;
174    }
175
176    /** Returns a SkPDFGlyphSetMap which represents glyph usage of every font
177     *  that shows on this device.
178     */
179    const SkPDFGlyphSetMap& getFontGlyphUsage() const {
180        return *(fFontGlyphUsage.get());
181    }
182
183protected:
184    const SkBitmap& onAccessBitmap() SK_OVERRIDE {
185        return fLegacyBitmap;
186    }
187
188    SkSurface* newSurface(const SkImageInfo&, const SkSurfaceProps&) SK_OVERRIDE;
189
190private:
191    // TODO(vandebo): push most of SkPDFDevice's state into a core object in
192    // order to get the right access levels without using friend.
193    friend class ScopedContentEntry;
194
195    SkISize fPageSize;
196    SkISize fContentSize;
197    SkMatrix fInitialTransform;
198    SkClipStack fExistingClipStack;
199    SkRegion fExistingClipRegion;
200    SkPDFArray* fAnnotations;
201    SkPDFResourceDict* fResourceDict;
202    SkTDArray<NamedDestination*> fNamedDestinations;
203
204    SkTDArray<SkPDFGraphicState*> fGraphicStateResources;
205    SkTDArray<SkPDFObject*> fXObjectResources;
206    SkTDArray<SkPDFFont*> fFontResources;
207    SkTDArray<SkPDFObject*> fShaderResources;
208
209    SkAutoTDelete<ContentEntry> fContentEntries;
210    ContentEntry* fLastContentEntry;
211    SkAutoTDelete<ContentEntry> fMarginContentEntries;
212    ContentEntry* fLastMarginContentEntry;
213    DrawingArea fDrawingArea;
214
215    const SkClipStack* fClipStack;
216
217    // Accessor and setter functions based on the current DrawingArea.
218    SkAutoTDelete<ContentEntry>* getContentEntries();
219
220    // Glyph ids used for each font on this device.
221    SkAutoTDelete<SkPDFGlyphSetMap> fFontGlyphUsage;
222
223    SkScalar fRasterDpi;
224
225    SkBitmap fLegacyBitmap;
226
227    SkPDFCanon* fCanon;  // Owned by SkDocument_PDF
228    ////////////////////////////////////////////////////////////////////////////
229
230    SkPDFDevice(SkISize pageSize,
231                SkScalar rasterDpi,
232                SkPDFCanon* canon,
233                bool flip);
234
235    ContentEntry* getLastContentEntry();
236    void setLastContentEntry(ContentEntry* contentEntry);
237
238    // override from SkBaseDevice
239    SkBaseDevice* onCreateCompatibleDevice(const CreateInfo&) SK_OVERRIDE;
240
241    void init();
242    void cleanUp(bool clearFontUsage);
243    SkPDFFormXObject* createFormXObjectFromDevice();
244
245    void drawFormXObjectWithMask(int xObjectIndex,
246                                 SkPDFFormXObject* mask,
247                                 const SkClipStack* clipStack,
248                                 const SkRegion& clipRegion,
249                                 SkXfermode::Mode mode,
250                                 bool invertClip);
251
252    // If the paint or clip is such that we shouldn't draw anything, this
253    // returns NULL and does not create a content entry.
254    // setUpContentEntry and finishContentEntry can be used directly, but
255    // the preferred method is to use the ScopedContentEntry helper class.
256    ContentEntry* setUpContentEntry(const SkClipStack* clipStack,
257                                    const SkRegion& clipRegion,
258                                    const SkMatrix& matrix,
259                                    const SkPaint& paint,
260                                    bool hasText,
261                                    SkPDFFormXObject** dst);
262    void finishContentEntry(SkXfermode::Mode xfermode,
263                            SkPDFFormXObject* dst,
264                            SkPath* shape);
265    bool isContentEmpty();
266
267    void populateGraphicStateEntryFromPaint(const SkMatrix& matrix,
268                                            const SkClipStack& clipStack,
269                                            const SkRegion& clipRegion,
270                                            const SkPaint& paint,
271                                            bool hasText,
272                                            GraphicStateEntry* entry);
273    int addGraphicStateResource(SkPDFGraphicState* gs);
274    int addXObjectResource(SkPDFObject* xObject);
275
276    void updateFont(const SkPaint& paint, uint16_t glyphID,
277                    ContentEntry* contentEntry);
278    int getFontResourceIndex(SkTypeface* typeface, uint16_t glyphID);
279
280    void internalDrawPaint(const SkPaint& paint, ContentEntry* contentEntry);
281    void internalDrawBitmap(const SkMatrix& matrix,
282                            const SkClipStack* clipStack,
283                            const SkRegion& clipRegion,
284                            const SkBitmap& bitmap,
285                            const SkIRect* srcRect,
286                            const SkPaint& paint);
287
288    /** Helper method for copyContentToData. It is responsible for copying the
289     *  list of content entries |entry| to |data|.
290     */
291    void copyContentEntriesToData(ContentEntry* entry, SkWStream* data) const;
292
293#ifdef SK_PDF_USE_PATHOPS
294    bool handleInversePath(const SkDraw& d, const SkPath& origPath,
295                           const SkPaint& paint, bool pathIsMutable,
296                           const SkMatrix* prePathMatrix = NULL);
297#endif
298    bool handleRectAnnotation(const SkRect& r, const SkMatrix& matrix,
299                              const SkPaint& paint);
300    bool handlePointAnnotation(const SkPoint* points, size_t count,
301                               const SkMatrix& matrix, const SkPaint& paint);
302    SkPDFDict* createLinkAnnotation(const SkRect& r, const SkMatrix& matrix);
303    void handleLinkToURL(SkData* urlData, const SkRect& r,
304                         const SkMatrix& matrix);
305    void handleLinkToNamedDest(SkData* nameData, const SkRect& r,
306                               const SkMatrix& matrix);
307    void defineNamedDestination(SkData* nameData, const SkPoint& point,
308                                const SkMatrix& matrix);
309
310    typedef SkBaseDevice INHERITED;
311
312    // TODO(edisonn): Only SkDocument_PDF and SkPDFImageShader should be able to create
313    // an SkPDFDevice
314    //friend class SkDocument_PDF;
315    //friend class SkPDFImageShader;
316};
317
318#endif
319