|
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 "SkBitmapDevice.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 SkPDFDevice; |
|
27 class SkPDFDict; |
|
28 class SkPDFFont; |
|
29 class SkPDFFormXObject; |
|
30 class SkPDFGlyphSetMap; |
|
31 class SkPDFGraphicState; |
|
32 class SkPDFObject; |
|
33 class SkPDFResourceDict; |
|
34 class SkPDFShader; |
|
35 class SkPDFStream; |
|
36 class SkRRect; |
|
37 template <typename T> class SkTSet; |
|
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 SkBitmapDevice { |
|
49 public: |
|
50 /** Create a PDF drawing context with the given width and height. |
|
51 * 72 points/in means letter paper is 612x792. |
|
52 * @param pageSize Page size in points. |
|
53 * @param contentSize The content size of the page in points. This will be |
|
54 * combined with the initial transform to determine the drawing area |
|
55 * (as reported by the width and height methods). Anything outside |
|
56 * of the drawing area will be clipped. |
|
57 * @param initialTransform The initial transform to apply to the page. |
|
58 * This may be useful to, for example, move the origin in and |
|
59 * over a bit to account for a margin, scale the canvas, |
|
60 * or apply a rotation. Note1: the SkPDFDevice also applies |
|
61 * a scale+translate transform to move the origin from the |
|
62 * bottom left (PDF default) to the top left. Note2: drawDevice |
|
63 * (used by layer restore) draws the device after this initial |
|
64 * transform is applied, so the PDF device does an |
|
65 * inverse scale+translate to accommodate the one that SkPDFDevice |
|
66 * always does. |
|
67 */ |
|
68 // Deprecated, please use SkDocument::CreatePdf() instead. |
|
69 SK_API SkPDFDevice(const SkISize& pageSize, const SkISize& contentSize, |
|
70 const SkMatrix& initialTransform); |
|
71 SK_API virtual ~SkPDFDevice(); |
|
72 |
|
73 virtual void clear(SkColor color) SK_OVERRIDE; |
|
74 |
|
75 /** These are called inside the per-device-layer loop for each draw call. |
|
76 When these are called, we have already applied any saveLayer operations, |
|
77 and are handling any looping from the paint, and any effects from the |
|
78 DrawFilter. |
|
79 */ |
|
80 virtual void drawPaint(const SkDraw&, const SkPaint& paint) SK_OVERRIDE; |
|
81 virtual void drawPoints(const SkDraw&, SkCanvas::PointMode mode, |
|
82 size_t count, const SkPoint[], |
|
83 const SkPaint& paint) SK_OVERRIDE; |
|
84 virtual void drawRect(const SkDraw&, const SkRect& r, const SkPaint& paint); |
|
85 virtual void drawRRect(const SkDraw&, const SkRRect& rr, |
|
86 const SkPaint& paint) SK_OVERRIDE; |
|
87 virtual void drawPath(const SkDraw&, const SkPath& origpath, |
|
88 const SkPaint& paint, const SkMatrix* prePathMatrix, |
|
89 bool pathIsMutable) SK_OVERRIDE; |
|
90 virtual void drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap, |
|
91 const SkRect* src, const SkRect& dst, |
|
92 const SkPaint& paint, |
|
93 SkCanvas::DrawBitmapRectFlags flags) SK_OVERRIDE; |
|
94 virtual void drawBitmap(const SkDraw&, const SkBitmap& bitmap, |
|
95 const SkMatrix& matrix, const SkPaint&) SK_OVERRIDE; |
|
96 virtual void drawSprite(const SkDraw&, const SkBitmap& bitmap, int x, int y, |
|
97 const SkPaint& paint) SK_OVERRIDE; |
|
98 virtual void drawText(const SkDraw&, const void* text, size_t len, |
|
99 SkScalar x, SkScalar y, const SkPaint&) SK_OVERRIDE; |
|
100 virtual void drawPosText(const SkDraw&, const void* text, size_t len, |
|
101 const SkScalar pos[], SkScalar constY, |
|
102 int scalarsPerPos, const SkPaint&) SK_OVERRIDE; |
|
103 virtual void drawTextOnPath(const SkDraw&, const void* text, size_t len, |
|
104 const SkPath& path, const SkMatrix* matrix, |
|
105 const SkPaint& paint) SK_OVERRIDE; |
|
106 virtual void drawVertices(const SkDraw&, SkCanvas::VertexMode, |
|
107 int vertexCount, const SkPoint verts[], |
|
108 const SkPoint texs[], const SkColor colors[], |
|
109 SkXfermode* xmode, const uint16_t indices[], |
|
110 int indexCount, const SkPaint& paint) SK_OVERRIDE; |
|
111 virtual void drawDevice(const SkDraw&, SkBaseDevice*, int x, int y, |
|
112 const SkPaint&) SK_OVERRIDE; |
|
113 |
|
114 virtual void onAttachToCanvas(SkCanvas* canvas) SK_OVERRIDE; |
|
115 virtual void onDetachFromCanvas() SK_OVERRIDE; |
|
116 |
|
117 enum DrawingArea { |
|
118 kContent_DrawingArea, // Drawing area for the page content. |
|
119 kMargin_DrawingArea, // Drawing area for the margin content. |
|
120 }; |
|
121 |
|
122 /** Sets the drawing area for the device. Subsequent draw calls are directed |
|
123 * to the specific drawing area (margin or content). The default drawing |
|
124 * area is the content drawing area. |
|
125 * |
|
126 * Currently if margin content is drawn and then a complex (for PDF) xfer |
|
127 * mode is used, like SrcIn, Clear, etc, the margin content will get |
|
128 * clipped. A simple way to avoid the bug is to always draw the margin |
|
129 * content last. |
|
130 */ |
|
131 SK_API void setDrawingArea(DrawingArea drawingArea); |
|
132 |
|
133 /** Sets the DCTEncoder for images. |
|
134 * @param encoder The encoder to encode a bitmap as JPEG (DCT). |
|
135 * Result of encodings are cached, if the encoder changes the |
|
136 * behaivor dynamically and an image is added to a second catalog, |
|
137 * we will likely use the result of the first encoding call. |
|
138 * By returning false from the encoder function, the encoder result |
|
139 * is not used. |
|
140 * Callers might not want to encode small images, as the time spent |
|
141 * encoding and decoding might not be worth the space savings, |
|
142 * if any at all. |
|
143 */ |
|
144 void setDCTEncoder(SkPicture::EncodeBitmap encoder) { |
|
145 fEncoder = encoder; |
|
146 } |
|
147 |
|
148 // PDF specific methods. |
|
149 |
|
150 /** Returns the resource dictionary for this device. |
|
151 */ |
|
152 SK_API SkPDFResourceDict* getResourceDict(); |
|
153 |
|
154 /** Get the fonts used on this device. |
|
155 */ |
|
156 SK_API const SkTDArray<SkPDFFont*>& getFontResources() const; |
|
157 |
|
158 /** Add our named destinations to the supplied dictionary. |
|
159 * @param dict Dictionary to add destinations to. |
|
160 * @param page The PDF object representing the page for this device. |
|
161 */ |
|
162 void appendDestinations(SkPDFDict* dict, SkPDFObject* page); |
|
163 |
|
164 /** Returns a copy of the media box for this device. The caller is required |
|
165 * to unref() this when it is finished. |
|
166 */ |
|
167 SK_API SkPDFArray* copyMediaBox() const; |
|
168 |
|
169 /** Get the annotations from this page, or NULL if there are none. |
|
170 */ |
|
171 SK_API SkPDFArray* getAnnotations() const { return fAnnotations; } |
|
172 |
|
173 /** Returns a SkStream with the page contents. The caller is responsible |
|
174 for a reference to the returned value. |
|
175 DEPRECATED: use copyContentToData() |
|
176 */ |
|
177 SK_API SkStream* content() const; |
|
178 |
|
179 /** Returns a SkStream with the page contents. The caller is responsible |
|
180 * for calling data->unref() when it is finished. |
|
181 */ |
|
182 SK_API SkData* copyContentToData() const; |
|
183 |
|
184 SK_API const SkMatrix& initialTransform() const { |
|
185 return fInitialTransform; |
|
186 } |
|
187 |
|
188 /** Returns a SkPDFGlyphSetMap which represents glyph usage of every font |
|
189 * that shows on this device. |
|
190 */ |
|
191 const SkPDFGlyphSetMap& getFontGlyphUsage() const { |
|
192 return *(fFontGlyphUsage.get()); |
|
193 } |
|
194 |
|
195 |
|
196 /** |
|
197 * rasterDpi - the DPI at which features without native PDF support |
|
198 * will be rasterized (e.g. draw image with perspective, |
|
199 * draw text with perspective, ...) |
|
200 * A larger DPI would create a PDF that reflects the original |
|
201 * intent with better fidelity, but it can make for larger |
|
202 * PDF files too, which would use more memory while rendering, |
|
203 * and it would be slower to be processed or sent online or |
|
204 * to printer. |
|
205 */ |
|
206 void setRasterDpi(SkScalar rasterDpi) { |
|
207 fRasterDpi = rasterDpi; |
|
208 } |
|
209 |
|
210 protected: |
|
211 virtual bool onReadPixels(const SkBitmap& bitmap, int x, int y, |
|
212 SkCanvas::Config8888) SK_OVERRIDE; |
|
213 |
|
214 virtual bool allowImageFilter(const SkImageFilter*) SK_OVERRIDE; |
|
215 |
|
216 private: |
|
217 // TODO(vandebo): push most of SkPDFDevice's state into a core object in |
|
218 // order to get the right access levels without using friend. |
|
219 friend class ScopedContentEntry; |
|
220 |
|
221 SkISize fPageSize; |
|
222 SkISize fContentSize; |
|
223 SkMatrix fInitialTransform; |
|
224 SkClipStack fExistingClipStack; |
|
225 SkRegion fExistingClipRegion; |
|
226 SkPDFArray* fAnnotations; |
|
227 SkPDFResourceDict* fResourceDict; |
|
228 SkTDArray<NamedDestination*> fNamedDestinations; |
|
229 |
|
230 SkTDArray<SkPDFGraphicState*> fGraphicStateResources; |
|
231 SkTDArray<SkPDFObject*> fXObjectResources; |
|
232 SkTDArray<SkPDFFont*> fFontResources; |
|
233 SkTDArray<SkPDFObject*> fShaderResources; |
|
234 |
|
235 SkAutoTDelete<ContentEntry> fContentEntries; |
|
236 ContentEntry* fLastContentEntry; |
|
237 SkAutoTDelete<ContentEntry> fMarginContentEntries; |
|
238 ContentEntry* fLastMarginContentEntry; |
|
239 DrawingArea fDrawingArea; |
|
240 |
|
241 const SkClipStack* fClipStack; |
|
242 |
|
243 // Accessor and setter functions based on the current DrawingArea. |
|
244 SkAutoTDelete<ContentEntry>* getContentEntries(); |
|
245 ContentEntry* getLastContentEntry(); |
|
246 void setLastContentEntry(ContentEntry* contentEntry); |
|
247 |
|
248 // Glyph ids used for each font on this device. |
|
249 SkAutoTDelete<SkPDFGlyphSetMap> fFontGlyphUsage; |
|
250 |
|
251 SkPicture::EncodeBitmap fEncoder; |
|
252 SkScalar fRasterDpi; |
|
253 |
|
254 SkPDFDevice(const SkISize& layerSize, const SkClipStack& existingClipStack, |
|
255 const SkRegion& existingClipRegion); |
|
256 |
|
257 // override from SkBaseDevice |
|
258 virtual SkBaseDevice* onCreateDevice(const SkImageInfo&, Usage) SK_OVERRIDE; |
|
259 |
|
260 void init(); |
|
261 void cleanUp(bool clearFontUsage); |
|
262 SkPDFFormXObject* createFormXObjectFromDevice(); |
|
263 |
|
264 void drawFormXObjectWithMask(int xObjectIndex, |
|
265 SkPDFFormXObject* mask, |
|
266 const SkClipStack* clipStack, |
|
267 const SkRegion& clipRegion, |
|
268 SkXfermode::Mode mode, |
|
269 bool invertClip); |
|
270 |
|
271 // If the paint or clip is such that we shouldn't draw anything, this |
|
272 // returns NULL and does not create a content entry. |
|
273 // setUpContentEntry and finishContentEntry can be used directly, but |
|
274 // the preferred method is to use the ScopedContentEntry helper class. |
|
275 ContentEntry* setUpContentEntry(const SkClipStack* clipStack, |
|
276 const SkRegion& clipRegion, |
|
277 const SkMatrix& matrix, |
|
278 const SkPaint& paint, |
|
279 bool hasText, |
|
280 SkPDFFormXObject** dst); |
|
281 void finishContentEntry(SkXfermode::Mode xfermode, |
|
282 SkPDFFormXObject* dst, |
|
283 SkPath* shape); |
|
284 bool isContentEmpty(); |
|
285 |
|
286 void populateGraphicStateEntryFromPaint(const SkMatrix& matrix, |
|
287 const SkClipStack& clipStack, |
|
288 const SkRegion& clipRegion, |
|
289 const SkPaint& paint, |
|
290 bool hasText, |
|
291 GraphicStateEntry* entry); |
|
292 int addGraphicStateResource(SkPDFGraphicState* gs); |
|
293 int addXObjectResource(SkPDFObject* xObject); |
|
294 |
|
295 void updateFont(const SkPaint& paint, uint16_t glyphID, |
|
296 ContentEntry* contentEntry); |
|
297 int getFontResourceIndex(SkTypeface* typeface, uint16_t glyphID); |
|
298 |
|
299 void internalDrawPaint(const SkPaint& paint, ContentEntry* contentEntry); |
|
300 void internalDrawBitmap(const SkMatrix& matrix, |
|
301 const SkClipStack* clipStack, |
|
302 const SkRegion& clipRegion, |
|
303 const SkBitmap& bitmap, |
|
304 const SkIRect* srcRect, |
|
305 const SkPaint& paint); |
|
306 |
|
307 /** Helper method for copyContentToData. It is responsible for copying the |
|
308 * list of content entries |entry| to |data|. |
|
309 */ |
|
310 void copyContentEntriesToData(ContentEntry* entry, SkWStream* data) const; |
|
311 |
|
312 #ifdef SK_PDF_USE_PATHOPS |
|
313 bool handleInversePath(const SkDraw& d, const SkPath& origPath, |
|
314 const SkPaint& paint, bool pathIsMutable, |
|
315 const SkMatrix* prePathMatrix = NULL); |
|
316 #endif |
|
317 bool handleRectAnnotation(const SkRect& r, const SkMatrix& matrix, |
|
318 const SkPaint& paint); |
|
319 bool handlePointAnnotation(const SkPoint* points, size_t count, |
|
320 const SkMatrix& matrix, const SkPaint& paint); |
|
321 SkPDFDict* createLinkAnnotation(const SkRect& r, const SkMatrix& matrix); |
|
322 void handleLinkToURL(SkData* urlData, const SkRect& r, |
|
323 const SkMatrix& matrix); |
|
324 void handleLinkToNamedDest(SkData* nameData, const SkRect& r, |
|
325 const SkMatrix& matrix); |
|
326 void defineNamedDestination(SkData* nameData, const SkPoint& point, |
|
327 const SkMatrix& matrix); |
|
328 |
|
329 typedef SkBitmapDevice INHERITED; |
|
330 |
|
331 // TODO(edisonn): Only SkDocument_PDF and SkPDFImageShader should be able to create |
|
332 // an SkPDFDevice |
|
333 //friend class SkDocument_PDF; |
|
334 //friend class SkPDFImageShader; |
|
335 }; |
|
336 |
|
337 #endif |