• 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 "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 
81     void drawImageRect(const SkImage*,
82                        const SkRect* src,
83                        const SkRect& dst,
84                        const SkSamplingOptions&,
85                        const SkPaint&,
86                        SkCanvas::SrcRectConstraint) override;
87     void onDrawGlyphRunList(const SkGlyphRunList& glyphRunList, const SkPaint& paint) override;
88     void drawVertices(const SkVertices*, SkBlendMode, const SkPaint&) override;
89 
90     // PDF specific methods.
91     void drawSprite(const SkBitmap& bitmap, int x, int y,
92                     const SkPaint& paint);
93 
94     /** Create the resource dictionary for this device. Destructive. */
95     std::unique_ptr<SkPDFDict> makeResourceDict();
96 
97     /** Returns a SkStream with the page contents.
98      */
99     std::unique_ptr<SkStreamAsset> content();
100 
size()101     SkISize size() const { return this->imageInfo().dimensions(); }
bounds()102     SkIRect bounds() const { return this->imageInfo().bounds(); }
103 
initialTransform()104     const SkMatrix& initialTransform() const { return fInitialTransform; }
105 
106 protected:
107     sk_sp<SkSurface> makeSurface(const SkImageInfo&, const SkSurfaceProps&) override;
108 
109     void drawAnnotation(const SkRect&, const char key[], SkData* value) override;
110 
111     void drawDevice(SkBaseDevice*, const SkSamplingOptions&, const SkPaint&) override;
112     void drawSpecial(SkSpecialImage*, const SkMatrix&, const SkSamplingOptions&,
113                      const SkPaint&) override;
114 
115     sk_sp<SkSpecialImage> makeSpecial(const SkBitmap&) override;
116     sk_sp<SkSpecialImage> makeSpecial(const SkImage*) override;
117     SkImageFilterCache* getImageFilterCache() override;
118 
119 private:
120     // TODO(vandebo): push most of SkPDFDevice's state into a core object in
121     // order to get the right access levels without using friend.
122     friend class ScopedContentEntry;
123 
124     SkMatrix fInitialTransform;
125 
126     SkTHashSet<SkPDFIndirectReference> fGraphicStateResources;
127     SkTHashSet<SkPDFIndirectReference> fXObjectResources;
128     SkTHashSet<SkPDFIndirectReference> fShaderResources;
129     SkTHashSet<SkPDFIndirectReference> fFontResources;
130     int fNodeId;
131 
132     SkDynamicMemoryWStream fContent;
133     SkDynamicMemoryWStream fContentBuffer;
134     bool fNeedsExtraSave = false;
135     SkPDFGraphicStackState fActiveStackState;
136     SkPDFDocument* fDocument;
137 
138     ////////////////////////////////////////////////////////////////////////////
139 
140     SkBaseDevice* onCreateDevice(const CreateInfo&, const SkPaint*) override;
141 
142     // Set alpha to true if making a transparency group form x-objects.
143     SkPDFIndirectReference makeFormXObjectFromDevice(bool alpha = false);
144     SkPDFIndirectReference makeFormXObjectFromDevice(SkIRect bbox, bool alpha = false);
145 
146     void drawFormXObjectWithMask(SkPDFIndirectReference xObject,
147                                  SkPDFIndirectReference sMask,
148                                  SkBlendMode,
149                                  bool invertClip);
150 
151     // If the paint or clip is such that we shouldn't draw anything, this
152     // returns nullptr and does not create a content entry.
153     // setUpContentEntry and finishContentEntry can be used directly, but
154     // the preferred method is to use the ScopedContentEntry helper class.
155     SkDynamicMemoryWStream* setUpContentEntry(const SkClipStack* clipStack,
156                                               const SkMatrix& matrix,
157                                               const SkPaint& paint,
158                                               SkScalar,
159                                               SkPDFIndirectReference* dst);
160     void finishContentEntry(const SkClipStack*, SkBlendMode, SkPDFIndirectReference, SkPath*);
161     bool isContentEmpty();
162 
163     void internalDrawGlyphRun(const SkGlyphRun& glyphRun, SkPoint offset, const SkPaint& runPaint);
164     void drawGlyphRunAsPath(const SkGlyphRun& glyphRun, SkPoint offset, const SkPaint& runPaint);
165 
166     void internalDrawImageRect(SkKeyedImage,
167                                const SkRect* src,
168                                const SkRect& dst,
169                                const SkSamplingOptions&,
170                                const SkPaint&,
171                                const SkMatrix& canvasTransformationMatrix);
172 
173     void internalDrawPath(const SkClipStack&,
174                           const SkMatrix&,
175                           const SkPath&,
176                           const SkPaint&,
177                           bool pathIsMutable);
178 
179     void internalDrawPathWithFilter(const SkClipStack& clipStack,
180                                     const SkMatrix& ctm,
181                                     const SkPath& origPath,
182                                     const SkPaint& paint);
183 
184     bool handleInversePath(const SkPath& origPath, const SkPaint& paint, bool pathIsMutable);
185 
186     void clearMaskOnGraphicState(SkDynamicMemoryWStream*);
187     void setGraphicState(SkPDFIndirectReference gs, SkDynamicMemoryWStream*);
188     void drawFormXObject(SkPDFIndirectReference xObject, SkDynamicMemoryWStream*);
189 
hasEmptyClip()190     bool hasEmptyClip() const { return this->cs().isEmpty(this->bounds()); }
191 
192     void reset();
193 
194     using INHERITED = SkClipStackDevice;
195 };
196 
197 #endif
198