3 * Copyright 2011 Google Inc.
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
10 #ifndef SkPDFDevice_DEFINED
11 #define SkPDFDevice_DEFINED
18 #include "SkPicture.h"
22 #include "SkTDArray.h"
23 #include "SkTemplates.h"
30 class SkPDFFormXObject;
31 class SkPDFGlyphSetMap;
32 class SkPDFGraphicState;
34 class SkPDFResourceDict;
41 struct GraphicStateEntry;
42 struct NamedDestination;
44 /** \class SkPDFDevice
46 The drawing context for the PDF backend.
48 class SkPDFDevice : public SkBaseDevice {
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.
67 static SkPDFDevice* Create(SkISize pageSize,
70 return SkNEW_ARGS(SkPDFDevice, (pageSize, rasterDpi, canon, true));
73 /** Create a PDF drawing context without fipping the y-axis. */
74 static SkPDFDevice* CreateUnflipped(SkISize pageSize,
77 return SkNEW_ARGS(SkPDFDevice, (pageSize, rasterDpi, canon, false));
80 virtual ~SkPDFDevice();
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
87 void drawPaint(const SkDraw&, const SkPaint& paint) override;
88 void drawPoints(const SkDraw&, SkCanvas::PointMode mode,
89 size_t count, const SkPoint[],
90 const SkPaint& paint) override;
91 void drawRect(const SkDraw&, const SkRect& r, const SkPaint& paint) override;
92 void drawOval(const SkDraw&, const SkRect& oval, const SkPaint& paint) override;
93 void drawRRect(const SkDraw&, const SkRRect& rr, const SkPaint& paint) override;
94 void drawPath(const SkDraw&, const SkPath& origpath,
95 const SkPaint& paint, const SkMatrix* prePathMatrix,
96 bool pathIsMutable) override;
97 void drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap,
98 const SkRect* src, const SkRect& dst,
100 SkCanvas::DrawBitmapRectFlags flags) override;
101 void drawBitmap(const SkDraw&, const SkBitmap& bitmap,
102 const SkMatrix& matrix, const SkPaint&) override;
103 void drawSprite(const SkDraw&, const SkBitmap& bitmap, int x, int y,
104 const SkPaint& paint) override;
105 void drawText(const SkDraw&, const void* text, size_t len,
106 SkScalar x, SkScalar y, const SkPaint&) override;
107 void drawPosText(const SkDraw&, const void* text, size_t len,
108 const SkScalar pos[], int scalarsPerPos,
109 const SkPoint& offset, const SkPaint&) 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) override;
115 void drawDevice(const SkDraw&, SkBaseDevice*, int x, int y,
116 const SkPaint&) override;
118 void onAttachToCanvas(SkCanvas* canvas) override;
119 void onDetachFromCanvas() override;
120 SkImageInfo imageInfo() const override;
123 kContent_DrawingArea, // Drawing area for the page content.
124 kMargin_DrawingArea, // Drawing area for the margin content.
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.
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
136 void setDrawingArea(DrawingArea drawingArea);
138 // PDF specific methods.
140 /** Create the resource dictionary for this device.
142 SkPDFResourceDict* createResourceDict() const;
144 /** Get the fonts used on this device.
146 const SkTDArray<SkPDFFont*>& getFontResources() const;
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.
152 void appendDestinations(SkPDFDict* dict, SkPDFObject* page) const;
154 /** Returns a copy of the media box for this device. The caller is required
155 * to unref() this when it is finished.
157 SkPDFArray* copyMediaBox() const;
159 /** Get the annotations from this page, or NULL if there are none.
161 SkPDFArray* getAnnotations() const { return fAnnotations; }
163 /** Returns a SkStream with the page contents. The caller is responsible
164 * for a deleting the returned value.
166 SkStreamAsset* content() const;
168 /** Writes the page contents to the stream. */
169 void writeContent(SkWStream*) const;
171 const SkMatrix& initialTransform() const {
172 return fInitialTransform;
175 /** Returns a SkPDFGlyphSetMap which represents glyph usage of every font
176 * that shows on this device.
178 const SkPDFGlyphSetMap& getFontGlyphUsage() const {
179 return *(fFontGlyphUsage.get());
183 SkPDFCanon* getCanon() const { return fCanon; }
187 const SkBitmap& onAccessBitmap() override {
188 return fLegacyBitmap;
191 SkSurface* newSurface(const SkImageInfo&, const SkSurfaceProps&) override;
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;
199 SkISize fContentSize;
200 SkMatrix fInitialTransform;
201 SkClipStack fExistingClipStack;
202 SkRegion fExistingClipRegion;
203 SkPDFArray* fAnnotations;
204 SkTDArray<NamedDestination*> fNamedDestinations;
206 SkTDArray<SkPDFGraphicState*> fGraphicStateResources;
207 SkTDArray<SkPDFObject*> fXObjectResources;
208 SkTDArray<SkPDFFont*> fFontResources;
209 SkTDArray<SkPDFObject*> fShaderResources;
211 SkAutoTDelete<ContentEntry> fContentEntries;
212 ContentEntry* fLastContentEntry;
213 SkAutoTDelete<ContentEntry> fMarginContentEntries;
214 ContentEntry* fLastMarginContentEntry;
215 DrawingArea fDrawingArea;
217 const SkClipStack* fClipStack;
219 // Accessor and setter functions based on the current DrawingArea.
220 SkAutoTDelete<ContentEntry>* getContentEntries();
222 // Glyph ids used for each font on this device.
223 SkAutoTDelete<SkPDFGlyphSetMap> fFontGlyphUsage;
227 SkBitmap fLegacyBitmap;
229 SkPDFCanon* fCanon; // Owned by SkDocument_PDF
230 ////////////////////////////////////////////////////////////////////////////
232 SkPDFDevice(SkISize pageSize,
237 ContentEntry* getLastContentEntry();
238 void setLastContentEntry(ContentEntry* contentEntry);
240 SkBaseDevice* onCreateDevice(const CreateInfo&, const SkPaint*) override;
243 void cleanUp(bool clearFontUsage);
244 SkPDFFormXObject* createFormXObjectFromDevice();
246 void drawFormXObjectWithMask(int xObjectIndex,
247 SkPDFFormXObject* mask,
248 const SkClipStack* clipStack,
249 const SkRegion& clipRegion,
250 SkXfermode::Mode mode,
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,
262 SkPDFFormXObject** dst);
263 void finishContentEntry(SkXfermode::Mode xfermode,
264 SkPDFFormXObject* dst,
266 bool isContentEmpty();
268 void populateGraphicStateEntryFromPaint(const SkMatrix& matrix,
269 const SkClipStack& clipStack,
270 const SkRegion& clipRegion,
271 const SkPaint& paint,
273 GraphicStateEntry* entry);
274 int addGraphicStateResource(SkPDFGraphicState* gs);
275 int addXObjectResource(SkPDFObject* xObject);
277 void updateFont(const SkPaint& paint, uint16_t glyphID,
278 ContentEntry* contentEntry);
279 int getFontResourceIndex(SkTypeface* typeface, uint16_t glyphID);
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);
289 /** Helper method for copyContentToData. It is responsible for copying the
290 * list of content entries |entry| to |data|.
292 void copyContentEntriesToData(ContentEntry* entry, SkWStream* data) const;
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);
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);
311 typedef SkBaseDevice INHERITED;
313 // TODO(edisonn): Only SkDocument_PDF and SkPDFImageShader should be able to create
315 //friend class SkDocument_PDF;
316 //friend class SkPDFImageShader;