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