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