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 "SkClipStackDevice.h"
     15 #include "SkData.h"
     16 #include "SkPaint.h"
     17 #include "SkRect.h"
     18 #include "SkRefCnt.h"
     19 #include "SkSinglyLinkedList.h"
     20 #include "SkStream.h"
     21 #include "SkTDArray.h"
     22 #include "SkTextBlob.h"
     23 #include "SkKeyedImage.h"
     24 
     25 class SkKeyedImage;
     26 class SkPath;
     27 class SkPDFArray;
     28 class SkPDFCanon;
     29 class SkPDFDevice;
     30 class SkPDFDocument;
     31 class SkPDFDict;
     32 class SkPDFFont;
     33 class SkPDFObject;
     34 class SkPDFStream;
     35 class SkRRect;
     36 
     37 /**
     38  *  \class SkPDFDevice
     39  *
     40  *  An SkPDFDevice is the drawing context for a page or layer of PDF
     41  *  content.
     42  */
     43 class SkPDFDevice final : public SkClipStackDevice {
     44 public:
     45     /**
     46      *  @param pageSize Page size in point units.
     47      *         1 point == 127/360 mm == 1/72 inch
     48      *  @param document  A non-null pointer back to the
     49      *         PDFDocument object.  The document is repsonsible for
     50      *         de-duplicating across pages (via the SkPDFCanon) and
     51      *         for early serializing of large immutable objects, such
     52      *         as images (via SkPDFDocument::serialize()).
     53      */
     54     SkPDFDevice(SkISize pageSize, SkPDFDocument* document);
     55 
     56     /**
     57      *  Apply a scale-and-translate transform to move the origin from the
     58      *  bottom left (PDF default) to the top left (Skia default).
     59      */
     60     void setFlip();
     61 
     62     sk_sp<SkPDFDevice> makeCongruentDevice() {
     63         return sk_make_sp<SkPDFDevice>(fPageSize, fDocument);
     64     }
     65 
     66     ~SkPDFDevice() override;
     67 
     68     /**
     69      *  These are called inside the per-device-layer loop for each draw call.
     70      *  When these are called, we have already applied any saveLayer
     71      *  operations, and are handling any looping from the paint, and any
     72      *  effects from the DrawFilter.
     73      */
     74     void drawPaint(const SkPaint& paint) override;
     75     void drawPoints(SkCanvas::PointMode mode,
     76                     size_t count, const SkPoint[],
     77                     const SkPaint& paint) override;
     78     void drawRect(const SkRect& r, const SkPaint& paint) override;
     79     void drawOval(const SkRect& oval, const SkPaint& paint) override;
     80     void drawRRect(const SkRRect& rr, const SkPaint& paint) override;
     81     void drawPath(const SkPath& origpath,
     82                   const SkPaint& paint, const SkMatrix* prePathMatrix,
     83                   bool pathIsMutable) override;
     84     void drawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
     85                         const SkRect& dst, const SkPaint&, SkCanvas::SrcRectConstraint) override;
     86     void drawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint&) override;
     87     void drawSprite(const SkBitmap& bitmap, int x, int y,
     88                     const SkPaint& paint) override;
     89     void drawImage(const SkImage*,
     90                    SkScalar x,
     91                    SkScalar y,
     92                    const SkPaint&) override;
     93     void drawImageRect(const SkImage*,
     94                        const SkRect* src,
     95                        const SkRect& dst,
     96                        const SkPaint&,
     97                        SkCanvas::SrcRectConstraint) override;
     98     void drawText(const void* text, size_t len,
     99                   SkScalar x, SkScalar y, const SkPaint&) override;
    100     void drawPosText(const void* text, size_t len,
    101                      const SkScalar pos[], int scalarsPerPos,
    102                      const SkPoint& offset, const SkPaint&) override;
    103     void drawTextBlob(const SkTextBlob*, SkScalar x, SkScalar y,
    104                       const SkPaint &, SkDrawFilter*) override;
    105     void drawVertices(const SkVertices*, SkBlendMode, const SkPaint&) override;
    106     void drawDevice(SkBaseDevice*, int x, int y,
    107                     const SkPaint&) override;
    108 
    109     // PDF specific methods.
    110 
    111     /** Create the resource dictionary for this device. */
    112     sk_sp<SkPDFDict> makeResourceDict() const;
    113 
    114     /** Add our annotations (link to urls and destinations) to the supplied
    115      *  array.
    116      *  @param array Array to add annotations to.
    117      */
    118     void appendAnnotations(SkPDFArray* array) const;
    119 
    120     /** Add our named destinations to the supplied dictionary.
    121      *  @param dict  Dictionary to add destinations to.
    122      *  @param page  The PDF object representing the page for this device.
    123      */
    124     void appendDestinations(SkPDFDict* dict, SkPDFObject* page) const;
    125 
    126     /** Returns a copy of the media box for this device. */
    127     sk_sp<SkPDFArray> copyMediaBox() const;
    128 
    129     /** Returns a SkStream with the page contents.
    130      */
    131     std::unique_ptr<SkStreamAsset> content() const;
    132 
    133     SkPDFCanon* getCanon() const;
    134 
    135     SkIRect bounds() const { return this->imageInfo().bounds(); }
    136 
    137     // It is important to not confuse GraphicStateEntry with SkPDFGraphicState, the
    138     // later being our representation of an object in the PDF file.
    139     struct GraphicStateEntry {
    140         GraphicStateEntry();
    141 
    142         // Compare the fields we care about when setting up a new content entry.
    143         bool compareInitialState(const GraphicStateEntry& b);
    144 
    145         SkMatrix fMatrix;
    146         // We can't do set operations on Paths, though PDF natively supports
    147         // intersect.  If the clip stack does anything other than intersect,
    148         // we have to fall back to the region.  Treat fClipStack as authoritative.
    149         // See https://bugs.skia.org/221
    150         SkClipStack fClipStack;
    151 
    152         // When emitting the content entry, we will ensure the graphic state
    153         // is set to these values first.
    154         SkColor fColor;
    155         SkScalar fTextScaleX;  // Zero means we don't care what the value is.
    156         SkPaint::Style fTextFill;  // Only if TextScaleX is non-zero.
    157         int fShaderIndex;
    158         int fGraphicStateIndex;
    159     };
    160 
    161 protected:
    162     sk_sp<SkSurface> makeSurface(const SkImageInfo&, const SkSurfaceProps&) override;
    163 
    164     void drawAnnotation(const SkRect&, const char key[], SkData* value) override;
    165 
    166     void drawSpecial(SkSpecialImage*, int x, int y, const SkPaint&,
    167                      SkImage*, const SkMatrix&) override;
    168     sk_sp<SkSpecialImage> makeSpecial(const SkBitmap&) override;
    169     sk_sp<SkSpecialImage> makeSpecial(const SkImage*) override;
    170     sk_sp<SkSpecialImage> snapSpecial() override;
    171     SkImageFilterCache* getImageFilterCache() override;
    172 
    173 private:
    174     struct RectWithData {
    175         SkRect rect;
    176         sk_sp<SkData> data;
    177     };
    178 
    179     struct NamedDestination {
    180         sk_sp<SkData> nameData;
    181         SkPoint point;
    182     };
    183 
    184     // TODO(vandebo): push most of SkPDFDevice's state into a core object in
    185     // order to get the right access levels without using friend.
    186     friend class ScopedContentEntry;
    187 
    188     SkISize fPageSize;
    189     SkMatrix fInitialTransform;
    190     SkClipStack fExistingClipStack;
    191 
    192     SkTArray<RectWithData> fLinkToURLs;
    193     SkTArray<RectWithData> fLinkToDestinations;
    194     SkTArray<NamedDestination> fNamedDestinations;
    195 
    196     SkTDArray<SkPDFObject*> fGraphicStateResources;
    197     SkTDArray<SkPDFObject*> fXObjectResources;
    198     SkTDArray<SkPDFFont*> fFontResources;
    199     SkTDArray<SkPDFObject*> fShaderResources;
    200 
    201     struct ContentEntry {
    202         GraphicStateEntry fState;
    203         SkDynamicMemoryWStream fContent;
    204     };
    205     SkSinglyLinkedList<ContentEntry> fContentEntries;
    206 
    207     SkPDFDocument* fDocument;
    208 
    209     ////////////////////////////////////////////////////////////////////////////
    210 
    211     SkBaseDevice* onCreateDevice(const CreateInfo&, const SkPaint*) override;
    212 
    213     void init();
    214     void cleanUp();
    215     // Set alpha to true if making a transparency group form x-objects.
    216     sk_sp<SkPDFObject> makeFormXObjectFromDevice(bool alpha = false);
    217 
    218     void drawFormXObjectWithMask(int xObjectIndex,
    219                                  sk_sp<SkPDFObject> mask,
    220                                  const SkClipStack& clipStack,
    221                                  SkBlendMode,
    222                                  bool invertClip);
    223 
    224     // If the paint or clip is such that we shouldn't draw anything, this
    225     // returns nullptr and does not create a content entry.
    226     // setUpContentEntry and finishContentEntry can be used directly, but
    227     // the preferred method is to use the ScopedContentEntry helper class.
    228     ContentEntry* setUpContentEntry(const SkClipStack& clipStack,
    229                                     const SkMatrix& matrix,
    230                                     const SkPaint& paint,
    231                                     bool hasText,
    232                                     sk_sp<SkPDFObject>* dst);
    233     void finishContentEntry(SkBlendMode, sk_sp<SkPDFObject> dst, SkPath* shape);
    234     bool isContentEmpty();
    235 
    236     void populateGraphicStateEntryFromPaint(const SkMatrix& matrix,
    237                                             const SkClipStack& clipStack,
    238                                             const SkPaint& paint,
    239                                             bool hasText,
    240                                             GraphicStateEntry* entry);
    241     int addGraphicStateResource(SkPDFObject* gs);
    242     int addXObjectResource(SkPDFObject* xObject);
    243 
    244     int getFontResourceIndex(SkTypeface* typeface, uint16_t glyphID);
    245 
    246 
    247     void internalDrawText( const void*, size_t, const SkScalar pos[],
    248                           SkTextBlob::GlyphPositioning, SkPoint, const SkPaint&,
    249                           const uint32_t*, uint32_t, const char*);
    250 
    251     void internalDrawPaint(const SkPaint& paint, ContentEntry* contentEntry);
    252 
    253     void internalDrawImageRect(SkKeyedImage,
    254                                const SkRect* src,
    255                                const SkRect& dst,
    256                                const SkPaint&,
    257                                const SkMatrix& canvasTransformationMatrix);
    258 
    259     void internalDrawPath(const SkClipStack&,
    260                           const SkMatrix&,
    261                           const SkPath&,
    262                           const SkPaint&,
    263                           const SkMatrix* prePathMatrix,
    264                           bool pathIsMutable);
    265 
    266     void internalDrawPathWithFilter(const SkClipStack& clipStack,
    267                                     const SkMatrix& ctm,
    268                                     const SkPath& origPath,
    269                                     const SkPaint& paint,
    270                                     const SkMatrix* prePathMatrix);
    271 
    272     bool handleInversePath(const SkPath& origPath,
    273                            const SkPaint& paint, bool pathIsMutable,
    274                            const SkMatrix* prePathMatrix = nullptr);
    275 
    276     void addSMaskGraphicState(sk_sp<SkPDFDevice> maskDevice, SkDynamicMemoryWStream*);
    277     void clearMaskOnGraphicState(SkDynamicMemoryWStream*);
    278 
    279     typedef SkClipStackDevice INHERITED;
    280 };
    281 
    282 #endif
    283