blob: 7bd1a0ee11ef11172c068402a6739605119d208b [file] [log] [blame]
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * Copyright 2011 Google Inc.
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +00003 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00004 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +00006 */
7
8#ifndef SkPDFDevice_DEFINED
9#define SkPDFDevice_DEFINED
10
commit-bot@chromium.org5e009892013-10-14 13:42:12 +000011#include "SkBitmap.h"
vandebo@chromium.orgb069c8c2011-05-24 17:19:38 +000012#include "SkCanvas.h"
bungemand3ebb482015-08-05 13:57:49 -070013#include "SkClipStack.h"
Mike Reedf0fb9292017-02-21 13:15:07 -050014#include "SkClipStackDevice.h"
halcanary91fcb3e2016-03-04 13:53:22 -080015#include "SkData.h"
vandebo@chromium.orga5180862010-10-26 19:48:49 +000016#include "SkPaint.h"
vandebo@chromium.org238be8c2012-07-13 20:06:02 +000017#include "SkRect.h"
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +000018#include "SkRefCnt.h"
halcanary4ed2f012016-08-15 18:40:07 -070019#include "SkSinglyLinkedList.h"
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +000020#include "SkStream.h"
epoger@google.comb58772f2013-03-08 09:09:10 +000021#include "SkTDArray.h"
Florin Malitaab54e732018-07-27 09:47:15 -040022#include "SkTextBlobPriv.h"
Hal Canary7cbf5e32017-07-12 13:10:23 -040023#include "SkKeyedImage.h"
halcanary2be7e012016-03-28 11:58:08 -070024
Herb Derby736db102018-07-19 12:52:16 -040025class SkGlyphRunList;
Hal Canary7cbf5e32017-07-12 13:10:23 -040026class SkKeyedImage;
martina.kollarovab8d6af12016-06-29 05:12:31 -070027class SkPath;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000028class SkPDFArray;
halcanarya1f1ee92015-02-20 06:17:26 -080029class SkPDFCanon;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000030class SkPDFDevice;
halcanary989da4a2016-03-21 14:33:17 -070031class SkPDFDocument;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000032class SkPDFDict;
vandebo@chromium.org28be72b2010-11-11 21:37:00 +000033class SkPDFFont;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000034class SkPDFObject;
halcanary4b1e17e2016-07-27 14:49:46 -070035class SkPDFStream;
scroggo@google.coma8e33a92013-11-08 18:02:53 +000036class SkRRect;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000037
Hal Canarya0622582017-06-29 18:51:35 -040038/**
39 * \class SkPDFDevice
40 *
41 * An SkPDFDevice is the drawing context for a page or layer of PDF
42 * content.
43 */
Mike Reedf0fb9292017-02-21 13:15:07 -050044class SkPDFDevice final : public SkClipStackDevice {
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000045public:
Hal Canarya0622582017-06-29 18:51:35 -040046 /**
halcanarya1f1ee92015-02-20 06:17:26 -080047 * @param pageSize Page size in point units.
48 * 1 point == 127/360 mm == 1/72 inch
Hal Canarya0622582017-06-29 18:51:35 -040049 * @param document A non-null pointer back to the
50 * PDFDocument object. The document is repsonsible for
halcanary989da4a2016-03-21 14:33:17 -070051 * de-duplicating across pages (via the SkPDFCanon) and
52 * for early serializing of large immutable objects, such
53 * as images (via SkPDFDocument::serialize()).
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000054 */
Hal Canarya0622582017-06-29 18:51:35 -040055 SkPDFDevice(SkISize pageSize, SkPDFDocument* document);
halcanarya1f1ee92015-02-20 06:17:26 -080056
Hal Canarya0622582017-06-29 18:51:35 -040057 /**
58 * Apply a scale-and-translate transform to move the origin from the
59 * bottom left (PDF default) to the top left (Skia default).
60 */
61 void setFlip();
Hal Canary51329c92017-06-27 14:28:37 -040062
63 sk_sp<SkPDFDevice> makeCongruentDevice() {
Hal Canarya0622582017-06-29 18:51:35 -040064 return sk_make_sp<SkPDFDevice>(fPageSize, fDocument);
halcanarya1f1ee92015-02-20 06:17:26 -080065 }
66
Brian Salomond3b65972017-03-22 12:05:03 -040067 ~SkPDFDevice() override;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000068
Hal Canarya0622582017-06-29 18:51:35 -040069 /**
70 * These are called inside the per-device-layer loop for each draw call.
71 * When these are called, we have already applied any saveLayer
Ben Wagner2c312c42018-06-27 14:46:46 -040072 * operations, and are handling any looping from the paint.
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000073 */
Mike Reeda1361362017-03-07 09:37:29 -050074 void drawPaint(const SkPaint& paint) override;
75 void drawPoints(SkCanvas::PointMode mode,
tfarinafa4f6cb2014-12-21 10:27:07 -080076 size_t count, const SkPoint[],
mtklein36352bf2015-03-25 18:17:31 -070077 const SkPaint& paint) override;
Mike Reeda1361362017-03-07 09:37:29 -050078 void drawRect(const SkRect& r, const SkPaint& paint) override;
79 void drawOval(const SkRect& oval, const SkPaint& paint) override;
80 void drawRRect(const SkRRect& rr, const SkPaint& paint) override;
81 void drawPath(const SkPath& origpath,
tfarinafa4f6cb2014-12-21 10:27:07 -080082 const SkPaint& paint, const SkMatrix* prePathMatrix,
mtklein36352bf2015-03-25 18:17:31 -070083 bool pathIsMutable) override;
Mike Reeda1361362017-03-07 09:37:29 -050084 void drawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
reed562fe472015-07-28 07:35:14 -070085 const SkRect& dst, const SkPaint&, SkCanvas::SrcRectConstraint) override;
Hal Canaryb9642382017-06-27 09:58:56 -040086 void drawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint&) override;
Mike Reeda1361362017-03-07 09:37:29 -050087 void drawSprite(const SkBitmap& bitmap, int x, int y,
mtklein36352bf2015-03-25 18:17:31 -070088 const SkPaint& paint) override;
Mike Reeda1361362017-03-07 09:37:29 -050089 void drawImage(const SkImage*,
halcanary7a14b312015-10-01 07:28:13 -070090 SkScalar x,
91 SkScalar y,
92 const SkPaint&) override;
Mike Reeda1361362017-03-07 09:37:29 -050093 void drawImageRect(const SkImage*,
halcanary7a14b312015-10-01 07:28:13 -070094 const SkRect* src,
95 const SkRect& dst,
96 const SkPaint&,
97 SkCanvas::SrcRectConstraint) override;
Mike Reeda1361362017-03-07 09:37:29 -050098 void drawPosText(const void* text, size_t len,
tfarinafa4f6cb2014-12-21 10:27:07 -080099 const SkScalar pos[], int scalarsPerPos,
Hal Canary98caedd2018-07-23 10:50:49 -0400100 const SkPoint& offset, const SkPaint&) override { SkASSERT(false); }
Herb Derbyb935cf82018-07-26 16:54:18 -0400101 void drawGlyphRunList(const SkGlyphRunList& glyphRunList) override;
Ruiqi Maof5101492018-06-29 14:32:21 -0400102 void drawVertices(const SkVertices*, const SkMatrix* bones, int boneCount, SkBlendMode,
103 const SkPaint&) override;
Mike Reeda1361362017-03-07 09:37:29 -0500104 void drawDevice(SkBaseDevice*, int x, int y,
mtklein36352bf2015-03-25 18:17:31 -0700105 const SkPaint&) override;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000106
107 // PDF specific methods.
108
halcanary8103a342016-03-08 15:10:16 -0800109 /** Create the resource dictionary for this device. */
110 sk_sp<SkPDFDict> makeResourceDict() const;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000111
wangxianzhuef6c50a2015-09-17 20:38:02 -0700112 /** Add our annotations (link to urls and destinations) to the supplied
113 * array.
114 * @param array Array to add annotations to.
115 */
116 void appendAnnotations(SkPDFArray* array) const;
117
epoger@google.comb58772f2013-03-08 09:09:10 +0000118 /** Add our named destinations to the supplied dictionary.
119 * @param dict Dictionary to add destinations to.
120 * @param page The PDF object representing the page for this device.
121 */
halcanary6d622702015-03-25 08:45:42 -0700122 void appendDestinations(SkPDFDict* dict, SkPDFObject* page) const;
epoger@google.comb58772f2013-03-08 09:09:10 +0000123
halcanary8103a342016-03-08 15:10:16 -0800124 /** Returns a copy of the media box for this device. */
125 sk_sp<SkPDFArray> copyMediaBox() const;
halcanary51d04d32016-03-08 13:03:55 -0800126
halcanary8103a342016-03-08 15:10:16 -0800127 /** Returns a SkStream with the page contents.
halcanary51d04d32016-03-08 13:03:55 -0800128 */
mtklein5f939ab2016-03-16 10:28:35 -0700129 std::unique_ptr<SkStreamAsset> content() const;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000130
halcanary989da4a2016-03-21 14:33:17 -0700131 SkPDFCanon* getCanon() const;
halcanary26b5d152015-03-25 08:38:03 -0700132
Hal Canary22b2d8c2017-07-19 14:46:12 -0400133 SkIRect bounds() const { return this->imageInfo().bounds(); }
134
halcanary2be7e012016-03-28 11:58:08 -0700135 // It is important to not confuse GraphicStateEntry with SkPDFGraphicState, the
136 // later being our representation of an object in the PDF file.
137 struct GraphicStateEntry {
138 GraphicStateEntry();
139
140 // Compare the fields we care about when setting up a new content entry.
141 bool compareInitialState(const GraphicStateEntry& b);
142
143 SkMatrix fMatrix;
144 // We can't do set operations on Paths, though PDF natively supports
145 // intersect. If the clip stack does anything other than intersect,
146 // we have to fall back to the region. Treat fClipStack as authoritative.
147 // See https://bugs.skia.org/221
148 SkClipStack fClipStack;
halcanary2be7e012016-03-28 11:58:08 -0700149
150 // When emitting the content entry, we will ensure the graphic state
151 // is set to these values first.
152 SkColor fColor;
153 SkScalar fTextScaleX; // Zero means we don't care what the value is.
154 SkPaint::Style fTextFill; // Only if TextScaleX is non-zero.
155 int fShaderIndex;
156 int fGraphicStateIndex;
halcanary2be7e012016-03-28 11:58:08 -0700157 };
158
edisonn@google.com73a7ea32013-11-11 20:55:15 +0000159protected:
reede8f30622016-03-23 18:59:25 -0700160 sk_sp<SkSurface> makeSurface(const SkImageInfo&, const SkSurfaceProps&) override;
edisonn@google.com73a7ea32013-11-11 20:55:15 +0000161
Mike Reeda1361362017-03-07 09:37:29 -0500162 void drawAnnotation(const SkRect&, const char key[], SkData* value) override;
reedf70b5312016-03-04 16:36:20 -0800163
Florin Malita53f77bd2017-04-28 13:48:37 -0400164 void drawSpecial(SkSpecialImage*, int x, int y, const SkPaint&,
165 SkImage*, const SkMatrix&) override;
reede51c3562016-07-19 14:33:20 -0700166 sk_sp<SkSpecialImage> makeSpecial(const SkBitmap&) override;
167 sk_sp<SkSpecialImage> makeSpecial(const SkImage*) override;
168 sk_sp<SkSpecialImage> snapSpecial() override;
brianosman04a44d02016-09-21 09:46:57 -0700169 SkImageFilterCache* getImageFilterCache() override;
reede51c3562016-07-19 14:33:20 -0700170
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000171private:
halcanary91fcb3e2016-03-04 13:53:22 -0800172 struct RectWithData {
173 SkRect rect;
halcanaryd7b28852016-03-07 12:39:14 -0800174 sk_sp<SkData> data;
halcanary91fcb3e2016-03-04 13:53:22 -0800175 };
176
177 struct NamedDestination {
halcanaryd7b28852016-03-07 12:39:14 -0800178 sk_sp<SkData> nameData;
halcanary91fcb3e2016-03-04 13:53:22 -0800179 SkPoint point;
halcanary91fcb3e2016-03-04 13:53:22 -0800180 };
181
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000182 // TODO(vandebo): push most of SkPDFDevice's state into a core object in
vandebo@chromium.orgb069c8c2011-05-24 17:19:38 +0000183 // order to get the right access levels without using friend.
vandebo@chromium.org13d14a92011-05-24 23:12:41 +0000184 friend class ScopedContentEntry;
vandebo@chromium.orga0c7edb2011-05-09 07:58:08 +0000185
ctguil@chromium.org15261292011-04-29 17:54:16 +0000186 SkISize fPageSize;
vandebo@chromium.org75f97e42011-04-11 23:24:18 +0000187 SkMatrix fInitialTransform;
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +0000188 SkClipStack fExistingClipStack;
wangxianzhuef6c50a2015-09-17 20:38:02 -0700189
halcanary91fcb3e2016-03-04 13:53:22 -0800190 SkTArray<RectWithData> fLinkToURLs;
191 SkTArray<RectWithData> fLinkToDestinations;
192 SkTArray<NamedDestination> fNamedDestinations;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000193
halcanarybe27a112015-04-01 13:31:19 -0700194 SkTDArray<SkPDFObject*> fGraphicStateResources;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000195 SkTDArray<SkPDFObject*> fXObjectResources;
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000196 SkTDArray<SkPDFFont*> fFontResources;
vandebo@chromium.org421d6442011-07-20 17:39:01 +0000197 SkTDArray<SkPDFObject*> fShaderResources;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000198
halcanary2be7e012016-03-28 11:58:08 -0700199 struct ContentEntry {
200 GraphicStateEntry fState;
201 SkDynamicMemoryWStream fContent;
202 };
203 SkSinglyLinkedList<ContentEntry> fContentEntries;
ctguil@chromium.org8dcf74f2011-07-12 21:56:27 +0000204
halcanary989da4a2016-03-21 14:33:17 -0700205 SkPDFDocument* fDocument;
halcanarya1f1ee92015-02-20 06:17:26 -0800206
Hal Canarya0622582017-06-29 18:51:35 -0400207 ////////////////////////////////////////////////////////////////////////////
halcanarya1f1ee92015-02-20 06:17:26 -0800208
mtklein36352bf2015-03-25 18:17:31 -0700209 SkBaseDevice* onCreateDevice(const CreateInfo&, const SkPaint*) override;
bsalomon@google.come97f0852011-06-17 13:10:25 +0000210
vandebo@chromium.org77bcaa32011-04-15 20:57:37 +0000211 void init();
halcanary3c35fb32016-06-30 11:55:07 -0700212 void cleanUp();
Hal Canaryb4bd5ef2017-07-26 09:16:01 -0400213 // Set alpha to true if making a transparency group form x-objects.
214 sk_sp<SkPDFObject> makeFormXObjectFromDevice(bool alpha = false);
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +0000215
vandebo@chromium.org3b416212013-10-30 20:48:05 +0000216 void drawFormXObjectWithMask(int xObjectIndex,
halcanarydabd4f02016-08-03 11:16:56 -0700217 sk_sp<SkPDFObject> mask,
Mike Reeda1361362017-03-07 09:37:29 -0500218 const SkClipStack& clipStack,
reed374772b2016-10-05 17:33:02 -0700219 SkBlendMode,
vandebo@chromium.org481aef62011-05-24 16:39:05 +0000220 bool invertClip);
vandebo@chromium.org466f3d62011-05-18 23:06:29 +0000221
vandebo@chromium.orgb069c8c2011-05-24 17:19:38 +0000222 // If the paint or clip is such that we shouldn't draw anything, this
halcanary96fcdcc2015-08-27 07:41:13 -0700223 // returns nullptr and does not create a content entry.
vandebo@chromium.orgb069c8c2011-05-24 17:19:38 +0000224 // setUpContentEntry and finishContentEntry can be used directly, but
vandebo@chromium.org13d14a92011-05-24 23:12:41 +0000225 // the preferred method is to use the ScopedContentEntry helper class.
Mike Reeda1361362017-03-07 09:37:29 -0500226 ContentEntry* setUpContentEntry(const SkClipStack& clipStack,
vandebo@chromium.orgb069c8c2011-05-24 17:19:38 +0000227 const SkMatrix& matrix,
228 const SkPaint& paint,
229 bool hasText,
halcanarydabd4f02016-08-03 11:16:56 -0700230 sk_sp<SkPDFObject>* dst);
reed374772b2016-10-05 17:33:02 -0700231 void finishContentEntry(SkBlendMode, sk_sp<SkPDFObject> dst, SkPath* shape);
vandebo@chromium.org481aef62011-05-24 16:39:05 +0000232 bool isContentEmpty();
233
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +0000234 void populateGraphicStateEntryFromPaint(const SkMatrix& matrix,
235 const SkClipStack& clipStack,
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +0000236 const SkPaint& paint,
237 bool hasText,
238 GraphicStateEntry* entry);
halcanarybe27a112015-04-01 13:31:19 -0700239 int addGraphicStateResource(SkPDFObject* gs);
vandebo@chromium.org3b416212013-10-30 20:48:05 +0000240 int addXObjectResource(SkPDFObject* xObject);
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +0000241
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000242 int getFontResourceIndex(SkTypeface* typeface, uint16_t glyphID);
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000243
Hal Canary98caedd2018-07-23 10:50:49 -0400244 void internalDrawGlyphRun(const SkGlyphRun& glyphRun, SkPoint offset);
halcanary4ed2f012016-08-15 18:40:07 -0700245
vandebo@chromium.orgb069c8c2011-05-24 17:19:38 +0000246 void internalDrawPaint(const SkPaint& paint, ContentEntry* contentEntry);
halcanarya50151d2016-03-25 11:57:49 -0700247
Hal Canary7cbf5e32017-07-12 13:10:23 -0400248 void internalDrawImageRect(SkKeyedImage,
249 const SkRect* src,
250 const SkRect& dst,
251 const SkPaint&,
252 const SkMatrix& canvasTransformationMatrix);
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +0000253
Mike Reeda1361362017-03-07 09:37:29 -0500254 void internalDrawPath(const SkClipStack&,
255 const SkMatrix&,
256 const SkPath&,
257 const SkPaint&,
258 const SkMatrix* prePathMatrix,
259 bool pathIsMutable);
260
Hal Canaryd12a6762017-05-26 17:01:16 -0400261 void internalDrawPathWithFilter(const SkClipStack& clipStack,
262 const SkMatrix& ctm,
263 const SkPath& origPath,
264 const SkPaint& paint,
265 const SkMatrix* prePathMatrix);
266
Mike Reeda1361362017-03-07 09:37:29 -0500267 bool handleInversePath(const SkPath& origPath,
edisonn@google.coma9ebd162013-10-07 13:22:21 +0000268 const SkPaint& paint, bool pathIsMutable,
halcanary96fcdcc2015-08-27 07:41:13 -0700269 const SkMatrix* prePathMatrix = nullptr);
vandebo@chromium.org238be8c2012-07-13 20:06:02 +0000270
Hal Canary51329c92017-06-27 14:28:37 -0400271 void addSMaskGraphicState(sk_sp<SkPDFDevice> maskDevice, SkDynamicMemoryWStream*);
272 void clearMaskOnGraphicState(SkDynamicMemoryWStream*);
commit-bot@chromium.org5e009892013-10-14 13:42:12 +0000273
Hal Canaryb4e528d2018-03-09 16:02:15 -0500274 bool hasEmptyClip() const { return this->cs().isEmpty(this->bounds()); }
275
Hal Canary51329c92017-06-27 14:28:37 -0400276 typedef SkClipStackDevice INHERITED;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000277};
278
279#endif