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 25 class SkPDFArray; 26 class SkPDFCanon; 27 class SkPDFDevice; 28 class SkPDFDict; 29 class SkPDFFont; 30 class SkPDFFormXObject; 31 class SkPDFGlyphSetMap; 32 class SkPDFGraphicState; 33 class SkPDFObject; 34 class SkPDFShader; 35 class SkPDFStream; 36 class SkRRect; 37 38 // Private classes. 39 struct ContentEntry; 40 struct GraphicStateEntry; 41 struct NamedDestination; 42 43 /** \class SkPDFDevice 44 45 The drawing context for the PDF backend. 46 */ 47 class SkPDFDevice : public SkBaseDevice { 48 public: 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 */ Create(SkISize pageSize,SkScalar rasterDpi,SkPDFCanon * canon)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. */ CreateUnflipped(SkISize pageSize,SkScalar rasterDpi,SkPDFCanon * canon)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, 97 const SkRect* src, const SkRect& dst, 98 const SkPaint& paint, 99 SkCanvas::DrawBitmapRectFlags flags) override; 100 void drawBitmap(const SkDraw&, const SkBitmap& bitmap, 101 const SkMatrix& matrix, const SkPaint&) override; 102 void drawSprite(const SkDraw&, const SkBitmap& bitmap, int x, int y, 103 const SkPaint& paint) override; 104 void drawText(const SkDraw&, const void* text, size_t len, 105 SkScalar x, SkScalar y, const SkPaint&) override; 106 void drawPosText(const SkDraw&, const void* text, size_t len, 107 const SkScalar pos[], int scalarsPerPos, 108 const SkPoint& offset, const SkPaint&) override; 109 void drawVertices(const SkDraw&, SkCanvas::VertexMode, 110 int vertexCount, const SkPoint verts[], 111 const SkPoint texs[], const SkColor colors[], 112 SkXfermode* xmode, const uint16_t indices[], 113 int indexCount, const SkPaint& paint) override; 114 void drawDevice(const SkDraw&, SkBaseDevice*, int x, int y, 115 const SkPaint&) override; 116 117 void onAttachToCanvas(SkCanvas* canvas) override; 118 void onDetachFromCanvas() override; 119 SkImageInfo imageInfo() const override; 120 121 enum DrawingArea { 122 kContent_DrawingArea, // Drawing area for the page content. 123 kMargin_DrawingArea, // Drawing area for the margin content. 124 }; 125 126 /** Sets the drawing area for the device. Subsequent draw calls are directed 127 * to the specific drawing area (margin or content). The default drawing 128 * area is the content drawing area. 129 * 130 * Currently if margin content is drawn and then a complex (for PDF) xfer 131 * mode is used, like SrcIn, Clear, etc, the margin content will get 132 * clipped. A simple way to avoid the bug is to always draw the margin 133 * content last. 134 */ 135 void setDrawingArea(DrawingArea drawingArea); 136 137 // PDF specific methods. 138 139 /** Create the resource dictionary for this device. 140 */ 141 SkPDFDict* createResourceDict() const; 142 143 /** Get the fonts used on this device. 144 */ 145 const SkTDArray<SkPDFFont*>& getFontResources() const; 146 147 /** Add our named destinations to the supplied dictionary. 148 * @param dict Dictionary to add destinations to. 149 * @param page The PDF object representing the page for this device. 150 */ 151 void appendDestinations(SkPDFDict* dict, SkPDFObject* page) const; 152 153 /** Returns a copy of the media box for this device. The caller is required 154 * to unref() this when it is finished. 155 */ 156 SkPDFArray* copyMediaBox() const; 157 158 /** Get the annotations from this page, or NULL if there are none. 159 */ getAnnotations()160 SkPDFArray* getAnnotations() const { return fAnnotations; } 161 162 /** Returns a SkStream with the page contents. The caller is responsible 163 * for a deleting the returned value. 164 */ 165 SkStreamAsset* content() const; 166 167 /** Writes the page contents to the stream. */ 168 void writeContent(SkWStream*) const; 169 initialTransform()170 const SkMatrix& initialTransform() const { 171 return fInitialTransform; 172 } 173 174 /** Returns a SkPDFGlyphSetMap which represents glyph usage of every font 175 * that shows on this device. 176 */ getFontGlyphUsage()177 const SkPDFGlyphSetMap& getFontGlyphUsage() const { 178 return *(fFontGlyphUsage.get()); 179 } 180 181 #ifdef SK_DEBUG getCanon()182 SkPDFCanon* getCanon() const { return fCanon; } 183 #endif // SK_DEBUG 184 185 protected: onAccessBitmap()186 const SkBitmap& onAccessBitmap() override { 187 return fLegacyBitmap; 188 } 189 190 SkSurface* newSurface(const SkImageInfo&, const SkSurfaceProps&) override; 191 192 private: 193 // TODO(vandebo): push most of SkPDFDevice's state into a core object in 194 // order to get the right access levels without using friend. 195 friend class ScopedContentEntry; 196 197 SkISize fPageSize; 198 SkISize fContentSize; 199 SkMatrix fInitialTransform; 200 SkClipStack fExistingClipStack; 201 SkRegion fExistingClipRegion; 202 SkPDFArray* fAnnotations; 203 SkTDArray<NamedDestination*> fNamedDestinations; 204 205 SkTDArray<SkPDFObject*> fGraphicStateResources; 206 SkTDArray<SkPDFObject*> fXObjectResources; 207 SkTDArray<SkPDFFont*> fFontResources; 208 SkTDArray<SkPDFObject*> fShaderResources; 209 210 SkAutoTDelete<ContentEntry> fContentEntries; 211 ContentEntry* fLastContentEntry; 212 SkAutoTDelete<ContentEntry> fMarginContentEntries; 213 ContentEntry* fLastMarginContentEntry; 214 DrawingArea fDrawingArea; 215 216 const SkClipStack* fClipStack; 217 218 // Accessor and setter functions based on the current DrawingArea. 219 SkAutoTDelete<ContentEntry>* getContentEntries(); 220 221 // Glyph ids used for each font on this device. 222 SkAutoTDelete<SkPDFGlyphSetMap> fFontGlyphUsage; 223 224 SkScalar fRasterDpi; 225 226 SkBitmap fLegacyBitmap; 227 228 SkPDFCanon* fCanon; // Owned by SkDocument_PDF 229 //////////////////////////////////////////////////////////////////////////// 230 231 SkPDFDevice(SkISize pageSize, 232 SkScalar rasterDpi, 233 SkPDFCanon* canon, 234 bool flip); 235 236 ContentEntry* getLastContentEntry(); 237 void setLastContentEntry(ContentEntry* contentEntry); 238 239 SkBaseDevice* onCreateDevice(const CreateInfo&, const SkPaint*) 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(SkPDFObject* 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 bool handleInversePath(const SkDraw& d, const SkPath& origPath, 294 const SkPaint& paint, bool pathIsMutable, 295 const SkMatrix* prePathMatrix = NULL); 296 bool handleRectAnnotation(const SkRect& r, const SkMatrix& matrix, 297 const SkPaint& paint); 298 bool handlePointAnnotation(const SkPoint* points, size_t count, 299 const SkMatrix& matrix, const SkPaint& paint); 300 void addAnnotation(SkPDFDict*); 301 void handleLinkToURL(SkData* urlData, const SkRect& r, 302 const SkMatrix& matrix); 303 void handleLinkToNamedDest(SkData* nameData, const SkRect& r, 304 const SkMatrix& matrix); 305 void defineNamedDestination(SkData* nameData, const SkPoint& point, 306 const SkMatrix& matrix); 307 308 typedef SkBaseDevice INHERITED; 309 310 // TODO(edisonn): Only SkDocument_PDF and SkPDFImageShader should be able to create 311 // an SkPDFDevice 312 //friend class SkDocument_PDF; 313 //friend class SkPDFImageShader; 314 }; 315 316 #endif 317