1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/include/pdf/SkPDFDevice.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,337 @@ 1.4 + 1.5 +/* 1.6 + * Copyright 2011 Google Inc. 1.7 + * 1.8 + * Use of this source code is governed by a BSD-style license that can be 1.9 + * found in the LICENSE file. 1.10 + */ 1.11 + 1.12 + 1.13 +#ifndef SkPDFDevice_DEFINED 1.14 +#define SkPDFDevice_DEFINED 1.15 + 1.16 +#include "SkBitmapDevice.h" 1.17 +#include "SkBitmap.h" 1.18 +#include "SkCanvas.h" 1.19 +#include "SkPaint.h" 1.20 +#include "SkPath.h" 1.21 +#include "SkPicture.h" 1.22 +#include "SkRect.h" 1.23 +#include "SkRefCnt.h" 1.24 +#include "SkStream.h" 1.25 +#include "SkTDArray.h" 1.26 +#include "SkTemplates.h" 1.27 + 1.28 +class SkPDFArray; 1.29 +class SkPDFDevice; 1.30 +class SkPDFDict; 1.31 +class SkPDFFont; 1.32 +class SkPDFFormXObject; 1.33 +class SkPDFGlyphSetMap; 1.34 +class SkPDFGraphicState; 1.35 +class SkPDFObject; 1.36 +class SkPDFResourceDict; 1.37 +class SkPDFShader; 1.38 +class SkPDFStream; 1.39 +class SkRRect; 1.40 +template <typename T> class SkTSet; 1.41 + 1.42 +// Private classes. 1.43 +struct ContentEntry; 1.44 +struct GraphicStateEntry; 1.45 +struct NamedDestination; 1.46 + 1.47 +/** \class SkPDFDevice 1.48 + 1.49 + The drawing context for the PDF backend. 1.50 +*/ 1.51 +class SkPDFDevice : public SkBitmapDevice { 1.52 +public: 1.53 + /** Create a PDF drawing context with the given width and height. 1.54 + * 72 points/in means letter paper is 612x792. 1.55 + * @param pageSize Page size in points. 1.56 + * @param contentSize The content size of the page in points. This will be 1.57 + * combined with the initial transform to determine the drawing area 1.58 + * (as reported by the width and height methods). Anything outside 1.59 + * of the drawing area will be clipped. 1.60 + * @param initialTransform The initial transform to apply to the page. 1.61 + * This may be useful to, for example, move the origin in and 1.62 + * over a bit to account for a margin, scale the canvas, 1.63 + * or apply a rotation. Note1: the SkPDFDevice also applies 1.64 + * a scale+translate transform to move the origin from the 1.65 + * bottom left (PDF default) to the top left. Note2: drawDevice 1.66 + * (used by layer restore) draws the device after this initial 1.67 + * transform is applied, so the PDF device does an 1.68 + * inverse scale+translate to accommodate the one that SkPDFDevice 1.69 + * always does. 1.70 + */ 1.71 + // Deprecated, please use SkDocument::CreatePdf() instead. 1.72 + SK_API SkPDFDevice(const SkISize& pageSize, const SkISize& contentSize, 1.73 + const SkMatrix& initialTransform); 1.74 + SK_API virtual ~SkPDFDevice(); 1.75 + 1.76 + virtual void clear(SkColor color) SK_OVERRIDE; 1.77 + 1.78 + /** These are called inside the per-device-layer loop for each draw call. 1.79 + When these are called, we have already applied any saveLayer operations, 1.80 + and are handling any looping from the paint, and any effects from the 1.81 + DrawFilter. 1.82 + */ 1.83 + virtual void drawPaint(const SkDraw&, const SkPaint& paint) SK_OVERRIDE; 1.84 + virtual void drawPoints(const SkDraw&, SkCanvas::PointMode mode, 1.85 + size_t count, const SkPoint[], 1.86 + const SkPaint& paint) SK_OVERRIDE; 1.87 + virtual void drawRect(const SkDraw&, const SkRect& r, const SkPaint& paint); 1.88 + virtual void drawRRect(const SkDraw&, const SkRRect& rr, 1.89 + const SkPaint& paint) SK_OVERRIDE; 1.90 + virtual void drawPath(const SkDraw&, const SkPath& origpath, 1.91 + const SkPaint& paint, const SkMatrix* prePathMatrix, 1.92 + bool pathIsMutable) SK_OVERRIDE; 1.93 + virtual void drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap, 1.94 + const SkRect* src, const SkRect& dst, 1.95 + const SkPaint& paint, 1.96 + SkCanvas::DrawBitmapRectFlags flags) SK_OVERRIDE; 1.97 + virtual void drawBitmap(const SkDraw&, const SkBitmap& bitmap, 1.98 + const SkMatrix& matrix, const SkPaint&) SK_OVERRIDE; 1.99 + virtual void drawSprite(const SkDraw&, const SkBitmap& bitmap, int x, int y, 1.100 + const SkPaint& paint) SK_OVERRIDE; 1.101 + virtual void drawText(const SkDraw&, const void* text, size_t len, 1.102 + SkScalar x, SkScalar y, const SkPaint&) SK_OVERRIDE; 1.103 + virtual void drawPosText(const SkDraw&, const void* text, size_t len, 1.104 + const SkScalar pos[], SkScalar constY, 1.105 + int scalarsPerPos, const SkPaint&) SK_OVERRIDE; 1.106 + virtual void drawTextOnPath(const SkDraw&, const void* text, size_t len, 1.107 + const SkPath& path, const SkMatrix* matrix, 1.108 + const SkPaint& paint) SK_OVERRIDE; 1.109 + virtual void drawVertices(const SkDraw&, SkCanvas::VertexMode, 1.110 + int vertexCount, const SkPoint verts[], 1.111 + const SkPoint texs[], const SkColor colors[], 1.112 + SkXfermode* xmode, const uint16_t indices[], 1.113 + int indexCount, const SkPaint& paint) SK_OVERRIDE; 1.114 + virtual void drawDevice(const SkDraw&, SkBaseDevice*, int x, int y, 1.115 + const SkPaint&) SK_OVERRIDE; 1.116 + 1.117 + virtual void onAttachToCanvas(SkCanvas* canvas) SK_OVERRIDE; 1.118 + virtual void onDetachFromCanvas() SK_OVERRIDE; 1.119 + 1.120 + enum DrawingArea { 1.121 + kContent_DrawingArea, // Drawing area for the page content. 1.122 + kMargin_DrawingArea, // Drawing area for the margin content. 1.123 + }; 1.124 + 1.125 + /** Sets the drawing area for the device. Subsequent draw calls are directed 1.126 + * to the specific drawing area (margin or content). The default drawing 1.127 + * area is the content drawing area. 1.128 + * 1.129 + * Currently if margin content is drawn and then a complex (for PDF) xfer 1.130 + * mode is used, like SrcIn, Clear, etc, the margin content will get 1.131 + * clipped. A simple way to avoid the bug is to always draw the margin 1.132 + * content last. 1.133 + */ 1.134 + SK_API void setDrawingArea(DrawingArea drawingArea); 1.135 + 1.136 + /** Sets the DCTEncoder for images. 1.137 + * @param encoder The encoder to encode a bitmap as JPEG (DCT). 1.138 + * Result of encodings are cached, if the encoder changes the 1.139 + * behaivor dynamically and an image is added to a second catalog, 1.140 + * we will likely use the result of the first encoding call. 1.141 + * By returning false from the encoder function, the encoder result 1.142 + * is not used. 1.143 + * Callers might not want to encode small images, as the time spent 1.144 + * encoding and decoding might not be worth the space savings, 1.145 + * if any at all. 1.146 + */ 1.147 + void setDCTEncoder(SkPicture::EncodeBitmap encoder) { 1.148 + fEncoder = encoder; 1.149 + } 1.150 + 1.151 + // PDF specific methods. 1.152 + 1.153 + /** Returns the resource dictionary for this device. 1.154 + */ 1.155 + SK_API SkPDFResourceDict* getResourceDict(); 1.156 + 1.157 + /** Get the fonts used on this device. 1.158 + */ 1.159 + SK_API const SkTDArray<SkPDFFont*>& getFontResources() const; 1.160 + 1.161 + /** Add our named destinations to the supplied dictionary. 1.162 + * @param dict Dictionary to add destinations to. 1.163 + * @param page The PDF object representing the page for this device. 1.164 + */ 1.165 + void appendDestinations(SkPDFDict* dict, SkPDFObject* page); 1.166 + 1.167 + /** Returns a copy of the media box for this device. The caller is required 1.168 + * to unref() this when it is finished. 1.169 + */ 1.170 + SK_API SkPDFArray* copyMediaBox() const; 1.171 + 1.172 + /** Get the annotations from this page, or NULL if there are none. 1.173 + */ 1.174 + SK_API SkPDFArray* getAnnotations() const { return fAnnotations; } 1.175 + 1.176 + /** Returns a SkStream with the page contents. The caller is responsible 1.177 + for a reference to the returned value. 1.178 + DEPRECATED: use copyContentToData() 1.179 + */ 1.180 + SK_API SkStream* content() const; 1.181 + 1.182 + /** Returns a SkStream with the page contents. The caller is responsible 1.183 + * for calling data->unref() when it is finished. 1.184 + */ 1.185 + SK_API SkData* copyContentToData() const; 1.186 + 1.187 + SK_API const SkMatrix& initialTransform() const { 1.188 + return fInitialTransform; 1.189 + } 1.190 + 1.191 + /** Returns a SkPDFGlyphSetMap which represents glyph usage of every font 1.192 + * that shows on this device. 1.193 + */ 1.194 + const SkPDFGlyphSetMap& getFontGlyphUsage() const { 1.195 + return *(fFontGlyphUsage.get()); 1.196 + } 1.197 + 1.198 + 1.199 + /** 1.200 + * rasterDpi - the DPI at which features without native PDF support 1.201 + * will be rasterized (e.g. draw image with perspective, 1.202 + * draw text with perspective, ...) 1.203 + * A larger DPI would create a PDF that reflects the original 1.204 + * intent with better fidelity, but it can make for larger 1.205 + * PDF files too, which would use more memory while rendering, 1.206 + * and it would be slower to be processed or sent online or 1.207 + * to printer. 1.208 + */ 1.209 + void setRasterDpi(SkScalar rasterDpi) { 1.210 + fRasterDpi = rasterDpi; 1.211 + } 1.212 + 1.213 +protected: 1.214 + virtual bool onReadPixels(const SkBitmap& bitmap, int x, int y, 1.215 + SkCanvas::Config8888) SK_OVERRIDE; 1.216 + 1.217 + virtual bool allowImageFilter(const SkImageFilter*) SK_OVERRIDE; 1.218 + 1.219 +private: 1.220 + // TODO(vandebo): push most of SkPDFDevice's state into a core object in 1.221 + // order to get the right access levels without using friend. 1.222 + friend class ScopedContentEntry; 1.223 + 1.224 + SkISize fPageSize; 1.225 + SkISize fContentSize; 1.226 + SkMatrix fInitialTransform; 1.227 + SkClipStack fExistingClipStack; 1.228 + SkRegion fExistingClipRegion; 1.229 + SkPDFArray* fAnnotations; 1.230 + SkPDFResourceDict* fResourceDict; 1.231 + SkTDArray<NamedDestination*> fNamedDestinations; 1.232 + 1.233 + SkTDArray<SkPDFGraphicState*> fGraphicStateResources; 1.234 + SkTDArray<SkPDFObject*> fXObjectResources; 1.235 + SkTDArray<SkPDFFont*> fFontResources; 1.236 + SkTDArray<SkPDFObject*> fShaderResources; 1.237 + 1.238 + SkAutoTDelete<ContentEntry> fContentEntries; 1.239 + ContentEntry* fLastContentEntry; 1.240 + SkAutoTDelete<ContentEntry> fMarginContentEntries; 1.241 + ContentEntry* fLastMarginContentEntry; 1.242 + DrawingArea fDrawingArea; 1.243 + 1.244 + const SkClipStack* fClipStack; 1.245 + 1.246 + // Accessor and setter functions based on the current DrawingArea. 1.247 + SkAutoTDelete<ContentEntry>* getContentEntries(); 1.248 + ContentEntry* getLastContentEntry(); 1.249 + void setLastContentEntry(ContentEntry* contentEntry); 1.250 + 1.251 + // Glyph ids used for each font on this device. 1.252 + SkAutoTDelete<SkPDFGlyphSetMap> fFontGlyphUsage; 1.253 + 1.254 + SkPicture::EncodeBitmap fEncoder; 1.255 + SkScalar fRasterDpi; 1.256 + 1.257 + SkPDFDevice(const SkISize& layerSize, const SkClipStack& existingClipStack, 1.258 + const SkRegion& existingClipRegion); 1.259 + 1.260 + // override from SkBaseDevice 1.261 + virtual SkBaseDevice* onCreateDevice(const SkImageInfo&, Usage) SK_OVERRIDE; 1.262 + 1.263 + void init(); 1.264 + void cleanUp(bool clearFontUsage); 1.265 + SkPDFFormXObject* createFormXObjectFromDevice(); 1.266 + 1.267 + void drawFormXObjectWithMask(int xObjectIndex, 1.268 + SkPDFFormXObject* mask, 1.269 + const SkClipStack* clipStack, 1.270 + const SkRegion& clipRegion, 1.271 + SkXfermode::Mode mode, 1.272 + bool invertClip); 1.273 + 1.274 + // If the paint or clip is such that we shouldn't draw anything, this 1.275 + // returns NULL and does not create a content entry. 1.276 + // setUpContentEntry and finishContentEntry can be used directly, but 1.277 + // the preferred method is to use the ScopedContentEntry helper class. 1.278 + ContentEntry* setUpContentEntry(const SkClipStack* clipStack, 1.279 + const SkRegion& clipRegion, 1.280 + const SkMatrix& matrix, 1.281 + const SkPaint& paint, 1.282 + bool hasText, 1.283 + SkPDFFormXObject** dst); 1.284 + void finishContentEntry(SkXfermode::Mode xfermode, 1.285 + SkPDFFormXObject* dst, 1.286 + SkPath* shape); 1.287 + bool isContentEmpty(); 1.288 + 1.289 + void populateGraphicStateEntryFromPaint(const SkMatrix& matrix, 1.290 + const SkClipStack& clipStack, 1.291 + const SkRegion& clipRegion, 1.292 + const SkPaint& paint, 1.293 + bool hasText, 1.294 + GraphicStateEntry* entry); 1.295 + int addGraphicStateResource(SkPDFGraphicState* gs); 1.296 + int addXObjectResource(SkPDFObject* xObject); 1.297 + 1.298 + void updateFont(const SkPaint& paint, uint16_t glyphID, 1.299 + ContentEntry* contentEntry); 1.300 + int getFontResourceIndex(SkTypeface* typeface, uint16_t glyphID); 1.301 + 1.302 + void internalDrawPaint(const SkPaint& paint, ContentEntry* contentEntry); 1.303 + void internalDrawBitmap(const SkMatrix& matrix, 1.304 + const SkClipStack* clipStack, 1.305 + const SkRegion& clipRegion, 1.306 + const SkBitmap& bitmap, 1.307 + const SkIRect* srcRect, 1.308 + const SkPaint& paint); 1.309 + 1.310 + /** Helper method for copyContentToData. It is responsible for copying the 1.311 + * list of content entries |entry| to |data|. 1.312 + */ 1.313 + void copyContentEntriesToData(ContentEntry* entry, SkWStream* data) const; 1.314 + 1.315 +#ifdef SK_PDF_USE_PATHOPS 1.316 + bool handleInversePath(const SkDraw& d, const SkPath& origPath, 1.317 + const SkPaint& paint, bool pathIsMutable, 1.318 + const SkMatrix* prePathMatrix = NULL); 1.319 +#endif 1.320 + bool handleRectAnnotation(const SkRect& r, const SkMatrix& matrix, 1.321 + const SkPaint& paint); 1.322 + bool handlePointAnnotation(const SkPoint* points, size_t count, 1.323 + const SkMatrix& matrix, const SkPaint& paint); 1.324 + SkPDFDict* createLinkAnnotation(const SkRect& r, const SkMatrix& matrix); 1.325 + void handleLinkToURL(SkData* urlData, const SkRect& r, 1.326 + const SkMatrix& matrix); 1.327 + void handleLinkToNamedDest(SkData* nameData, const SkRect& r, 1.328 + const SkMatrix& matrix); 1.329 + void defineNamedDestination(SkData* nameData, const SkPoint& point, 1.330 + const SkMatrix& matrix); 1.331 + 1.332 + typedef SkBitmapDevice INHERITED; 1.333 + 1.334 + // TODO(edisonn): Only SkDocument_PDF and SkPDFImageShader should be able to create 1.335 + // an SkPDFDevice 1.336 + //friend class SkDocument_PDF; 1.337 + //friend class SkPDFImageShader; 1.338 +}; 1.339 + 1.340 +#endif