blob: fbd5fb3c9cf1fdafb632bfffbbe4069f1a69c919 [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;
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +000041
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000042/** \class SkPDFDevice
43
44 The drawing context for the PDF backend.
45*/
reed89443ab2014-06-27 11:34:19 -070046class SkPDFDevice : public SkBaseDevice {
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000047public:
halcanarya1f1ee92015-02-20 06:17:26 -080048 /** Create a PDF drawing context. SkPDFDevice applies a
49 * scale-and-translate transform to move the origin from the
50 * bottom left (PDF default) to the top left (Skia default).
51 * @param pageSize Page size in point units.
52 * 1 point == 127/360 mm == 1/72 inch
53 * @param rasterDpi the DPI at which features without native PDF
54 * support will be rasterized (e.g. draw image with
55 * perspective, draw text with perspective, ...). A
56 * larger DPI would create a PDF that reflects the
57 * original intent with better fidelity, but it can make
58 * for larger PDF files too, which would use more memory
59 * while rendering, and it would be slower to be processed
60 * or sent online or to printer. A good choice is
61 * SK_ScalarDefaultRasterDPI(72.0f).
62 * @param SkPDFCanon. Should be non-null, and shared by all
63 * devices in a document.
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000064 */
halcanarya1f1ee92015-02-20 06:17:26 -080065 static SkPDFDevice* Create(SkISize pageSize,
66 SkScalar rasterDpi,
67 SkPDFCanon* canon) {
halcanary385fe4d2015-08-26 13:07:48 -070068 return new SkPDFDevice(pageSize, rasterDpi, canon, true);
halcanarya1f1ee92015-02-20 06:17:26 -080069 }
70
71 /** Create a PDF drawing context without fipping the y-axis. */
72 static SkPDFDevice* CreateUnflipped(SkISize pageSize,
73 SkScalar rasterDpi,
74 SkPDFCanon* canon) {
halcanary385fe4d2015-08-26 13:07:48 -070075 return new SkPDFDevice(pageSize, rasterDpi, canon, false);
halcanarya1f1ee92015-02-20 06:17:26 -080076 }
77
78 virtual ~SkPDFDevice();
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000079
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000080 /** These are called inside the per-device-layer loop for each draw call.
81 When these are called, we have already applied any saveLayer operations,
82 and are handling any looping from the paint, and any effects from the
83 DrawFilter.
84 */
mtklein36352bf2015-03-25 18:17:31 -070085 void drawPaint(const SkDraw&, const SkPaint& paint) override;
tfarinafa4f6cb2014-12-21 10:27:07 -080086 void drawPoints(const SkDraw&, SkCanvas::PointMode mode,
87 size_t count, const SkPoint[],
mtklein36352bf2015-03-25 18:17:31 -070088 const SkPaint& paint) override;
89 void drawRect(const SkDraw&, const SkRect& r, const SkPaint& paint) override;
90 void drawOval(const SkDraw&, const SkRect& oval, const SkPaint& paint) override;
91 void drawRRect(const SkDraw&, const SkRRect& rr, const SkPaint& paint) override;
tfarinafa4f6cb2014-12-21 10:27:07 -080092 void drawPath(const SkDraw&, const SkPath& origpath,
93 const SkPaint& paint, const SkMatrix* prePathMatrix,
mtklein36352bf2015-03-25 18:17:31 -070094 bool pathIsMutable) override;
reed562fe472015-07-28 07:35:14 -070095 void drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap, const SkRect* src,
96 const SkRect& dst, const SkPaint&, SkCanvas::SrcRectConstraint) override;
tfarinafa4f6cb2014-12-21 10:27:07 -080097 void drawBitmap(const SkDraw&, const SkBitmap& bitmap,
mtklein36352bf2015-03-25 18:17:31 -070098 const SkMatrix& matrix, const SkPaint&) override;
tfarinafa4f6cb2014-12-21 10:27:07 -080099 void drawSprite(const SkDraw&, const SkBitmap& bitmap, int x, int y,
mtklein36352bf2015-03-25 18:17:31 -0700100 const SkPaint& paint) override;
tfarinafa4f6cb2014-12-21 10:27:07 -0800101 void drawText(const SkDraw&, const void* text, size_t len,
mtklein36352bf2015-03-25 18:17:31 -0700102 SkScalar x, SkScalar y, const SkPaint&) override;
tfarinafa4f6cb2014-12-21 10:27:07 -0800103 void drawPosText(const SkDraw&, const void* text, size_t len,
104 const SkScalar pos[], int scalarsPerPos,
mtklein36352bf2015-03-25 18:17:31 -0700105 const SkPoint& offset, const SkPaint&) override;
tfarinafa4f6cb2014-12-21 10:27:07 -0800106 void drawVertices(const SkDraw&, SkCanvas::VertexMode,
107 int vertexCount, const SkPoint verts[],
108 const SkPoint texs[], const SkColor colors[],
109 SkXfermode* xmode, const uint16_t indices[],
mtklein36352bf2015-03-25 18:17:31 -0700110 int indexCount, const SkPaint& paint) override;
tfarinafa4f6cb2014-12-21 10:27:07 -0800111 void drawDevice(const SkDraw&, SkBaseDevice*, int x, int y,
mtklein36352bf2015-03-25 18:17:31 -0700112 const SkPaint&) override;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000113
mtklein36352bf2015-03-25 18:17:31 -0700114 void onAttachToCanvas(SkCanvas* canvas) override;
115 void onDetachFromCanvas() override;
116 SkImageInfo imageInfo() const override;
robertphillips@google.com40a1ae42012-07-13 15:36:15 +0000117
ctguil@chromium.org8dcf74f2011-07-12 21:56:27 +0000118 enum DrawingArea {
ctguil@chromium.org9510ccc2011-07-27 00:10:51 +0000119 kContent_DrawingArea, // Drawing area for the page content.
120 kMargin_DrawingArea, // Drawing area for the margin content.
ctguil@chromium.org8dcf74f2011-07-12 21:56:27 +0000121 };
122
123 /** Sets the drawing area for the device. Subsequent draw calls are directed
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000124 * to the specific drawing area (margin or content). The default drawing
ctguil@chromium.org8dcf74f2011-07-12 21:56:27 +0000125 * area is the content drawing area.
ctguil@chromium.org9510ccc2011-07-27 00:10:51 +0000126 *
127 * Currently if margin content is drawn and then a complex (for PDF) xfer
128 * mode is used, like SrcIn, Clear, etc, the margin content will get
129 * clipped. A simple way to avoid the bug is to always draw the margin
130 * content last.
ctguil@chromium.org8dcf74f2011-07-12 21:56:27 +0000131 */
halcanary4e4e8162015-02-25 08:59:48 -0800132 void setDrawingArea(DrawingArea drawingArea);
ctguil@chromium.org8dcf74f2011-07-12 21:56:27 +0000133
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000134 // PDF specific methods.
135
halcanary6d622702015-03-25 08:45:42 -0700136 /** Create the resource dictionary for this device.
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000137 */
halcanary2b861552015-04-09 13:27:40 -0700138 SkPDFDict* createResourceDict() const;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000139
vandebo@chromium.orgf0ec2662011-05-29 05:55:42 +0000140 /** Get the fonts used on this device.
141 */
halcanary4e4e8162015-02-25 08:59:48 -0800142 const SkTDArray<SkPDFFont*>& getFontResources() const;
vandebo@chromium.orgf0ec2662011-05-29 05:55:42 +0000143
epoger@google.comb58772f2013-03-08 09:09:10 +0000144 /** Add our named destinations to the supplied dictionary.
145 * @param dict Dictionary to add destinations to.
146 * @param page The PDF object representing the page for this device.
147 */
halcanary6d622702015-03-25 08:45:42 -0700148 void appendDestinations(SkPDFDict* dict, SkPDFObject* page) const;
epoger@google.comb58772f2013-03-08 09:09:10 +0000149
reed@google.com2a006c12012-09-19 17:05:55 +0000150 /** Returns a copy of the media box for this device. The caller is required
151 * to unref() this when it is finished.
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000152 */
halcanary4e4e8162015-02-25 08:59:48 -0800153 SkPDFArray* copyMediaBox() const;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000154
halcanary96fcdcc2015-08-27 07:41:13 -0700155 /** Get the annotations from this page, or nullptr if there are none.
vandebo@chromium.org238be8c2012-07-13 20:06:02 +0000156 */
halcanary4e4e8162015-02-25 08:59:48 -0800157 SkPDFArray* getAnnotations() const { return fAnnotations; }
vandebo@chromium.org238be8c2012-07-13 20:06:02 +0000158
vandebo@chromium.orgc2a9b7f2011-02-24 23:22:30 +0000159 /** Returns a SkStream with the page contents. The caller is responsible
halcanary4e4e8162015-02-25 08:59:48 -0800160 * for a deleting the returned value.
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000161 */
halcanary4e4e8162015-02-25 08:59:48 -0800162 SkStreamAsset* content() const;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000163
halcanary334fcbc2015-02-24 12:56:16 -0800164 /** Writes the page contents to the stream. */
halcanary4e4e8162015-02-25 08:59:48 -0800165 void writeContent(SkWStream*) const;
vandebo@chromium.org98594282011-07-25 22:34:12 +0000166
halcanary4e4e8162015-02-25 08:59:48 -0800167 const SkMatrix& initialTransform() const {
vandebo@chromium.org3509f052011-05-30 20:52:33 +0000168 return fInitialTransform;
169 }
vandebo@chromium.org61d26782011-05-24 23:02:07 +0000170
vandebo@chromium.org98594282011-07-25 22:34:12 +0000171 /** Returns a SkPDFGlyphSetMap which represents glyph usage of every font
172 * that shows on this device.
173 */
174 const SkPDFGlyphSetMap& getFontGlyphUsage() const {
175 return *(fFontGlyphUsage.get());
176 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000177
halcanary26b5d152015-03-25 08:38:03 -0700178#ifdef SK_DEBUG
179 SkPDFCanon* getCanon() const { return fCanon; }
180#endif // SK_DEBUG
181
edisonn@google.com73a7ea32013-11-11 20:55:15 +0000182protected:
mtklein36352bf2015-03-25 18:17:31 -0700183 const SkBitmap& onAccessBitmap() override {
reed89443ab2014-06-27 11:34:19 -0700184 return fLegacyBitmap;
185 }
186
mtklein36352bf2015-03-25 18:17:31 -0700187 SkSurface* newSurface(const SkImageInfo&, const SkSurfaceProps&) override;
edisonn@google.com73a7ea32013-11-11 20:55:15 +0000188
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000189private:
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000190 // TODO(vandebo): push most of SkPDFDevice's state into a core object in
vandebo@chromium.orgb069c8c2011-05-24 17:19:38 +0000191 // order to get the right access levels without using friend.
vandebo@chromium.org13d14a92011-05-24 23:12:41 +0000192 friend class ScopedContentEntry;
vandebo@chromium.orga0c7edb2011-05-09 07:58:08 +0000193
ctguil@chromium.org15261292011-04-29 17:54:16 +0000194 SkISize fPageSize;
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +0000195 SkISize fContentSize;
vandebo@chromium.org75f97e42011-04-11 23:24:18 +0000196 SkMatrix fInitialTransform;
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +0000197 SkClipStack fExistingClipStack;
198 SkRegion fExistingClipRegion;
reed@google.com2a006c12012-09-19 17:05:55 +0000199 SkPDFArray* fAnnotations;
epoger@google.comb58772f2013-03-08 09:09:10 +0000200 SkTDArray<NamedDestination*> fNamedDestinations;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000201
halcanarybe27a112015-04-01 13:31:19 -0700202 SkTDArray<SkPDFObject*> fGraphicStateResources;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000203 SkTDArray<SkPDFObject*> fXObjectResources;
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000204 SkTDArray<SkPDFFont*> fFontResources;
vandebo@chromium.org421d6442011-07-20 17:39:01 +0000205 SkTDArray<SkPDFObject*> fShaderResources;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000206
commit-bot@chromium.orge0294402013-08-29 22:14:04 +0000207 SkAutoTDelete<ContentEntry> fContentEntries;
vandebo@chromium.orgb069c8c2011-05-24 17:19:38 +0000208 ContentEntry* fLastContentEntry;
commit-bot@chromium.orge0294402013-08-29 22:14:04 +0000209 SkAutoTDelete<ContentEntry> fMarginContentEntries;
ctguil@chromium.org8dcf74f2011-07-12 21:56:27 +0000210 ContentEntry* fLastMarginContentEntry;
211 DrawingArea fDrawingArea;
212
robertphillips@google.com40a1ae42012-07-13 15:36:15 +0000213 const SkClipStack* fClipStack;
214
ctguil@chromium.org8dcf74f2011-07-12 21:56:27 +0000215 // Accessor and setter functions based on the current DrawingArea.
commit-bot@chromium.orge0294402013-08-29 22:14:04 +0000216 SkAutoTDelete<ContentEntry>* getContentEntries();
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000217
vandebo@chromium.org98594282011-07-25 22:34:12 +0000218 // Glyph ids used for each font on this device.
commit-bot@chromium.orge0294402013-08-29 22:14:04 +0000219 SkAutoTDelete<SkPDFGlyphSetMap> fFontGlyphUsage;
vandebo@chromium.org98594282011-07-25 22:34:12 +0000220
commit-bot@chromium.org8c294902013-10-21 17:14:37 +0000221 SkScalar fRasterDpi;
edisonn@google.comd9dfa182013-04-24 13:01:01 +0000222
reed89443ab2014-06-27 11:34:19 -0700223 SkBitmap fLegacyBitmap;
224
halcanarya1f1ee92015-02-20 06:17:26 -0800225 SkPDFCanon* fCanon; // Owned by SkDocument_PDF
226 ////////////////////////////////////////////////////////////////////////////
227
228 SkPDFDevice(SkISize pageSize,
229 SkScalar rasterDpi,
230 SkPDFCanon* canon,
231 bool flip);
232
233 ContentEntry* getLastContentEntry();
234 void setLastContentEntry(ContentEntry* contentEntry);
vandebo@chromium.orga0c7edb2011-05-09 07:58:08 +0000235
mtklein36352bf2015-03-25 18:17:31 -0700236 SkBaseDevice* onCreateDevice(const CreateInfo&, const SkPaint*) override;
bsalomon@google.come97f0852011-06-17 13:10:25 +0000237
vandebo@chromium.org77bcaa32011-04-15 20:57:37 +0000238 void init();
vandebo@chromium.org98594282011-07-25 22:34:12 +0000239 void cleanUp(bool clearFontUsage);
reed@google.comfc641d02012-09-20 17:52:20 +0000240 SkPDFFormXObject* createFormXObjectFromDevice();
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +0000241
vandebo@chromium.org3b416212013-10-30 20:48:05 +0000242 void drawFormXObjectWithMask(int xObjectIndex,
243 SkPDFFormXObject* mask,
vandebo@chromium.org481aef62011-05-24 16:39:05 +0000244 const SkClipStack* clipStack,
245 const SkRegion& clipRegion,
vandebo@chromium.org3b416212013-10-30 20:48:05 +0000246 SkXfermode::Mode mode,
vandebo@chromium.org481aef62011-05-24 16:39:05 +0000247 bool invertClip);
vandebo@chromium.org466f3d62011-05-18 23:06:29 +0000248
vandebo@chromium.orgb069c8c2011-05-24 17:19:38 +0000249 // If the paint or clip is such that we shouldn't draw anything, this
halcanary96fcdcc2015-08-27 07:41:13 -0700250 // returns nullptr and does not create a content entry.
vandebo@chromium.orgb069c8c2011-05-24 17:19:38 +0000251 // setUpContentEntry and finishContentEntry can be used directly, but
vandebo@chromium.org13d14a92011-05-24 23:12:41 +0000252 // the preferred method is to use the ScopedContentEntry helper class.
vandebo@chromium.orgb069c8c2011-05-24 17:19:38 +0000253 ContentEntry* setUpContentEntry(const SkClipStack* clipStack,
254 const SkRegion& clipRegion,
255 const SkMatrix& matrix,
256 const SkPaint& paint,
257 bool hasText,
reed@google.comfc641d02012-09-20 17:52:20 +0000258 SkPDFFormXObject** dst);
vandebo@chromium.orgb069c8c2011-05-24 17:19:38 +0000259 void finishContentEntry(SkXfermode::Mode xfermode,
vandebo@chromium.org3b416212013-10-30 20:48:05 +0000260 SkPDFFormXObject* dst,
261 SkPath* shape);
vandebo@chromium.org481aef62011-05-24 16:39:05 +0000262 bool isContentEmpty();
263
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +0000264 void populateGraphicStateEntryFromPaint(const SkMatrix& matrix,
265 const SkClipStack& clipStack,
266 const SkRegion& clipRegion,
267 const SkPaint& paint,
268 bool hasText,
269 GraphicStateEntry* entry);
halcanarybe27a112015-04-01 13:31:19 -0700270 int addGraphicStateResource(SkPDFObject* gs);
vandebo@chromium.org3b416212013-10-30 20:48:05 +0000271 int addXObjectResource(SkPDFObject* xObject);
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +0000272
robertphillips8e0c1502015-07-07 10:28:43 -0700273 void updateFont(const SkPaint& paint, uint16_t glyphID, ContentEntry* contentEntry);
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000274 int getFontResourceIndex(SkTypeface* typeface, uint16_t glyphID);
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000275
vandebo@chromium.orgb069c8c2011-05-24 17:19:38 +0000276 void internalDrawPaint(const SkPaint& paint, ContentEntry* contentEntry);
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +0000277 void internalDrawBitmap(const SkMatrix& matrix,
vandebo@chromium.org78dad542011-05-11 18:46:03 +0000278 const SkClipStack* clipStack,
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +0000279 const SkRegion& clipRegion,
280 const SkBitmap& bitmap,
281 const SkIRect* srcRect,
282 const SkPaint& paint);
283
ctguil@chromium.org8dcf74f2011-07-12 21:56:27 +0000284 /** Helper method for copyContentToData. It is responsible for copying the
285 * list of content entries |entry| to |data|.
286 */
287 void copyContentEntriesToData(ContentEntry* entry, SkWStream* data) const;
ctguil@chromium.org9510ccc2011-07-27 00:10:51 +0000288
commit-bot@chromium.org92ffe7d2013-07-31 22:54:31 +0000289 bool handleInversePath(const SkDraw& d, const SkPath& origPath,
edisonn@google.coma9ebd162013-10-07 13:22:21 +0000290 const SkPaint& paint, bool pathIsMutable,
halcanary96fcdcc2015-08-27 07:41:13 -0700291 const SkMatrix* prePathMatrix = nullptr);
epoger@google.comb58772f2013-03-08 09:09:10 +0000292 bool handlePointAnnotation(const SkPoint* points, size_t count,
wangxianzhud76665d2015-07-17 17:23:15 -0700293 const SkMatrix& matrix, SkAnnotation* annot);
halcanary438de492015-04-28 06:21:01 -0700294 void addAnnotation(SkPDFDict*);
vandebo@chromium.org238be8c2012-07-13 20:06:02 +0000295
reed89443ab2014-06-27 11:34:19 -0700296 typedef SkBaseDevice INHERITED;
commit-bot@chromium.org5e009892013-10-14 13:42:12 +0000297
298 // TODO(edisonn): Only SkDocument_PDF and SkPDFImageShader should be able to create
299 // an SkPDFDevice
300 //friend class SkDocument_PDF;
301 //friend class SkPDFImageShader;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000302};
303
304#endif