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 "include/core/SkBitmap.h"
12 #include "include/core/SkCanvas.h"
13 #include "include/core/SkData.h"
14 #include "include/core/SkPaint.h"
15 #include "include/core/SkRect.h"
16 #include "include/core/SkRefCnt.h"
17 #include "include/core/SkStream.h"
18 #include "include/private/SkTHash.h"
19 #include "src/core/SkClipStack.h"
20 #include "src/core/SkClipStackDevice.h"
21 #include "src/core/SkTextBlobPriv.h"
22 #include "src/pdf/SkKeyedImage.h"
23 #include "src/pdf/SkPDFGraphicStackState.h"
24 #include "src/pdf/SkPDFTypes.h"
25 
26 #include <vector>
27 
28 class SkGlyphRunList;
29 class SkKeyedImage;
30 class SkPDFArray;
31 class SkPDFDevice;
32 class SkPDFDict;
33 class SkPDFDocument;
34 class SkPDFFont;
35 class SkPDFObject;
36 class SkPath;
37 class SkRRect;
38 struct SkPDFIndirectReference;
39 
40 /**
41  *  \class SkPDFDevice
42  *
43  *  An SkPDFDevice is the drawing context for a page or layer of PDF
44  *  content.
45  */
46 class SkPDFDevice final : public SkClipStackDevice {
47 public:
48     /**
49      *  @param pageSize Page size in point units.
50      *         1 point == 127/360 mm == 1/72 inch
51      *  @param document  A non-null pointer back to the
52      *         PDFDocument object.  The document is responsible for
53      *         de-duplicating across pages (via the SkPDFDocument) and
54      *         for early serializing of large immutable objects, such
55      *         as images (via SkPDFDocument::serialize()).
56      *  @param initialTransform Transform to be applied to the entire page.
57      */
58     SkPDFDevice(SkISize pageSize, SkPDFDocument* document,
59                 const SkMatrix& initialTransform = SkMatrix::I());
60 
makeCongruentDevice()61     sk_sp<SkPDFDevice> makeCongruentDevice() {
62         return sk_make_sp<SkPDFDevice>(this->size(), fDocument);
63     }
64 
65     ~SkPDFDevice() override;
66 
67     /**
68      *  These are called inside the per-device-layer loop for each draw call.
69      *  When these are called, we have already applied any saveLayer
70      *  operations, and are handling any looping from the paint.
71      */
72     void drawPaint(const SkPaint& paint) override;
73     void drawPoints(SkCanvas::PointMode mode,
74                     size_t count, const SkPoint[],
75                     const SkPaint& paint) override;
76     void drawRect(const SkRect& r, const SkPaint& paint) override;
77     void drawOval(const SkRect& oval, const SkPaint& paint) override;
78     void drawRRect(const SkRRect& rr, const SkPaint& paint) override;
79     void drawPath(const SkPath& origpath, const SkPaint& paint, bool pathIsMutable) override;
80     void drawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
81                         const SkRect& dst, const SkPaint&, SkCanvas::SrcRectConstraint) override;
82     void drawSprite(const SkBitmap& bitmap, int x, int y,
83                     const SkPaint& paint) override;
84 
85     void drawImageRect(const SkImage*,
86                        const SkRect* src,
87                        const SkRect& dst,
88                        const SkPaint&,
89                        SkCanvas::SrcRectConstraint) override;
90     void drawGlyphRunList(const SkGlyphRunList& glyphRunList) override;
91     void drawVertices(const SkVertices*, const SkVertices::Bone bones[], int boneCount, SkBlendMode,
92                       const SkPaint&) override;
93     void drawDevice(SkBaseDevice*, int x, int y,
94                     const SkPaint&) override;
95 
96     // PDF specific methods.
97 
98     /** Create the resource dictionary for this device. Destructive. */
99     std::unique_ptr<SkPDFDict> makeResourceDict();
100 
101     /** Returns a SkStream with the page contents.
102      */
103     std::unique_ptr<SkStreamAsset> content();
104 
size()105     SkISize size() const { return this->imageInfo().dimensions(); }
bounds()106     SkIRect bounds() const { return this->imageInfo().bounds(); }
107 
108     void DrawGlyphRunAsPath(SkPDFDevice* dev, const SkGlyphRun& glyphRun, SkPoint offset);
109 
initialTransform()110     const SkMatrix& initialTransform() const { return fInitialTransform; }
111 
112 protected:
113     sk_sp<SkSurface> makeSurface(const SkImageInfo&, const SkSurfaceProps&) override;
114 
115     void drawAnnotation(const SkRect&, const char key[], SkData* value) override;
116 
117     void drawSpecial(SkSpecialImage*, int x, int y, const SkPaint&,
118                      SkImage*, const SkMatrix&) override;
119     sk_sp<SkSpecialImage> makeSpecial(const SkBitmap&) override;
120     sk_sp<SkSpecialImage> makeSpecial(const SkImage*) override;
121     SkImageFilterCache* getImageFilterCache() override;
122 
123 private:
124     // TODO(vandebo): push most of SkPDFDevice's state into a core object in
125     // order to get the right access levels without using friend.
126     friend class ScopedContentEntry;
127 
128     SkMatrix fInitialTransform;
129 
130     SkTHashSet<SkPDFIndirectReference> fGraphicStateResources;
131     SkTHashSet<SkPDFIndirectReference> fXObjectResources;
132     SkTHashSet<SkPDFIndirectReference> fShaderResources;
133     SkTHashSet<SkPDFIndirectReference> fFontResources;
134     int fNodeId;
135 
136     SkDynamicMemoryWStream fContent;
137     SkDynamicMemoryWStream fContentBuffer;
138     bool fNeedsExtraSave = false;
139     SkPDFGraphicStackState fActiveStackState;
140     SkPDFDocument* fDocument;
141 
142     ////////////////////////////////////////////////////////////////////////////
143 
144     SkBaseDevice* onCreateDevice(const CreateInfo&, const SkPaint*) override;
145 
146     // Set alpha to true if making a transparency group form x-objects.
147     SkPDFIndirectReference makeFormXObjectFromDevice(bool alpha = false);
148     SkPDFIndirectReference makeFormXObjectFromDevice(SkIRect bbox, bool alpha = false);
149 
150     void drawFormXObjectWithMask(SkPDFIndirectReference xObject,
151                                  SkPDFIndirectReference sMask,
152                                  SkBlendMode,
153                                  bool invertClip);
154 
155     // If the paint or clip is such that we shouldn't draw anything, this
156     // returns nullptr and does not create a content entry.
157     // setUpContentEntry and finishContentEntry can be used directly, but
158     // the preferred method is to use the ScopedContentEntry helper class.
159     SkDynamicMemoryWStream* setUpContentEntry(const SkClipStack* clipStack,
160                                               const SkMatrix& matrix,
161                                               const SkPaint& paint,
162                                               SkScalar,
163                                               SkPDFIndirectReference* dst);
164     void finishContentEntry(const SkClipStack*, SkBlendMode, SkPDFIndirectReference, SkPath*);
165     bool isContentEmpty();
166 
167     void internalDrawGlyphRun(const SkGlyphRun& glyphRun, SkPoint offset, const SkPaint& runPaint);
168     void drawGlyphRunAsPath(const SkGlyphRun& glyphRun, SkPoint offset, const SkPaint& runPaint);
169 
170     void internalDrawImageRect(SkKeyedImage,
171                                const SkRect* src,
172                                const SkRect& dst,
173                                const SkPaint&,
174                                const SkMatrix& canvasTransformationMatrix);
175 
176     void internalDrawPath(const SkClipStack&,
177                           const SkMatrix&,
178                           const SkPath&,
179                           const SkPaint&,
180                           bool pathIsMutable);
181 
182     void internalDrawPathWithFilter(const SkClipStack& clipStack,
183                                     const SkMatrix& ctm,
184                                     const SkPath& origPath,
185                                     const SkPaint& paint);
186 
187     bool handleInversePath(const SkPath& origPath, const SkPaint& paint, bool pathIsMutable);
188 
189     void clearMaskOnGraphicState(SkDynamicMemoryWStream*);
190     void setGraphicState(SkPDFIndirectReference gs, SkDynamicMemoryWStream*);
191     void drawFormXObject(SkPDFIndirectReference xObject, SkDynamicMemoryWStream*);
192 
hasEmptyClip()193     bool hasEmptyClip() const { return this->cs().isEmpty(this->bounds()); }
194 
195     void reset();
196 
197     typedef SkClipStackDevice INHERITED;
198 };
199 
200 #endif
201