SkPDFDevice.h revision 562fe4767cc73e08a4e039362bc0336aea66ecfb
1 2/* 3 * Copyright 2011 Google Inc. 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 9 10#ifndef SkPDFDevice_DEFINED 11#define SkPDFDevice_DEFINED 12 13#include "SkDevice.h" 14#include "SkBitmap.h" 15#include "SkCanvas.h" 16#include "SkPaint.h" 17#include "SkPath.h" 18#include "SkPicture.h" 19#include "SkRect.h" 20#include "SkRefCnt.h" 21#include "SkStream.h" 22#include "SkTDArray.h" 23#include "SkTemplates.h" 24 25class SkPDFArray; 26class SkPDFCanon; 27class SkPDFDevice; 28class SkPDFDict; 29class SkPDFFont; 30class SkPDFFormXObject; 31class SkPDFGlyphSetMap; 32class SkPDFGraphicState; 33class SkPDFObject; 34class SkPDFShader; 35class SkPDFStream; 36class SkRRect; 37 38// Private classes. 39struct ContentEntry; 40struct GraphicStateEntry; 41struct NamedDestination; 42 43/** \class SkPDFDevice 44 45 The drawing context for the PDF backend. 46*/ 47class SkPDFDevice : public SkBaseDevice { 48public: 49 /** 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. 65 */ 66 static SkPDFDevice* Create(SkISize pageSize, 67 SkScalar rasterDpi, 68 SkPDFCanon* canon) { 69 return SkNEW_ARGS(SkPDFDevice, (pageSize, rasterDpi, canon, true)); 70 } 71 72 /** Create a PDF drawing context without fipping the y-axis. */ 73 static SkPDFDevice* CreateUnflipped(SkISize pageSize, 74 SkScalar rasterDpi, 75 SkPDFCanon* canon) { 76 return SkNEW_ARGS(SkPDFDevice, (pageSize, rasterDpi, canon, false)); 77 } 78 79 virtual ~SkPDFDevice(); 80 81 /** 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 */ 86 void drawPaint(const SkDraw&, const SkPaint& paint) override; 87 void drawPoints(const SkDraw&, SkCanvas::PointMode mode, 88 size_t count, const SkPoint[], 89 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; 93 void drawPath(const SkDraw&, const SkPath& origpath, 94 const SkPaint& paint, const SkMatrix* prePathMatrix, 95 bool pathIsMutable) override; 96 void drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap, const SkRect* src, 97 const SkRect& dst, const SkPaint&, SkCanvas::SrcRectConstraint) override; 98 void drawBitmap(const SkDraw&, const SkBitmap& bitmap, 99 const SkMatrix& matrix, const SkPaint&) override; 100 void drawSprite(const SkDraw&, const SkBitmap& bitmap, int x, int y, 101 const SkPaint& paint) override; 102 void drawText(const SkDraw&, const void* text, size_t len, 103 SkScalar x, SkScalar y, const SkPaint&) override; 104 void drawPosText(const SkDraw&, const void* text, size_t len, 105 const SkScalar pos[], int scalarsPerPos, 106 const SkPoint& offset, const SkPaint&) override; 107 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[], 111 int indexCount, const SkPaint& paint) override; 112 void drawDevice(const SkDraw&, SkBaseDevice*, int x, int y, 113 const SkPaint&) override; 114 115 void onAttachToCanvas(SkCanvas* canvas) override; 116 void onDetachFromCanvas() override; 117 SkImageInfo imageInfo() const override; 118 119 enum DrawingArea { 120 kContent_DrawingArea, // Drawing area for the page content. 121 kMargin_DrawingArea, // Drawing area for the margin content. 122 }; 123 124 /** Sets the drawing area for the device. Subsequent draw calls are directed 125 * to the specific drawing area (margin or content). The default drawing 126 * area is the content drawing area. 127 * 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. 132 */ 133 void setDrawingArea(DrawingArea drawingArea); 134 135 // PDF specific methods. 136 137 /** Create the resource dictionary for this device. 138 */ 139 SkPDFDict* createResourceDict() const; 140 141 /** Get the fonts used on this device. 142 */ 143 const SkTDArray<SkPDFFont*>& getFontResources() const; 144 145 /** Add our named destinations to the supplied dictionary. 146 * @param dict Dictionary to add destinations to. 147 * @param page The PDF object representing the page for this device. 148 */ 149 void appendDestinations(SkPDFDict* dict, SkPDFObject* page) const; 150 151 /** Returns a copy of the media box for this device. The caller is required 152 * to unref() this when it is finished. 153 */ 154 SkPDFArray* copyMediaBox() const; 155 156 /** Get the annotations from this page, or NULL if there are none. 157 */ 158 SkPDFArray* getAnnotations() const { return fAnnotations; } 159 160 /** Returns a SkStream with the page contents. The caller is responsible 161 * for a deleting the returned value. 162 */ 163 SkStreamAsset* content() const; 164 165 /** Writes the page contents to the stream. */ 166 void writeContent(SkWStream*) const; 167 168 const SkMatrix& initialTransform() const { 169 return fInitialTransform; 170 } 171 172 /** Returns a SkPDFGlyphSetMap which represents glyph usage of every font 173 * that shows on this device. 174 */ 175 const SkPDFGlyphSetMap& getFontGlyphUsage() const { 176 return *(fFontGlyphUsage.get()); 177 } 178 179#ifdef SK_DEBUG 180 SkPDFCanon* getCanon() const { return fCanon; } 181#endif // SK_DEBUG 182 183protected: 184 const SkBitmap& onAccessBitmap() override { 185 return fLegacyBitmap; 186 } 187 188 SkSurface* newSurface(const SkImageInfo&, const SkSurfaceProps&) override; 189 190private: 191 // TODO(vandebo): push most of SkPDFDevice's state into a core object in 192 // order to get the right access levels without using friend. 193 friend class ScopedContentEntry; 194 195 SkISize fPageSize; 196 SkISize fContentSize; 197 SkMatrix fInitialTransform; 198 SkClipStack fExistingClipStack; 199 SkRegion fExistingClipRegion; 200 SkPDFArray* fAnnotations; 201 SkTDArray<NamedDestination*> fNamedDestinations; 202 203 SkTDArray<SkPDFObject*> fGraphicStateResources; 204 SkTDArray<SkPDFObject*> fXObjectResources; 205 SkTDArray<SkPDFFont*> fFontResources; 206 SkTDArray<SkPDFObject*> fShaderResources; 207 208 SkAutoTDelete<ContentEntry> fContentEntries; 209 ContentEntry* fLastContentEntry; 210 SkAutoTDelete<ContentEntry> fMarginContentEntries; 211 ContentEntry* fLastMarginContentEntry; 212 DrawingArea fDrawingArea; 213 214 const SkClipStack* fClipStack; 215 216 // Accessor and setter functions based on the current DrawingArea. 217 SkAutoTDelete<ContentEntry>* getContentEntries(); 218 219 // Glyph ids used for each font on this device. 220 SkAutoTDelete<SkPDFGlyphSetMap> fFontGlyphUsage; 221 222 SkScalar fRasterDpi; 223 224 SkBitmap fLegacyBitmap; 225 226 SkPDFCanon* fCanon; // Owned by SkDocument_PDF 227 //////////////////////////////////////////////////////////////////////////// 228 229 SkPDFDevice(SkISize pageSize, 230 SkScalar rasterDpi, 231 SkPDFCanon* canon, 232 bool flip); 233 234 ContentEntry* getLastContentEntry(); 235 void setLastContentEntry(ContentEntry* contentEntry); 236 237 SkBaseDevice* onCreateDevice(const CreateInfo&, const SkPaint*) override; 238 239 void init(); 240 void cleanUp(bool clearFontUsage); 241 SkPDFFormXObject* createFormXObjectFromDevice(); 242 243 void drawFormXObjectWithMask(int xObjectIndex, 244 SkPDFFormXObject* mask, 245 const SkClipStack* clipStack, 246 const SkRegion& clipRegion, 247 SkXfermode::Mode mode, 248 bool invertClip); 249 250 // If the paint or clip is such that we shouldn't draw anything, this 251 // returns NULL and does not create a content entry. 252 // setUpContentEntry and finishContentEntry can be used directly, but 253 // the preferred method is to use the ScopedContentEntry helper class. 254 ContentEntry* setUpContentEntry(const SkClipStack* clipStack, 255 const SkRegion& clipRegion, 256 const SkMatrix& matrix, 257 const SkPaint& paint, 258 bool hasText, 259 SkPDFFormXObject** dst); 260 void finishContentEntry(SkXfermode::Mode xfermode, 261 SkPDFFormXObject* dst, 262 SkPath* shape); 263 bool isContentEmpty(); 264 265 void populateGraphicStateEntryFromPaint(const SkMatrix& matrix, 266 const SkClipStack& clipStack, 267 const SkRegion& clipRegion, 268 const SkPaint& paint, 269 bool hasText, 270 GraphicStateEntry* entry); 271 int addGraphicStateResource(SkPDFObject* gs); 272 int addXObjectResource(SkPDFObject* xObject); 273 274 void updateFont(const SkPaint& paint, uint16_t glyphID, ContentEntry* contentEntry); 275 int getFontResourceIndex(SkTypeface* typeface, uint16_t glyphID); 276 277 void internalDrawPaint(const SkPaint& paint, ContentEntry* contentEntry); 278 void internalDrawBitmap(const SkMatrix& matrix, 279 const SkClipStack* clipStack, 280 const SkRegion& clipRegion, 281 const SkBitmap& bitmap, 282 const SkIRect* srcRect, 283 const SkPaint& paint); 284 285 /** Helper method for copyContentToData. It is responsible for copying the 286 * list of content entries |entry| to |data|. 287 */ 288 void copyContentEntriesToData(ContentEntry* entry, SkWStream* data) const; 289 290 bool handleInversePath(const SkDraw& d, const SkPath& origPath, 291 const SkPaint& paint, bool pathIsMutable, 292 const SkMatrix* prePathMatrix = NULL); 293 bool handlePointAnnotation(const SkPoint* points, size_t count, 294 const SkMatrix& matrix, SkAnnotation* annot); 295 void addAnnotation(SkPDFDict*); 296 297 typedef SkBaseDevice INHERITED; 298 299 // TODO(edisonn): Only SkDocument_PDF and SkPDFImageShader should be able to create 300 // an SkPDFDevice 301 //friend class SkDocument_PDF; 302 //friend class SkPDFImageShader; 303}; 304 305#endif 306