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 "include/core/SkBitmap.h" 12 #include "include/core/SkCanvas.h" 13 #include "include/core/SkData.h" 14 #include "include/core/SkPaint.h" 15 #include "include/core/SkRect.h" 16 #include "include/core/SkRefCnt.h" 17 #include "include/core/SkStream.h" 18 #include "include/private/SkTHash.h" 19 #include "src/core/SkClipStack.h" 20 #include "src/core/SkClipStackDevice.h" 21 #include "src/core/SkTextBlobPriv.h" 22 #include "src/pdf/SkKeyedImage.h" 23 #include "src/pdf/SkPDFGraphicStackState.h" 24 #include "src/pdf/SkPDFTypes.h" 25 26 #include <vector> 27 28 class SkGlyphRunList; 29 class SkKeyedImage; 30 class SkPDFArray; 31 class SkPDFDevice; 32 class SkPDFDict; 33 class SkPDFDocument; 34 class SkPDFFont; 35 class SkPDFObject; 36 class SkPath; 37 class SkRRect; 38 struct SkPDFIndirectReference; 39 40 /** 41 * \class SkPDFDevice 42 * 43 * An SkPDFDevice is the drawing context for a page or layer of PDF 44 * content. 45 */ 46 class SkPDFDevice final : public SkClipStackDevice { 47 public: 48 /** 49 * @param pageSize Page size in point units. 50 * 1 point == 127/360 mm == 1/72 inch 51 * @param document A non-null pointer back to the 52 * PDFDocument object. The document is responsible for 53 * de-duplicating across pages (via the SkPDFDocument) and 54 * for early serializing of large immutable objects, such 55 * as images (via SkPDFDocument::serialize()). 56 * @param initialTransform Transform to be applied to the entire page. 57 */ 58 SkPDFDevice(SkISize pageSize, SkPDFDocument* document, 59 const SkMatrix& initialTransform = SkMatrix::I()); 60 makeCongruentDevice()61 sk_sp<SkPDFDevice> makeCongruentDevice() { 62 return sk_make_sp<SkPDFDevice>(this->size(), fDocument); 63 } 64 65 ~SkPDFDevice() override; 66 67 /** 68 * These are called inside the per-device-layer loop for each draw call. 69 * When these are called, we have already applied any saveLayer 70 * operations, and are handling any looping from the paint. 71 */ 72 void drawPaint(const SkPaint& paint) override; 73 void drawPoints(SkCanvas::PointMode mode, 74 size_t count, const SkPoint[], 75 const SkPaint& paint) override; 76 void drawRect(const SkRect& r, const SkPaint& paint) override; 77 void drawOval(const SkRect& oval, const SkPaint& paint) override; 78 void drawRRect(const SkRRect& rr, const SkPaint& paint) override; 79 void drawPath(const SkPath& origpath, const SkPaint& paint, bool pathIsMutable) override; 80 81 void drawImageRect(const SkImage*, 82 const SkRect* src, 83 const SkRect& dst, 84 const SkPaint&, 85 SkCanvas::SrcRectConstraint) override; 86 void drawGlyphRunList(const SkGlyphRunList& glyphRunList) override; 87 void drawVertices(const SkVertices*, SkBlendMode, const SkPaint&) override; 88 void drawDevice(SkBaseDevice*, int x, int y, 89 const SkPaint&) override; 90 91 // PDF specific methods. 92 void drawSprite(const SkBitmap& bitmap, int x, int y, 93 const SkPaint& paint); 94 95 /** Create the resource dictionary for this device. Destructive. */ 96 std::unique_ptr<SkPDFDict> makeResourceDict(); 97 98 /** Returns a SkStream with the page contents. 99 */ 100 std::unique_ptr<SkStreamAsset> content(); 101 size()102 SkISize size() const { return this->imageInfo().dimensions(); } bounds()103 SkIRect bounds() const { return this->imageInfo().bounds(); } 104 105 void DrawGlyphRunAsPath(SkPDFDevice* dev, const SkGlyphRun& glyphRun, SkPoint offset); 106 initialTransform()107 const SkMatrix& initialTransform() const { return fInitialTransform; } 108 109 protected: 110 sk_sp<SkSurface> makeSurface(const SkImageInfo&, const SkSurfaceProps&) override; 111 112 void drawAnnotation(const SkRect&, const char key[], SkData* value) override; 113 114 void drawSpecial(SkSpecialImage*, int x, int y, const SkPaint&, 115 SkImage*, const SkMatrix&) override; 116 sk_sp<SkSpecialImage> makeSpecial(const SkBitmap&) override; 117 sk_sp<SkSpecialImage> makeSpecial(const SkImage*) override; 118 SkImageFilterCache* getImageFilterCache() override; 119 120 private: 121 // TODO(vandebo): push most of SkPDFDevice's state into a core object in 122 // order to get the right access levels without using friend. 123 friend class ScopedContentEntry; 124 125 SkMatrix fInitialTransform; 126 127 SkTHashSet<SkPDFIndirectReference> fGraphicStateResources; 128 SkTHashSet<SkPDFIndirectReference> fXObjectResources; 129 SkTHashSet<SkPDFIndirectReference> fShaderResources; 130 SkTHashSet<SkPDFIndirectReference> fFontResources; 131 int fNodeId; 132 133 SkDynamicMemoryWStream fContent; 134 SkDynamicMemoryWStream fContentBuffer; 135 bool fNeedsExtraSave = false; 136 SkPDFGraphicStackState fActiveStackState; 137 SkPDFDocument* fDocument; 138 139 //////////////////////////////////////////////////////////////////////////// 140 141 SkBaseDevice* onCreateDevice(const CreateInfo&, const SkPaint*) override; 142 143 // Set alpha to true if making a transparency group form x-objects. 144 SkPDFIndirectReference makeFormXObjectFromDevice(bool alpha = false); 145 SkPDFIndirectReference makeFormXObjectFromDevice(SkIRect bbox, bool alpha = false); 146 147 void drawFormXObjectWithMask(SkPDFIndirectReference xObject, 148 SkPDFIndirectReference sMask, 149 SkBlendMode, 150 bool invertClip); 151 152 // If the paint or clip is such that we shouldn't draw anything, this 153 // returns nullptr and does not create a content entry. 154 // setUpContentEntry and finishContentEntry can be used directly, but 155 // the preferred method is to use the ScopedContentEntry helper class. 156 SkDynamicMemoryWStream* setUpContentEntry(const SkClipStack* clipStack, 157 const SkMatrix& matrix, 158 const SkPaint& paint, 159 SkScalar, 160 SkPDFIndirectReference* dst); 161 void finishContentEntry(const SkClipStack*, SkBlendMode, SkPDFIndirectReference, SkPath*); 162 bool isContentEmpty(); 163 164 void internalDrawGlyphRun(const SkGlyphRun& glyphRun, SkPoint offset, const SkPaint& runPaint); 165 void drawGlyphRunAsPath(const SkGlyphRun& glyphRun, SkPoint offset, const SkPaint& runPaint); 166 167 void internalDrawImageRect(SkKeyedImage, 168 const SkRect* src, 169 const SkRect& dst, 170 const SkPaint&, 171 const SkMatrix& canvasTransformationMatrix); 172 173 void internalDrawPath(const SkClipStack&, 174 const SkMatrix&, 175 const SkPath&, 176 const SkPaint&, 177 bool pathIsMutable); 178 179 void internalDrawPathWithFilter(const SkClipStack& clipStack, 180 const SkMatrix& ctm, 181 const SkPath& origPath, 182 const SkPaint& paint); 183 184 bool handleInversePath(const SkPath& origPath, const SkPaint& paint, bool pathIsMutable); 185 186 void clearMaskOnGraphicState(SkDynamicMemoryWStream*); 187 void setGraphicState(SkPDFIndirectReference gs, SkDynamicMemoryWStream*); 188 void drawFormXObject(SkPDFIndirectReference xObject, SkDynamicMemoryWStream*); 189 hasEmptyClip()190 bool hasEmptyClip() const { return this->cs().isEmpty(this->bounds()); } 191 192 void reset(); 193 194 typedef SkClipStackDevice INHERITED; 195 }; 196 197 #endif 198