blob: 8a883140091740fa28bfea1a62804966263f0248 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +00002/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00003 * Copyright 2011 Google Inc.
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +00004 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00005 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +00007 */
8
epoger@google.comec3ed6a2011-07-28 14:26:00 +00009
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000010#ifndef SkPDFDevice_DEFINED
11#define SkPDFDevice_DEFINED
12
reed89443ab2014-06-27 11:34:19 -070013#include "SkDevice.h"
commit-bot@chromium.org5e009892013-10-14 13:42:12 +000014#include "SkBitmap.h"
vandebo@chromium.orgb069c8c2011-05-24 17:19:38 +000015#include "SkCanvas.h"
vandebo@chromium.orga5180862010-10-26 19:48:49 +000016#include "SkPaint.h"
17#include "SkPath.h"
commit-bot@chromium.org608ea652013-10-03 19:29:21 +000018#include "SkPicture.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"
epoger@google.comb58772f2013-03-08 09:09:10 +000022#include "SkTDArray.h"
commit-bot@chromium.orge0294402013-08-29 22:14:04 +000023#include "SkTemplates.h"
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000024
25class SkPDFArray;
halcanarya1f1ee92015-02-20 06:17:26 -080026class SkPDFCanon;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000027class SkPDFDevice;
28class SkPDFDict;
vandebo@chromium.org28be72b2010-11-11 21:37:00 +000029class SkPDFFont;
vandebo@chromium.org6112c212011-05-13 03:50:38 +000030class SkPDFFormXObject;
vandebo@chromium.org98594282011-07-25 22:34:12 +000031class SkPDFGlyphSetMap;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000032class SkPDFGraphicState;
33class SkPDFObject;
commit-bot@chromium.org47401352013-07-23 21:49:29 +000034class SkPDFResourceDict;
vandebo@chromium.orgda912d62011-03-08 18:31:02 +000035class SkPDFShader;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000036class SkPDFStream;
scroggo@google.coma8e33a92013-11-08 18:02:53 +000037class SkRRect;
edisonn@google.coma20e42c2013-05-31 18:04:20 +000038template <typename T> class SkTSet;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000039
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +000040// Private classes.
41struct ContentEntry;
42struct GraphicStateEntry;
epoger@google.comb58772f2013-03-08 09:09:10 +000043struct NamedDestination;
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +000044
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000045/** \class SkPDFDevice
46
47 The drawing context for the PDF backend.
48*/
reed89443ab2014-06-27 11:34:19 -070049class SkPDFDevice : public SkBaseDevice {
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000050public:
halcanarya1f1ee92015-02-20 06:17:26 -080051 /** Create a PDF drawing context. SkPDFDevice applies a
52 * scale-and-translate transform to move the origin from the
53 * bottom left (PDF default) to the top left (Skia default).
54 * @param pageSize Page size in point units.
55 * 1 point == 127/360 mm == 1/72 inch
56 * @param rasterDpi the DPI at which features without native PDF
57 * support will be rasterized (e.g. draw image with
58 * perspective, draw text with perspective, ...). A
59 * larger DPI would create a PDF that reflects the
60 * original intent with better fidelity, but it can make
61 * for larger PDF files too, which would use more memory
62 * while rendering, and it would be slower to be processed
63 * or sent online or to printer. A good choice is
64 * SK_ScalarDefaultRasterDPI(72.0f).
65 * @param SkPDFCanon. Should be non-null, and shared by all
66 * devices in a document.
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000067 */
halcanarya1f1ee92015-02-20 06:17:26 -080068 static SkPDFDevice* Create(SkISize pageSize,
69 SkScalar rasterDpi,
70 SkPDFCanon* canon) {
71 return SkNEW_ARGS(SkPDFDevice, (pageSize, rasterDpi, canon, true));
72 }
73
74 /** Create a PDF drawing context without fipping the y-axis. */
75 static SkPDFDevice* CreateUnflipped(SkISize pageSize,
76 SkScalar rasterDpi,
77 SkPDFCanon* canon) {
78 return SkNEW_ARGS(SkPDFDevice, (pageSize, rasterDpi, canon, false));
79 }
80
81 virtual ~SkPDFDevice();
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000082
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000083 /** These are called inside the per-device-layer loop for each draw call.
84 When these are called, we have already applied any saveLayer operations,
85 and are handling any looping from the paint, and any effects from the
86 DrawFilter.
87 */
tfarinafa4f6cb2014-12-21 10:27:07 -080088 void drawPaint(const SkDraw&, const SkPaint& paint) SK_OVERRIDE;
89 void drawPoints(const SkDraw&, SkCanvas::PointMode mode,
90 size_t count, const SkPoint[],
91 const SkPaint& paint) SK_OVERRIDE;
92 void drawRect(const SkDraw&, const SkRect& r, const SkPaint& paint) SK_OVERRIDE;
93 void drawOval(const SkDraw&, const SkRect& oval, const SkPaint& paint) SK_OVERRIDE;
94 void drawRRect(const SkDraw&, const SkRRect& rr, const SkPaint& paint) SK_OVERRIDE;
95 void drawPath(const SkDraw&, const SkPath& origpath,
96 const SkPaint& paint, const SkMatrix* prePathMatrix,
97 bool pathIsMutable) SK_OVERRIDE;
98 void drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap,
99 const SkRect* src, const SkRect& dst,
100 const SkPaint& paint,
101 SkCanvas::DrawBitmapRectFlags flags) SK_OVERRIDE;
102 void drawBitmap(const SkDraw&, const SkBitmap& bitmap,
103 const SkMatrix& matrix, const SkPaint&) SK_OVERRIDE;
104 void drawSprite(const SkDraw&, const SkBitmap& bitmap, int x, int y,
105 const SkPaint& paint) SK_OVERRIDE;
106 void drawText(const SkDraw&, const void* text, size_t len,
107 SkScalar x, SkScalar y, const SkPaint&) SK_OVERRIDE;
108 void drawPosText(const SkDraw&, const void* text, size_t len,
109 const SkScalar pos[], int scalarsPerPos,
110 const SkPoint& offset, const SkPaint&) SK_OVERRIDE;
tfarinafa4f6cb2014-12-21 10:27:07 -0800111 void drawVertices(const SkDraw&, SkCanvas::VertexMode,
112 int vertexCount, const SkPoint verts[],
113 const SkPoint texs[], const SkColor colors[],
114 SkXfermode* xmode, const uint16_t indices[],
115 int indexCount, const SkPaint& paint) SK_OVERRIDE;
116 void drawDevice(const SkDraw&, SkBaseDevice*, int x, int y,
117 const SkPaint&) SK_OVERRIDE;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000118
tfarinafa4f6cb2014-12-21 10:27:07 -0800119 void onAttachToCanvas(SkCanvas* canvas) SK_OVERRIDE;
120 void onDetachFromCanvas() SK_OVERRIDE;
121 SkImageInfo imageInfo() const SK_OVERRIDE;
robertphillips@google.com40a1ae42012-07-13 15:36:15 +0000122
ctguil@chromium.org8dcf74f2011-07-12 21:56:27 +0000123 enum DrawingArea {
ctguil@chromium.org9510ccc2011-07-27 00:10:51 +0000124 kContent_DrawingArea, // Drawing area for the page content.
125 kMargin_DrawingArea, // Drawing area for the margin content.
ctguil@chromium.org8dcf74f2011-07-12 21:56:27 +0000126 };
127
128 /** Sets the drawing area for the device. Subsequent draw calls are directed
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000129 * to the specific drawing area (margin or content). The default drawing
ctguil@chromium.org8dcf74f2011-07-12 21:56:27 +0000130 * area is the content drawing area.
ctguil@chromium.org9510ccc2011-07-27 00:10:51 +0000131 *
132 * Currently if margin content is drawn and then a complex (for PDF) xfer
133 * mode is used, like SrcIn, Clear, etc, the margin content will get
134 * clipped. A simple way to avoid the bug is to always draw the margin
135 * content last.
ctguil@chromium.org8dcf74f2011-07-12 21:56:27 +0000136 */
halcanary4e4e8162015-02-25 08:59:48 -0800137 void setDrawingArea(DrawingArea drawingArea);
ctguil@chromium.org8dcf74f2011-07-12 21:56:27 +0000138
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000139 // PDF specific methods.
140
reed@google.com1feb3302011-07-20 18:43:19 +0000141 /** Returns the resource dictionary for this device.
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000142 */
halcanary4e4e8162015-02-25 08:59:48 -0800143 SkPDFResourceDict* getResourceDict();
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000144
vandebo@chromium.orgf0ec2662011-05-29 05:55:42 +0000145 /** Get the fonts used on this device.
146 */
halcanary4e4e8162015-02-25 08:59:48 -0800147 const SkTDArray<SkPDFFont*>& getFontResources() const;
vandebo@chromium.orgf0ec2662011-05-29 05:55:42 +0000148
epoger@google.comb58772f2013-03-08 09:09:10 +0000149 /** Add our named destinations to the supplied dictionary.
150 * @param dict Dictionary to add destinations to.
151 * @param page The PDF object representing the page for this device.
152 */
153 void appendDestinations(SkPDFDict* dict, SkPDFObject* page);
154
reed@google.com2a006c12012-09-19 17:05:55 +0000155 /** Returns a copy of the media box for this device. The caller is required
156 * to unref() this when it is finished.
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000157 */
halcanary4e4e8162015-02-25 08:59:48 -0800158 SkPDFArray* copyMediaBox() const;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000159
reed@google.com2a006c12012-09-19 17:05:55 +0000160 /** Get the annotations from this page, or NULL if there are none.
vandebo@chromium.org238be8c2012-07-13 20:06:02 +0000161 */
halcanary4e4e8162015-02-25 08:59:48 -0800162 SkPDFArray* getAnnotations() const { return fAnnotations; }
vandebo@chromium.org238be8c2012-07-13 20:06:02 +0000163
vandebo@chromium.orgc2a9b7f2011-02-24 23:22:30 +0000164 /** Returns a SkStream with the page contents. The caller is responsible
halcanary4e4e8162015-02-25 08:59:48 -0800165 * for a deleting the returned value.
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000166 */
halcanary4e4e8162015-02-25 08:59:48 -0800167 SkStreamAsset* content() const;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000168
halcanary334fcbc2015-02-24 12:56:16 -0800169 /** Writes the page contents to the stream. */
halcanary4e4e8162015-02-25 08:59:48 -0800170 void writeContent(SkWStream*) const;
vandebo@chromium.org98594282011-07-25 22:34:12 +0000171
halcanary4e4e8162015-02-25 08:59:48 -0800172 const SkMatrix& initialTransform() const {
vandebo@chromium.org3509f052011-05-30 20:52:33 +0000173 return fInitialTransform;
174 }
vandebo@chromium.org61d26782011-05-24 23:02:07 +0000175
vandebo@chromium.org98594282011-07-25 22:34:12 +0000176 /** Returns a SkPDFGlyphSetMap which represents glyph usage of every font
177 * that shows on this device.
178 */
179 const SkPDFGlyphSetMap& getFontGlyphUsage() const {
180 return *(fFontGlyphUsage.get());
181 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000182
edisonn@google.com73a7ea32013-11-11 20:55:15 +0000183protected:
mtklein72c9faa2015-01-09 10:06:39 -0800184 const SkBitmap& onAccessBitmap() SK_OVERRIDE {
reed89443ab2014-06-27 11:34:19 -0700185 return fLegacyBitmap;
186 }
187
mtklein72c9faa2015-01-09 10:06:39 -0800188 SkSurface* newSurface(const SkImageInfo&, const SkSurfaceProps&) SK_OVERRIDE;
edisonn@google.com73a7ea32013-11-11 20:55:15 +0000189
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000190private:
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000191 // TODO(vandebo): push most of SkPDFDevice's state into a core object in
vandebo@chromium.orgb069c8c2011-05-24 17:19:38 +0000192 // order to get the right access levels without using friend.
vandebo@chromium.org13d14a92011-05-24 23:12:41 +0000193 friend class ScopedContentEntry;
vandebo@chromium.orga0c7edb2011-05-09 07:58:08 +0000194
ctguil@chromium.org15261292011-04-29 17:54:16 +0000195 SkISize fPageSize;
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +0000196 SkISize fContentSize;
vandebo@chromium.org75f97e42011-04-11 23:24:18 +0000197 SkMatrix fInitialTransform;
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +0000198 SkClipStack fExistingClipStack;
199 SkRegion fExistingClipRegion;
reed@google.com2a006c12012-09-19 17:05:55 +0000200 SkPDFArray* fAnnotations;
commit-bot@chromium.org47401352013-07-23 21:49:29 +0000201 SkPDFResourceDict* fResourceDict;
epoger@google.comb58772f2013-03-08 09:09:10 +0000202 SkTDArray<NamedDestination*> fNamedDestinations;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000203
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000204 SkTDArray<SkPDFGraphicState*> fGraphicStateResources;
205 SkTDArray<SkPDFObject*> fXObjectResources;
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000206 SkTDArray<SkPDFFont*> fFontResources;
vandebo@chromium.org421d6442011-07-20 17:39:01 +0000207 SkTDArray<SkPDFObject*> fShaderResources;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000208
commit-bot@chromium.orge0294402013-08-29 22:14:04 +0000209 SkAutoTDelete<ContentEntry> fContentEntries;
vandebo@chromium.orgb069c8c2011-05-24 17:19:38 +0000210 ContentEntry* fLastContentEntry;
commit-bot@chromium.orge0294402013-08-29 22:14:04 +0000211 SkAutoTDelete<ContentEntry> fMarginContentEntries;
ctguil@chromium.org8dcf74f2011-07-12 21:56:27 +0000212 ContentEntry* fLastMarginContentEntry;
213 DrawingArea fDrawingArea;
214
robertphillips@google.com40a1ae42012-07-13 15:36:15 +0000215 const SkClipStack* fClipStack;
216
ctguil@chromium.org8dcf74f2011-07-12 21:56:27 +0000217 // Accessor and setter functions based on the current DrawingArea.
commit-bot@chromium.orge0294402013-08-29 22:14:04 +0000218 SkAutoTDelete<ContentEntry>* getContentEntries();
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000219
vandebo@chromium.org98594282011-07-25 22:34:12 +0000220 // Glyph ids used for each font on this device.
commit-bot@chromium.orge0294402013-08-29 22:14:04 +0000221 SkAutoTDelete<SkPDFGlyphSetMap> fFontGlyphUsage;
vandebo@chromium.org98594282011-07-25 22:34:12 +0000222
commit-bot@chromium.org8c294902013-10-21 17:14:37 +0000223 SkScalar fRasterDpi;
edisonn@google.comd9dfa182013-04-24 13:01:01 +0000224
reed89443ab2014-06-27 11:34:19 -0700225 SkBitmap fLegacyBitmap;
226
halcanarya1f1ee92015-02-20 06:17:26 -0800227 SkPDFCanon* fCanon; // Owned by SkDocument_PDF
228 ////////////////////////////////////////////////////////////////////////////
229
230 SkPDFDevice(SkISize pageSize,
231 SkScalar rasterDpi,
232 SkPDFCanon* canon,
233 bool flip);
234
235 ContentEntry* getLastContentEntry();
236 void setLastContentEntry(ContentEntry* contentEntry);
vandebo@chromium.orga0c7edb2011-05-09 07:58:08 +0000237
reed0e040f72015-03-13 07:28:28 -0700238 // override from SkBaseDevice
239 SkBaseDevice* onCreateCompatibleDevice(const CreateInfo&) SK_OVERRIDE;
bsalomon@google.come97f0852011-06-17 13:10:25 +0000240
vandebo@chromium.org77bcaa32011-04-15 20:57:37 +0000241 void init();
vandebo@chromium.org98594282011-07-25 22:34:12 +0000242 void cleanUp(bool clearFontUsage);
reed@google.comfc641d02012-09-20 17:52:20 +0000243 SkPDFFormXObject* createFormXObjectFromDevice();
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +0000244
vandebo@chromium.org3b416212013-10-30 20:48:05 +0000245 void drawFormXObjectWithMask(int xObjectIndex,
246 SkPDFFormXObject* mask,
vandebo@chromium.org481aef62011-05-24 16:39:05 +0000247 const SkClipStack* clipStack,
248 const SkRegion& clipRegion,
vandebo@chromium.org3b416212013-10-30 20:48:05 +0000249 SkXfermode::Mode mode,
vandebo@chromium.org481aef62011-05-24 16:39:05 +0000250 bool invertClip);
vandebo@chromium.org466f3d62011-05-18 23:06:29 +0000251
vandebo@chromium.orgb069c8c2011-05-24 17:19:38 +0000252 // If the paint or clip is such that we shouldn't draw anything, this
253 // returns NULL and does not create a content entry.
254 // setUpContentEntry and finishContentEntry can be used directly, but
vandebo@chromium.org13d14a92011-05-24 23:12:41 +0000255 // the preferred method is to use the ScopedContentEntry helper class.
vandebo@chromium.orgb069c8c2011-05-24 17:19:38 +0000256 ContentEntry* setUpContentEntry(const SkClipStack* clipStack,
257 const SkRegion& clipRegion,
258 const SkMatrix& matrix,
259 const SkPaint& paint,
260 bool hasText,
reed@google.comfc641d02012-09-20 17:52:20 +0000261 SkPDFFormXObject** dst);
vandebo@chromium.orgb069c8c2011-05-24 17:19:38 +0000262 void finishContentEntry(SkXfermode::Mode xfermode,
vandebo@chromium.org3b416212013-10-30 20:48:05 +0000263 SkPDFFormXObject* dst,
264 SkPath* shape);
vandebo@chromium.org481aef62011-05-24 16:39:05 +0000265 bool isContentEmpty();
266
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +0000267 void populateGraphicStateEntryFromPaint(const SkMatrix& matrix,
268 const SkClipStack& clipStack,
269 const SkRegion& clipRegion,
270 const SkPaint& paint,
271 bool hasText,
272 GraphicStateEntry* entry);
vandebo@chromium.org6112c212011-05-13 03:50:38 +0000273 int addGraphicStateResource(SkPDFGraphicState* gs);
vandebo@chromium.org3b416212013-10-30 20:48:05 +0000274 int addXObjectResource(SkPDFObject* xObject);
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +0000275
vandebo@chromium.orgb069c8c2011-05-24 17:19:38 +0000276 void updateFont(const SkPaint& paint, uint16_t glyphID,
277 ContentEntry* contentEntry);
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000278 int getFontResourceIndex(SkTypeface* typeface, uint16_t glyphID);
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000279
vandebo@chromium.orgb069c8c2011-05-24 17:19:38 +0000280 void internalDrawPaint(const SkPaint& paint, ContentEntry* contentEntry);
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +0000281 void internalDrawBitmap(const SkMatrix& matrix,
vandebo@chromium.org78dad542011-05-11 18:46:03 +0000282 const SkClipStack* clipStack,
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +0000283 const SkRegion& clipRegion,
284 const SkBitmap& bitmap,
285 const SkIRect* srcRect,
286 const SkPaint& paint);
287
ctguil@chromium.org8dcf74f2011-07-12 21:56:27 +0000288 /** Helper method for copyContentToData. It is responsible for copying the
289 * list of content entries |entry| to |data|.
290 */
291 void copyContentEntriesToData(ContentEntry* entry, SkWStream* data) const;
ctguil@chromium.org9510ccc2011-07-27 00:10:51 +0000292
commit-bot@chromium.orgd2623a12013-08-08 02:52:05 +0000293#ifdef SK_PDF_USE_PATHOPS
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,
296 const SkMatrix* prePathMatrix = NULL);
commit-bot@chromium.orgd2623a12013-08-08 02:52:05 +0000297#endif
epoger@google.comb58772f2013-03-08 09:09:10 +0000298 bool handleRectAnnotation(const SkRect& r, const SkMatrix& matrix,
299 const SkPaint& paint);
300 bool handlePointAnnotation(const SkPoint* points, size_t count,
301 const SkMatrix& matrix, const SkPaint& paint);
302 SkPDFDict* createLinkAnnotation(const SkRect& r, const SkMatrix& matrix);
303 void handleLinkToURL(SkData* urlData, const SkRect& r,
304 const SkMatrix& matrix);
305 void handleLinkToNamedDest(SkData* nameData, const SkRect& r,
306 const SkMatrix& matrix);
307 void defineNamedDestination(SkData* nameData, const SkPoint& point,
308 const SkMatrix& matrix);
vandebo@chromium.org238be8c2012-07-13 20:06:02 +0000309
reed89443ab2014-06-27 11:34:19 -0700310 typedef SkBaseDevice INHERITED;
commit-bot@chromium.org5e009892013-10-14 13:42:12 +0000311
312 // TODO(edisonn): Only SkDocument_PDF and SkPDFImageShader should be able to create
313 // an SkPDFDevice
314 //friend class SkDocument_PDF;
315 //friend class SkPDFImageShader;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000316};
317
318#endif