Home | History | Annotate | Download | only in pdf
      1 /*
      2  * Copyright 2011 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #ifndef SkPDFDevice_DEFINED
      9 #define SkPDFDevice_DEFINED
     10 
     11 #include "SkBitmap.h"
     12 #include "SkCanvas.h"
     13 #include "SkClipStack.h"
     14 #include "SkDevice.h"
     15 #include "SkPaint.h"
     16 #include "SkPath.h"
     17 #include "SkPicture.h"
     18 #include "SkRect.h"
     19 #include "SkRefCnt.h"
     20 #include "SkStream.h"
     21 #include "SkTDArray.h"
     22 #include "SkTemplates.h"
     23 
     24 class SkPDFArray;
     25 class SkPDFCanon;
     26 class SkPDFDevice;
     27 class SkPDFDict;
     28 class SkPDFFont;
     29 class SkPDFFormXObject;
     30 class SkPDFGlyphSetMap;
     31 class SkPDFGraphicState;
     32 class SkPDFObject;
     33 class SkPDFShader;
     34 class SkPDFStream;
     35 class SkRRect;
     36 
     37 // Private classes.
     38 struct ContentEntry;
     39 struct GraphicStateEntry;
     40 struct NamedDestination;
     41 struct RectWithData;
     42 
     43 /** \class SkPDFDevice
     44 
     45     The drawing context for the PDF backend.
     46 */
     47 class SkPDFDevice final : 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 new 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 new 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, const SkRect* src,
     97                         const SkRect& dst, const SkPaint&, SkCanvas::SrcRectConstraint) override;
     98     void drawBitmap(const SkDraw&, const SkBitmap& bitmap,
     99                     const SkMatrix& matrix, const SkPaint&) override;
    100     void drawSprite(const SkDraw&, const SkBitmap& bitmap, int x, int y,
    101                     const SkPaint& paint) override;
    102     void drawImage(const SkDraw&,
    103                    const SkImage*,
    104                    SkScalar x,
    105                    SkScalar y,
    106                    const SkPaint&) override;
    107     void drawImageRect(const SkDraw&,
    108                        const SkImage*,
    109                        const SkRect* src,
    110                        const SkRect& dst,
    111                        const SkPaint&,
    112                        SkCanvas::SrcRectConstraint) override;
    113     void drawText(const SkDraw&, const void* text, size_t len,
    114                   SkScalar x, SkScalar y, const SkPaint&) override;
    115     void drawPosText(const SkDraw&, const void* text, size_t len,
    116                      const SkScalar pos[], int scalarsPerPos,
    117                      const SkPoint& offset, const SkPaint&) override;
    118     void drawVertices(const SkDraw&, SkCanvas::VertexMode,
    119                       int vertexCount, const SkPoint verts[],
    120                       const SkPoint texs[], const SkColor colors[],
    121                       SkXfermode* xmode, const uint16_t indices[],
    122                       int indexCount, const SkPaint& paint) override;
    123     void drawDevice(const SkDraw&, SkBaseDevice*, int x, int y,
    124                     const SkPaint&) override;
    125 
    126     void onAttachToCanvas(SkCanvas* canvas) override;
    127     void onDetachFromCanvas() override;
    128     SkImageInfo imageInfo() const override;
    129 
    130     enum DrawingArea {
    131         kContent_DrawingArea,  // Drawing area for the page content.
    132         kMargin_DrawingArea,   // Drawing area for the margin content.
    133     };
    134 
    135     /** Sets the drawing area for the device. Subsequent draw calls are directed
    136      *  to the specific drawing area (margin or content). The default drawing
    137      *  area is the content drawing area.
    138      *
    139      *  Currently if margin content is drawn and then a complex (for PDF) xfer
    140      *  mode is used, like SrcIn, Clear, etc, the margin content will get
    141      *  clipped. A simple way to avoid the bug is to always draw the margin
    142      *  content last.
    143      */
    144     void setDrawingArea(DrawingArea drawingArea);
    145 
    146     // PDF specific methods.
    147 
    148     /** Create the resource dictionary for this device.
    149      */
    150     SkPDFDict* createResourceDict() const;
    151 
    152     /** Get the fonts used on this device.
    153      */
    154     const SkTDArray<SkPDFFont*>& getFontResources() const;
    155 
    156     /** Add our annotations (link to urls and destinations) to the supplied
    157      *  array.
    158      *  @param array Array to add annotations to.
    159      */
    160     void appendAnnotations(SkPDFArray* array) const;
    161 
    162     /** Add our named destinations to the supplied dictionary.
    163      *  @param dict  Dictionary to add destinations to.
    164      *  @param page  The PDF object representing the page for this device.
    165      */
    166     void appendDestinations(SkPDFDict* dict, SkPDFObject* page) const;
    167 
    168     /** Returns a copy of the media box for this device. The caller is required
    169      *  to unref() this when it is finished.
    170      */
    171     SkPDFArray* copyMediaBox() const;
    172 
    173     /** Returns a SkStream with the page contents.  The caller is responsible
    174      *  for a deleting the returned value.
    175      */
    176     SkStreamAsset* content() const;
    177 
    178     /** Writes the page contents to the stream. */
    179     void writeContent(SkWStream*) const;
    180 
    181     const SkMatrix& initialTransform() const {
    182         return fInitialTransform;
    183     }
    184 
    185     /** Returns a SkPDFGlyphSetMap which represents glyph usage of every font
    186      *  that shows on this device.
    187      */
    188     const SkPDFGlyphSetMap& getFontGlyphUsage() const {
    189         return *(fFontGlyphUsage.get());
    190     }
    191 
    192     SkPDFCanon* getCanon() const { return fCanon; }
    193 
    194 protected:
    195     const SkBitmap& onAccessBitmap() override {
    196         return fLegacyBitmap;
    197     }
    198 
    199     SkSurface* newSurface(const SkImageInfo&, const SkSurfaceProps&) override;
    200 
    201 private:
    202     // TODO(vandebo): push most of SkPDFDevice's state into a core object in
    203     // order to get the right access levels without using friend.
    204     friend class ScopedContentEntry;
    205 
    206     SkISize fPageSize;
    207     SkISize fContentSize;
    208     SkMatrix fInitialTransform;
    209     SkClipStack fExistingClipStack;
    210     SkRegion fExistingClipRegion;
    211 
    212     SkTDArray<RectWithData*> fLinkToURLs;
    213     SkTDArray<RectWithData*> fLinkToDestinations;
    214     SkTDArray<NamedDestination*> fNamedDestinations;
    215 
    216     SkTDArray<SkPDFObject*> fGraphicStateResources;
    217     SkTDArray<SkPDFObject*> fXObjectResources;
    218     SkTDArray<SkPDFFont*> fFontResources;
    219     SkTDArray<SkPDFObject*> fShaderResources;
    220 
    221     SkAutoTDelete<ContentEntry> fContentEntries;
    222     ContentEntry* fLastContentEntry;
    223     SkAutoTDelete<ContentEntry> fMarginContentEntries;
    224     ContentEntry* fLastMarginContentEntry;
    225     DrawingArea fDrawingArea;
    226 
    227     const SkClipStack* fClipStack;
    228 
    229     // Accessor and setter functions based on the current DrawingArea.
    230     SkAutoTDelete<ContentEntry>* getContentEntries();
    231 
    232     // Glyph ids used for each font on this device.
    233     SkAutoTDelete<SkPDFGlyphSetMap> fFontGlyphUsage;
    234 
    235     SkScalar fRasterDpi;
    236 
    237     SkBitmap fLegacyBitmap;
    238 
    239     SkPDFCanon* fCanon;  // Owned by SkDocument_PDF
    240     ////////////////////////////////////////////////////////////////////////////
    241 
    242     SkPDFDevice(SkISize pageSize,
    243                 SkScalar rasterDpi,
    244                 SkPDFCanon* canon,
    245                 bool flip);
    246 
    247     ContentEntry* getLastContentEntry();
    248     void setLastContentEntry(ContentEntry* contentEntry);
    249 
    250     SkBaseDevice* onCreateDevice(const CreateInfo&, const SkPaint*) override;
    251 
    252     void init();
    253     void cleanUp(bool clearFontUsage);
    254     SkPDFFormXObject* createFormXObjectFromDevice();
    255 
    256     void drawFormXObjectWithMask(int xObjectIndex,
    257                                  SkPDFFormXObject* mask,
    258                                  const SkClipStack* clipStack,
    259                                  const SkRegion& clipRegion,
    260                                  SkXfermode::Mode mode,
    261                                  bool invertClip);
    262 
    263     // If the paint or clip is such that we shouldn't draw anything, this
    264     // returns nullptr and does not create a content entry.
    265     // setUpContentEntry and finishContentEntry can be used directly, but
    266     // the preferred method is to use the ScopedContentEntry helper class.
    267     ContentEntry* setUpContentEntry(const SkClipStack* clipStack,
    268                                     const SkRegion& clipRegion,
    269                                     const SkMatrix& matrix,
    270                                     const SkPaint& paint,
    271                                     bool hasText,
    272                                     SkPDFFormXObject** dst);
    273     void finishContentEntry(SkXfermode::Mode xfermode,
    274                             SkPDFFormXObject* dst,
    275                             SkPath* shape);
    276     bool isContentEmpty();
    277 
    278     void populateGraphicStateEntryFromPaint(const SkMatrix& matrix,
    279                                             const SkClipStack& clipStack,
    280                                             const SkRegion& clipRegion,
    281                                             const SkPaint& paint,
    282                                             bool hasText,
    283                                             GraphicStateEntry* entry);
    284     int addGraphicStateResource(SkPDFObject* gs);
    285     int addXObjectResource(SkPDFObject* xObject);
    286 
    287     void updateFont(const SkPaint& paint, uint16_t glyphID, ContentEntry* contentEntry);
    288     int getFontResourceIndex(SkTypeface* typeface, uint16_t glyphID);
    289 
    290     void internalDrawPaint(const SkPaint& paint, ContentEntry* contentEntry);
    291     void internalDrawImage(const SkMatrix& matrix,
    292                            const SkClipStack* clipStack,
    293                            const SkRegion& clipRegion,
    294                            const SkImage* image,
    295                            const SkIRect* srcRect,
    296                            const SkPaint& paint);
    297 
    298     /** Helper method for copyContentToData. It is responsible for copying the
    299      *  list of content entries |entry| to |data|.
    300      */
    301     void copyContentEntriesToData(ContentEntry* entry, SkWStream* data) const;
    302 
    303     bool handleInversePath(const SkDraw& d, const SkPath& origPath,
    304                            const SkPaint& paint, bool pathIsMutable,
    305                            const SkMatrix* prePathMatrix = nullptr);
    306     bool handlePointAnnotation(const SkPoint* points, size_t count,
    307                                const SkMatrix& matrix, SkAnnotation* annot);
    308     bool handlePathAnnotation(const SkPath& path, const SkDraw& d,
    309                               SkAnnotation* annot);
    310 
    311     typedef SkBaseDevice INHERITED;
    312 
    313     // TODO(edisonn): Only SkDocument_PDF and SkPDFImageShader should be able to create
    314     // an SkPDFDevice
    315     //friend class SkDocument_PDF;
    316     //friend class SkPDFImageShader;
    317 };
    318 
    319 #endif
    320