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