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