blob: 0197b5a6d33b5fa15bcaf5f920dcfc7debbdda88 [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;
Robert Phillips137ca522018-08-15 10:14:33 -040081 void drawPath(const SkPath& origpath, const SkPaint& paint, bool pathIsMutable) override;
Mike Reeda1361362017-03-07 09:37:29 -050082 void drawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
reed562fe472015-07-28 07:35:14 -070083 const SkRect& dst, const SkPaint&, SkCanvas::SrcRectConstraint) override;
Hal Canaryb9642382017-06-27 09:58:56 -040084 void drawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint&) override;
Mike Reeda1361362017-03-07 09:37:29 -050085 void drawSprite(const SkBitmap& bitmap, int x, int y,
mtklein36352bf2015-03-25 18:17:31 -070086 const SkPaint& paint) override;
Mike Reeda1361362017-03-07 09:37:29 -050087 void drawImage(const SkImage*,
halcanary7a14b312015-10-01 07:28:13 -070088 SkScalar x,
89 SkScalar y,
90 const SkPaint&) override;
Mike Reeda1361362017-03-07 09:37:29 -050091 void drawImageRect(const SkImage*,
halcanary7a14b312015-10-01 07:28:13 -070092 const SkRect* src,
93 const SkRect& dst,
94 const SkPaint&,
95 SkCanvas::SrcRectConstraint) override;
Mike Reeda1361362017-03-07 09:37:29 -050096 void drawPosText(const void* text, size_t len,
tfarinafa4f6cb2014-12-21 10:27:07 -080097 const SkScalar pos[], int scalarsPerPos,
Hal Canary98caedd2018-07-23 10:50:49 -040098 const SkPoint& offset, const SkPaint&) override { SkASSERT(false); }
Herb Derbyb935cf82018-07-26 16:54:18 -040099 void drawGlyphRunList(const SkGlyphRunList& glyphRunList) override;
Ruiqi Maoc97a3392018-08-15 10:44:19 -0400100 void drawVertices(const SkVertices*, const SkVertices::Bone bones[], int boneCount, SkBlendMode,
Ruiqi Maof5101492018-06-29 14:32:21 -0400101 const SkPaint&) override;
Mike Reeda1361362017-03-07 09:37:29 -0500102 void drawDevice(SkBaseDevice*, int x, int y,
mtklein36352bf2015-03-25 18:17:31 -0700103 const SkPaint&) override;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000104
105 // PDF specific methods.
106
halcanary8103a342016-03-08 15:10:16 -0800107 /** Create the resource dictionary for this device. */
108 sk_sp<SkPDFDict> makeResourceDict() const;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000109
wangxianzhuef6c50a2015-09-17 20:38:02 -0700110 /** Add our annotations (link to urls and destinations) to the supplied
111 * array.
112 * @param array Array to add annotations to.
113 */
114 void appendAnnotations(SkPDFArray* array) const;
115
epoger@google.comb58772f2013-03-08 09:09:10 +0000116 /** Add our named destinations to the supplied dictionary.
117 * @param dict Dictionary to add destinations to.
118 * @param page The PDF object representing the page for this device.
119 */
halcanary6d622702015-03-25 08:45:42 -0700120 void appendDestinations(SkPDFDict* dict, SkPDFObject* page) const;
epoger@google.comb58772f2013-03-08 09:09:10 +0000121
halcanary8103a342016-03-08 15:10:16 -0800122 /** Returns a copy of the media box for this device. */
123 sk_sp<SkPDFArray> copyMediaBox() const;
halcanary51d04d32016-03-08 13:03:55 -0800124
halcanary8103a342016-03-08 15:10:16 -0800125 /** Returns a SkStream with the page contents.
halcanary51d04d32016-03-08 13:03:55 -0800126 */
mtklein5f939ab2016-03-16 10:28:35 -0700127 std::unique_ptr<SkStreamAsset> content() const;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000128
halcanary989da4a2016-03-21 14:33:17 -0700129 SkPDFCanon* getCanon() const;
halcanary26b5d152015-03-25 08:38:03 -0700130
Hal Canary22b2d8c2017-07-19 14:46:12 -0400131 SkIRect bounds() const { return this->imageInfo().bounds(); }
132
halcanary2be7e012016-03-28 11:58:08 -0700133 // It is important to not confuse GraphicStateEntry with SkPDFGraphicState, the
134 // later being our representation of an object in the PDF file.
135 struct GraphicStateEntry {
136 GraphicStateEntry();
137
138 // Compare the fields we care about when setting up a new content entry.
139 bool compareInitialState(const GraphicStateEntry& b);
140
141 SkMatrix fMatrix;
142 // We can't do set operations on Paths, though PDF natively supports
143 // intersect. If the clip stack does anything other than intersect,
144 // we have to fall back to the region. Treat fClipStack as authoritative.
145 // See https://bugs.skia.org/221
146 SkClipStack fClipStack;
halcanary2be7e012016-03-28 11:58:08 -0700147
148 // When emitting the content entry, we will ensure the graphic state
149 // is set to these values first.
150 SkColor fColor;
151 SkScalar fTextScaleX; // Zero means we don't care what the value is.
152 SkPaint::Style fTextFill; // Only if TextScaleX is non-zero.
153 int fShaderIndex;
154 int fGraphicStateIndex;
halcanary2be7e012016-03-28 11:58:08 -0700155 };
156
edisonn@google.com73a7ea32013-11-11 20:55:15 +0000157protected:
reede8f30622016-03-23 18:59:25 -0700158 sk_sp<SkSurface> makeSurface(const SkImageInfo&, const SkSurfaceProps&) override;
edisonn@google.com73a7ea32013-11-11 20:55:15 +0000159
Mike Reeda1361362017-03-07 09:37:29 -0500160 void drawAnnotation(const SkRect&, const char key[], SkData* value) override;
reedf70b5312016-03-04 16:36:20 -0800161
Florin Malita53f77bd2017-04-28 13:48:37 -0400162 void drawSpecial(SkSpecialImage*, int x, int y, const SkPaint&,
163 SkImage*, const SkMatrix&) override;
reede51c3562016-07-19 14:33:20 -0700164 sk_sp<SkSpecialImage> makeSpecial(const SkBitmap&) override;
165 sk_sp<SkSpecialImage> makeSpecial(const SkImage*) override;
166 sk_sp<SkSpecialImage> snapSpecial() override;
brianosman04a44d02016-09-21 09:46:57 -0700167 SkImageFilterCache* getImageFilterCache() override;
reede51c3562016-07-19 14:33:20 -0700168
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000169private:
halcanary91fcb3e2016-03-04 13:53:22 -0800170 struct RectWithData {
171 SkRect rect;
halcanaryd7b28852016-03-07 12:39:14 -0800172 sk_sp<SkData> data;
halcanary91fcb3e2016-03-04 13:53:22 -0800173 };
174
175 struct NamedDestination {
halcanaryd7b28852016-03-07 12:39:14 -0800176 sk_sp<SkData> nameData;
halcanary91fcb3e2016-03-04 13:53:22 -0800177 SkPoint point;
halcanary91fcb3e2016-03-04 13:53:22 -0800178 };
179
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000180 // TODO(vandebo): push most of SkPDFDevice's state into a core object in
vandebo@chromium.orgb069c8c2011-05-24 17:19:38 +0000181 // order to get the right access levels without using friend.
vandebo@chromium.org13d14a92011-05-24 23:12:41 +0000182 friend class ScopedContentEntry;
vandebo@chromium.orga0c7edb2011-05-09 07:58:08 +0000183
ctguil@chromium.org15261292011-04-29 17:54:16 +0000184 SkISize fPageSize;
vandebo@chromium.org75f97e42011-04-11 23:24:18 +0000185 SkMatrix fInitialTransform;
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +0000186 SkClipStack fExistingClipStack;
wangxianzhuef6c50a2015-09-17 20:38:02 -0700187
halcanary91fcb3e2016-03-04 13:53:22 -0800188 SkTArray<RectWithData> fLinkToURLs;
189 SkTArray<RectWithData> fLinkToDestinations;
190 SkTArray<NamedDestination> fNamedDestinations;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000191
halcanarybe27a112015-04-01 13:31:19 -0700192 SkTDArray<SkPDFObject*> fGraphicStateResources;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000193 SkTDArray<SkPDFObject*> fXObjectResources;
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000194 SkTDArray<SkPDFFont*> fFontResources;
vandebo@chromium.org421d6442011-07-20 17:39:01 +0000195 SkTDArray<SkPDFObject*> fShaderResources;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000196
halcanary2be7e012016-03-28 11:58:08 -0700197 struct ContentEntry {
198 GraphicStateEntry fState;
199 SkDynamicMemoryWStream fContent;
200 };
201 SkSinglyLinkedList<ContentEntry> fContentEntries;
ctguil@chromium.org8dcf74f2011-07-12 21:56:27 +0000202
halcanary989da4a2016-03-21 14:33:17 -0700203 SkPDFDocument* fDocument;
halcanarya1f1ee92015-02-20 06:17:26 -0800204
Hal Canarya0622582017-06-29 18:51:35 -0400205 ////////////////////////////////////////////////////////////////////////////
halcanarya1f1ee92015-02-20 06:17:26 -0800206
mtklein36352bf2015-03-25 18:17:31 -0700207 SkBaseDevice* onCreateDevice(const CreateInfo&, const SkPaint*) override;
bsalomon@google.come97f0852011-06-17 13:10:25 +0000208
vandebo@chromium.org77bcaa32011-04-15 20:57:37 +0000209 void init();
halcanary3c35fb32016-06-30 11:55:07 -0700210 void cleanUp();
Hal Canaryb4bd5ef2017-07-26 09:16:01 -0400211 // Set alpha to true if making a transparency group form x-objects.
212 sk_sp<SkPDFObject> makeFormXObjectFromDevice(bool alpha = false);
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +0000213
vandebo@chromium.org3b416212013-10-30 20:48:05 +0000214 void drawFormXObjectWithMask(int xObjectIndex,
halcanarydabd4f02016-08-03 11:16:56 -0700215 sk_sp<SkPDFObject> mask,
Mike Reeda1361362017-03-07 09:37:29 -0500216 const SkClipStack& clipStack,
reed374772b2016-10-05 17:33:02 -0700217 SkBlendMode,
vandebo@chromium.org481aef62011-05-24 16:39:05 +0000218 bool invertClip);
vandebo@chromium.org466f3d62011-05-18 23:06:29 +0000219
vandebo@chromium.orgb069c8c2011-05-24 17:19:38 +0000220 // If the paint or clip is such that we shouldn't draw anything, this
halcanary96fcdcc2015-08-27 07:41:13 -0700221 // returns nullptr and does not create a content entry.
vandebo@chromium.orgb069c8c2011-05-24 17:19:38 +0000222 // setUpContentEntry and finishContentEntry can be used directly, but
vandebo@chromium.org13d14a92011-05-24 23:12:41 +0000223 // the preferred method is to use the ScopedContentEntry helper class.
Mike Reeda1361362017-03-07 09:37:29 -0500224 ContentEntry* setUpContentEntry(const SkClipStack& clipStack,
vandebo@chromium.orgb069c8c2011-05-24 17:19:38 +0000225 const SkMatrix& matrix,
226 const SkPaint& paint,
227 bool hasText,
halcanarydabd4f02016-08-03 11:16:56 -0700228 sk_sp<SkPDFObject>* dst);
reed374772b2016-10-05 17:33:02 -0700229 void finishContentEntry(SkBlendMode, sk_sp<SkPDFObject> dst, SkPath* shape);
vandebo@chromium.org481aef62011-05-24 16:39:05 +0000230 bool isContentEmpty();
231
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +0000232 void populateGraphicStateEntryFromPaint(const SkMatrix& matrix,
233 const SkClipStack& clipStack,
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +0000234 const SkPaint& paint,
235 bool hasText,
236 GraphicStateEntry* entry);
halcanarybe27a112015-04-01 13:31:19 -0700237 int addGraphicStateResource(SkPDFObject* gs);
vandebo@chromium.org3b416212013-10-30 20:48:05 +0000238 int addXObjectResource(SkPDFObject* xObject);
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +0000239
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000240 int getFontResourceIndex(SkTypeface* typeface, uint16_t glyphID);
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000241
Hal Canary98caedd2018-07-23 10:50:49 -0400242 void internalDrawGlyphRun(const SkGlyphRun& glyphRun, SkPoint offset);
halcanary4ed2f012016-08-15 18:40:07 -0700243
vandebo@chromium.orgb069c8c2011-05-24 17:19:38 +0000244 void internalDrawPaint(const SkPaint& paint, ContentEntry* contentEntry);
halcanarya50151d2016-03-25 11:57:49 -0700245
Hal Canary7cbf5e32017-07-12 13:10:23 -0400246 void internalDrawImageRect(SkKeyedImage,
247 const SkRect* src,
248 const SkRect& dst,
249 const SkPaint&,
250 const SkMatrix& canvasTransformationMatrix);
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +0000251
Mike Reeda1361362017-03-07 09:37:29 -0500252 void internalDrawPath(const SkClipStack&,
253 const SkMatrix&,
254 const SkPath&,
255 const SkPaint&,
Mike Reeda1361362017-03-07 09:37:29 -0500256 bool pathIsMutable);
257
Hal Canaryd12a6762017-05-26 17:01:16 -0400258 void internalDrawPathWithFilter(const SkClipStack& clipStack,
259 const SkMatrix& ctm,
260 const SkPath& origPath,
Robert Phillips137ca522018-08-15 10:14:33 -0400261 const SkPaint& paint);
Hal Canaryd12a6762017-05-26 17:01:16 -0400262
Robert Phillips137ca522018-08-15 10:14:33 -0400263 bool handleInversePath(const SkPath& origPath, const SkPaint& paint, bool pathIsMutable);
vandebo@chromium.org238be8c2012-07-13 20:06:02 +0000264
Hal Canary51329c92017-06-27 14:28:37 -0400265 void addSMaskGraphicState(sk_sp<SkPDFDevice> maskDevice, SkDynamicMemoryWStream*);
266 void clearMaskOnGraphicState(SkDynamicMemoryWStream*);
commit-bot@chromium.org5e009892013-10-14 13:42:12 +0000267
Hal Canaryb4e528d2018-03-09 16:02:15 -0500268 bool hasEmptyClip() const { return this->cs().isEmpty(this->bounds()); }
269
Hal Canary51329c92017-06-27 14:28:37 -0400270 typedef SkClipStackDevice INHERITED;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000271};
272
273#endif