1 /* 2 * Copyright 2011 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #ifndef SkPDFDevice_DEFINED 9 #define SkPDFDevice_DEFINED 10 11 #include "SkBitmap.h" 12 #include "SkCanvas.h" 13 #include "SkClipStack.h" 14 #include "SkDevice.h" 15 #include "SkPaint.h" 16 #include "SkPath.h" 17 #include "SkPicture.h" 18 #include "SkRect.h" 19 #include "SkRefCnt.h" 20 #include "SkStream.h" 21 #include "SkTDArray.h" 22 #include "SkTemplates.h" 23 24 class SkPDFArray; 25 class SkPDFCanon; 26 class SkPDFDevice; 27 class SkPDFDict; 28 class SkPDFFont; 29 class SkPDFFormXObject; 30 class SkPDFGlyphSetMap; 31 class SkPDFGraphicState; 32 class SkPDFObject; 33 class SkPDFShader; 34 class SkPDFStream; 35 class SkRRect; 36 37 // Private classes. 38 struct ContentEntry; 39 struct GraphicStateEntry; 40 struct NamedDestination; 41 struct RectWithData; 42 43 /** \class SkPDFDevice 44 45 The drawing context for the PDF backend. 46 */ 47 class SkPDFDevice final : 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 */ 66 static SkPDFDevice* Create(SkISize pageSize, 67 SkScalar rasterDpi, 68 SkPDFCanon* canon) { 69 return new 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 new 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 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; 113 void drawText(const SkDraw&, const void* text, size_t len, 114 SkScalar x, SkScalar y, const SkPaint&) override; 115 void drawPosText(const SkDraw&, const void* text, size_t len, 116 const SkScalar pos[], int scalarsPerPos, 117 const SkPoint& offset, const SkPaint&) override; 118 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[], 122 int indexCount, const SkPaint& paint) override; 123 void drawDevice(const SkDraw&, SkBaseDevice*, int x, int y, 124 const SkPaint&) override; 125 126 void onAttachToCanvas(SkCanvas* canvas) override; 127 void onDetachFromCanvas() override; 128 SkImageInfo imageInfo() const override; 129 130 enum DrawingArea { 131 kContent_DrawingArea, // Drawing area for the page content. 132 kMargin_DrawingArea, // Drawing area for the margin content. 133 }; 134 135 /** Sets the drawing area for the device. Subsequent draw calls are directed 136 * to the specific drawing area (margin or content). The default drawing 137 * area is the content drawing area. 138 * 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. 143 */ 144 void setDrawingArea(DrawingArea drawingArea); 145 146 // PDF specific methods. 147 148 /** Create the resource dictionary for this device. 149 */ 150 SkPDFDict* createResourceDict() const; 151 152 /** Get the fonts used on this device. 153 */ 154 const SkTDArray<SkPDFFont*>& getFontResources() const; 155 156 /** 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 162 /** 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 */ 166 void appendDestinations(SkPDFDict* dict, SkPDFObject* page) const; 167 168 /** Returns a copy of the media box for this device. The caller is required 169 * to unref() this when it is finished. 170 */ 171 SkPDFArray* copyMediaBox() const; 172 173 /** Returns a SkStream with the page contents. The caller is responsible 174 * for a deleting the returned value. 175 */ 176 SkStreamAsset* content() const; 177 178 /** Writes the page contents to the stream. */ 179 void writeContent(SkWStream*) const; 180 181 const SkMatrix& initialTransform() const { 182 return fInitialTransform; 183 } 184 185 /** 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 } 191 192 SkPDFCanon* getCanon() const { return fCanon; } 193 194 protected: 195 const SkBitmap& onAccessBitmap() override { 196 return fLegacyBitmap; 197 } 198 199 SkSurface* newSurface(const SkImageInfo&, const SkSurfaceProps&) override; 200 201 private: 202 // TODO(vandebo): push most of SkPDFDevice's state into a core object in 203 // order to get the right access levels without using friend. 204 friend class ScopedContentEntry; 205 206 SkISize fPageSize; 207 SkISize fContentSize; 208 SkMatrix fInitialTransform; 209 SkClipStack fExistingClipStack; 210 SkRegion fExistingClipRegion; 211 212 SkTDArray<RectWithData*> fLinkToURLs; 213 SkTDArray<RectWithData*> fLinkToDestinations; 214 SkTDArray<NamedDestination*> fNamedDestinations; 215 216 SkTDArray<SkPDFObject*> fGraphicStateResources; 217 SkTDArray<SkPDFObject*> fXObjectResources; 218 SkTDArray<SkPDFFont*> fFontResources; 219 SkTDArray<SkPDFObject*> fShaderResources; 220 221 SkAutoTDelete<ContentEntry> fContentEntries; 222 ContentEntry* fLastContentEntry; 223 SkAutoTDelete<ContentEntry> fMarginContentEntries; 224 ContentEntry* fLastMarginContentEntry; 225 DrawingArea fDrawingArea; 226 227 const SkClipStack* fClipStack; 228 229 // Accessor and setter functions based on the current DrawingArea. 230 SkAutoTDelete<ContentEntry>* getContentEntries(); 231 232 // Glyph ids used for each font on this device. 233 SkAutoTDelete<SkPDFGlyphSetMap> fFontGlyphUsage; 234 235 SkScalar fRasterDpi; 236 237 SkBitmap fLegacyBitmap; 238 239 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); 249 250 SkBaseDevice* onCreateDevice(const CreateInfo&, const SkPaint*) override; 251 252 void init(); 253 void cleanUp(bool clearFontUsage); 254 SkPDFFormXObject* createFormXObjectFromDevice(); 255 256 void drawFormXObjectWithMask(int xObjectIndex, 257 SkPDFFormXObject* mask, 258 const SkClipStack* clipStack, 259 const SkRegion& clipRegion, 260 SkXfermode::Mode mode, 261 bool invertClip); 262 263 // If the paint or clip is such that we shouldn't draw anything, this 264 // returns nullptr and does not create a content entry. 265 // setUpContentEntry and finishContentEntry can be used directly, but 266 // the preferred method is to use the ScopedContentEntry helper class. 267 ContentEntry* setUpContentEntry(const SkClipStack* clipStack, 268 const SkRegion& clipRegion, 269 const SkMatrix& matrix, 270 const SkPaint& paint, 271 bool hasText, 272 SkPDFFormXObject** dst); 273 void finishContentEntry(SkXfermode::Mode xfermode, 274 SkPDFFormXObject* dst, 275 SkPath* shape); 276 bool isContentEmpty(); 277 278 void populateGraphicStateEntryFromPaint(const SkMatrix& matrix, 279 const SkClipStack& clipStack, 280 const SkRegion& clipRegion, 281 const SkPaint& paint, 282 bool hasText, 283 GraphicStateEntry* entry); 284 int addGraphicStateResource(SkPDFObject* gs); 285 int addXObjectResource(SkPDFObject* xObject); 286 287 void updateFont(const SkPaint& paint, uint16_t glyphID, ContentEntry* contentEntry); 288 int getFontResourceIndex(SkTypeface* typeface, uint16_t glyphID); 289 290 void internalDrawPaint(const SkPaint& paint, ContentEntry* contentEntry); 291 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); 297 298 /** 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; 302 303 bool handleInversePath(const SkDraw& d, const SkPath& origPath, 304 const SkPaint& paint, bool pathIsMutable, 305 const SkMatrix* prePathMatrix = nullptr); 306 bool handlePointAnnotation(const SkPoint* points, size_t count, 307 const SkMatrix& matrix, SkAnnotation* annot); 308 bool handlePathAnnotation(const SkPath& path, const SkDraw& d, 309 SkAnnotation* annot); 310 311 typedef SkBaseDevice INHERITED; 312 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; 317 }; 318 319 #endif 320