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