blob: 31f6de11eefd7b561d247a722d4391772f30d82d [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*/
halcanary70d15542015-11-22 12:55:04 -080047class SkPDFDevice final : 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;
halcanary7a14b312015-10-01 07:28:13 -0700102 void drawImage(const SkDraw&,
103 const SkImage*,
104 SkScalar x,
105 SkScalar y,
106 const SkPaint&) override;
107 void drawImageRect(const SkDraw&,
108 const SkImage*,
109 const SkRect* src,
110 const SkRect& dst,
111 const SkPaint&,
112 SkCanvas::SrcRectConstraint) override;
tfarinafa4f6cb2014-12-21 10:27:07 -0800113 void drawText(const SkDraw&, const void* text, size_t len,
mtklein36352bf2015-03-25 18:17:31 -0700114 SkScalar x, SkScalar y, const SkPaint&) override;
tfarinafa4f6cb2014-12-21 10:27:07 -0800115 void drawPosText(const SkDraw&, const void* text, size_t len,
116 const SkScalar pos[], int scalarsPerPos,
mtklein36352bf2015-03-25 18:17:31 -0700117 const SkPoint& offset, const SkPaint&) override;
tfarinafa4f6cb2014-12-21 10:27:07 -0800118 void drawVertices(const SkDraw&, SkCanvas::VertexMode,
119 int vertexCount, const SkPoint verts[],
120 const SkPoint texs[], const SkColor colors[],
121 SkXfermode* xmode, const uint16_t indices[],
mtklein36352bf2015-03-25 18:17:31 -0700122 int indexCount, const SkPaint& paint) override;
tfarinafa4f6cb2014-12-21 10:27:07 -0800123 void drawDevice(const SkDraw&, SkBaseDevice*, int x, int y,
mtklein36352bf2015-03-25 18:17:31 -0700124 const SkPaint&) override;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000125
mtklein36352bf2015-03-25 18:17:31 -0700126 void onAttachToCanvas(SkCanvas* canvas) override;
127 void onDetachFromCanvas() override;
128 SkImageInfo imageInfo() const override;
robertphillips@google.com40a1ae42012-07-13 15:36:15 +0000129
ctguil@chromium.org8dcf74f2011-07-12 21:56:27 +0000130 enum DrawingArea {
ctguil@chromium.org9510ccc2011-07-27 00:10:51 +0000131 kContent_DrawingArea, // Drawing area for the page content.
132 kMargin_DrawingArea, // Drawing area for the margin content.
ctguil@chromium.org8dcf74f2011-07-12 21:56:27 +0000133 };
134
135 /** Sets the drawing area for the device. Subsequent draw calls are directed
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000136 * to the specific drawing area (margin or content). The default drawing
ctguil@chromium.org8dcf74f2011-07-12 21:56:27 +0000137 * area is the content drawing area.
ctguil@chromium.org9510ccc2011-07-27 00:10:51 +0000138 *
139 * Currently if margin content is drawn and then a complex (for PDF) xfer
140 * mode is used, like SrcIn, Clear, etc, the margin content will get
141 * clipped. A simple way to avoid the bug is to always draw the margin
142 * content last.
ctguil@chromium.org8dcf74f2011-07-12 21:56:27 +0000143 */
halcanary4e4e8162015-02-25 08:59:48 -0800144 void setDrawingArea(DrawingArea drawingArea);
ctguil@chromium.org8dcf74f2011-07-12 21:56:27 +0000145
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000146 // PDF specific methods.
147
halcanary6d622702015-03-25 08:45:42 -0700148 /** Create the resource dictionary for this device.
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000149 */
halcanary2b861552015-04-09 13:27:40 -0700150 SkPDFDict* createResourceDict() const;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000151
vandebo@chromium.orgf0ec2662011-05-29 05:55:42 +0000152 /** Get the fonts used on this device.
153 */
halcanary4e4e8162015-02-25 08:59:48 -0800154 const SkTDArray<SkPDFFont*>& getFontResources() const;
vandebo@chromium.orgf0ec2662011-05-29 05:55:42 +0000155
wangxianzhuef6c50a2015-09-17 20:38:02 -0700156 /** Add our annotations (link to urls and destinations) to the supplied
157 * array.
158 * @param array Array to add annotations to.
159 */
160 void appendAnnotations(SkPDFArray* array) const;
161
epoger@google.comb58772f2013-03-08 09:09:10 +0000162 /** Add our named destinations to the supplied dictionary.
163 * @param dict Dictionary to add destinations to.
164 * @param page The PDF object representing the page for this device.
165 */
halcanary6d622702015-03-25 08:45:42 -0700166 void appendDestinations(SkPDFDict* dict, SkPDFObject* page) const;
epoger@google.comb58772f2013-03-08 09:09:10 +0000167
reed@google.com2a006c12012-09-19 17:05:55 +0000168 /** Returns a copy of the media box for this device. The caller is required
169 * to unref() this when it is finished.
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000170 */
halcanary4e4e8162015-02-25 08:59:48 -0800171 SkPDFArray* copyMediaBox() const;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000172
vandebo@chromium.orgc2a9b7f2011-02-24 23:22:30 +0000173 /** Returns a SkStream with the page contents. The caller is responsible
halcanary4e4e8162015-02-25 08:59:48 -0800174 * for a deleting the returned value.
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000175 */
halcanary4e4e8162015-02-25 08:59:48 -0800176 SkStreamAsset* content() const;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000177
halcanary334fcbc2015-02-24 12:56:16 -0800178 /** Writes the page contents to the stream. */
halcanary4e4e8162015-02-25 08:59:48 -0800179 void writeContent(SkWStream*) const;
vandebo@chromium.org98594282011-07-25 22:34:12 +0000180
halcanary4e4e8162015-02-25 08:59:48 -0800181 const SkMatrix& initialTransform() const {
vandebo@chromium.org3509f052011-05-30 20:52:33 +0000182 return fInitialTransform;
183 }
vandebo@chromium.org61d26782011-05-24 23:02:07 +0000184
vandebo@chromium.org98594282011-07-25 22:34:12 +0000185 /** Returns a SkPDFGlyphSetMap which represents glyph usage of every font
186 * that shows on this device.
187 */
188 const SkPDFGlyphSetMap& getFontGlyphUsage() const {
189 return *(fFontGlyphUsage.get());
190 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000191
halcanary26b5d152015-03-25 08:38:03 -0700192 SkPDFCanon* getCanon() const { return fCanon; }
halcanary26b5d152015-03-25 08:38:03 -0700193
edisonn@google.com73a7ea32013-11-11 20:55:15 +0000194protected:
mtklein36352bf2015-03-25 18:17:31 -0700195 const SkBitmap& onAccessBitmap() override {
reed89443ab2014-06-27 11:34:19 -0700196 return fLegacyBitmap;
197 }
198
mtklein36352bf2015-03-25 18:17:31 -0700199 SkSurface* newSurface(const SkImageInfo&, const SkSurfaceProps&) override;
edisonn@google.com73a7ea32013-11-11 20:55:15 +0000200
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000201private:
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000202 // TODO(vandebo): push most of SkPDFDevice's state into a core object in
vandebo@chromium.orgb069c8c2011-05-24 17:19:38 +0000203 // order to get the right access levels without using friend.
vandebo@chromium.org13d14a92011-05-24 23:12:41 +0000204 friend class ScopedContentEntry;
vandebo@chromium.orga0c7edb2011-05-09 07:58:08 +0000205
ctguil@chromium.org15261292011-04-29 17:54:16 +0000206 SkISize fPageSize;
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +0000207 SkISize fContentSize;
vandebo@chromium.org75f97e42011-04-11 23:24:18 +0000208 SkMatrix fInitialTransform;
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +0000209 SkClipStack fExistingClipStack;
210 SkRegion fExistingClipRegion;
wangxianzhuef6c50a2015-09-17 20:38:02 -0700211
212 SkTDArray<RectWithData*> fLinkToURLs;
213 SkTDArray<RectWithData*> fLinkToDestinations;
epoger@google.comb58772f2013-03-08 09:09:10 +0000214 SkTDArray<NamedDestination*> fNamedDestinations;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000215
halcanarybe27a112015-04-01 13:31:19 -0700216 SkTDArray<SkPDFObject*> fGraphicStateResources;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000217 SkTDArray<SkPDFObject*> fXObjectResources;
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000218 SkTDArray<SkPDFFont*> fFontResources;
vandebo@chromium.org421d6442011-07-20 17:39:01 +0000219 SkTDArray<SkPDFObject*> fShaderResources;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000220
commit-bot@chromium.orge0294402013-08-29 22:14:04 +0000221 SkAutoTDelete<ContentEntry> fContentEntries;
vandebo@chromium.orgb069c8c2011-05-24 17:19:38 +0000222 ContentEntry* fLastContentEntry;
commit-bot@chromium.orge0294402013-08-29 22:14:04 +0000223 SkAutoTDelete<ContentEntry> fMarginContentEntries;
ctguil@chromium.org8dcf74f2011-07-12 21:56:27 +0000224 ContentEntry* fLastMarginContentEntry;
225 DrawingArea fDrawingArea;
226
robertphillips@google.com40a1ae42012-07-13 15:36:15 +0000227 const SkClipStack* fClipStack;
228
ctguil@chromium.org8dcf74f2011-07-12 21:56:27 +0000229 // Accessor and setter functions based on the current DrawingArea.
commit-bot@chromium.orge0294402013-08-29 22:14:04 +0000230 SkAutoTDelete<ContentEntry>* getContentEntries();
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000231
vandebo@chromium.org98594282011-07-25 22:34:12 +0000232 // Glyph ids used for each font on this device.
commit-bot@chromium.orge0294402013-08-29 22:14:04 +0000233 SkAutoTDelete<SkPDFGlyphSetMap> fFontGlyphUsage;
vandebo@chromium.org98594282011-07-25 22:34:12 +0000234
commit-bot@chromium.org8c294902013-10-21 17:14:37 +0000235 SkScalar fRasterDpi;
edisonn@google.comd9dfa182013-04-24 13:01:01 +0000236
reed89443ab2014-06-27 11:34:19 -0700237 SkBitmap fLegacyBitmap;
238
halcanarya1f1ee92015-02-20 06:17:26 -0800239 SkPDFCanon* fCanon; // Owned by SkDocument_PDF
240 ////////////////////////////////////////////////////////////////////////////
241
242 SkPDFDevice(SkISize pageSize,
243 SkScalar rasterDpi,
244 SkPDFCanon* canon,
245 bool flip);
246
247 ContentEntry* getLastContentEntry();
248 void setLastContentEntry(ContentEntry* contentEntry);
vandebo@chromium.orga0c7edb2011-05-09 07:58:08 +0000249
mtklein36352bf2015-03-25 18:17:31 -0700250 SkBaseDevice* onCreateDevice(const CreateInfo&, const SkPaint*) override;
bsalomon@google.come97f0852011-06-17 13:10:25 +0000251
vandebo@chromium.org77bcaa32011-04-15 20:57:37 +0000252 void init();
vandebo@chromium.org98594282011-07-25 22:34:12 +0000253 void cleanUp(bool clearFontUsage);
reed@google.comfc641d02012-09-20 17:52:20 +0000254 SkPDFFormXObject* createFormXObjectFromDevice();
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +0000255
vandebo@chromium.org3b416212013-10-30 20:48:05 +0000256 void drawFormXObjectWithMask(int xObjectIndex,
257 SkPDFFormXObject* mask,
vandebo@chromium.org481aef62011-05-24 16:39:05 +0000258 const SkClipStack* clipStack,
259 const SkRegion& clipRegion,
vandebo@chromium.org3b416212013-10-30 20:48:05 +0000260 SkXfermode::Mode mode,
vandebo@chromium.org481aef62011-05-24 16:39:05 +0000261 bool invertClip);
vandebo@chromium.org466f3d62011-05-18 23:06:29 +0000262
vandebo@chromium.orgb069c8c2011-05-24 17:19:38 +0000263 // If the paint or clip is such that we shouldn't draw anything, this
halcanary96fcdcc2015-08-27 07:41:13 -0700264 // returns nullptr and does not create a content entry.
vandebo@chromium.orgb069c8c2011-05-24 17:19:38 +0000265 // setUpContentEntry and finishContentEntry can be used directly, but
vandebo@chromium.org13d14a92011-05-24 23:12:41 +0000266 // the preferred method is to use the ScopedContentEntry helper class.
vandebo@chromium.orgb069c8c2011-05-24 17:19:38 +0000267 ContentEntry* setUpContentEntry(const SkClipStack* clipStack,
268 const SkRegion& clipRegion,
269 const SkMatrix& matrix,
270 const SkPaint& paint,
271 bool hasText,
reed@google.comfc641d02012-09-20 17:52:20 +0000272 SkPDFFormXObject** dst);
vandebo@chromium.orgb069c8c2011-05-24 17:19:38 +0000273 void finishContentEntry(SkXfermode::Mode xfermode,
vandebo@chromium.org3b416212013-10-30 20:48:05 +0000274 SkPDFFormXObject* dst,
275 SkPath* shape);
vandebo@chromium.org481aef62011-05-24 16:39:05 +0000276 bool isContentEmpty();
277
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +0000278 void populateGraphicStateEntryFromPaint(const SkMatrix& matrix,
279 const SkClipStack& clipStack,
280 const SkRegion& clipRegion,
281 const SkPaint& paint,
282 bool hasText,
283 GraphicStateEntry* entry);
halcanarybe27a112015-04-01 13:31:19 -0700284 int addGraphicStateResource(SkPDFObject* gs);
vandebo@chromium.org3b416212013-10-30 20:48:05 +0000285 int addXObjectResource(SkPDFObject* xObject);
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +0000286
robertphillips8e0c1502015-07-07 10:28:43 -0700287 void updateFont(const SkPaint& paint, uint16_t glyphID, ContentEntry* contentEntry);
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000288 int getFontResourceIndex(SkTypeface* typeface, uint16_t glyphID);
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000289
vandebo@chromium.orgb069c8c2011-05-24 17:19:38 +0000290 void internalDrawPaint(const SkPaint& paint, ContentEntry* contentEntry);
halcanary7a14b312015-10-01 07:28:13 -0700291 void internalDrawImage(const SkMatrix& matrix,
292 const SkClipStack* clipStack,
293 const SkRegion& clipRegion,
294 const SkImage* image,
295 const SkIRect* srcRect,
296 const SkPaint& paint);
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +0000297
ctguil@chromium.org8dcf74f2011-07-12 21:56:27 +0000298 /** Helper method for copyContentToData. It is responsible for copying the
299 * list of content entries |entry| to |data|.
300 */
301 void copyContentEntriesToData(ContentEntry* entry, SkWStream* data) const;
ctguil@chromium.org9510ccc2011-07-27 00:10:51 +0000302
commit-bot@chromium.org92ffe7d2013-07-31 22:54:31 +0000303 bool handleInversePath(const SkDraw& d, const SkPath& origPath,
edisonn@google.coma9ebd162013-10-07 13:22:21 +0000304 const SkPaint& paint, bool pathIsMutable,
halcanary96fcdcc2015-08-27 07:41:13 -0700305 const SkMatrix* prePathMatrix = nullptr);
epoger@google.comb58772f2013-03-08 09:09:10 +0000306 bool handlePointAnnotation(const SkPoint* points, size_t count,
wangxianzhud76665d2015-07-17 17:23:15 -0700307 const SkMatrix& matrix, SkAnnotation* annot);
wangxianzhuef6c50a2015-09-17 20:38:02 -0700308 bool handlePathAnnotation(const SkPath& path, const SkDraw& d,
309 SkAnnotation* annot);
vandebo@chromium.org238be8c2012-07-13 20:06:02 +0000310
reed89443ab2014-06-27 11:34:19 -0700311 typedef SkBaseDevice INHERITED;
commit-bot@chromium.org5e009892013-10-14 13:42:12 +0000312
313 // TODO(edisonn): Only SkDocument_PDF and SkPDFImageShader should be able to create
314 // an SkPDFDevice
315 //friend class SkDocument_PDF;
316 //friend class SkPDFImageShader;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000317};
318
319#endif