• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2011 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #ifndef SkPDFDevice_DEFINED
9 #define SkPDFDevice_DEFINED
10 
11 #include "SkBitmap.h"
12 #include "SkCanvas.h"
13 #include "SkClipStack.h"
14 #include "SkDevice.h"
15 #include "SkPaint.h"
16 #include "SkPath.h"
17 #include "SkPicture.h"
18 #include "SkRect.h"
19 #include "SkRefCnt.h"
20 #include "SkStream.h"
21 #include "SkTDArray.h"
22 #include "SkTemplates.h"
23 
24 class SkPDFArray;
25 class SkPDFCanon;
26 class SkPDFDevice;
27 class SkPDFDict;
28 class SkPDFFont;
29 class SkPDFFormXObject;
30 class SkPDFGlyphSetMap;
31 class SkPDFGraphicState;
32 class SkPDFObject;
33 class SkPDFShader;
34 class SkPDFStream;
35 class SkRRect;
36 
37 // Private classes.
38 struct ContentEntry;
39 struct GraphicStateEntry;
40 struct NamedDestination;
41 struct RectWithData;
42 
43 /** \class SkPDFDevice
44 
45     The drawing context for the PDF backend.
46 */
47 class SkPDFDevice final : 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 new 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 new 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, const SkRect* src,
97                         const SkRect& dst, const SkPaint&, SkCanvas::SrcRectConstraint) override;
98     void drawBitmap(const SkDraw&, const SkBitmap& bitmap,
99                     const SkMatrix& matrix, const SkPaint&) override;
100     void drawSprite(const SkDraw&, const SkBitmap& bitmap, int x, int y,
101                     const SkPaint& paint) override;
102     void drawImage(const SkDraw&,
103                    const SkImage*,
104                    SkScalar x,
105                    SkScalar y,
106                    const SkPaint&) override;
107     void drawImageRect(const SkDraw&,
108                        const SkImage*,
109                        const SkRect* src,
110                        const SkRect& dst,
111                        const SkPaint&,
112                        SkCanvas::SrcRectConstraint) override;
113     void drawText(const SkDraw&, const void* text, size_t len,
114                   SkScalar x, SkScalar y, const SkPaint&) override;
115     void drawPosText(const SkDraw&, const void* text, size_t len,
116                      const SkScalar pos[], int scalarsPerPos,
117                      const SkPoint& offset, const SkPaint&) override;
118     void drawVertices(const SkDraw&, SkCanvas::VertexMode,
119                       int vertexCount, const SkPoint verts[],
120                       const SkPoint texs[], const SkColor colors[],
121                       SkXfermode* xmode, const uint16_t indices[],
122                       int indexCount, const SkPaint& paint) override;
123     void drawDevice(const SkDraw&, SkBaseDevice*, int x, int y,
124                     const SkPaint&) override;
125 
126     void onAttachToCanvas(SkCanvas* canvas) override;
127     void onDetachFromCanvas() override;
128     SkImageInfo imageInfo() const override;
129 
130     enum DrawingArea {
131         kContent_DrawingArea,  // Drawing area for the page content.
132         kMargin_DrawingArea,   // Drawing area for the margin content.
133     };
134 
135     /** Sets the drawing area for the device. Subsequent draw calls are directed
136      *  to the specific drawing area (margin or content). The default drawing
137      *  area is the content drawing area.
138      *
139      *  Currently if margin content is drawn and then a complex (for PDF) xfer
140      *  mode is used, like SrcIn, Clear, etc, the margin content will get
141      *  clipped. A simple way to avoid the bug is to always draw the margin
142      *  content last.
143      */
144     void setDrawingArea(DrawingArea drawingArea);
145 
146     // PDF specific methods.
147 
148     /** Create the resource dictionary for this device.
149      */
150     SkPDFDict* createResourceDict() const;
151 
152     /** Get the fonts used on this device.
153      */
154     const SkTDArray<SkPDFFont*>& getFontResources() const;
155 
156     /** Add our annotations (link to urls and destinations) to the supplied
157      *  array.
158      *  @param array Array to add annotations to.
159      */
160     void appendAnnotations(SkPDFArray* array) const;
161 
162     /** Add our named destinations to the supplied dictionary.
163      *  @param dict  Dictionary to add destinations to.
164      *  @param page  The PDF object representing the page for this device.
165      */
166     void appendDestinations(SkPDFDict* dict, SkPDFObject* page) const;
167 
168     /** Returns a copy of the media box for this device. The caller is required
169      *  to unref() this when it is finished.
170      */
171     SkPDFArray* copyMediaBox() const;
172 
173     /** Returns a SkStream with the page contents.  The caller is responsible
174      *  for a deleting the returned value.
175      */
176     SkStreamAsset* content() const;
177 
178     /** Writes the page contents to the stream. */
179     void writeContent(SkWStream*) const;
180 
initialTransform()181     const SkMatrix& initialTransform() const {
182         return fInitialTransform;
183     }
184 
185     /** Returns a SkPDFGlyphSetMap which represents glyph usage of every font
186      *  that shows on this device.
187      */
getFontGlyphUsage()188     const SkPDFGlyphSetMap& getFontGlyphUsage() const {
189         return *(fFontGlyphUsage.get());
190     }
191 
getCanon()192     SkPDFCanon* getCanon() const { return fCanon; }
193 
194 protected:
onAccessBitmap()195     const SkBitmap& onAccessBitmap() override {
196         return fLegacyBitmap;
197     }
198 
199     SkSurface* newSurface(const SkImageInfo&, const SkSurfaceProps&) override;
200 
201 private:
202     // TODO(vandebo): push most of SkPDFDevice's state into a core object in
203     // order to get the right access levels without using friend.
204     friend class ScopedContentEntry;
205 
206     SkISize fPageSize;
207     SkISize fContentSize;
208     SkMatrix fInitialTransform;
209     SkClipStack fExistingClipStack;
210     SkRegion fExistingClipRegion;
211 
212     SkTDArray<RectWithData*> fLinkToURLs;
213     SkTDArray<RectWithData*> fLinkToDestinations;
214     SkTDArray<NamedDestination*> fNamedDestinations;
215 
216     SkTDArray<SkPDFObject*> fGraphicStateResources;
217     SkTDArray<SkPDFObject*> fXObjectResources;
218     SkTDArray<SkPDFFont*> fFontResources;
219     SkTDArray<SkPDFObject*> fShaderResources;
220 
221     SkAutoTDelete<ContentEntry> fContentEntries;
222     ContentEntry* fLastContentEntry;
223     SkAutoTDelete<ContentEntry> fMarginContentEntries;
224     ContentEntry* fLastMarginContentEntry;
225     DrawingArea fDrawingArea;
226 
227     const SkClipStack* fClipStack;
228 
229     // Accessor and setter functions based on the current DrawingArea.
230     SkAutoTDelete<ContentEntry>* getContentEntries();
231 
232     // Glyph ids used for each font on this device.
233     SkAutoTDelete<SkPDFGlyphSetMap> fFontGlyphUsage;
234 
235     SkScalar fRasterDpi;
236 
237     SkBitmap fLegacyBitmap;
238 
239     SkPDFCanon* fCanon;  // Owned by SkDocument_PDF
240     ////////////////////////////////////////////////////////////////////////////
241 
242     SkPDFDevice(SkISize pageSize,
243                 SkScalar rasterDpi,
244                 SkPDFCanon* canon,
245                 bool flip);
246 
247     ContentEntry* getLastContentEntry();
248     void setLastContentEntry(ContentEntry* contentEntry);
249 
250     SkBaseDevice* onCreateDevice(const CreateInfo&, const SkPaint*) override;
251 
252     void init();
253     void cleanUp(bool clearFontUsage);
254     SkPDFFormXObject* createFormXObjectFromDevice();
255 
256     void drawFormXObjectWithMask(int xObjectIndex,
257                                  SkPDFFormXObject* mask,
258                                  const SkClipStack* clipStack,
259                                  const SkRegion& clipRegion,
260                                  SkXfermode::Mode mode,
261                                  bool invertClip);
262 
263     // If the paint or clip is such that we shouldn't draw anything, this
264     // returns nullptr and does not create a content entry.
265     // setUpContentEntry and finishContentEntry can be used directly, but
266     // the preferred method is to use the ScopedContentEntry helper class.
267     ContentEntry* setUpContentEntry(const SkClipStack* clipStack,
268                                     const SkRegion& clipRegion,
269                                     const SkMatrix& matrix,
270                                     const SkPaint& paint,
271                                     bool hasText,
272                                     SkPDFFormXObject** dst);
273     void finishContentEntry(SkXfermode::Mode xfermode,
274                             SkPDFFormXObject* dst,
275                             SkPath* shape);
276     bool isContentEmpty();
277 
278     void populateGraphicStateEntryFromPaint(const SkMatrix& matrix,
279                                             const SkClipStack& clipStack,
280                                             const SkRegion& clipRegion,
281                                             const SkPaint& paint,
282                                             bool hasText,
283                                             GraphicStateEntry* entry);
284     int addGraphicStateResource(SkPDFObject* gs);
285     int addXObjectResource(SkPDFObject* xObject);
286 
287     void updateFont(const SkPaint& paint, uint16_t glyphID, ContentEntry* contentEntry);
288     int getFontResourceIndex(SkTypeface* typeface, uint16_t glyphID);
289 
290     void internalDrawPaint(const SkPaint& paint, ContentEntry* contentEntry);
291     void internalDrawImage(const SkMatrix& matrix,
292                            const SkClipStack* clipStack,
293                            const SkRegion& clipRegion,
294                            const SkImage* image,
295                            const SkIRect* srcRect,
296                            const SkPaint& paint);
297 
298     /** Helper method for copyContentToData. It is responsible for copying the
299      *  list of content entries |entry| to |data|.
300      */
301     void copyContentEntriesToData(ContentEntry* entry, SkWStream* data) const;
302 
303     bool handleInversePath(const SkDraw& d, const SkPath& origPath,
304                            const SkPaint& paint, bool pathIsMutable,
305                            const SkMatrix* prePathMatrix = nullptr);
306     bool handlePointAnnotation(const SkPoint* points, size_t count,
307                                const SkMatrix& matrix, SkAnnotation* annot);
308     bool handlePathAnnotation(const SkPath& path, const SkDraw& d,
309                               SkAnnotation* annot);
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
320