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