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 "SkBitmap.h" 14 #include "SkCanvas.h" 15 #include "SkDevice.h" 16 #include "SkPaint.h" 17 #include "SkPath.h" 18 #include "SkRect.h" 19 #include "SkRefCnt.h" 20 #include "SkStream.h" 21 #include "SkTDArray.h" 22 #include "SkTScopedPtr.h" 23 24 class SkPDFArray; 25 class SkPDFDevice; 26 class SkPDFDict; 27 class SkPDFFont; 28 class SkPDFFormXObject; 29 class SkPDFGlyphSetMap; 30 class SkPDFGraphicState; 31 class SkPDFObject; 32 class SkPDFResourceDict; 33 class SkPDFShader; 34 class SkPDFStream; 35 class SkRRect; 36 template <typename T> class SkTSet; 37 38 // Private classes. 39 struct ContentEntry; 40 struct GraphicStateEntry; 41 struct NamedDestination; 42 43 typedef bool (*EncodeToDCTStream)(SkWStream* stream, const SkBitmap& bitmap, const SkIRect& rect); 44 45 /** \class SkPDFDevice 46 47 The drawing context for the PDF backend. 48 */ 49 class SkPDFDevice : public SkDevice { 50 public: 51 /** Create a PDF drawing context with the given width and height. 52 * 72 points/in means letter paper is 612x792. 53 * @param pageSize Page size in points. 54 * @param contentSize The content size of the page in points. This will be 55 * combined with the initial transform to determine the drawing area 56 * (as reported by the width and height methods). Anything outside 57 * of the drawing area will be clipped. 58 * @param initialTransform The initial transform to apply to the page. 59 * This may be useful to, for example, move the origin in and 60 * over a bit to account for a margin, scale the canvas, 61 * or apply a rotation. Note1: the SkPDFDevice also applies 62 * a scale+translate transform to move the origin from the 63 * bottom left (PDF default) to the top left. Note2: drawDevice 64 * (used by layer restore) draws the device after this initial 65 * transform is applied, so the PDF device does an 66 * inverse scale+translate to accommodate the one that SkPDFDevice 67 * always does. 68 */ 69 // Deprecated, please use SkDocument::CreatePdf() instead. 70 SK_API SkPDFDevice(const SkISize& pageSize, const SkISize& contentSize, 71 const SkMatrix& initialTransform); 72 SK_API virtual ~SkPDFDevice(); 73 74 virtual uint32_t getDeviceCapabilities() SK_OVERRIDE; 75 76 virtual void clear(SkColor color) SK_OVERRIDE; 77 78 /** These are called inside the per-device-layer loop for each draw call. 79 When these are called, we have already applied any saveLayer operations, 80 and are handling any looping from the paint, and any effects from the 81 DrawFilter. 82 */ 83 virtual void drawPaint(const SkDraw&, const SkPaint& paint) SK_OVERRIDE; 84 virtual void drawPoints(const SkDraw&, SkCanvas::PointMode mode, 85 size_t count, const SkPoint[], 86 const SkPaint& paint) SK_OVERRIDE; 87 virtual void drawRect(const SkDraw&, const SkRect& r, const SkPaint& paint); 88 virtual void drawRRect(const SkDraw&, const SkRRect& rr, 89 const SkPaint& paint) SK_OVERRIDE; 90 virtual void drawPath(const SkDraw&, const SkPath& origpath, 91 const SkPaint& paint, const SkMatrix* prePathMatrix, 92 bool pathIsMutable) SK_OVERRIDE; 93 virtual void drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap, 94 const SkRect* src, const SkRect& dst, 95 const SkPaint& paint) SK_OVERRIDE; 96 virtual void drawBitmap(const SkDraw&, const SkBitmap& bitmap, 97 const SkMatrix& matrix, const SkPaint&) SK_OVERRIDE; 98 virtual void drawSprite(const SkDraw&, const SkBitmap& bitmap, int x, int y, 99 const SkPaint& paint) SK_OVERRIDE; 100 virtual void drawText(const SkDraw&, const void* text, size_t len, 101 SkScalar x, SkScalar y, const SkPaint&) SK_OVERRIDE; 102 virtual void drawPosText(const SkDraw&, const void* text, size_t len, 103 const SkScalar pos[], SkScalar constY, 104 int scalarsPerPos, const SkPaint&) SK_OVERRIDE; 105 virtual void drawTextOnPath(const SkDraw&, const void* text, size_t len, 106 const SkPath& path, const SkMatrix* matrix, 107 const SkPaint& paint) SK_OVERRIDE; 108 virtual void drawVertices(const SkDraw&, SkCanvas::VertexMode, 109 int vertexCount, const SkPoint verts[], 110 const SkPoint texs[], const SkColor colors[], 111 SkXfermode* xmode, const uint16_t indices[], 112 int indexCount, const SkPaint& paint) SK_OVERRIDE; 113 virtual void drawDevice(const SkDraw&, SkDevice*, int x, int y, 114 const SkPaint&) SK_OVERRIDE; 115 116 virtual void onAttachToCanvas(SkCanvas* canvas) SK_OVERRIDE; 117 virtual void onDetachFromCanvas() SK_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 SK_API void setDrawingArea(DrawingArea drawingArea); 134 135 /** Sets the DCTEncoder for images. 136 * @param encoder The encoder to encode a bitmap as JPEG (DCT). 137 * Result of encodings are cached, if the encoder changes the 138 * behaivor dynamically and an image is added to a second catalog, 139 * we will likely use the result of the first encoding call. 140 * By returning false from the encoder function, the encoder result 141 * is not used. 142 * Callers might not want to encode small images, as the time spent 143 * encoding and decoding might not be worth the space savings, 144 * if any at all. 145 */ 146 void setDCTEncoder(EncodeToDCTStream encoder) { 147 fEncoder = encoder; 148 } 149 150 // PDF specific methods. 151 152 /** Returns the resource dictionary for this device. 153 */ 154 SK_API SkPDFResourceDict* getResourceDict(); 155 156 /** Get the fonts used on this device. 157 */ 158 SK_API const SkTDArray<SkPDFFont*>& getFontResources() const; 159 160 /** Add our named destinations to the supplied dictionary. 161 * @param dict Dictionary to add destinations to. 162 * @param page The PDF object representing the page for this device. 163 */ 164 void appendDestinations(SkPDFDict* dict, SkPDFObject* page); 165 166 /** Returns a copy of the media box for this device. The caller is required 167 * to unref() this when it is finished. 168 */ 169 SK_API SkPDFArray* copyMediaBox() const; 170 171 /** Get the annotations from this page, or NULL if there are none. 172 */ 173 SK_API SkPDFArray* getAnnotations() const { return fAnnotations; } 174 175 /** Returns a SkStream with the page contents. The caller is responsible 176 for a reference to the returned value. 177 DEPRECATED: use copyContentToData() 178 */ 179 SK_API SkStream* content() const; 180 181 /** Returns a SkStream with the page contents. The caller is responsible 182 * for calling data->unref() when it is finished. 183 */ 184 SK_API SkData* copyContentToData() const; 185 186 SK_API const SkMatrix& initialTransform() const { 187 return fInitialTransform; 188 } 189 190 /** Returns a SkPDFGlyphSetMap which represents glyph usage of every font 191 * that shows on this device. 192 */ 193 const SkPDFGlyphSetMap& getFontGlyphUsage() const { 194 return *(fFontGlyphUsage.get()); 195 } 196 197 protected: 198 virtual bool onReadPixels(const SkBitmap& bitmap, int x, int y, 199 SkCanvas::Config8888) SK_OVERRIDE; 200 201 virtual bool allowImageFilter(SkImageFilter*) SK_OVERRIDE; 202 203 private: 204 // TODO(vandebo): push most of SkPDFDevice's state into a core object in 205 // order to get the right access levels without using friend. 206 friend class ScopedContentEntry; 207 208 SkISize fPageSize; 209 SkISize fContentSize; 210 SkMatrix fInitialTransform; 211 SkClipStack fExistingClipStack; 212 SkRegion fExistingClipRegion; 213 SkPDFArray* fAnnotations; 214 SkPDFResourceDict* fResourceDict; 215 SkTDArray<NamedDestination*> fNamedDestinations; 216 217 SkTDArray<SkPDFGraphicState*> fGraphicStateResources; 218 SkTDArray<SkPDFObject*> fXObjectResources; 219 SkTDArray<SkPDFFont*> fFontResources; 220 SkTDArray<SkPDFObject*> fShaderResources; 221 222 SkTScopedPtr<ContentEntry> fContentEntries; 223 ContentEntry* fLastContentEntry; 224 SkTScopedPtr<ContentEntry> fMarginContentEntries; 225 ContentEntry* fLastMarginContentEntry; 226 DrawingArea fDrawingArea; 227 228 const SkClipStack* fClipStack; 229 230 // Accessor and setter functions based on the current DrawingArea. 231 SkTScopedPtr<ContentEntry>* getContentEntries(); 232 ContentEntry* getLastContentEntry(); 233 void setLastContentEntry(ContentEntry* contentEntry); 234 235 // Glyph ids used for each font on this device. 236 SkTScopedPtr<SkPDFGlyphSetMap> fFontGlyphUsage; 237 238 EncodeToDCTStream fEncoder; 239 240 SkPDFDevice(const SkISize& layerSize, const SkClipStack& existingClipStack, 241 const SkRegion& existingClipRegion); 242 243 // override from SkDevice 244 virtual SkDevice* onCreateCompatibleDevice(SkBitmap::Config config, 245 int width, int height, 246 bool isOpaque, 247 Usage usage) SK_OVERRIDE; 248 249 void init(); 250 void cleanUp(bool clearFontUsage); 251 SkPDFFormXObject* createFormXObjectFromDevice(); 252 253 void drawFormXObjectWithMask(int xObjectIndex, 254 SkPDFFormXObject* mask, 255 const SkClipStack* clipStack, 256 const SkRegion& clipRegion, 257 SkXfermode::Mode mode, 258 bool invertClip); 259 260 // If the paint or clip is such that we shouldn't draw anything, this 261 // returns NULL and does not create a content entry. 262 // setUpContentEntry and finishContentEntry can be used directly, but 263 // the preferred method is to use the ScopedContentEntry helper class. 264 ContentEntry* setUpContentEntry(const SkClipStack* clipStack, 265 const SkRegion& clipRegion, 266 const SkMatrix& matrix, 267 const SkPaint& paint, 268 bool hasText, 269 SkPDFFormXObject** dst); 270 void finishContentEntry(SkXfermode::Mode xfermode, 271 SkPDFFormXObject* dst, 272 SkPath* shape); 273 bool isContentEmpty(); 274 275 void populateGraphicStateEntryFromPaint(const SkMatrix& matrix, 276 const SkClipStack& clipStack, 277 const SkRegion& clipRegion, 278 const SkPaint& paint, 279 bool hasText, 280 GraphicStateEntry* entry); 281 int addGraphicStateResource(SkPDFGraphicState* gs); 282 int addXObjectResource(SkPDFObject* xObject); 283 284 void updateFont(const SkPaint& paint, uint16_t glyphID, 285 ContentEntry* contentEntry); 286 int getFontResourceIndex(SkTypeface* typeface, uint16_t glyphID); 287 288 void internalDrawPaint(const SkPaint& paint, ContentEntry* contentEntry); 289 void internalDrawBitmap(const SkMatrix& matrix, 290 const SkClipStack* clipStack, 291 const SkRegion& clipRegion, 292 const SkBitmap& bitmap, 293 const SkIRect* srcRect, 294 const SkPaint& paint); 295 296 /** Helper method for copyContentToData. It is responsible for copying the 297 * list of content entries |entry| to |data|. 298 */ 299 void copyContentEntriesToData(ContentEntry* entry, SkWStream* data) const; 300 301 #ifdef SK_PDF_USE_PATHOPS 302 bool handleInversePath(const SkDraw& d, const SkPath& origPath, 303 const SkPaint& paint, bool pathIsMutable); 304 #endif 305 bool handleRectAnnotation(const SkRect& r, const SkMatrix& matrix, 306 const SkPaint& paint); 307 bool handlePointAnnotation(const SkPoint* points, size_t count, 308 const SkMatrix& matrix, const SkPaint& paint); 309 SkPDFDict* createLinkAnnotation(const SkRect& r, const SkMatrix& matrix); 310 void handleLinkToURL(SkData* urlData, const SkRect& r, 311 const SkMatrix& matrix); 312 void handleLinkToNamedDest(SkData* nameData, const SkRect& r, 313 const SkMatrix& matrix); 314 void defineNamedDestination(SkData* nameData, const SkPoint& point, 315 const SkMatrix& matrix); 316 317 typedef SkDevice INHERITED; 318 }; 319 320 #endif 321