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
28class SkGlyphRunList;
29class SkKeyedImage;
30class SkPDFArray;
31class SkPDFDevice;
32class SkPDFDict;
33class SkPDFDocument;
34class SkPDFFont;
35class SkPDFObject;
36class SkPath;
37class SkRRect;
38struct SkPDFIndirectReference;
39
40/**
41 * \class SkPDFDevice
42 *
43 * An SkPDFDevice is the drawing context for a page or layer of PDF
44 * content.
45 */
46class SkPDFDevice final : public SkClipStackDevice {
47public:
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
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 SkPaint&,
85 SkCanvas::SrcRectConstraint) override;
86 void drawGlyphRunList(const SkGlyphRunList& glyphRunList) override;
87 void drawVertices(const SkVertices*, SkBlendMode, const SkPaint&) override;
88 void drawDevice(SkBaseDevice*, int x, int y,
89 const SkPaint&) override;
90
91 // PDF specific methods.
92 void drawSprite(const SkBitmap& bitmap, int x, int y,
93 const SkPaint& paint);
94
95 /** Create the resource dictionary for this device. Destructive. */
96 std::unique_ptr<SkPDFDict> makeResourceDict();
97
98 /** Returns a SkStream with the page contents.
99 */
100 std::unique_ptr<SkStreamAsset> content();
101
102 SkISize size() const { return this->imageInfo().dimensions(); }
103 SkIRect bounds() const { return this->imageInfo().bounds(); }
104
105 void DrawGlyphRunAsPath(SkPDFDevice* dev, const SkGlyphRun& glyphRun, SkPoint offset);
106
107 const SkMatrix& initialTransform() const { return fInitialTransform; }
108
109protected:
110 sk_sp<SkSurface> makeSurface(const SkImageInfo&, const SkSurfaceProps&) override;
111
112 void drawAnnotation(const SkRect&, const char key[], SkData* value) override;
113
114 void drawSpecial(SkSpecialImage*, int x, int y, const SkPaint&,
115 SkImage*, const SkMatrix&) override;
116 sk_sp<SkSpecialImage> makeSpecial(const SkBitmap&) override;
117 sk_sp<SkSpecialImage> makeSpecial(const SkImage*) override;
118 SkImageFilterCache* getImageFilterCache() override;
119
120private:
121 // TODO(vandebo): push most of SkPDFDevice's state into a core object in
122 // order to get the right access levels without using friend.
123 friend class ScopedContentEntry;
124
125 SkMatrix fInitialTransform;
126
127 SkTHashSet<SkPDFIndirectReference> fGraphicStateResources;
128 SkTHashSet<SkPDFIndirectReference> fXObjectResources;
129 SkTHashSet<SkPDFIndirectReference> fShaderResources;
130 SkTHashSet<SkPDFIndirectReference> fFontResources;
131 int fNodeId;
132
133 SkDynamicMemoryWStream fContent;
134 SkDynamicMemoryWStream fContentBuffer;
135 bool fNeedsExtraSave = false;
136 SkPDFGraphicStackState fActiveStackState;
137 SkPDFDocument* fDocument;
138
139 ////////////////////////////////////////////////////////////////////////////
140
141 SkBaseDevice* onCreateDevice(const CreateInfo&, const SkPaint*) override;
142
143 // Set alpha to true if making a transparency group form x-objects.
144 SkPDFIndirectReference makeFormXObjectFromDevice(bool alpha = false);
145 SkPDFIndirectReference makeFormXObjectFromDevice(SkIRect bbox, bool alpha = false);
146
147 void drawFormXObjectWithMask(SkPDFIndirectReference xObject,
148 SkPDFIndirectReference sMask,
149 SkBlendMode,
150 bool invertClip);
151
152 // If the paint or clip is such that we shouldn't draw anything, this
153 // returns nullptr and does not create a content entry.
154 // setUpContentEntry and finishContentEntry can be used directly, but
155 // the preferred method is to use the ScopedContentEntry helper class.
156 SkDynamicMemoryWStream* setUpContentEntry(const SkClipStack* clipStack,
157 const SkMatrix& matrix,
158 const SkPaint& paint,
159 SkScalar,
160 SkPDFIndirectReference* dst);
161 void finishContentEntry(const SkClipStack*, SkBlendMode, SkPDFIndirectReference, SkPath*);
162 bool isContentEmpty();
163
164 void internalDrawGlyphRun(const SkGlyphRun& glyphRun, SkPoint offset, const SkPaint& runPaint);
165 void drawGlyphRunAsPath(const SkGlyphRun& glyphRun, SkPoint offset, const SkPaint& runPaint);
166
167 void internalDrawImageRect(SkKeyedImage,
168 const SkRect* src,
169 const SkRect& dst,
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
190 bool hasEmptyClip() const { return this->cs().isEmpty(this->bounds()); }
191
192 void reset();
193
194 typedef SkClipStackDevice INHERITED;
195};
196
197#endif
198