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 makeCongruentDevice()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 // It is important to not confuse GraphicStateEntry with SkPDFGraphicState, the 136 // later being our representation of an object in the PDF file. 137 struct GraphicStateEntry { 138 GraphicStateEntry(); 139 140 // Compare the fields we care about when setting up a new content entry. 141 bool compareInitialState(const GraphicStateEntry& b); 142 143 SkMatrix fMatrix; 144 // We can't do set operations on Paths, though PDF natively supports 145 // intersect. If the clip stack does anything other than intersect, 146 // we have to fall back to the region. Treat fClipStack as authoritative. 147 // See https://bugs.skia.org/221 148 SkClipStack fClipStack; 149 150 // When emitting the content entry, we will ensure the graphic state 151 // is set to these values first. 152 SkColor fColor; 153 SkScalar fTextScaleX; // Zero means we don't care what the value is. 154 SkPaint::Style fTextFill; // Only if TextScaleX is non-zero. 155 int fShaderIndex; 156 int fGraphicStateIndex; 157 }; 158 159 protected: 160 sk_sp<SkSurface> makeSurface(const SkImageInfo&, const SkSurfaceProps&) override; 161 162 void drawAnnotation(const SkRect&, const char key[], SkData* value) override; 163 164 void drawSpecial(SkSpecialImage*, int x, int y, const SkPaint&, 165 SkImage*, const SkMatrix&) override; 166 sk_sp<SkSpecialImage> makeSpecial(const SkBitmap&) override; 167 sk_sp<SkSpecialImage> makeSpecial(const SkImage*) override; 168 sk_sp<SkSpecialImage> snapSpecial() override; 169 SkImageFilterCache* getImageFilterCache() override; 170 171 private: 172 struct RectWithData { 173 SkRect rect; 174 sk_sp<SkData> data; 175 }; 176 177 struct NamedDestination { 178 sk_sp<SkData> nameData; 179 SkPoint point; 180 }; 181 182 // TODO(vandebo): push most of SkPDFDevice's state into a core object in 183 // order to get the right access levels without using friend. 184 friend class ScopedContentEntry; 185 186 SkISize fPageSize; 187 SkMatrix fInitialTransform; 188 SkClipStack fExistingClipStack; 189 190 SkTArray<RectWithData> fLinkToURLs; 191 SkTArray<RectWithData> fLinkToDestinations; 192 SkTArray<NamedDestination> fNamedDestinations; 193 194 SkTDArray<SkPDFObject*> fGraphicStateResources; 195 SkTDArray<SkPDFObject*> fXObjectResources; 196 SkTDArray<SkPDFFont*> fFontResources; 197 SkTDArray<SkPDFObject*> fShaderResources; 198 199 struct ContentEntry { 200 GraphicStateEntry fState; 201 SkDynamicMemoryWStream fContent; 202 }; 203 SkSinglyLinkedList<ContentEntry> fContentEntries; 204 205 SkPDFDocument* fDocument; 206 207 //////////////////////////////////////////////////////////////////////////// 208 209 SkBaseDevice* onCreateDevice(const CreateInfo&, const SkPaint*) override; 210 211 void init(); 212 void cleanUp(); 213 sk_sp<SkPDFObject> makeFormXObjectFromDevice(); 214 215 void drawFormXObjectWithMask(int xObjectIndex, 216 sk_sp<SkPDFObject> mask, 217 const SkClipStack& clipStack, 218 SkBlendMode, 219 bool invertClip); 220 221 // If the paint or clip is such that we shouldn't draw anything, this 222 // returns nullptr and does not create a content entry. 223 // setUpContentEntry and finishContentEntry can be used directly, but 224 // the preferred method is to use the ScopedContentEntry helper class. 225 ContentEntry* setUpContentEntry(const SkClipStack& clipStack, 226 const SkMatrix& matrix, 227 const SkPaint& paint, 228 bool hasText, 229 sk_sp<SkPDFObject>* dst); 230 void finishContentEntry(SkBlendMode, sk_sp<SkPDFObject> dst, SkPath* shape); 231 bool isContentEmpty(); 232 233 void populateGraphicStateEntryFromPaint(const SkMatrix& matrix, 234 const SkClipStack& clipStack, 235 const SkPaint& paint, 236 bool hasText, 237 GraphicStateEntry* entry); 238 int addGraphicStateResource(SkPDFObject* gs); 239 int addXObjectResource(SkPDFObject* xObject); 240 241 int getFontResourceIndex(SkTypeface* typeface, uint16_t glyphID); 242 243 244 void internalDrawText( const void*, size_t, const SkScalar pos[], 245 SkTextBlob::GlyphPositioning, SkPoint, const SkPaint&, 246 const uint32_t*, uint32_t, const char*); 247 248 void internalDrawPaint(const SkPaint& paint, ContentEntry* contentEntry); 249 250 void internalDrawImageRect(SkKeyedImage, 251 const SkRect* src, 252 const SkRect& dst, 253 const SkPaint&, 254 const SkMatrix& canvasTransformationMatrix); 255 256 void internalDrawPath(const SkClipStack&, 257 const SkMatrix&, 258 const SkPath&, 259 const SkPaint&, 260 const SkMatrix* prePathMatrix, 261 bool pathIsMutable); 262 263 void internalDrawPathWithFilter(const SkClipStack& clipStack, 264 const SkMatrix& ctm, 265 const SkPath& origPath, 266 const SkPaint& paint, 267 const SkMatrix* prePathMatrix); 268 269 bool handleInversePath(const SkPath& origPath, 270 const SkPaint& paint, bool pathIsMutable, 271 const SkMatrix* prePathMatrix = nullptr); 272 273 void addSMaskGraphicState(sk_sp<SkPDFDevice> maskDevice, SkDynamicMemoryWStream*); 274 void clearMaskOnGraphicState(SkDynamicMemoryWStream*); 275 276 typedef SkClipStackDevice INHERITED; 277 }; 278 279 #endif 280