2 * Copyright 2011 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
8 #ifndef SkPDFDevice_DEFINED
9 #define SkPDFDevice_DEFINED
13 #include "SkClipStack.h"
19 #include "SkSinglyLinkedList.h"
21 #include "SkTDArray.h"
22 #include "SkTextBlob.h"
36 /** \class SkPDFDevice
38 The drawing context for the PDF backend.
40 class SkPDFDevice final : public SkBaseDevice {
42 /** Create a PDF drawing context. SkPDFDevice applies a
43 * scale-and-translate transform to move the origin from the
44 * bottom left (PDF default) to the top left (Skia default).
45 * @param pageSize Page size in point units.
46 * 1 point == 127/360 mm == 1/72 inch
47 * @param rasterDpi the DPI at which features without native PDF
48 * support will be rasterized (e.g. draw image with
49 * perspective, draw text with perspective, ...). A
50 * larger DPI would create a PDF that reflects the
51 * original intent with better fidelity, but it can make
52 * for larger PDF files too, which would use more memory
53 * while rendering, and it would be slower to be processed
54 * or sent online or to printer. A good choice is
55 * SK_ScalarDefaultRasterDPI(72.0f).
56 * @param SkPDFDocument. A non-null pointer back to the
57 * document. The document is repsonsible for
58 * de-duplicating across pages (via the SkPDFCanon) and
59 * for early serializing of large immutable objects, such
60 * as images (via SkPDFDocument::serialize()).
62 static SkPDFDevice* Create(SkISize pageSize,
65 return new SkPDFDevice(pageSize, rasterDpi, doc, true);
68 /** Create a PDF drawing context without fipping the y-axis. */
69 static SkPDFDevice* CreateUnflipped(SkISize pageSize,
72 return new SkPDFDevice(pageSize, rasterDpi, doc, false);
75 virtual ~SkPDFDevice();
77 /** These are called inside the per-device-layer loop for each draw call.
78 When these are called, we have already applied any saveLayer operations,
79 and are handling any looping from the paint, and any effects from the
82 void drawPaint(const SkDraw&, const SkPaint& paint) override;
83 void drawPoints(const SkDraw&, SkCanvas::PointMode mode,
84 size_t count, const SkPoint[],
85 const SkPaint& paint) override;
86 void drawRect(const SkDraw&, const SkRect& r, const SkPaint& paint) override;
87 void drawOval(const SkDraw&, const SkRect& oval, const SkPaint& paint) override;
88 void drawRRect(const SkDraw&, const SkRRect& rr, const SkPaint& paint) override;
89 void drawPath(const SkDraw&, const SkPath& origpath,
90 const SkPaint& paint, const SkMatrix* prePathMatrix,
91 bool pathIsMutable) override;
92 void drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap, const SkRect* src,
93 const SkRect& dst, const SkPaint&, SkCanvas::SrcRectConstraint) override;
94 void drawBitmap(const SkDraw&, const SkBitmap& bitmap,
95 const SkMatrix& matrix, const SkPaint&) override;
96 void drawSprite(const SkDraw&, const SkBitmap& bitmap, int x, int y,
97 const SkPaint& paint) override;
98 void drawImage(const SkDraw&,
102 const SkPaint&) override;
103 void drawImageRect(const SkDraw&,
108 SkCanvas::SrcRectConstraint) override;
109 void drawText(const SkDraw&, const void* text, size_t len,
110 SkScalar x, SkScalar y, const SkPaint&) override;
111 void drawPosText(const SkDraw&, const void* text, size_t len,
112 const SkScalar pos[], int scalarsPerPos,
113 const SkPoint& offset, const SkPaint&) override;
114 void drawTextBlob(const SkDraw&, const SkTextBlob*, SkScalar x, SkScalar y,
115 const SkPaint &, SkDrawFilter*) override;
116 void drawVertices(const SkDraw&, SkCanvas::VertexMode,
117 int vertexCount, const SkPoint verts[],
118 const SkPoint texs[], const SkColor colors[],
119 SkXfermode* xmode, const uint16_t indices[],
120 int indexCount, const SkPaint& paint) override;
121 void drawDevice(const SkDraw&, SkBaseDevice*, int x, int y,
122 const SkPaint&) override;
124 // PDF specific methods.
126 /** Create the resource dictionary for this device. */
127 sk_sp<SkPDFDict> makeResourceDict() const;
129 /** Add our annotations (link to urls and destinations) to the supplied
131 * @param array Array to add annotations to.
133 void appendAnnotations(SkPDFArray* array) const;
135 /** Add our named destinations to the supplied dictionary.
136 * @param dict Dictionary to add destinations to.
137 * @param page The PDF object representing the page for this device.
139 void appendDestinations(SkPDFDict* dict, SkPDFObject* page) const;
141 /** Returns a copy of the media box for this device. */
142 sk_sp<SkPDFArray> copyMediaBox() const;
144 /** Returns a SkStream with the page contents.
146 std::unique_ptr<SkStreamAsset> content() const;
148 SkPDFCanon* getCanon() const;
150 // It is important to not confuse GraphicStateEntry with SkPDFGraphicState, the
151 // later being our representation of an object in the PDF file.
152 struct GraphicStateEntry {
155 // Compare the fields we care about when setting up a new content entry.
156 bool compareInitialState(const GraphicStateEntry& b);
159 // We can't do set operations on Paths, though PDF natively supports
160 // intersect. If the clip stack does anything other than intersect,
161 // we have to fall back to the region. Treat fClipStack as authoritative.
162 // See https://bugs.skia.org/221
163 SkClipStack fClipStack;
164 SkRegion fClipRegion;
166 // When emitting the content entry, we will ensure the graphic state
167 // is set to these values first.
169 SkScalar fTextScaleX; // Zero means we don't care what the value is.
170 SkPaint::Style fTextFill; // Only if TextScaleX is non-zero.
172 int fGraphicStateIndex;
176 sk_sp<SkSurface> makeSurface(const SkImageInfo&, const SkSurfaceProps&) override;
178 void drawAnnotation(const SkDraw&, const SkRect&, const char key[], SkData* value) override;
180 void drawSpecial(const SkDraw&, SkSpecialImage*, int x, int y, const SkPaint&) override;
181 sk_sp<SkSpecialImage> makeSpecial(const SkBitmap&) override;
182 sk_sp<SkSpecialImage> makeSpecial(const SkImage*) override;
183 sk_sp<SkSpecialImage> snapSpecial() override;
184 SkImageFilterCache* getImageFilterCache() override;
187 struct RectWithData {
190 RectWithData(const SkRect& rect, SkData* data)
191 : rect(rect), data(SkRef(data)) {}
192 RectWithData(RectWithData&&) = default;
193 RectWithData& operator=(RectWithData&& other) = default;
196 struct NamedDestination {
197 sk_sp<SkData> nameData;
199 NamedDestination(SkData* nameData, const SkPoint& point)
200 : nameData(SkRef(nameData)), point(point) {}
201 NamedDestination(NamedDestination&&) = default;
202 NamedDestination& operator=(NamedDestination&&) = default;
205 // TODO(vandebo): push most of SkPDFDevice's state into a core object in
206 // order to get the right access levels without using friend.
207 friend class ScopedContentEntry;
210 SkMatrix fInitialTransform;
211 SkClipStack fExistingClipStack;
212 SkRegion fExistingClipRegion;
214 SkTArray<RectWithData> fLinkToURLs;
215 SkTArray<RectWithData> fLinkToDestinations;
216 SkTArray<NamedDestination> fNamedDestinations;
218 SkTDArray<SkPDFObject*> fGraphicStateResources;
219 SkTDArray<SkPDFObject*> fXObjectResources;
220 SkTDArray<SkPDFFont*> fFontResources;
221 SkTDArray<SkPDFObject*> fShaderResources;
223 struct ContentEntry {
224 GraphicStateEntry fState;
225 SkDynamicMemoryWStream fContent;
227 SkSinglyLinkedList<ContentEntry> fContentEntries;
231 SkPDFDocument* fDocument;
232 ////////////////////////////////////////////////////////////////////////////
234 SkPDFDevice(SkISize pageSize,
239 SkBaseDevice* onCreateDevice(const CreateInfo&, const SkPaint*) override;
243 sk_sp<SkPDFObject> makeFormXObjectFromDevice();
245 void drawFormXObjectWithMask(int xObjectIndex,
246 sk_sp<SkPDFObject> mask,
247 const SkClipStack* clipStack,
248 const SkRegion& clipRegion,
252 // If the paint or clip is such that we shouldn't draw anything, this
253 // returns nullptr 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,
261 sk_sp<SkPDFObject>* dst);
262 void finishContentEntry(SkBlendMode, sk_sp<SkPDFObject> dst, SkPath* shape);
263 bool isContentEmpty();
265 void populateGraphicStateEntryFromPaint(const SkMatrix& matrix,
266 const SkClipStack& clipStack,
267 const SkRegion& clipRegion,
268 const SkPaint& paint,
270 GraphicStateEntry* entry);
271 int addGraphicStateResource(SkPDFObject* gs);
272 int addXObjectResource(SkPDFObject* xObject);
274 int getFontResourceIndex(SkTypeface* typeface, uint16_t glyphID);
277 void internalDrawText(const SkDraw&, const void*, size_t, const SkScalar pos[],
278 SkTextBlob::GlyphPositioning, SkPoint, const SkPaint&,
279 const uint32_t*, uint32_t, const char*);
281 void internalDrawPaint(const SkPaint& paint, ContentEntry* contentEntry);
283 void internalDrawImage(const SkMatrix& origMatrix,
284 const SkClipStack* clipStack,
285 const SkRegion& origClipRegion,
286 SkImageSubset imageSubset,
287 const SkPaint& paint);
289 bool handleInversePath(const SkDraw& d, const SkPath& origPath,
290 const SkPaint& paint, bool pathIsMutable,
291 const SkMatrix* prePathMatrix = nullptr);
292 void handlePointAnnotation(const SkPoint&, const SkMatrix&, const char key[], SkData* value);
293 void handlePathAnnotation(const SkPath&, const SkDraw& d, const char key[], SkData* value);
295 typedef SkBaseDevice INHERITED;
297 // TODO(edisonn): Only SkDocument_PDF and SkPDFImageShader should be able to create
299 //friend class SkDocument_PDF;
300 //friend class SkPDFImageShader;