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 "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