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