7d207e7cf9441c6ad4151894fdde5f741d072a23
[platform/upstream/libSkiaSharp.git] / src / pdf / SkPDFDevice.h
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 "SkData.h"
15 #include "SkDevice.h"
16 #include "SkPaint.h"
17 #include "SkRect.h"
18 #include "SkRefCnt.h"
19 #include "SkSinglyLinkedList.h"
20 #include "SkStream.h"
21 #include "SkTDArray.h"
22 #include "SkTextBlob.h"
23
24 class SkImageSubset;
25 class SkPath;
26 class SkPDFArray;
27 class SkPDFCanon;
28 class SkPDFDevice;
29 class SkPDFDocument;
30 class SkPDFDict;
31 class SkPDFFont;
32 class SkPDFObject;
33 class SkPDFStream;
34 class SkRRect;
35
36 /** \class SkPDFDevice
37
38     The drawing context for the PDF backend.
39 */
40 class SkPDFDevice final : public SkBaseDevice {
41 public:
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()).
61      */
62     static SkPDFDevice* Create(SkISize pageSize,
63                                SkScalar rasterDpi,
64                                SkPDFDocument* doc) {
65         return new SkPDFDevice(pageSize, rasterDpi, doc, true);
66     }
67
68     /** Create a PDF drawing context without fipping the y-axis. */
69     static SkPDFDevice* CreateUnflipped(SkISize pageSize,
70                                         SkScalar rasterDpi,
71                                         SkPDFDocument* doc) {
72         return new SkPDFDevice(pageSize, rasterDpi, doc, false);
73     }
74
75     virtual ~SkPDFDevice();
76
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
80      DrawFilter.
81      */
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&,
99                    const SkImage*,
100                    SkScalar x,
101                    SkScalar y,
102                    const SkPaint&) override;
103     void drawImageRect(const SkDraw&,
104                        const SkImage*,
105                        const SkRect* src,
106                        const SkRect& dst,
107                        const SkPaint&,
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;
123
124     // PDF specific methods.
125
126     /** Create the resource dictionary for this device. */
127     sk_sp<SkPDFDict> makeResourceDict() const;
128
129     /** Add our annotations (link to urls and destinations) to the supplied
130      *  array.
131      *  @param array Array to add annotations to.
132      */
133     void appendAnnotations(SkPDFArray* array) const;
134
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.
138      */
139     void appendDestinations(SkPDFDict* dict, SkPDFObject* page) const;
140
141     /** Returns a copy of the media box for this device. */
142     sk_sp<SkPDFArray> copyMediaBox() const;
143
144     /** Returns a SkStream with the page contents.
145      */
146     std::unique_ptr<SkStreamAsset> content() const;
147
148     SkPDFCanon* getCanon() const;
149
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 {
153         GraphicStateEntry();
154
155         // Compare the fields we care about when setting up a new content entry.
156         bool compareInitialState(const GraphicStateEntry& b);
157
158         SkMatrix fMatrix;
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;
165
166         // When emitting the content entry, we will ensure the graphic state
167         // is set to these values first.
168         SkColor fColor;
169         SkScalar fTextScaleX;  // Zero means we don't care what the value is.
170         SkPaint::Style fTextFill;  // Only if TextScaleX is non-zero.
171         int fShaderIndex;
172         int fGraphicStateIndex;
173     };
174
175 protected:
176     sk_sp<SkSurface> makeSurface(const SkImageInfo&, const SkSurfaceProps&) override;
177
178     void drawAnnotation(const SkDraw&, const SkRect&, const char key[], SkData* value) override;
179
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;
185
186 private:
187     struct RectWithData {
188         SkRect rect;
189         sk_sp<SkData> data;
190         RectWithData(const SkRect& rect, SkData* data)
191             : rect(rect), data(SkRef(data)) {}
192         RectWithData(RectWithData&&) = default;
193         RectWithData& operator=(RectWithData&& other) = default;
194     };
195
196     struct NamedDestination {
197         sk_sp<SkData> nameData;
198         SkPoint point;
199         NamedDestination(SkData* nameData, const SkPoint& point)
200             : nameData(SkRef(nameData)), point(point) {}
201         NamedDestination(NamedDestination&&) = default;
202         NamedDestination& operator=(NamedDestination&&) = default;
203     };
204
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;
208
209     SkISize fPageSize;
210     SkMatrix fInitialTransform;
211     SkClipStack fExistingClipStack;
212     SkRegion fExistingClipRegion;
213
214     SkTArray<RectWithData> fLinkToURLs;
215     SkTArray<RectWithData> fLinkToDestinations;
216     SkTArray<NamedDestination> fNamedDestinations;
217
218     SkTDArray<SkPDFObject*> fGraphicStateResources;
219     SkTDArray<SkPDFObject*> fXObjectResources;
220     SkTDArray<SkPDFFont*> fFontResources;
221     SkTDArray<SkPDFObject*> fShaderResources;
222
223     struct ContentEntry {
224         GraphicStateEntry fState;
225         SkDynamicMemoryWStream fContent;
226     };
227     SkSinglyLinkedList<ContentEntry> fContentEntries;
228
229     SkScalar fRasterDpi;
230
231     SkPDFDocument* fDocument;
232     ////////////////////////////////////////////////////////////////////////////
233
234     SkPDFDevice(SkISize pageSize,
235                 SkScalar rasterDpi,
236                 SkPDFDocument* doc,
237                 bool flip);
238
239     SkBaseDevice* onCreateDevice(const CreateInfo&, const SkPaint*) override;
240
241     void init();
242     void cleanUp();
243     sk_sp<SkPDFObject> makeFormXObjectFromDevice();
244
245     void drawFormXObjectWithMask(int xObjectIndex,
246                                  sk_sp<SkPDFObject> mask,
247                                  const SkClipStack* clipStack,
248                                  const SkRegion& clipRegion,
249                                  SkBlendMode,
250                                  bool invertClip);
251
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,
260                                     bool hasText,
261                                     sk_sp<SkPDFObject>* dst);
262     void finishContentEntry(SkBlendMode, sk_sp<SkPDFObject> dst, SkPath* shape);
263     bool isContentEmpty();
264
265     void populateGraphicStateEntryFromPaint(const SkMatrix& matrix,
266                                             const SkClipStack& clipStack,
267                                             const SkRegion& clipRegion,
268                                             const SkPaint& paint,
269                                             bool hasText,
270                                             GraphicStateEntry* entry);
271     int addGraphicStateResource(SkPDFObject* gs);
272     int addXObjectResource(SkPDFObject* xObject);
273
274     int getFontResourceIndex(SkTypeface* typeface, uint16_t glyphID);
275
276
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*);
280
281     void internalDrawPaint(const SkPaint& paint, ContentEntry* contentEntry);
282
283     void internalDrawImage(const SkMatrix& origMatrix,
284                            const SkClipStack* clipStack,
285                            const SkRegion& origClipRegion,
286                            SkImageSubset imageSubset,
287                            const SkPaint& paint);
288
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);
294
295     typedef SkBaseDevice INHERITED;
296
297     // TODO(edisonn): Only SkDocument_PDF and SkPDFImageShader should be able to create
298     // an SkPDFDevice
299     //friend class SkDocument_PDF;
300     //friend class SkPDFImageShader;
301 };
302
303 #endif