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