• 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 "SkClipStackDevice.h"
15 #include "SkData.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 #include "SkKeyedImage.h"
24 
25 class SkKeyedImage;
26 class SkPath;
27 class SkPDFArray;
28 class SkPDFCanon;
29 class SkPDFDevice;
30 class SkPDFDocument;
31 class SkPDFDict;
32 class SkPDFFont;
33 class SkPDFObject;
34 class SkPDFStream;
35 class SkRRect;
36 
37 /**
38  *  \class SkPDFDevice
39  *
40  *  An SkPDFDevice is the drawing context for a page or layer of PDF
41  *  content.
42  */
43 class SkPDFDevice final : public SkClipStackDevice {
44 public:
45     /**
46      *  @param pageSize Page size in point units.
47      *         1 point == 127/360 mm == 1/72 inch
48      *  @param document  A non-null pointer back to the
49      *         PDFDocument object.  The document is repsonsible for
50      *         de-duplicating across pages (via the SkPDFCanon) and
51      *         for early serializing of large immutable objects, such
52      *         as images (via SkPDFDocument::serialize()).
53      */
54     SkPDFDevice(SkISize pageSize, SkPDFDocument* document);
55 
56     /**
57      *  Apply a scale-and-translate transform to move the origin from the
58      *  bottom left (PDF default) to the top left (Skia default).
59      */
60     void setFlip();
61 
makeCongruentDevice()62     sk_sp<SkPDFDevice> makeCongruentDevice() {
63         return sk_make_sp<SkPDFDevice>(fPageSize, fDocument);
64     }
65 
66     ~SkPDFDevice() override;
67 
68     /**
69      *  These are called inside the per-device-layer loop for each draw call.
70      *  When these are called, we have already applied any saveLayer
71      *  operations, and are handling any looping from the paint, and any
72      *  effects from the DrawFilter.
73      */
74     void drawPaint(const SkPaint& paint) override;
75     void drawPoints(SkCanvas::PointMode mode,
76                     size_t count, const SkPoint[],
77                     const SkPaint& paint) override;
78     void drawRect(const SkRect& r, const SkPaint& paint) override;
79     void drawOval(const SkRect& oval, const SkPaint& paint) override;
80     void drawRRect(const SkRRect& rr, const SkPaint& paint) override;
81     void drawPath(const SkPath& origpath,
82                   const SkPaint& paint, const SkMatrix* prePathMatrix,
83                   bool pathIsMutable) override;
84     void drawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
85                         const SkRect& dst, const SkPaint&, SkCanvas::SrcRectConstraint) override;
86     void drawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint&) override;
87     void drawSprite(const SkBitmap& bitmap, int x, int y,
88                     const SkPaint& paint) override;
89     void drawImage(const SkImage*,
90                    SkScalar x,
91                    SkScalar y,
92                    const SkPaint&) override;
93     void drawImageRect(const SkImage*,
94                        const SkRect* src,
95                        const SkRect& dst,
96                        const SkPaint&,
97                        SkCanvas::SrcRectConstraint) override;
98     void drawText(const void* text, size_t len,
99                   SkScalar x, SkScalar y, const SkPaint&) override;
100     void drawPosText(const void* text, size_t len,
101                      const SkScalar pos[], int scalarsPerPos,
102                      const SkPoint& offset, const SkPaint&) override;
103     void drawTextBlob(const SkTextBlob*, SkScalar x, SkScalar y,
104                       const SkPaint &, SkDrawFilter*) override;
105     void drawVertices(const SkVertices*, SkBlendMode, const SkPaint&) override;
106     void drawDevice(SkBaseDevice*, int x, int y,
107                     const SkPaint&) override;
108 
109     // PDF specific methods.
110 
111     /** Create the resource dictionary for this device. */
112     sk_sp<SkPDFDict> makeResourceDict() const;
113 
114     /** Add our annotations (link to urls and destinations) to the supplied
115      *  array.
116      *  @param array Array to add annotations to.
117      */
118     void appendAnnotations(SkPDFArray* array) const;
119 
120     /** Add our named destinations to the supplied dictionary.
121      *  @param dict  Dictionary to add destinations to.
122      *  @param page  The PDF object representing the page for this device.
123      */
124     void appendDestinations(SkPDFDict* dict, SkPDFObject* page) const;
125 
126     /** Returns a copy of the media box for this device. */
127     sk_sp<SkPDFArray> copyMediaBox() const;
128 
129     /** Returns a SkStream with the page contents.
130      */
131     std::unique_ptr<SkStreamAsset> content() const;
132 
133     SkPDFCanon* getCanon() const;
134 
135     // It is important to not confuse GraphicStateEntry with SkPDFGraphicState, the
136     // later being our representation of an object in the PDF file.
137     struct GraphicStateEntry {
138         GraphicStateEntry();
139 
140         // Compare the fields we care about when setting up a new content entry.
141         bool compareInitialState(const GraphicStateEntry& b);
142 
143         SkMatrix fMatrix;
144         // We can't do set operations on Paths, though PDF natively supports
145         // intersect.  If the clip stack does anything other than intersect,
146         // we have to fall back to the region.  Treat fClipStack as authoritative.
147         // See https://bugs.skia.org/221
148         SkClipStack fClipStack;
149 
150         // When emitting the content entry, we will ensure the graphic state
151         // is set to these values first.
152         SkColor fColor;
153         SkScalar fTextScaleX;  // Zero means we don't care what the value is.
154         SkPaint::Style fTextFill;  // Only if TextScaleX is non-zero.
155         int fShaderIndex;
156         int fGraphicStateIndex;
157     };
158 
159 protected:
160     sk_sp<SkSurface> makeSurface(const SkImageInfo&, const SkSurfaceProps&) override;
161 
162     void drawAnnotation(const SkRect&, const char key[], SkData* value) override;
163 
164     void drawSpecial(SkSpecialImage*, int x, int y, const SkPaint&,
165                      SkImage*, const SkMatrix&) override;
166     sk_sp<SkSpecialImage> makeSpecial(const SkBitmap&) override;
167     sk_sp<SkSpecialImage> makeSpecial(const SkImage*) override;
168     sk_sp<SkSpecialImage> snapSpecial() override;
169     SkImageFilterCache* getImageFilterCache() override;
170 
171 private:
172     struct RectWithData {
173         SkRect rect;
174         sk_sp<SkData> data;
175     };
176 
177     struct NamedDestination {
178         sk_sp<SkData> nameData;
179         SkPoint point;
180     };
181 
182     // TODO(vandebo): push most of SkPDFDevice's state into a core object in
183     // order to get the right access levels without using friend.
184     friend class ScopedContentEntry;
185 
186     SkISize fPageSize;
187     SkMatrix fInitialTransform;
188     SkClipStack fExistingClipStack;
189 
190     SkTArray<RectWithData> fLinkToURLs;
191     SkTArray<RectWithData> fLinkToDestinations;
192     SkTArray<NamedDestination> fNamedDestinations;
193 
194     SkTDArray<SkPDFObject*> fGraphicStateResources;
195     SkTDArray<SkPDFObject*> fXObjectResources;
196     SkTDArray<SkPDFFont*> fFontResources;
197     SkTDArray<SkPDFObject*> fShaderResources;
198 
199     struct ContentEntry {
200         GraphicStateEntry fState;
201         SkDynamicMemoryWStream fContent;
202     };
203     SkSinglyLinkedList<ContentEntry> fContentEntries;
204 
205     SkPDFDocument* fDocument;
206 
207     ////////////////////////////////////////////////////////////////////////////
208 
209     SkBaseDevice* onCreateDevice(const CreateInfo&, const SkPaint*) override;
210 
211     void init();
212     void cleanUp();
213     sk_sp<SkPDFObject> makeFormXObjectFromDevice();
214 
215     void drawFormXObjectWithMask(int xObjectIndex,
216                                  sk_sp<SkPDFObject> mask,
217                                  const SkClipStack& clipStack,
218                                  SkBlendMode,
219                                  bool invertClip);
220 
221     // If the paint or clip is such that we shouldn't draw anything, this
222     // returns nullptr and does not create a content entry.
223     // setUpContentEntry and finishContentEntry can be used directly, but
224     // the preferred method is to use the ScopedContentEntry helper class.
225     ContentEntry* setUpContentEntry(const SkClipStack& clipStack,
226                                     const SkMatrix& matrix,
227                                     const SkPaint& paint,
228                                     bool hasText,
229                                     sk_sp<SkPDFObject>* dst);
230     void finishContentEntry(SkBlendMode, sk_sp<SkPDFObject> dst, SkPath* shape);
231     bool isContentEmpty();
232 
233     void populateGraphicStateEntryFromPaint(const SkMatrix& matrix,
234                                             const SkClipStack& clipStack,
235                                             const SkPaint& paint,
236                                             bool hasText,
237                                             GraphicStateEntry* entry);
238     int addGraphicStateResource(SkPDFObject* gs);
239     int addXObjectResource(SkPDFObject* xObject);
240 
241     int getFontResourceIndex(SkTypeface* typeface, uint16_t glyphID);
242 
243 
244     void internalDrawText( const void*, size_t, const SkScalar pos[],
245                           SkTextBlob::GlyphPositioning, SkPoint, const SkPaint&,
246                           const uint32_t*, uint32_t, const char*);
247 
248     void internalDrawPaint(const SkPaint& paint, ContentEntry* contentEntry);
249 
250     void internalDrawImageRect(SkKeyedImage,
251                                const SkRect* src,
252                                const SkRect& dst,
253                                const SkPaint&,
254                                const SkMatrix& canvasTransformationMatrix);
255 
256     void internalDrawPath(const SkClipStack&,
257                           const SkMatrix&,
258                           const SkPath&,
259                           const SkPaint&,
260                           const SkMatrix* prePathMatrix,
261                           bool pathIsMutable);
262 
263     void internalDrawPathWithFilter(const SkClipStack& clipStack,
264                                     const SkMatrix& ctm,
265                                     const SkPath& origPath,
266                                     const SkPaint& paint,
267                                     const SkMatrix* prePathMatrix);
268 
269     bool handleInversePath(const SkPath& origPath,
270                            const SkPaint& paint, bool pathIsMutable,
271                            const SkMatrix* prePathMatrix = nullptr);
272 
273     void addSMaskGraphicState(sk_sp<SkPDFDevice> maskDevice, SkDynamicMemoryWStream*);
274     void clearMaskOnGraphicState(SkDynamicMemoryWStream*);
275 
276     typedef SkClipStackDevice INHERITED;
277 };
278 
279 #endif
280