blob: 45aba2988602cf5a9f8a15304b5265e7a793ce66 [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"
14#include "SkDevice.h"
vandebo@chromium.orga5180862010-10-26 19:48:49 +000015#include "SkPaint.h"
16#include "SkPath.h"
commit-bot@chromium.org608ea652013-10-03 19:29:21 +000017#include "SkPicture.h"
vandebo@chromium.org238be8c2012-07-13 20:06:02 +000018#include "SkRect.h"
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +000019#include "SkRefCnt.h"
20#include "SkStream.h"
epoger@google.comb58772f2013-03-08 09:09:10 +000021#include "SkTDArray.h"
commit-bot@chromium.orge0294402013-08-29 22:14:04 +000022#include "SkTemplates.h"
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000023
24class SkPDFArray;
halcanarya1f1ee92015-02-20 06:17:26 -080025class SkPDFCanon;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000026class SkPDFDevice;
27class SkPDFDict;
vandebo@chromium.org28be72b2010-11-11 21:37:00 +000028class SkPDFFont;
vandebo@chromium.org6112c212011-05-13 03:50:38 +000029class SkPDFFormXObject;
vandebo@chromium.org98594282011-07-25 22:34:12 +000030class SkPDFGlyphSetMap;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000031class SkPDFGraphicState;
32class SkPDFObject;
vandebo@chromium.orgda912d62011-03-08 18:31:02 +000033class SkPDFShader;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000034class SkPDFStream;
scroggo@google.coma8e33a92013-11-08 18:02:53 +000035class SkRRect;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000036
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +000037// Private classes.
38struct ContentEntry;
39struct GraphicStateEntry;
epoger@google.comb58772f2013-03-08 09:09:10 +000040struct NamedDestination;
wangxianzhuef6c50a2015-09-17 20:38:02 -070041struct RectWithData;
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +000042
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000043/** \class SkPDFDevice
44
45 The drawing context for the PDF backend.
46*/
reed89443ab2014-06-27 11:34:19 -070047class SkPDFDevice : public SkBaseDevice {
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000048public:
halcanarya1f1ee92015-02-20 06:17:26 -080049 /** Create a PDF drawing context. SkPDFDevice applies a
50 * scale-and-translate transform to move the origin from the
51 * bottom left (PDF default) to the top left (Skia default).
52 * @param pageSize Page size in point units.
53 * 1 point == 127/360 mm == 1/72 inch
54 * @param rasterDpi the DPI at which features without native PDF
55 * support will be rasterized (e.g. draw image with
56 * perspective, draw text with perspective, ...). A
57 * larger DPI would create a PDF that reflects the
58 * original intent with better fidelity, but it can make
59 * for larger PDF files too, which would use more memory
60 * while rendering, and it would be slower to be processed
61 * or sent online or to printer. A good choice is
62 * SK_ScalarDefaultRasterDPI(72.0f).
63 * @param SkPDFCanon. Should be non-null, and shared by all
64 * devices in a document.
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000065 */
halcanarya1f1ee92015-02-20 06:17:26 -080066 static SkPDFDevice* Create(SkISize pageSize,
67 SkScalar rasterDpi,
68 SkPDFCanon* canon) {
halcanary385fe4d2015-08-26 13:07:48 -070069 return new SkPDFDevice(pageSize, rasterDpi, canon, true);
halcanarya1f1ee92015-02-20 06:17:26 -080070 }
71
72 /** Create a PDF drawing context without fipping the y-axis. */
73 static SkPDFDevice* CreateUnflipped(SkISize pageSize,
74 SkScalar rasterDpi,
75 SkPDFCanon* canon) {
halcanary385fe4d2015-08-26 13:07:48 -070076 return new SkPDFDevice(pageSize, rasterDpi, canon, false);
halcanarya1f1ee92015-02-20 06:17:26 -080077 }
78
79 virtual ~SkPDFDevice();
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000080
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000081 /** These are called inside the per-device-layer loop for each draw call.
82 When these are called, we have already applied any saveLayer operations,
83 and are handling any looping from the paint, and any effects from the
84 DrawFilter.
85 */
mtklein36352bf2015-03-25 18:17:31 -070086 void drawPaint(const SkDraw&, const SkPaint& paint) override;
tfarinafa4f6cb2014-12-21 10:27:07 -080087 void drawPoints(const SkDraw&, SkCanvas::PointMode mode,
88 size_t count, const SkPoint[],
mtklein36352bf2015-03-25 18:17:31 -070089 const SkPaint& paint) override;
90 void drawRect(const SkDraw&, const SkRect& r, const SkPaint& paint) override;
91 void drawOval(const SkDraw&, const SkRect& oval, const SkPaint& paint) override;
92 void drawRRect(const SkDraw&, const SkRRect& rr, const SkPaint& paint) override;
tfarinafa4f6cb2014-12-21 10:27:07 -080093 void drawPath(const SkDraw&, const SkPath& origpath,
94 const SkPaint& paint, const SkMatrix* prePathMatrix,
mtklein36352bf2015-03-25 18:17:31 -070095 bool pathIsMutable) override;
reed562fe472015-07-28 07:35:14 -070096 void drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap, const SkRect* src,
97 const SkRect& dst, const SkPaint&, SkCanvas::SrcRectConstraint) override;
tfarinafa4f6cb2014-12-21 10:27:07 -080098 void drawBitmap(const SkDraw&, const SkBitmap& bitmap,
mtklein36352bf2015-03-25 18:17:31 -070099 const SkMatrix& matrix, const SkPaint&) override;
tfarinafa4f6cb2014-12-21 10:27:07 -0800100 void drawSprite(const SkDraw&, const SkBitmap& bitmap, int x, int y,
mtklein36352bf2015-03-25 18:17:31 -0700101 const SkPaint& paint) override;
tfarinafa4f6cb2014-12-21 10:27:07 -0800102 void drawText(const SkDraw&, const void* text, size_t len,
mtklein36352bf2015-03-25 18:17:31 -0700103 SkScalar x, SkScalar y, const SkPaint&) override;
tfarinafa4f6cb2014-12-21 10:27:07 -0800104 void drawPosText(const SkDraw&, const void* text, size_t len,
105 const SkScalar pos[], int scalarsPerPos,
mtklein36352bf2015-03-25 18:17:31 -0700106 const SkPoint& offset, const SkPaint&) override;
tfarinafa4f6cb2014-12-21 10:27:07 -0800107 void drawVertices(const SkDraw&, SkCanvas::VertexMode,
108 int vertexCount, const SkPoint verts[],
109 const SkPoint texs[], const SkColor colors[],
110 SkXfermode* xmode, const uint16_t indices[],
mtklein36352bf2015-03-25 18:17:31 -0700111 int indexCount, const SkPaint& paint) override;
tfarinafa4f6cb2014-12-21 10:27:07 -0800112 void drawDevice(const SkDraw&, SkBaseDevice*, int x, int y,
mtklein36352bf2015-03-25 18:17:31 -0700113 const SkPaint&) override;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000114
mtklein36352bf2015-03-25 18:17:31 -0700115 void onAttachToCanvas(SkCanvas* canvas) override;
116 void onDetachFromCanvas() override;
117 SkImageInfo imageInfo() const override;
robertphillips@google.com40a1ae42012-07-13 15:36:15 +0000118
ctguil@chromium.org8dcf74f2011-07-12 21:56:27 +0000119 enum DrawingArea {
ctguil@chromium.org9510ccc2011-07-27 00:10:51 +0000120 kContent_DrawingArea, // Drawing area for the page content.
121 kMargin_DrawingArea, // Drawing area for the margin content.
ctguil@chromium.org8dcf74f2011-07-12 21:56:27 +0000122 };
123
124 /** Sets the drawing area for the device. Subsequent draw calls are directed
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000125 * to the specific drawing area (margin or content). The default drawing
ctguil@chromium.org8dcf74f2011-07-12 21:56:27 +0000126 * area is the content drawing area.
ctguil@chromium.org9510ccc2011-07-27 00:10:51 +0000127 *
128 * Currently if margin content is drawn and then a complex (for PDF) xfer
129 * mode is used, like SrcIn, Clear, etc, the margin content will get
130 * clipped. A simple way to avoid the bug is to always draw the margin
131 * content last.
ctguil@chromium.org8dcf74f2011-07-12 21:56:27 +0000132 */
halcanary4e4e8162015-02-25 08:59:48 -0800133 void setDrawingArea(DrawingArea drawingArea);
ctguil@chromium.org8dcf74f2011-07-12 21:56:27 +0000134
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000135 // PDF specific methods.
136
halcanary6d622702015-03-25 08:45:42 -0700137 /** Create the resource dictionary for this device.
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000138 */
halcanary2b861552015-04-09 13:27:40 -0700139 SkPDFDict* createResourceDict() const;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000140
vandebo@chromium.orgf0ec2662011-05-29 05:55:42 +0000141 /** Get the fonts used on this device.
142 */
halcanary4e4e8162015-02-25 08:59:48 -0800143 const SkTDArray<SkPDFFont*>& getFontResources() const;
vandebo@chromium.orgf0ec2662011-05-29 05:55:42 +0000144
wangxianzhuef6c50a2015-09-17 20:38:02 -0700145 /** Add our annotations (link to urls and destinations) to the supplied
146 * array.
147 * @param array Array to add annotations to.
148 */
149 void appendAnnotations(SkPDFArray* array) const;
150
epoger@google.comb58772f2013-03-08 09:09:10 +0000151 /** Add our named destinations to the supplied dictionary.
152 * @param dict Dictionary to add destinations to.
153 * @param page The PDF object representing the page for this device.
154 */
halcanary6d622702015-03-25 08:45:42 -0700155 void appendDestinations(SkPDFDict* dict, SkPDFObject* page) const;
epoger@google.comb58772f2013-03-08 09:09:10 +0000156
reed@google.com2a006c12012-09-19 17:05:55 +0000157 /** Returns a copy of the media box for this device. The caller is required
158 * to unref() this when it is finished.
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000159 */
halcanary4e4e8162015-02-25 08:59:48 -0800160 SkPDFArray* copyMediaBox() const;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000161
vandebo@chromium.orgc2a9b7f2011-02-24 23:22:30 +0000162 /** Returns a SkStream with the page contents. The caller is responsible
halcanary4e4e8162015-02-25 08:59:48 -0800163 * for a deleting the returned value.
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000164 */
halcanary4e4e8162015-02-25 08:59:48 -0800165 SkStreamAsset* content() const;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000166
halcanary334fcbc2015-02-24 12:56:16 -0800167 /** Writes the page contents to the stream. */
halcanary4e4e8162015-02-25 08:59:48 -0800168 void writeContent(SkWStream*) const;
vandebo@chromium.org98594282011-07-25 22:34:12 +0000169
halcanary4e4e8162015-02-25 08:59:48 -0800170 const SkMatrix& initialTransform() const {
vandebo@chromium.org3509f052011-05-30 20:52:33 +0000171 return fInitialTransform;
172 }
vandebo@chromium.org61d26782011-05-24 23:02:07 +0000173
vandebo@chromium.org98594282011-07-25 22:34:12 +0000174 /** Returns a SkPDFGlyphSetMap which represents glyph usage of every font
175 * that shows on this device.
176 */
177 const SkPDFGlyphSetMap& getFontGlyphUsage() const {
178 return *(fFontGlyphUsage.get());
179 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000180
halcanary26b5d152015-03-25 08:38:03 -0700181#ifdef SK_DEBUG
182 SkPDFCanon* getCanon() const { return fCanon; }
183#endif // SK_DEBUG
184
edisonn@google.com73a7ea32013-11-11 20:55:15 +0000185protected:
mtklein36352bf2015-03-25 18:17:31 -0700186 const SkBitmap& onAccessBitmap() override {
reed89443ab2014-06-27 11:34:19 -0700187 return fLegacyBitmap;
188 }
189
mtklein36352bf2015-03-25 18:17:31 -0700190 SkSurface* newSurface(const SkImageInfo&, const SkSurfaceProps&) override;
edisonn@google.com73a7ea32013-11-11 20:55:15 +0000191
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000192private:
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000193 // TODO(vandebo): push most of SkPDFDevice's state into a core object in
vandebo@chromium.orgb069c8c2011-05-24 17:19:38 +0000194 // order to get the right access levels without using friend.
vandebo@chromium.org13d14a92011-05-24 23:12:41 +0000195 friend class ScopedContentEntry;
vandebo@chromium.orga0c7edb2011-05-09 07:58:08 +0000196
ctguil@chromium.org15261292011-04-29 17:54:16 +0000197 SkISize fPageSize;
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +0000198 SkISize fContentSize;
vandebo@chromium.org75f97e42011-04-11 23:24:18 +0000199 SkMatrix fInitialTransform;
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +0000200 SkClipStack fExistingClipStack;
201 SkRegion fExistingClipRegion;
wangxianzhuef6c50a2015-09-17 20:38:02 -0700202
203 SkTDArray<RectWithData*> fLinkToURLs;
204 SkTDArray<RectWithData*> fLinkToDestinations;
epoger@google.comb58772f2013-03-08 09:09:10 +0000205 SkTDArray<NamedDestination*> fNamedDestinations;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000206
halcanarybe27a112015-04-01 13:31:19 -0700207 SkTDArray<SkPDFObject*> fGraphicStateResources;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000208 SkTDArray<SkPDFObject*> fXObjectResources;
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000209 SkTDArray<SkPDFFont*> fFontResources;
vandebo@chromium.org421d6442011-07-20 17:39:01 +0000210 SkTDArray<SkPDFObject*> fShaderResources;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000211
commit-bot@chromium.orge0294402013-08-29 22:14:04 +0000212 SkAutoTDelete<ContentEntry> fContentEntries;
vandebo@chromium.orgb069c8c2011-05-24 17:19:38 +0000213 ContentEntry* fLastContentEntry;
commit-bot@chromium.orge0294402013-08-29 22:14:04 +0000214 SkAutoTDelete<ContentEntry> fMarginContentEntries;
ctguil@chromium.org8dcf74f2011-07-12 21:56:27 +0000215 ContentEntry* fLastMarginContentEntry;
216 DrawingArea fDrawingArea;
217
robertphillips@google.com40a1ae42012-07-13 15:36:15 +0000218 const SkClipStack* fClipStack;
219
ctguil@chromium.org8dcf74f2011-07-12 21:56:27 +0000220 // Accessor and setter functions based on the current DrawingArea.
commit-bot@chromium.orge0294402013-08-29 22:14:04 +0000221 SkAutoTDelete<ContentEntry>* getContentEntries();
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000222
vandebo@chromium.org98594282011-07-25 22:34:12 +0000223 // Glyph ids used for each font on this device.
commit-bot@chromium.orge0294402013-08-29 22:14:04 +0000224 SkAutoTDelete<SkPDFGlyphSetMap> fFontGlyphUsage;
vandebo@chromium.org98594282011-07-25 22:34:12 +0000225
commit-bot@chromium.org8c294902013-10-21 17:14:37 +0000226 SkScalar fRasterDpi;
edisonn@google.comd9dfa182013-04-24 13:01:01 +0000227
reed89443ab2014-06-27 11:34:19 -0700228 SkBitmap fLegacyBitmap;
229
halcanarya1f1ee92015-02-20 06:17:26 -0800230 SkPDFCanon* fCanon; // Owned by SkDocument_PDF
231 ////////////////////////////////////////////////////////////////////////////
232
233 SkPDFDevice(SkISize pageSize,
234 SkScalar rasterDpi,
235 SkPDFCanon* canon,
236 bool flip);
237
238 ContentEntry* getLastContentEntry();
239 void setLastContentEntry(ContentEntry* contentEntry);
vandebo@chromium.orga0c7edb2011-05-09 07:58:08 +0000240
mtklein36352bf2015-03-25 18:17:31 -0700241 SkBaseDevice* onCreateDevice(const CreateInfo&, const SkPaint*) override;
bsalomon@google.come97f0852011-06-17 13:10:25 +0000242
vandebo@chromium.org77bcaa32011-04-15 20:57:37 +0000243 void init();
vandebo@chromium.org98594282011-07-25 22:34:12 +0000244 void cleanUp(bool clearFontUsage);
reed@google.comfc641d02012-09-20 17:52:20 +0000245 SkPDFFormXObject* createFormXObjectFromDevice();
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +0000246
vandebo@chromium.org3b416212013-10-30 20:48:05 +0000247 void drawFormXObjectWithMask(int xObjectIndex,
248 SkPDFFormXObject* mask,
vandebo@chromium.org481aef62011-05-24 16:39:05 +0000249 const SkClipStack* clipStack,
250 const SkRegion& clipRegion,
vandebo@chromium.org3b416212013-10-30 20:48:05 +0000251 SkXfermode::Mode mode,
vandebo@chromium.org481aef62011-05-24 16:39:05 +0000252 bool invertClip);
vandebo@chromium.org466f3d62011-05-18 23:06:29 +0000253
vandebo@chromium.orgb069c8c2011-05-24 17:19:38 +0000254 // If the paint or clip is such that we shouldn't draw anything, this
halcanary96fcdcc2015-08-27 07:41:13 -0700255 // returns nullptr and does not create a content entry.
vandebo@chromium.orgb069c8c2011-05-24 17:19:38 +0000256 // setUpContentEntry and finishContentEntry can be used directly, but
vandebo@chromium.org13d14a92011-05-24 23:12:41 +0000257 // the preferred method is to use the ScopedContentEntry helper class.
vandebo@chromium.orgb069c8c2011-05-24 17:19:38 +0000258 ContentEntry* setUpContentEntry(const SkClipStack* clipStack,
259 const SkRegion& clipRegion,
260 const SkMatrix& matrix,
261 const SkPaint& paint,
262 bool hasText,
reed@google.comfc641d02012-09-20 17:52:20 +0000263 SkPDFFormXObject** dst);
vandebo@chromium.orgb069c8c2011-05-24 17:19:38 +0000264 void finishContentEntry(SkXfermode::Mode xfermode,
vandebo@chromium.org3b416212013-10-30 20:48:05 +0000265 SkPDFFormXObject* dst,
266 SkPath* shape);
vandebo@chromium.org481aef62011-05-24 16:39:05 +0000267 bool isContentEmpty();
268
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +0000269 void populateGraphicStateEntryFromPaint(const SkMatrix& matrix,
270 const SkClipStack& clipStack,
271 const SkRegion& clipRegion,
272 const SkPaint& paint,
273 bool hasText,
274 GraphicStateEntry* entry);
halcanarybe27a112015-04-01 13:31:19 -0700275 int addGraphicStateResource(SkPDFObject* gs);
vandebo@chromium.org3b416212013-10-30 20:48:05 +0000276 int addXObjectResource(SkPDFObject* xObject);
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +0000277
robertphillips8e0c1502015-07-07 10:28:43 -0700278 void updateFont(const SkPaint& paint, uint16_t glyphID, ContentEntry* contentEntry);
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000279 int getFontResourceIndex(SkTypeface* typeface, uint16_t glyphID);
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000280
vandebo@chromium.orgb069c8c2011-05-24 17:19:38 +0000281 void internalDrawPaint(const SkPaint& paint, ContentEntry* contentEntry);
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +0000282 void internalDrawBitmap(const SkMatrix& matrix,
vandebo@chromium.org78dad542011-05-11 18:46:03 +0000283 const SkClipStack* clipStack,
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +0000284 const SkRegion& clipRegion,
285 const SkBitmap& bitmap,
286 const SkIRect* srcRect,
287 const SkPaint& paint);
288
ctguil@chromium.org8dcf74f2011-07-12 21:56:27 +0000289 /** Helper method for copyContentToData. It is responsible for copying the
290 * list of content entries |entry| to |data|.
291 */
292 void copyContentEntriesToData(ContentEntry* entry, SkWStream* data) const;
ctguil@chromium.org9510ccc2011-07-27 00:10:51 +0000293
commit-bot@chromium.org92ffe7d2013-07-31 22:54:31 +0000294 bool handleInversePath(const SkDraw& d, const SkPath& origPath,
edisonn@google.coma9ebd162013-10-07 13:22:21 +0000295 const SkPaint& paint, bool pathIsMutable,
halcanary96fcdcc2015-08-27 07:41:13 -0700296 const SkMatrix* prePathMatrix = nullptr);
epoger@google.comb58772f2013-03-08 09:09:10 +0000297 bool handlePointAnnotation(const SkPoint* points, size_t count,
wangxianzhud76665d2015-07-17 17:23:15 -0700298 const SkMatrix& matrix, SkAnnotation* annot);
wangxianzhuef6c50a2015-09-17 20:38:02 -0700299 bool handlePathAnnotation(const SkPath& path, const SkDraw& d,
300 SkAnnotation* annot);
vandebo@chromium.org238be8c2012-07-13 20:06:02 +0000301
reed89443ab2014-06-27 11:34:19 -0700302 typedef SkBaseDevice INHERITED;
commit-bot@chromium.org5e009892013-10-14 13:42:12 +0000303
304 // TODO(edisonn): Only SkDocument_PDF and SkPDFImageShader should be able to create
305 // an SkPDFDevice
306 //friend class SkDocument_PDF;
307 //friend class SkPDFImageShader;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000308};
309
310#endif