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 SkSamplingOptions&, 85 const SkPaint&, 86 SkCanvas::SrcRectConstraint) override; 87 void onDrawGlyphRunList(const SkGlyphRunList& glyphRunList, const SkPaint& paint) override; 88 void drawVertices(const SkVertices*, SkBlendMode, const SkPaint&) override; 89 90 // PDF specific methods. 91 void drawSprite(const SkBitmap& bitmap, int x, int y, 92 const SkPaint& paint); 93 94 /** Create the resource dictionary for this device. Destructive. */ 95 std::unique_ptr<SkPDFDict> makeResourceDict(); 96 97 /** Returns a SkStream with the page contents. 98 */ 99 std::unique_ptr<SkStreamAsset> content(); 100 size()101 SkISize size() const { return this->imageInfo().dimensions(); } bounds()102 SkIRect bounds() const { return this->imageInfo().bounds(); } 103 initialTransform()104 const SkMatrix& initialTransform() const { return fInitialTransform; } 105 106 protected: 107 sk_sp<SkSurface> makeSurface(const SkImageInfo&, const SkSurfaceProps&) override; 108 109 void drawAnnotation(const SkRect&, const char key[], SkData* value) override; 110 111 void drawDevice(SkBaseDevice*, const SkSamplingOptions&, const SkPaint&) override; 112 void drawSpecial(SkSpecialImage*, const SkMatrix&, const SkSamplingOptions&, 113 const SkPaint&) override; 114 115 sk_sp<SkSpecialImage> makeSpecial(const SkBitmap&) override; 116 sk_sp<SkSpecialImage> makeSpecial(const SkImage*) override; 117 SkImageFilterCache* getImageFilterCache() override; 118 119 private: 120 // TODO(vandebo): push most of SkPDFDevice's state into a core object in 121 // order to get the right access levels without using friend. 122 friend class ScopedContentEntry; 123 124 SkMatrix fInitialTransform; 125 126 SkTHashSet<SkPDFIndirectReference> fGraphicStateResources; 127 SkTHashSet<SkPDFIndirectReference> fXObjectResources; 128 SkTHashSet<SkPDFIndirectReference> fShaderResources; 129 SkTHashSet<SkPDFIndirectReference> fFontResources; 130 int fNodeId; 131 132 SkDynamicMemoryWStream fContent; 133 SkDynamicMemoryWStream fContentBuffer; 134 bool fNeedsExtraSave = false; 135 SkPDFGraphicStackState fActiveStackState; 136 SkPDFDocument* fDocument; 137 138 //////////////////////////////////////////////////////////////////////////// 139 140 SkBaseDevice* onCreateDevice(const CreateInfo&, const SkPaint*) override; 141 142 // Set alpha to true if making a transparency group form x-objects. 143 SkPDFIndirectReference makeFormXObjectFromDevice(bool alpha = false); 144 SkPDFIndirectReference makeFormXObjectFromDevice(SkIRect bbox, bool alpha = false); 145 146 void drawFormXObjectWithMask(SkPDFIndirectReference xObject, 147 SkPDFIndirectReference sMask, 148 SkBlendMode, 149 bool invertClip); 150 151 // If the paint or clip is such that we shouldn't draw anything, this 152 // returns nullptr and does not create a content entry. 153 // setUpContentEntry and finishContentEntry can be used directly, but 154 // the preferred method is to use the ScopedContentEntry helper class. 155 SkDynamicMemoryWStream* setUpContentEntry(const SkClipStack* clipStack, 156 const SkMatrix& matrix, 157 const SkPaint& paint, 158 SkScalar, 159 SkPDFIndirectReference* dst); 160 void finishContentEntry(const SkClipStack*, SkBlendMode, SkPDFIndirectReference, SkPath*); 161 bool isContentEmpty(); 162 163 void internalDrawGlyphRun(const SkGlyphRun& glyphRun, SkPoint offset, const SkPaint& runPaint); 164 void drawGlyphRunAsPath(const SkGlyphRun& glyphRun, SkPoint offset, const SkPaint& runPaint); 165 166 void internalDrawImageRect(SkKeyedImage, 167 const SkRect* src, 168 const SkRect& dst, 169 const SkSamplingOptions&, 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 using INHERITED = SkClipStackDevice; 195 }; 196 197 #endif 198