SkPDFDevice.h revision 334fcbc167237f02058cb508cb5f51b718141461
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 SkPDFResourceDict; 35class SkPDFShader; 36class SkPDFStream; 37class SkRRect; 38template <typename T> class SkTSet; 39 40// Private classes. 41struct ContentEntry; 42struct GraphicStateEntry; 43struct NamedDestination; 44 45/** \class SkPDFDevice 46 47 The drawing context for the PDF backend. 48*/ 49class SkPDFDevice : public SkBaseDevice { 50public: 51 /** 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. 67 */ 68 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(); 82 83 /** 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 */ 88 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; 111 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; 118 119 void onAttachToCanvas(SkCanvas* canvas) SK_OVERRIDE; 120 void onDetachFromCanvas() SK_OVERRIDE; 121 SkImageInfo imageInfo() const SK_OVERRIDE; 122 123 enum DrawingArea { 124 kContent_DrawingArea, // Drawing area for the page content. 125 kMargin_DrawingArea, // Drawing area for the margin content. 126 }; 127 128 /** Sets the drawing area for the device. Subsequent draw calls are directed 129 * to the specific drawing area (margin or content). The default drawing 130 * area is the content drawing area. 131 * 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. 136 */ 137 SK_API void setDrawingArea(DrawingArea drawingArea); 138 139 // PDF specific methods. 140 141 /** Returns the resource dictionary for this device. 142 */ 143 SK_API SkPDFResourceDict* getResourceDict(); 144 145 /** Get the fonts used on this device. 146 */ 147 SK_API const SkTDArray<SkPDFFont*>& getFontResources() const; 148 149 /** 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 155 /** Returns a copy of the media box for this device. The caller is required 156 * to unref() this when it is finished. 157 */ 158 SK_API SkPDFArray* copyMediaBox() const; 159 160 /** Get the annotations from this page, or NULL if there are none. 161 */ 162 SK_API SkPDFArray* getAnnotations() const { return fAnnotations; } 163 164 /** Returns a SkStream with the page contents. The caller is responsible 165 for a deleting the returned value. 166 */ 167 SK_API SkStreamAsset* content() const; 168 169 /** Writes the page contents to the stream. */ 170 SK_API void writeContent(SkWStream*) const; 171 172 SK_API const SkMatrix& initialTransform() const { 173 return fInitialTransform; 174 } 175 176 /** 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 } 182 183protected: 184 const SkBitmap& onAccessBitmap() SK_OVERRIDE { 185 return fLegacyBitmap; 186 } 187 188 SkSurface* newSurface(const SkImageInfo&, const SkSurfaceProps&) SK_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 SkPDFResourceDict* fResourceDict; 202 SkTDArray<NamedDestination*> fNamedDestinations; 203 204 SkTDArray<SkPDFGraphicState*> fGraphicStateResources; 205 SkTDArray<SkPDFObject*> fXObjectResources; 206 SkTDArray<SkPDFFont*> fFontResources; 207 SkTDArray<SkPDFObject*> fShaderResources; 208 209 SkAutoTDelete<ContentEntry> fContentEntries; 210 ContentEntry* fLastContentEntry; 211 SkAutoTDelete<ContentEntry> fMarginContentEntries; 212 ContentEntry* fLastMarginContentEntry; 213 DrawingArea fDrawingArea; 214 215 const SkClipStack* fClipStack; 216 217 // Accessor and setter functions based on the current DrawingArea. 218 SkAutoTDelete<ContentEntry>* getContentEntries(); 219 220 // Glyph ids used for each font on this device. 221 SkAutoTDelete<SkPDFGlyphSetMap> fFontGlyphUsage; 222 223 SkScalar fRasterDpi; 224 225 SkBitmap fLegacyBitmap; 226 227 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); 237 238 // override from SkBaseDevice 239 SkBaseDevice* onCreateCompatibleDevice(const CreateInfo&) SK_OVERRIDE; 240 241 void init(); 242 void cleanUp(bool clearFontUsage); 243 SkPDFFormXObject* createFormXObjectFromDevice(); 244 245 void drawFormXObjectWithMask(int xObjectIndex, 246 SkPDFFormXObject* mask, 247 const SkClipStack* clipStack, 248 const SkRegion& clipRegion, 249 SkXfermode::Mode mode, 250 bool invertClip); 251 252 // 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 255 // the preferred method is to use the ScopedContentEntry helper class. 256 ContentEntry* setUpContentEntry(const SkClipStack* clipStack, 257 const SkRegion& clipRegion, 258 const SkMatrix& matrix, 259 const SkPaint& paint, 260 bool hasText, 261 SkPDFFormXObject** dst); 262 void finishContentEntry(SkXfermode::Mode xfermode, 263 SkPDFFormXObject* dst, 264 SkPath* shape); 265 bool isContentEmpty(); 266 267 void populateGraphicStateEntryFromPaint(const SkMatrix& matrix, 268 const SkClipStack& clipStack, 269 const SkRegion& clipRegion, 270 const SkPaint& paint, 271 bool hasText, 272 GraphicStateEntry* entry); 273 int addGraphicStateResource(SkPDFGraphicState* gs); 274 int addXObjectResource(SkPDFObject* xObject); 275 276 void updateFont(const SkPaint& paint, uint16_t glyphID, 277 ContentEntry* contentEntry); 278 int getFontResourceIndex(SkTypeface* typeface, uint16_t glyphID); 279 280 void internalDrawPaint(const SkPaint& paint, ContentEntry* contentEntry); 281 void internalDrawBitmap(const SkMatrix& matrix, 282 const SkClipStack* clipStack, 283 const SkRegion& clipRegion, 284 const SkBitmap& bitmap, 285 const SkIRect* srcRect, 286 const SkPaint& paint); 287 288 /** 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; 292 293#ifdef SK_PDF_USE_PATHOPS 294 bool handleInversePath(const SkDraw& d, const SkPath& origPath, 295 const SkPaint& paint, bool pathIsMutable, 296 const SkMatrix* prePathMatrix = NULL); 297#endif 298 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); 309 310 typedef SkBaseDevice INHERITED; 311 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; 316}; 317 318#endif 319