SkPDFDevice.h revision 385fe4d4b62d7d1dd76116dd570df3290a2f487b
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 24class SkPDFArray; 25class SkPDFCanon; 26class SkPDFDevice; 27class SkPDFDict; 28class SkPDFFont; 29class SkPDFFormXObject; 30class SkPDFGlyphSetMap; 31class SkPDFGraphicState; 32class SkPDFObject; 33class SkPDFShader; 34class SkPDFStream; 35class SkRRect; 36 37// Private classes. 38struct ContentEntry; 39struct GraphicStateEntry; 40struct NamedDestination; 41 42/** \class SkPDFDevice 43 44 The drawing context for the PDF backend. 45*/ 46class SkPDFDevice : public SkBaseDevice { 47public: 48 /** Create a PDF drawing context. SkPDFDevice applies a 49 * scale-and-translate transform to move the origin from the 50 * bottom left (PDF default) to the top left (Skia default). 51 * @param pageSize Page size in point units. 52 * 1 point == 127/360 mm == 1/72 inch 53 * @param rasterDpi the DPI at which features without native PDF 54 * support will be rasterized (e.g. draw image with 55 * perspective, draw text with perspective, ...). A 56 * larger DPI would create a PDF that reflects the 57 * original intent with better fidelity, but it can make 58 * for larger PDF files too, which would use more memory 59 * while rendering, and it would be slower to be processed 60 * or sent online or to printer. A good choice is 61 * SK_ScalarDefaultRasterDPI(72.0f). 62 * @param SkPDFCanon. Should be non-null, and shared by all 63 * devices in a document. 64 */ 65 static SkPDFDevice* Create(SkISize pageSize, 66 SkScalar rasterDpi, 67 SkPDFCanon* canon) { 68 return new SkPDFDevice(pageSize, rasterDpi, canon, true); 69 } 70 71 /** Create a PDF drawing context without fipping the y-axis. */ 72 static SkPDFDevice* CreateUnflipped(SkISize pageSize, 73 SkScalar rasterDpi, 74 SkPDFCanon* canon) { 75 return new SkPDFDevice(pageSize, rasterDpi, canon, false); 76 } 77 78 virtual ~SkPDFDevice(); 79 80 /** These are called inside the per-device-layer loop for each draw call. 81 When these are called, we have already applied any saveLayer operations, 82 and are handling any looping from the paint, and any effects from the 83 DrawFilter. 84 */ 85 void drawPaint(const SkDraw&, const SkPaint& paint) override; 86 void drawPoints(const SkDraw&, SkCanvas::PointMode mode, 87 size_t count, const SkPoint[], 88 const SkPaint& paint) override; 89 void drawRect(const SkDraw&, const SkRect& r, const SkPaint& paint) override; 90 void drawOval(const SkDraw&, const SkRect& oval, const SkPaint& paint) override; 91 void drawRRect(const SkDraw&, const SkRRect& rr, const SkPaint& paint) override; 92 void drawPath(const SkDraw&, const SkPath& origpath, 93 const SkPaint& paint, const SkMatrix* prePathMatrix, 94 bool pathIsMutable) override; 95 void drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap, const SkRect* src, 96 const SkRect& dst, const SkPaint&, SkCanvas::SrcRectConstraint) override; 97 void drawBitmap(const SkDraw&, const SkBitmap& bitmap, 98 const SkMatrix& matrix, const SkPaint&) override; 99 void drawSprite(const SkDraw&, const SkBitmap& bitmap, int x, int y, 100 const SkPaint& paint) override; 101 void drawText(const SkDraw&, const void* text, size_t len, 102 SkScalar x, SkScalar y, const SkPaint&) override; 103 void drawPosText(const SkDraw&, const void* text, size_t len, 104 const SkScalar pos[], int scalarsPerPos, 105 const SkPoint& offset, const SkPaint&) override; 106 void drawVertices(const SkDraw&, SkCanvas::VertexMode, 107 int vertexCount, const SkPoint verts[], 108 const SkPoint texs[], const SkColor colors[], 109 SkXfermode* xmode, const uint16_t indices[], 110 int indexCount, const SkPaint& paint) override; 111 void drawDevice(const SkDraw&, SkBaseDevice*, int x, int y, 112 const SkPaint&) override; 113 114 void onAttachToCanvas(SkCanvas* canvas) override; 115 void onDetachFromCanvas() override; 116 SkImageInfo imageInfo() const override; 117 118 enum DrawingArea { 119 kContent_DrawingArea, // Drawing area for the page content. 120 kMargin_DrawingArea, // Drawing area for the margin content. 121 }; 122 123 /** Sets the drawing area for the device. Subsequent draw calls are directed 124 * to the specific drawing area (margin or content). The default drawing 125 * area is the content drawing area. 126 * 127 * Currently if margin content is drawn and then a complex (for PDF) xfer 128 * mode is used, like SrcIn, Clear, etc, the margin content will get 129 * clipped. A simple way to avoid the bug is to always draw the margin 130 * content last. 131 */ 132 void setDrawingArea(DrawingArea drawingArea); 133 134 // PDF specific methods. 135 136 /** Create the resource dictionary for this device. 137 */ 138 SkPDFDict* createResourceDict() const; 139 140 /** Get the fonts used on this device. 141 */ 142 const SkTDArray<SkPDFFont*>& getFontResources() const; 143 144 /** Add our named destinations to the supplied dictionary. 145 * @param dict Dictionary to add destinations to. 146 * @param page The PDF object representing the page for this device. 147 */ 148 void appendDestinations(SkPDFDict* dict, SkPDFObject* page) const; 149 150 /** Returns a copy of the media box for this device. The caller is required 151 * to unref() this when it is finished. 152 */ 153 SkPDFArray* copyMediaBox() const; 154 155 /** Get the annotations from this page, or NULL if there are none. 156 */ 157 SkPDFArray* getAnnotations() const { return fAnnotations; } 158 159 /** Returns a SkStream with the page contents. The caller is responsible 160 * for a deleting the returned value. 161 */ 162 SkStreamAsset* content() const; 163 164 /** Writes the page contents to the stream. */ 165 void writeContent(SkWStream*) const; 166 167 const SkMatrix& initialTransform() const { 168 return fInitialTransform; 169 } 170 171 /** Returns a SkPDFGlyphSetMap which represents glyph usage of every font 172 * that shows on this device. 173 */ 174 const SkPDFGlyphSetMap& getFontGlyphUsage() const { 175 return *(fFontGlyphUsage.get()); 176 } 177 178#ifdef SK_DEBUG 179 SkPDFCanon* getCanon() const { return fCanon; } 180#endif // SK_DEBUG 181 182protected: 183 const SkBitmap& onAccessBitmap() override { 184 return fLegacyBitmap; 185 } 186 187 SkSurface* newSurface(const SkImageInfo&, const SkSurfaceProps&) override; 188 189private: 190 // TODO(vandebo): push most of SkPDFDevice's state into a core object in 191 // order to get the right access levels without using friend. 192 friend class ScopedContentEntry; 193 194 SkISize fPageSize; 195 SkISize fContentSize; 196 SkMatrix fInitialTransform; 197 SkClipStack fExistingClipStack; 198 SkRegion fExistingClipRegion; 199 SkPDFArray* fAnnotations; 200 SkTDArray<NamedDestination*> fNamedDestinations; 201 202 SkTDArray<SkPDFObject*> fGraphicStateResources; 203 SkTDArray<SkPDFObject*> fXObjectResources; 204 SkTDArray<SkPDFFont*> fFontResources; 205 SkTDArray<SkPDFObject*> fShaderResources; 206 207 SkAutoTDelete<ContentEntry> fContentEntries; 208 ContentEntry* fLastContentEntry; 209 SkAutoTDelete<ContentEntry> fMarginContentEntries; 210 ContentEntry* fLastMarginContentEntry; 211 DrawingArea fDrawingArea; 212 213 const SkClipStack* fClipStack; 214 215 // Accessor and setter functions based on the current DrawingArea. 216 SkAutoTDelete<ContentEntry>* getContentEntries(); 217 218 // Glyph ids used for each font on this device. 219 SkAutoTDelete<SkPDFGlyphSetMap> fFontGlyphUsage; 220 221 SkScalar fRasterDpi; 222 223 SkBitmap fLegacyBitmap; 224 225 SkPDFCanon* fCanon; // Owned by SkDocument_PDF 226 //////////////////////////////////////////////////////////////////////////// 227 228 SkPDFDevice(SkISize pageSize, 229 SkScalar rasterDpi, 230 SkPDFCanon* canon, 231 bool flip); 232 233 ContentEntry* getLastContentEntry(); 234 void setLastContentEntry(ContentEntry* contentEntry); 235 236 SkBaseDevice* onCreateDevice(const CreateInfo&, const SkPaint*) override; 237 238 void init(); 239 void cleanUp(bool clearFontUsage); 240 SkPDFFormXObject* createFormXObjectFromDevice(); 241 242 void drawFormXObjectWithMask(int xObjectIndex, 243 SkPDFFormXObject* mask, 244 const SkClipStack* clipStack, 245 const SkRegion& clipRegion, 246 SkXfermode::Mode mode, 247 bool invertClip); 248 249 // If the paint or clip is such that we shouldn't draw anything, this 250 // returns NULL and does not create a content entry. 251 // setUpContentEntry and finishContentEntry can be used directly, but 252 // the preferred method is to use the ScopedContentEntry helper class. 253 ContentEntry* setUpContentEntry(const SkClipStack* clipStack, 254 const SkRegion& clipRegion, 255 const SkMatrix& matrix, 256 const SkPaint& paint, 257 bool hasText, 258 SkPDFFormXObject** dst); 259 void finishContentEntry(SkXfermode::Mode xfermode, 260 SkPDFFormXObject* dst, 261 SkPath* shape); 262 bool isContentEmpty(); 263 264 void populateGraphicStateEntryFromPaint(const SkMatrix& matrix, 265 const SkClipStack& clipStack, 266 const SkRegion& clipRegion, 267 const SkPaint& paint, 268 bool hasText, 269 GraphicStateEntry* entry); 270 int addGraphicStateResource(SkPDFObject* gs); 271 int addXObjectResource(SkPDFObject* xObject); 272 273 void updateFont(const SkPaint& paint, uint16_t glyphID, ContentEntry* contentEntry); 274 int getFontResourceIndex(SkTypeface* typeface, uint16_t glyphID); 275 276 void internalDrawPaint(const SkPaint& paint, ContentEntry* contentEntry); 277 void internalDrawBitmap(const SkMatrix& matrix, 278 const SkClipStack* clipStack, 279 const SkRegion& clipRegion, 280 const SkBitmap& bitmap, 281 const SkIRect* srcRect, 282 const SkPaint& paint); 283 284 /** Helper method for copyContentToData. It is responsible for copying the 285 * list of content entries |entry| to |data|. 286 */ 287 void copyContentEntriesToData(ContentEntry* entry, SkWStream* data) const; 288 289 bool handleInversePath(const SkDraw& d, const SkPath& origPath, 290 const SkPaint& paint, bool pathIsMutable, 291 const SkMatrix* prePathMatrix = NULL); 292 bool handlePointAnnotation(const SkPoint* points, size_t count, 293 const SkMatrix& matrix, SkAnnotation* annot); 294 void addAnnotation(SkPDFDict*); 295 296 typedef SkBaseDevice INHERITED; 297 298 // TODO(edisonn): Only SkDocument_PDF and SkPDFImageShader should be able to create 299 // an SkPDFDevice 300 //friend class SkDocument_PDF; 301 //friend class SkPDFImageShader; 302}; 303 304#endif 305