blob: 516088e484c2d5201f3c4d3fc8abe3b25fcfd76c [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"
Hal Canaryb10f92e2018-11-16 17:01:50 -050016#include "SkKeyedImage.h"
Hal Canary74801582018-12-18 16:30:41 -050017#include "SkPDFTypes.h"
vandebo@chromium.orga5180862010-10-26 19:48:49 +000018#include "SkPaint.h"
vandebo@chromium.org238be8c2012-07-13 20:06:02 +000019#include "SkRect.h"
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +000020#include "SkRefCnt.h"
21#include "SkStream.h"
Hal Canaryb10f92e2018-11-16 17:01:50 -050022#include "SkTHash.h"
Florin Malitaab54e732018-07-27 09:47:15 -040023#include "SkTextBlobPriv.h"
halcanary2be7e012016-03-28 11:58:08 -070024
Hal Canary9e41c212018-09-03 12:00:23 -040025#include <vector>
26
Herb Derby736db102018-07-19 12:52:16 -040027class SkGlyphRunList;
Hal Canary7cbf5e32017-07-12 13:10:23 -040028class SkKeyedImage;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000029class SkPDFArray;
30class SkPDFDevice;
31class SkPDFDict;
Hal Canary4ca9fa32018-12-21 16:15:01 -050032class SkPDFDocument;
vandebo@chromium.org28be72b2010-11-11 21:37:00 +000033class SkPDFFont;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000034class SkPDFObject;
Hal Canary4ca9fa32018-12-21 16:15:01 -050035class SkPath;
scroggo@google.coma8e33a92013-11-08 18:02:53 +000036class SkRRect;
Hal Canaryb10f92e2018-11-16 17:01:50 -050037struct SkPDFIndirectReference;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000038
Hal Canarya0622582017-06-29 18:51:35 -040039/**
40 * \class SkPDFDevice
41 *
42 * An SkPDFDevice is the drawing context for a page or layer of PDF
43 * content.
44 */
Mike Reedf0fb9292017-02-21 13:15:07 -050045class SkPDFDevice final : public SkClipStackDevice {
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000046public:
Hal Canarya0622582017-06-29 18:51:35 -040047 /**
halcanarya1f1ee92015-02-20 06:17:26 -080048 * @param pageSize Page size in point units.
49 * 1 point == 127/360 mm == 1/72 inch
Hal Canarya0622582017-06-29 18:51:35 -040050 * @param document A non-null pointer back to the
Hal Canaryac907bd2019-01-09 14:00:49 -050051 * PDFDocument object. The document is responsible for
Hal Canary4ca9fa32018-12-21 16:15:01 -050052 * de-duplicating across pages (via the SkPDFDocument) and
halcanary989da4a2016-03-21 14:33:17 -070053 * for early serializing of large immutable objects, such
54 * as images (via SkPDFDocument::serialize()).
Hal Canary7d06ab22018-09-10 14:39:13 -040055 * @param initialTransform Transform to be applied to the entire page.
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000056 */
Hal Canary7d06ab22018-09-10 14:39:13 -040057 SkPDFDevice(SkISize pageSize, SkPDFDocument* document,
58 const SkMatrix& initialTransform = SkMatrix::I());
Hal Canary51329c92017-06-27 14:28:37 -040059
60 sk_sp<SkPDFDevice> makeCongruentDevice() {
Hal Canary813b5ac2018-09-28 12:30:37 -040061 return sk_make_sp<SkPDFDevice>(this->size(), fDocument);
halcanarya1f1ee92015-02-20 06:17:26 -080062 }
63
Brian Salomond3b65972017-03-22 12:05:03 -040064 ~SkPDFDevice() override;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000065
Hal Canarya0622582017-06-29 18:51:35 -040066 /**
67 * These are called inside the per-device-layer loop for each draw call.
68 * When these are called, we have already applied any saveLayer
Ben Wagner2c312c42018-06-27 14:46:46 -040069 * operations, and are handling any looping from the paint.
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000070 */
Mike Reeda1361362017-03-07 09:37:29 -050071 void drawPaint(const SkPaint& paint) override;
72 void drawPoints(SkCanvas::PointMode mode,
tfarinafa4f6cb2014-12-21 10:27:07 -080073 size_t count, const SkPoint[],
mtklein36352bf2015-03-25 18:17:31 -070074 const SkPaint& paint) override;
Mike Reeda1361362017-03-07 09:37:29 -050075 void drawRect(const SkRect& r, const SkPaint& paint) override;
76 void drawOval(const SkRect& oval, const SkPaint& paint) override;
77 void drawRRect(const SkRRect& rr, const SkPaint& paint) override;
Robert Phillips137ca522018-08-15 10:14:33 -040078 void drawPath(const SkPath& origpath, const SkPaint& paint, bool pathIsMutable) override;
Mike Reeda1361362017-03-07 09:37:29 -050079 void drawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
reed562fe472015-07-28 07:35:14 -070080 const SkRect& dst, const SkPaint&, SkCanvas::SrcRectConstraint) override;
Mike Reeda1361362017-03-07 09:37:29 -050081 void drawSprite(const SkBitmap& bitmap, int x, int y,
mtklein36352bf2015-03-25 18:17:31 -070082 const SkPaint& paint) override;
Michael Ludwigb7d64b92019-02-11 11:09:15 -050083
Mike Reeda1361362017-03-07 09:37:29 -050084 void drawImageRect(const SkImage*,
halcanary7a14b312015-10-01 07:28:13 -070085 const SkRect* src,
86 const SkRect& dst,
87 const SkPaint&,
88 SkCanvas::SrcRectConstraint) override;
Herb Derbyb935cf82018-07-26 16:54:18 -040089 void drawGlyphRunList(const SkGlyphRunList& glyphRunList) override;
Ruiqi Maoc97a3392018-08-15 10:44:19 -040090 void drawVertices(const SkVertices*, const SkVertices::Bone bones[], int boneCount, SkBlendMode,
Ruiqi Maof5101492018-06-29 14:32:21 -040091 const SkPaint&) override;
Mike Reeda1361362017-03-07 09:37:29 -050092 void drawDevice(SkBaseDevice*, int x, int y,
mtklein36352bf2015-03-25 18:17:31 -070093 const SkPaint&) override;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000094
95 // PDF specific methods.
96
Hal Canary9e41c212018-09-03 12:00:23 -040097 /** Create the resource dictionary for this device. Destructive. */
Hal Canary74801582018-12-18 16:30:41 -050098 std::unique_ptr<SkPDFDict> makeResourceDict();
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000099
Hal Canary9e41c212018-09-03 12:00:23 -0400100 /** return annotations (link to urls and destinations) or nulltpr */
Hal Canary74801582018-12-18 16:30:41 -0500101 std::unique_ptr<SkPDFArray> getAnnotations();
wangxianzhuef6c50a2015-09-17 20:38:02 -0700102
epoger@google.comb58772f2013-03-08 09:09:10 +0000103 /** Add our named destinations to the supplied dictionary.
104 * @param dict Dictionary to add destinations to.
105 * @param page The PDF object representing the page for this device.
106 */
Hal Canaryfba5b6c2018-12-18 12:55:18 -0500107 void appendDestinations(SkPDFDict* dict, SkPDFIndirectReference page) const;
epoger@google.comb58772f2013-03-08 09:09:10 +0000108
halcanary8103a342016-03-08 15:10:16 -0800109 /** Returns a SkStream with the page contents.
halcanary51d04d32016-03-08 13:03:55 -0800110 */
Hal Canaryb400d4d2018-09-26 16:33:52 -0400111 std::unique_ptr<SkStreamAsset> content();
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000112
Hal Canary813b5ac2018-09-28 12:30:37 -0400113 SkISize size() const { return this->imageInfo().dimensions(); }
Hal Canary22b2d8c2017-07-19 14:46:12 -0400114 SkIRect bounds() const { return this->imageInfo().bounds(); }
115
halcanary2be7e012016-03-28 11:58:08 -0700116 // It is important to not confuse GraphicStateEntry with SkPDFGraphicState, the
117 // later being our representation of an object in the PDF file.
118 struct GraphicStateEntry {
Hal Canarya9adb6f2018-09-24 10:33:34 -0400119 SkMatrix fMatrix = SkMatrix::I();
Hal Canaryb400d4d2018-09-26 16:33:52 -0400120 uint32_t fClipStackGenID = SkClipStack::kWideOpenGenID;
Hal Canary04ac4612018-10-10 13:09:43 -0400121 SkColor4f fColor = {0, 0, 0, 1};
Hal Canarya9adb6f2018-09-24 10:33:34 -0400122 SkScalar fTextScaleX = 1; // Zero means we don't care what the value is.
123 SkPaint::Style fTextFill = SkPaint::kFill_Style; // Only if TextScaleX is non-zero.
124 int fShaderIndex = -1;
125 int fGraphicStateIndex = -1;
halcanary2be7e012016-03-28 11:58:08 -0700126 };
127
Hal Canary575be302018-09-28 15:01:14 -0400128 void DrawGlyphRunAsPath(SkPDFDevice* dev, const SkGlyphRun& glyphRun, SkPoint offset);
129
edisonn@google.com73a7ea32013-11-11 20:55:15 +0000130protected:
reede8f30622016-03-23 18:59:25 -0700131 sk_sp<SkSurface> makeSurface(const SkImageInfo&, const SkSurfaceProps&) override;
edisonn@google.com73a7ea32013-11-11 20:55:15 +0000132
Mike Reeda1361362017-03-07 09:37:29 -0500133 void drawAnnotation(const SkRect&, const char key[], SkData* value) override;
reedf70b5312016-03-04 16:36:20 -0800134
Florin Malita53f77bd2017-04-28 13:48:37 -0400135 void drawSpecial(SkSpecialImage*, int x, int y, const SkPaint&,
136 SkImage*, const SkMatrix&) override;
reede51c3562016-07-19 14:33:20 -0700137 sk_sp<SkSpecialImage> makeSpecial(const SkBitmap&) override;
138 sk_sp<SkSpecialImage> makeSpecial(const SkImage*) override;
139 sk_sp<SkSpecialImage> snapSpecial() override;
brianosman04a44d02016-09-21 09:46:57 -0700140 SkImageFilterCache* getImageFilterCache() override;
reede51c3562016-07-19 14:33:20 -0700141
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000142private:
halcanary91fcb3e2016-03-04 13:53:22 -0800143 struct RectWithData {
144 SkRect rect;
halcanaryd7b28852016-03-07 12:39:14 -0800145 sk_sp<SkData> data;
halcanary91fcb3e2016-03-04 13:53:22 -0800146 };
147
148 struct NamedDestination {
halcanaryd7b28852016-03-07 12:39:14 -0800149 sk_sp<SkData> nameData;
halcanary91fcb3e2016-03-04 13:53:22 -0800150 SkPoint point;
halcanary91fcb3e2016-03-04 13:53:22 -0800151 };
152
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000153 // TODO(vandebo): push most of SkPDFDevice's state into a core object in
vandebo@chromium.orgb069c8c2011-05-24 17:19:38 +0000154 // order to get the right access levels without using friend.
vandebo@chromium.org13d14a92011-05-24 23:12:41 +0000155 friend class ScopedContentEntry;
vandebo@chromium.orga0c7edb2011-05-09 07:58:08 +0000156
vandebo@chromium.org75f97e42011-04-11 23:24:18 +0000157 SkMatrix fInitialTransform;
wangxianzhuef6c50a2015-09-17 20:38:02 -0700158
Hal Canary9e41c212018-09-03 12:00:23 -0400159 std::vector<RectWithData> fLinkToURLs;
160 std::vector<RectWithData> fLinkToDestinations;
161 std::vector<NamedDestination> fNamedDestinations;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000162
Hal Canary9a3f5542018-12-10 19:59:07 -0500163 SkTHashSet<SkPDFIndirectReference> fGraphicStateResources;
164 SkTHashSet<SkPDFIndirectReference> fXObjectResources;
165 SkTHashSet<SkPDFIndirectReference> fShaderResources;
Hal Canaryb10f92e2018-11-16 17:01:50 -0500166 SkTHashSet<SkPDFIndirectReference> fFontResources;
Dominic Mazzoni656cefe2018-09-25 20:29:15 -0700167 int fNodeId;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000168
Hal Canary42137de2018-10-08 16:00:37 -0400169 SkDynamicMemoryWStream fContent;
170 SkDynamicMemoryWStream fContentBuffer;
171 bool fNeedsExtraSave = false;
Hal Canaryb400d4d2018-09-26 16:33:52 -0400172 struct GraphicStackState {
Hal Canary42137de2018-10-08 16:00:37 -0400173 GraphicStackState(SkDynamicMemoryWStream* s = nullptr);
Hal Canaryb400d4d2018-09-26 16:33:52 -0400174 void updateClip(const SkClipStack* clipStack, const SkIRect& bounds);
175 void updateMatrix(const SkMatrix& matrix);
176 void updateDrawingState(const SkPDFDevice::GraphicStateEntry& state);
177 void push();
178 void pop();
179 void drainStack();
180 SkPDFDevice::GraphicStateEntry* currentEntry() { return &fEntries[fStackDepth]; }
Hal Canaryb5b72792018-09-28 08:49:33 -0400181 // Must use stack for matrix, and for clip, plus one for no matrix or clip.
182 static constexpr int kMaxStackDepth = 2;
Hal Canaryb400d4d2018-09-26 16:33:52 -0400183 SkPDFDevice::GraphicStateEntry fEntries[kMaxStackDepth + 1];
184 int fStackDepth = 0;
185 SkDynamicMemoryWStream* fContentStream;
halcanary2be7e012016-03-28 11:58:08 -0700186 };
Hal Canaryb400d4d2018-09-26 16:33:52 -0400187 GraphicStackState fActiveStackState;
halcanary989da4a2016-03-21 14:33:17 -0700188 SkPDFDocument* fDocument;
halcanarya1f1ee92015-02-20 06:17:26 -0800189
Hal Canarya0622582017-06-29 18:51:35 -0400190 ////////////////////////////////////////////////////////////////////////////
halcanarya1f1ee92015-02-20 06:17:26 -0800191
mtklein36352bf2015-03-25 18:17:31 -0700192 SkBaseDevice* onCreateDevice(const CreateInfo&, const SkPaint*) override;
bsalomon@google.come97f0852011-06-17 13:10:25 +0000193
Hal Canaryb4bd5ef2017-07-26 09:16:01 -0400194 // Set alpha to true if making a transparency group form x-objects.
Hal Canary9a3f5542018-12-10 19:59:07 -0500195 SkPDFIndirectReference makeFormXObjectFromDevice(bool alpha = false);
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +0000196
Hal Canary9a3f5542018-12-10 19:59:07 -0500197 void drawFormXObjectWithMask(SkPDFIndirectReference xObject,
198 SkPDFIndirectReference sMask,
reed374772b2016-10-05 17:33:02 -0700199 SkBlendMode,
vandebo@chromium.org481aef62011-05-24 16:39:05 +0000200 bool invertClip);
vandebo@chromium.org466f3d62011-05-18 23:06:29 +0000201
vandebo@chromium.orgb069c8c2011-05-24 17:19:38 +0000202 // If the paint or clip is such that we shouldn't draw anything, this
halcanary96fcdcc2015-08-27 07:41:13 -0700203 // returns nullptr and does not create a content entry.
vandebo@chromium.orgb069c8c2011-05-24 17:19:38 +0000204 // setUpContentEntry and finishContentEntry can be used directly, but
vandebo@chromium.org13d14a92011-05-24 23:12:41 +0000205 // the preferred method is to use the ScopedContentEntry helper class.
Hal Canaryb400d4d2018-09-26 16:33:52 -0400206 SkDynamicMemoryWStream* setUpContentEntry(const SkClipStack* clipStack,
Hal Canary9a3f5542018-12-10 19:59:07 -0500207 const SkMatrix& matrix,
208 const SkPaint& paint,
Hal Canary8f37ce52018-12-28 11:40:10 -0500209 SkScalar,
Hal Canary9a3f5542018-12-10 19:59:07 -0500210 SkPDFIndirectReference* dst);
211 void finishContentEntry(const SkClipStack*, SkBlendMode, SkPDFIndirectReference, SkPath*);
vandebo@chromium.org481aef62011-05-24 16:39:05 +0000212 bool isContentEmpty();
213
Herb Derby95e17602018-12-06 17:11:43 -0500214 void internalDrawGlyphRun(const SkGlyphRun& glyphRun, SkPoint offset, const SkPaint& runPaint);
215 void drawGlyphRunAsPath(const SkGlyphRun& glyphRun, SkPoint offset, const SkPaint& runPaint);
halcanary4ed2f012016-08-15 18:40:07 -0700216
Hal Canary7cbf5e32017-07-12 13:10:23 -0400217 void internalDrawImageRect(SkKeyedImage,
218 const SkRect* src,
219 const SkRect& dst,
220 const SkPaint&,
221 const SkMatrix& canvasTransformationMatrix);
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +0000222
Mike Reeda1361362017-03-07 09:37:29 -0500223 void internalDrawPath(const SkClipStack&,
224 const SkMatrix&,
225 const SkPath&,
226 const SkPaint&,
Mike Reeda1361362017-03-07 09:37:29 -0500227 bool pathIsMutable);
228
Hal Canaryd12a6762017-05-26 17:01:16 -0400229 void internalDrawPathWithFilter(const SkClipStack& clipStack,
230 const SkMatrix& ctm,
231 const SkPath& origPath,
Robert Phillips137ca522018-08-15 10:14:33 -0400232 const SkPaint& paint);
Hal Canaryd12a6762017-05-26 17:01:16 -0400233
Robert Phillips137ca522018-08-15 10:14:33 -0400234 bool handleInversePath(const SkPath& origPath, const SkPaint& paint, bool pathIsMutable);
vandebo@chromium.org238be8c2012-07-13 20:06:02 +0000235
Hal Canary51329c92017-06-27 14:28:37 -0400236 void addSMaskGraphicState(sk_sp<SkPDFDevice> maskDevice, SkDynamicMemoryWStream*);
237 void clearMaskOnGraphicState(SkDynamicMemoryWStream*);
Hal Canary9a3f5542018-12-10 19:59:07 -0500238 void setGraphicState(SkPDFIndirectReference gs, SkDynamicMemoryWStream*);
239 void drawFormXObject(SkPDFIndirectReference xObject, SkDynamicMemoryWStream*);
commit-bot@chromium.org5e009892013-10-14 13:42:12 +0000240
Hal Canaryb4e528d2018-03-09 16:02:15 -0500241 bool hasEmptyClip() const { return this->cs().isEmpty(this->bounds()); }
242
Hal Canary9e41c212018-09-03 12:00:23 -0400243 void reset();
244
Hal Canary51329c92017-06-27 14:28:37 -0400245 typedef SkClipStackDevice INHERITED;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000246};
247
248#endif