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