blob: ce99f064774702d7713981187138fdf16d164301 [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"
Florin Malitaab54e732018-07-27 09:47:15 -040021#include "SkTextBlobPriv.h"
Hal Canary7cbf5e32017-07-12 13:10:23 -040022#include "SkKeyedImage.h"
halcanary2be7e012016-03-28 11:58:08 -070023
Hal Canary9e41c212018-09-03 12:00:23 -040024#include <vector>
25
Herb Derby736db102018-07-19 12:52:16 -040026class SkGlyphRunList;
Hal Canary7cbf5e32017-07-12 13:10:23 -040027class SkKeyedImage;
martina.kollarovab8d6af12016-06-29 05:12:31 -070028class SkPath;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000029class SkPDFArray;
halcanarya1f1ee92015-02-20 06:17:26 -080030class SkPDFCanon;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000031class SkPDFDevice;
halcanary989da4a2016-03-21 14:33:17 -070032class SkPDFDocument;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000033class SkPDFDict;
vandebo@chromium.org28be72b2010-11-11 21:37:00 +000034class SkPDFFont;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000035class SkPDFObject;
halcanary4b1e17e2016-07-27 14:49:46 -070036class SkPDFStream;
scroggo@google.coma8e33a92013-11-08 18:02:53 +000037class SkRRect;
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
51 * PDFDocument object. The document is repsonsible for
halcanary989da4a2016-03-21 14:33:17 -070052 * de-duplicating across pages (via the SkPDFCanon) and
53 * 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 Canary9f61f402018-09-10 15:06:24 -040061 return sk_make_sp<SkPDFDevice>(this->imageInfo().dimensions(), 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;
Hal Canaryb9642382017-06-27 09:58:56 -040081 void drawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint&) override;
Mike Reeda1361362017-03-07 09:37:29 -050082 void drawSprite(const SkBitmap& bitmap, int x, int y,
mtklein36352bf2015-03-25 18:17:31 -070083 const SkPaint& paint) override;
Mike Reeda1361362017-03-07 09:37:29 -050084 void drawImage(const SkImage*,
halcanary7a14b312015-10-01 07:28:13 -070085 SkScalar x,
86 SkScalar y,
87 const SkPaint&) override;
Mike Reeda1361362017-03-07 09:37:29 -050088 void drawImageRect(const SkImage*,
halcanary7a14b312015-10-01 07:28:13 -070089 const SkRect* src,
90 const SkRect& dst,
91 const SkPaint&,
92 SkCanvas::SrcRectConstraint) override;
Herb Derbyb935cf82018-07-26 16:54:18 -040093 void drawGlyphRunList(const SkGlyphRunList& glyphRunList) override;
Ruiqi Maoc97a3392018-08-15 10:44:19 -040094 void drawVertices(const SkVertices*, const SkVertices::Bone bones[], int boneCount, SkBlendMode,
Ruiqi Maof5101492018-06-29 14:32:21 -040095 const SkPaint&) override;
Mike Reeda1361362017-03-07 09:37:29 -050096 void drawDevice(SkBaseDevice*, int x, int y,
mtklein36352bf2015-03-25 18:17:31 -070097 const SkPaint&) override;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000098
99 // PDF specific methods.
100
Hal Canary9e41c212018-09-03 12:00:23 -0400101 /** Create the resource dictionary for this device. Destructive. */
102 sk_sp<SkPDFDict> makeResourceDict();
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000103
Hal Canary9e41c212018-09-03 12:00:23 -0400104 /** return annotations (link to urls and destinations) or nulltpr */
105 sk_sp<SkPDFArray> getAnnotations();
wangxianzhuef6c50a2015-09-17 20:38:02 -0700106
epoger@google.comb58772f2013-03-08 09:09:10 +0000107 /** Add our named destinations to the supplied dictionary.
108 * @param dict Dictionary to add destinations to.
109 * @param page The PDF object representing the page for this device.
110 */
halcanary6d622702015-03-25 08:45:42 -0700111 void appendDestinations(SkPDFDict* dict, SkPDFObject* page) const;
epoger@google.comb58772f2013-03-08 09:09:10 +0000112
halcanary8103a342016-03-08 15:10:16 -0800113 /** Returns a SkStream with the page contents.
halcanary51d04d32016-03-08 13:03:55 -0800114 */
mtklein5f939ab2016-03-16 10:28:35 -0700115 std::unique_ptr<SkStreamAsset> content() const;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000116
halcanary989da4a2016-03-21 14:33:17 -0700117 SkPDFCanon* getCanon() const;
halcanary26b5d152015-03-25 08:38:03 -0700118
Hal Canary22b2d8c2017-07-19 14:46:12 -0400119 SkIRect bounds() const { return this->imageInfo().bounds(); }
120
halcanary2be7e012016-03-28 11:58:08 -0700121 // It is important to not confuse GraphicStateEntry with SkPDFGraphicState, the
122 // later being our representation of an object in the PDF file.
123 struct GraphicStateEntry {
124 GraphicStateEntry();
125
126 // Compare the fields we care about when setting up a new content entry.
127 bool compareInitialState(const GraphicStateEntry& b);
128
129 SkMatrix fMatrix;
130 // We can't do set operations on Paths, though PDF natively supports
131 // intersect. If the clip stack does anything other than intersect,
132 // we have to fall back to the region. Treat fClipStack as authoritative.
133 // See https://bugs.skia.org/221
134 SkClipStack fClipStack;
halcanary2be7e012016-03-28 11:58:08 -0700135
136 // When emitting the content entry, we will ensure the graphic state
137 // is set to these values first.
138 SkColor fColor;
139 SkScalar fTextScaleX; // Zero means we don't care what the value is.
140 SkPaint::Style fTextFill; // Only if TextScaleX is non-zero.
141 int fShaderIndex;
142 int fGraphicStateIndex;
halcanary2be7e012016-03-28 11:58:08 -0700143 };
144
edisonn@google.com73a7ea32013-11-11 20:55:15 +0000145protected:
reede8f30622016-03-23 18:59:25 -0700146 sk_sp<SkSurface> makeSurface(const SkImageInfo&, const SkSurfaceProps&) override;
edisonn@google.com73a7ea32013-11-11 20:55:15 +0000147
Mike Reeda1361362017-03-07 09:37:29 -0500148 void drawAnnotation(const SkRect&, const char key[], SkData* value) override;
reedf70b5312016-03-04 16:36:20 -0800149
Florin Malita53f77bd2017-04-28 13:48:37 -0400150 void drawSpecial(SkSpecialImage*, int x, int y, const SkPaint&,
151 SkImage*, const SkMatrix&) override;
reede51c3562016-07-19 14:33:20 -0700152 sk_sp<SkSpecialImage> makeSpecial(const SkBitmap&) override;
153 sk_sp<SkSpecialImage> makeSpecial(const SkImage*) override;
154 sk_sp<SkSpecialImage> snapSpecial() override;
brianosman04a44d02016-09-21 09:46:57 -0700155 SkImageFilterCache* getImageFilterCache() override;
reede51c3562016-07-19 14:33:20 -0700156
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000157private:
halcanary91fcb3e2016-03-04 13:53:22 -0800158 struct RectWithData {
159 SkRect rect;
halcanaryd7b28852016-03-07 12:39:14 -0800160 sk_sp<SkData> data;
halcanary91fcb3e2016-03-04 13:53:22 -0800161 };
162
163 struct NamedDestination {
halcanaryd7b28852016-03-07 12:39:14 -0800164 sk_sp<SkData> nameData;
halcanary91fcb3e2016-03-04 13:53:22 -0800165 SkPoint point;
halcanary91fcb3e2016-03-04 13:53:22 -0800166 };
167
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000168 // TODO(vandebo): push most of SkPDFDevice's state into a core object in
vandebo@chromium.orgb069c8c2011-05-24 17:19:38 +0000169 // order to get the right access levels without using friend.
vandebo@chromium.org13d14a92011-05-24 23:12:41 +0000170 friend class ScopedContentEntry;
vandebo@chromium.orga0c7edb2011-05-09 07:58:08 +0000171
vandebo@chromium.org75f97e42011-04-11 23:24:18 +0000172 SkMatrix fInitialTransform;
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +0000173 SkClipStack fExistingClipStack;
wangxianzhuef6c50a2015-09-17 20:38:02 -0700174
Hal Canary9e41c212018-09-03 12:00:23 -0400175 std::vector<RectWithData> fLinkToURLs;
176 std::vector<RectWithData> fLinkToDestinations;
177 std::vector<NamedDestination> fNamedDestinations;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000178
Hal Canary9e41c212018-09-03 12:00:23 -0400179 std::vector<sk_sp<SkPDFObject>> fGraphicStateResources;
180 std::vector<sk_sp<SkPDFObject>> fXObjectResources;
181 std::vector<sk_sp<SkPDFObject>> fShaderResources;
182 std::vector<sk_sp<SkPDFFont>> fFontResources;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000183
halcanary2be7e012016-03-28 11:58:08 -0700184 struct ContentEntry {
185 GraphicStateEntry fState;
186 SkDynamicMemoryWStream fContent;
187 };
188 SkSinglyLinkedList<ContentEntry> fContentEntries;
ctguil@chromium.org8dcf74f2011-07-12 21:56:27 +0000189
halcanary989da4a2016-03-21 14:33:17 -0700190 SkPDFDocument* fDocument;
halcanarya1f1ee92015-02-20 06:17:26 -0800191
Hal Canarya0622582017-06-29 18:51:35 -0400192 ////////////////////////////////////////////////////////////////////////////
halcanarya1f1ee92015-02-20 06:17:26 -0800193
mtklein36352bf2015-03-25 18:17:31 -0700194 SkBaseDevice* onCreateDevice(const CreateInfo&, const SkPaint*) override;
bsalomon@google.come97f0852011-06-17 13:10:25 +0000195
Hal Canaryb4bd5ef2017-07-26 09:16:01 -0400196 // Set alpha to true if making a transparency group form x-objects.
197 sk_sp<SkPDFObject> makeFormXObjectFromDevice(bool alpha = false);
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +0000198
vandebo@chromium.org3b416212013-10-30 20:48:05 +0000199 void drawFormXObjectWithMask(int xObjectIndex,
halcanarydabd4f02016-08-03 11:16:56 -0700200 sk_sp<SkPDFObject> mask,
Mike Reeda1361362017-03-07 09:37:29 -0500201 const SkClipStack& clipStack,
reed374772b2016-10-05 17:33:02 -0700202 SkBlendMode,
vandebo@chromium.org481aef62011-05-24 16:39:05 +0000203 bool invertClip);
vandebo@chromium.org466f3d62011-05-18 23:06:29 +0000204
vandebo@chromium.orgb069c8c2011-05-24 17:19:38 +0000205 // If the paint or clip is such that we shouldn't draw anything, this
halcanary96fcdcc2015-08-27 07:41:13 -0700206 // returns nullptr and does not create a content entry.
vandebo@chromium.orgb069c8c2011-05-24 17:19:38 +0000207 // setUpContentEntry and finishContentEntry can be used directly, but
vandebo@chromium.org13d14a92011-05-24 23:12:41 +0000208 // the preferred method is to use the ScopedContentEntry helper class.
Mike Reeda1361362017-03-07 09:37:29 -0500209 ContentEntry* setUpContentEntry(const SkClipStack& clipStack,
vandebo@chromium.orgb069c8c2011-05-24 17:19:38 +0000210 const SkMatrix& matrix,
211 const SkPaint& paint,
212 bool hasText,
halcanarydabd4f02016-08-03 11:16:56 -0700213 sk_sp<SkPDFObject>* dst);
reed374772b2016-10-05 17:33:02 -0700214 void finishContentEntry(SkBlendMode, sk_sp<SkPDFObject> dst, SkPath* shape);
vandebo@chromium.org481aef62011-05-24 16:39:05 +0000215 bool isContentEmpty();
216
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +0000217 void populateGraphicStateEntryFromPaint(const SkMatrix& matrix,
218 const SkClipStack& clipStack,
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +0000219 const SkPaint& paint,
220 bool hasText,
221 GraphicStateEntry* entry);
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000222
Hal Canary98caedd2018-07-23 10:50:49 -0400223 void internalDrawGlyphRun(const SkGlyphRun& glyphRun, SkPoint offset);
halcanary4ed2f012016-08-15 18:40:07 -0700224
vandebo@chromium.orgb069c8c2011-05-24 17:19:38 +0000225 void internalDrawPaint(const SkPaint& paint, ContentEntry* contentEntry);
halcanarya50151d2016-03-25 11:57:49 -0700226
Hal Canary7cbf5e32017-07-12 13:10:23 -0400227 void internalDrawImageRect(SkKeyedImage,
228 const SkRect* src,
229 const SkRect& dst,
230 const SkPaint&,
231 const SkMatrix& canvasTransformationMatrix);
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +0000232
Mike Reeda1361362017-03-07 09:37:29 -0500233 void internalDrawPath(const SkClipStack&,
234 const SkMatrix&,
235 const SkPath&,
236 const SkPaint&,
Mike Reeda1361362017-03-07 09:37:29 -0500237 bool pathIsMutable);
238
Hal Canaryd12a6762017-05-26 17:01:16 -0400239 void internalDrawPathWithFilter(const SkClipStack& clipStack,
240 const SkMatrix& ctm,
241 const SkPath& origPath,
Robert Phillips137ca522018-08-15 10:14:33 -0400242 const SkPaint& paint);
Hal Canaryd12a6762017-05-26 17:01:16 -0400243
Robert Phillips137ca522018-08-15 10:14:33 -0400244 bool handleInversePath(const SkPath& origPath, const SkPaint& paint, bool pathIsMutable);
vandebo@chromium.org238be8c2012-07-13 20:06:02 +0000245
Hal Canary51329c92017-06-27 14:28:37 -0400246 void addSMaskGraphicState(sk_sp<SkPDFDevice> maskDevice, SkDynamicMemoryWStream*);
247 void clearMaskOnGraphicState(SkDynamicMemoryWStream*);
commit-bot@chromium.org5e009892013-10-14 13:42:12 +0000248
Hal Canaryb4e528d2018-03-09 16:02:15 -0500249 bool hasEmptyClip() const { return this->cs().isEmpty(this->bounds()); }
250
Hal Canary9e41c212018-09-03 12:00:23 -0400251 void reset();
252
Hal Canary51329c92017-06-27 14:28:37 -0400253 typedef SkClipStackDevice INHERITED;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000254};
255
256#endif