blob: d02c671b76c2d1845c3b6daf957714e865d860fd [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()).
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000055 */
Hal Canarya0622582017-06-29 18:51:35 -040056 SkPDFDevice(SkISize pageSize, SkPDFDocument* document);
halcanarya1f1ee92015-02-20 06:17:26 -080057
Hal Canarya0622582017-06-29 18:51:35 -040058 /**
59 * Apply a scale-and-translate transform to move the origin from the
60 * bottom left (PDF default) to the top left (Skia default).
61 */
62 void setFlip();
Hal Canary51329c92017-06-27 14:28:37 -040063
64 sk_sp<SkPDFDevice> makeCongruentDevice() {
Hal Canary9f61f402018-09-10 15:06:24 -040065 return sk_make_sp<SkPDFDevice>(this->imageInfo().dimensions(), fDocument);
halcanarya1f1ee92015-02-20 06:17:26 -080066 }
67
Brian Salomond3b65972017-03-22 12:05:03 -040068 ~SkPDFDevice() override;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000069
Hal Canarya0622582017-06-29 18:51:35 -040070 /**
71 * These are called inside the per-device-layer loop for each draw call.
72 * When these are called, we have already applied any saveLayer
Ben Wagner2c312c42018-06-27 14:46:46 -040073 * operations, and are handling any looping from the paint.
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000074 */
Mike Reeda1361362017-03-07 09:37:29 -050075 void drawPaint(const SkPaint& paint) override;
76 void drawPoints(SkCanvas::PointMode mode,
tfarinafa4f6cb2014-12-21 10:27:07 -080077 size_t count, const SkPoint[],
mtklein36352bf2015-03-25 18:17:31 -070078 const SkPaint& paint) override;
Mike Reeda1361362017-03-07 09:37:29 -050079 void drawRect(const SkRect& r, const SkPaint& paint) override;
80 void drawOval(const SkRect& oval, const SkPaint& paint) override;
81 void drawRRect(const SkRRect& rr, const SkPaint& paint) override;
Robert Phillips137ca522018-08-15 10:14:33 -040082 void drawPath(const SkPath& origpath, const SkPaint& paint, bool pathIsMutable) override;
Mike Reeda1361362017-03-07 09:37:29 -050083 void drawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
reed562fe472015-07-28 07:35:14 -070084 const SkRect& dst, const SkPaint&, SkCanvas::SrcRectConstraint) override;
Hal Canaryb9642382017-06-27 09:58:56 -040085 void drawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint&) override;
Mike Reeda1361362017-03-07 09:37:29 -050086 void drawSprite(const SkBitmap& bitmap, int x, int y,
mtklein36352bf2015-03-25 18:17:31 -070087 const SkPaint& paint) override;
Mike Reeda1361362017-03-07 09:37:29 -050088 void drawImage(const SkImage*,
halcanary7a14b312015-10-01 07:28:13 -070089 SkScalar x,
90 SkScalar y,
91 const SkPaint&) override;
Mike Reeda1361362017-03-07 09:37:29 -050092 void drawImageRect(const SkImage*,
halcanary7a14b312015-10-01 07:28:13 -070093 const SkRect* src,
94 const SkRect& dst,
95 const SkPaint&,
96 SkCanvas::SrcRectConstraint) override;
Herb Derbyb935cf82018-07-26 16:54:18 -040097 void drawGlyphRunList(const SkGlyphRunList& glyphRunList) override;
Ruiqi Maoc97a3392018-08-15 10:44:19 -040098 void drawVertices(const SkVertices*, const SkVertices::Bone bones[], int boneCount, SkBlendMode,
Ruiqi Maof5101492018-06-29 14:32:21 -040099 const SkPaint&) override;
Mike Reeda1361362017-03-07 09:37:29 -0500100 void drawDevice(SkBaseDevice*, int x, int y,
mtklein36352bf2015-03-25 18:17:31 -0700101 const SkPaint&) override;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000102
103 // PDF specific methods.
104
Hal Canary9e41c212018-09-03 12:00:23 -0400105 /** Create the resource dictionary for this device. Destructive. */
106 sk_sp<SkPDFDict> makeResourceDict();
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000107
Hal Canary9e41c212018-09-03 12:00:23 -0400108 /** return annotations (link to urls and destinations) or nulltpr */
109 sk_sp<SkPDFArray> getAnnotations();
wangxianzhuef6c50a2015-09-17 20:38:02 -0700110
epoger@google.comb58772f2013-03-08 09:09:10 +0000111 /** Add our named destinations to the supplied dictionary.
112 * @param dict Dictionary to add destinations to.
113 * @param page The PDF object representing the page for this device.
114 */
halcanary6d622702015-03-25 08:45:42 -0700115 void appendDestinations(SkPDFDict* dict, SkPDFObject* page) const;
epoger@google.comb58772f2013-03-08 09:09:10 +0000116
halcanary8103a342016-03-08 15:10:16 -0800117 /** Returns a copy of the media box for this device. */
118 sk_sp<SkPDFArray> copyMediaBox() const;
halcanary51d04d32016-03-08 13:03:55 -0800119
halcanary8103a342016-03-08 15:10:16 -0800120 /** Returns a SkStream with the page contents.
halcanary51d04d32016-03-08 13:03:55 -0800121 */
mtklein5f939ab2016-03-16 10:28:35 -0700122 std::unique_ptr<SkStreamAsset> content() const;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000123
halcanary989da4a2016-03-21 14:33:17 -0700124 SkPDFCanon* getCanon() const;
halcanary26b5d152015-03-25 08:38:03 -0700125
Hal Canary22b2d8c2017-07-19 14:46:12 -0400126 SkIRect bounds() const { return this->imageInfo().bounds(); }
127
halcanary2be7e012016-03-28 11:58:08 -0700128 // It is important to not confuse GraphicStateEntry with SkPDFGraphicState, the
129 // later being our representation of an object in the PDF file.
130 struct GraphicStateEntry {
131 GraphicStateEntry();
132
133 // Compare the fields we care about when setting up a new content entry.
134 bool compareInitialState(const GraphicStateEntry& b);
135
136 SkMatrix fMatrix;
137 // We can't do set operations on Paths, though PDF natively supports
138 // intersect. If the clip stack does anything other than intersect,
139 // we have to fall back to the region. Treat fClipStack as authoritative.
140 // See https://bugs.skia.org/221
141 SkClipStack fClipStack;
halcanary2be7e012016-03-28 11:58:08 -0700142
143 // When emitting the content entry, we will ensure the graphic state
144 // is set to these values first.
145 SkColor fColor;
146 SkScalar fTextScaleX; // Zero means we don't care what the value is.
147 SkPaint::Style fTextFill; // Only if TextScaleX is non-zero.
148 int fShaderIndex;
149 int fGraphicStateIndex;
halcanary2be7e012016-03-28 11:58:08 -0700150 };
151
edisonn@google.com73a7ea32013-11-11 20:55:15 +0000152protected:
reede8f30622016-03-23 18:59:25 -0700153 sk_sp<SkSurface> makeSurface(const SkImageInfo&, const SkSurfaceProps&) override;
edisonn@google.com73a7ea32013-11-11 20:55:15 +0000154
Mike Reeda1361362017-03-07 09:37:29 -0500155 void drawAnnotation(const SkRect&, const char key[], SkData* value) override;
reedf70b5312016-03-04 16:36:20 -0800156
Florin Malita53f77bd2017-04-28 13:48:37 -0400157 void drawSpecial(SkSpecialImage*, int x, int y, const SkPaint&,
158 SkImage*, const SkMatrix&) override;
reede51c3562016-07-19 14:33:20 -0700159 sk_sp<SkSpecialImage> makeSpecial(const SkBitmap&) override;
160 sk_sp<SkSpecialImage> makeSpecial(const SkImage*) override;
161 sk_sp<SkSpecialImage> snapSpecial() override;
brianosman04a44d02016-09-21 09:46:57 -0700162 SkImageFilterCache* getImageFilterCache() override;
reede51c3562016-07-19 14:33:20 -0700163
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000164private:
halcanary91fcb3e2016-03-04 13:53:22 -0800165 struct RectWithData {
166 SkRect rect;
halcanaryd7b28852016-03-07 12:39:14 -0800167 sk_sp<SkData> data;
halcanary91fcb3e2016-03-04 13:53:22 -0800168 };
169
170 struct NamedDestination {
halcanaryd7b28852016-03-07 12:39:14 -0800171 sk_sp<SkData> nameData;
halcanary91fcb3e2016-03-04 13:53:22 -0800172 SkPoint point;
halcanary91fcb3e2016-03-04 13:53:22 -0800173 };
174
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000175 // TODO(vandebo): push most of SkPDFDevice's state into a core object in
vandebo@chromium.orgb069c8c2011-05-24 17:19:38 +0000176 // order to get the right access levels without using friend.
vandebo@chromium.org13d14a92011-05-24 23:12:41 +0000177 friend class ScopedContentEntry;
vandebo@chromium.orga0c7edb2011-05-09 07:58:08 +0000178
vandebo@chromium.org75f97e42011-04-11 23:24:18 +0000179 SkMatrix fInitialTransform;
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +0000180 SkClipStack fExistingClipStack;
wangxianzhuef6c50a2015-09-17 20:38:02 -0700181
Hal Canary9e41c212018-09-03 12:00:23 -0400182 std::vector<RectWithData> fLinkToURLs;
183 std::vector<RectWithData> fLinkToDestinations;
184 std::vector<NamedDestination> fNamedDestinations;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000185
Hal Canary9e41c212018-09-03 12:00:23 -0400186 std::vector<sk_sp<SkPDFObject>> fGraphicStateResources;
187 std::vector<sk_sp<SkPDFObject>> fXObjectResources;
188 std::vector<sk_sp<SkPDFObject>> fShaderResources;
189 std::vector<sk_sp<SkPDFFont>> fFontResources;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000190
halcanary2be7e012016-03-28 11:58:08 -0700191 struct ContentEntry {
192 GraphicStateEntry fState;
193 SkDynamicMemoryWStream fContent;
194 };
195 SkSinglyLinkedList<ContentEntry> fContentEntries;
ctguil@chromium.org8dcf74f2011-07-12 21:56:27 +0000196
halcanary989da4a2016-03-21 14:33:17 -0700197 SkPDFDocument* fDocument;
halcanarya1f1ee92015-02-20 06:17:26 -0800198
Hal Canarya0622582017-06-29 18:51:35 -0400199 ////////////////////////////////////////////////////////////////////////////
halcanarya1f1ee92015-02-20 06:17:26 -0800200
mtklein36352bf2015-03-25 18:17:31 -0700201 SkBaseDevice* onCreateDevice(const CreateInfo&, const SkPaint*) override;
bsalomon@google.come97f0852011-06-17 13:10:25 +0000202
Hal Canaryb4bd5ef2017-07-26 09:16:01 -0400203 // Set alpha to true if making a transparency group form x-objects.
204 sk_sp<SkPDFObject> makeFormXObjectFromDevice(bool alpha = false);
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +0000205
vandebo@chromium.org3b416212013-10-30 20:48:05 +0000206 void drawFormXObjectWithMask(int xObjectIndex,
halcanarydabd4f02016-08-03 11:16:56 -0700207 sk_sp<SkPDFObject> mask,
Mike Reeda1361362017-03-07 09:37:29 -0500208 const SkClipStack& clipStack,
reed374772b2016-10-05 17:33:02 -0700209 SkBlendMode,
vandebo@chromium.org481aef62011-05-24 16:39:05 +0000210 bool invertClip);
vandebo@chromium.org466f3d62011-05-18 23:06:29 +0000211
vandebo@chromium.orgb069c8c2011-05-24 17:19:38 +0000212 // If the paint or clip is such that we shouldn't draw anything, this
halcanary96fcdcc2015-08-27 07:41:13 -0700213 // returns nullptr and does not create a content entry.
vandebo@chromium.orgb069c8c2011-05-24 17:19:38 +0000214 // setUpContentEntry and finishContentEntry can be used directly, but
vandebo@chromium.org13d14a92011-05-24 23:12:41 +0000215 // the preferred method is to use the ScopedContentEntry helper class.
Mike Reeda1361362017-03-07 09:37:29 -0500216 ContentEntry* setUpContentEntry(const SkClipStack& clipStack,
vandebo@chromium.orgb069c8c2011-05-24 17:19:38 +0000217 const SkMatrix& matrix,
218 const SkPaint& paint,
219 bool hasText,
halcanarydabd4f02016-08-03 11:16:56 -0700220 sk_sp<SkPDFObject>* dst);
reed374772b2016-10-05 17:33:02 -0700221 void finishContentEntry(SkBlendMode, sk_sp<SkPDFObject> dst, SkPath* shape);
vandebo@chromium.org481aef62011-05-24 16:39:05 +0000222 bool isContentEmpty();
223
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +0000224 void populateGraphicStateEntryFromPaint(const SkMatrix& matrix,
225 const SkClipStack& clipStack,
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +0000226 const SkPaint& paint,
227 bool hasText,
228 GraphicStateEntry* entry);
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000229
Hal Canary98caedd2018-07-23 10:50:49 -0400230 void internalDrawGlyphRun(const SkGlyphRun& glyphRun, SkPoint offset);
halcanary4ed2f012016-08-15 18:40:07 -0700231
vandebo@chromium.orgb069c8c2011-05-24 17:19:38 +0000232 void internalDrawPaint(const SkPaint& paint, ContentEntry* contentEntry);
halcanarya50151d2016-03-25 11:57:49 -0700233
Hal Canary7cbf5e32017-07-12 13:10:23 -0400234 void internalDrawImageRect(SkKeyedImage,
235 const SkRect* src,
236 const SkRect& dst,
237 const SkPaint&,
238 const SkMatrix& canvasTransformationMatrix);
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +0000239
Mike Reeda1361362017-03-07 09:37:29 -0500240 void internalDrawPath(const SkClipStack&,
241 const SkMatrix&,
242 const SkPath&,
243 const SkPaint&,
Mike Reeda1361362017-03-07 09:37:29 -0500244 bool pathIsMutable);
245
Hal Canaryd12a6762017-05-26 17:01:16 -0400246 void internalDrawPathWithFilter(const SkClipStack& clipStack,
247 const SkMatrix& ctm,
248 const SkPath& origPath,
Robert Phillips137ca522018-08-15 10:14:33 -0400249 const SkPaint& paint);
Hal Canaryd12a6762017-05-26 17:01:16 -0400250
Robert Phillips137ca522018-08-15 10:14:33 -0400251 bool handleInversePath(const SkPath& origPath, const SkPaint& paint, bool pathIsMutable);
vandebo@chromium.org238be8c2012-07-13 20:06:02 +0000252
Hal Canary51329c92017-06-27 14:28:37 -0400253 void addSMaskGraphicState(sk_sp<SkPDFDevice> maskDevice, SkDynamicMemoryWStream*);
254 void clearMaskOnGraphicState(SkDynamicMemoryWStream*);
commit-bot@chromium.org5e009892013-10-14 13:42:12 +0000255
Hal Canaryb4e528d2018-03-09 16:02:15 -0500256 bool hasEmptyClip() const { return this->cs().isEmpty(this->bounds()); }
257
Hal Canary9e41c212018-09-03 12:00:23 -0400258 void reset();
259
Hal Canary51329c92017-06-27 14:28:37 -0400260 typedef SkClipStackDevice INHERITED;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000261};
262
263#endif