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 #include "SkData.h" 9 #include "SkLazyPtr.h" 10 #include "SkPDFCanon.h" 11 #include "SkPDFFormXObject.h" 12 #include "SkPDFGraphicState.h" 13 #include "SkPDFUtils.h" 14 #include "SkTypes.h" 15 16 static const char* as_blend_mode(SkXfermode::Mode mode) { 17 switch (mode) { 18 case SkXfermode::kSrcOver_Mode: 19 return "Normal"; 20 case SkXfermode::kMultiply_Mode: 21 return "Multiply"; 22 case SkXfermode::kScreen_Mode: 23 return "Screen"; 24 case SkXfermode::kOverlay_Mode: 25 return "Overlay"; 26 case SkXfermode::kDarken_Mode: 27 return "Darken"; 28 case SkXfermode::kLighten_Mode: 29 return "Lighten"; 30 case SkXfermode::kColorDodge_Mode: 31 return "ColorDodge"; 32 case SkXfermode::kColorBurn_Mode: 33 return "ColorBurn"; 34 case SkXfermode::kHardLight_Mode: 35 return "HardLight"; 36 case SkXfermode::kSoftLight_Mode: 37 return "SoftLight"; 38 case SkXfermode::kDifference_Mode: 39 return "Difference"; 40 case SkXfermode::kExclusion_Mode: 41 return "Exclusion"; 42 case SkXfermode::kHue_Mode: 43 return "Hue"; 44 case SkXfermode::kSaturation_Mode: 45 return "Saturation"; 46 case SkXfermode::kColor_Mode: 47 return "Color"; 48 case SkXfermode::kLuminosity_Mode: 49 return "Luminosity"; 50 51 // These are handled in SkPDFDevice::setUpContentEntry. 52 case SkXfermode::kClear_Mode: 53 case SkXfermode::kSrc_Mode: 54 case SkXfermode::kDst_Mode: 55 case SkXfermode::kDstOver_Mode: 56 case SkXfermode::kSrcIn_Mode: 57 case SkXfermode::kDstIn_Mode: 58 case SkXfermode::kSrcOut_Mode: 59 case SkXfermode::kDstOut_Mode: 60 case SkXfermode::kSrcATop_Mode: 61 case SkXfermode::kDstATop_Mode: 62 case SkXfermode::kModulate_Mode: 63 return "Normal"; 64 65 // TODO(vandebo): Figure out if we can support more of these modes. 66 case SkXfermode::kXor_Mode: 67 case SkXfermode::kPlus_Mode: 68 return NULL; 69 } 70 return NULL; 71 } 72 73 // If a SkXfermode is unsupported in PDF, this function returns 74 // SrcOver, otherwise, it returns that Xfermode as a Mode. 75 static SkXfermode::Mode mode_for_pdf(const SkXfermode* xfermode) { 76 SkXfermode::Mode mode = SkXfermode::kSrcOver_Mode; 77 if (xfermode) { 78 xfermode->asMode(&mode); 79 } 80 switch (mode) { 81 case SkXfermode::kSrcOver_Mode: 82 case SkXfermode::kMultiply_Mode: 83 case SkXfermode::kScreen_Mode: 84 case SkXfermode::kOverlay_Mode: 85 case SkXfermode::kDarken_Mode: 86 case SkXfermode::kLighten_Mode: 87 case SkXfermode::kColorDodge_Mode: 88 case SkXfermode::kColorBurn_Mode: 89 case SkXfermode::kHardLight_Mode: 90 case SkXfermode::kSoftLight_Mode: 91 case SkXfermode::kDifference_Mode: 92 case SkXfermode::kExclusion_Mode: 93 case SkXfermode::kHue_Mode: 94 case SkXfermode::kSaturation_Mode: 95 case SkXfermode::kColor_Mode: 96 case SkXfermode::kLuminosity_Mode: 97 // Mode is suppported and handled by pdf graphics state. 98 return mode; 99 default: 100 return SkXfermode::kSrcOver_Mode; // Default mode. 101 } 102 } 103 104 SkPDFGraphicState::SkPDFGraphicState(const SkPaint& p) 105 : fStrokeWidth(p.getStrokeWidth()) 106 , fStrokeMiter(p.getStrokeMiter()) 107 , fAlpha(p.getAlpha()) 108 , fStrokeCap(SkToU8(p.getStrokeCap())) 109 , fStrokeJoin(SkToU8(p.getStrokeJoin())) 110 , fMode(SkToU8(mode_for_pdf(p.getXfermode()))) {} 111 112 // static 113 SkPDFGraphicState* SkPDFGraphicState::GetGraphicStateForPaint( 114 SkPDFCanon* canon, const SkPaint& paint) { 115 SkASSERT(canon); 116 SkPDFGraphicState key(paint); 117 if (const SkPDFGraphicState* canonGS = canon->findGraphicState(key)) { 118 // The returned SkPDFGraphicState must be made non-const, 119 // since the emitObject() interface is non-const. But We 120 // promise that there is no way to mutate this object from 121 // here on out. 122 return SkRef(const_cast<SkPDFGraphicState*>(canonGS)); 123 } 124 SkPDFGraphicState* pdfGraphicState = new SkPDFGraphicState(paint); 125 canon->addGraphicState(pdfGraphicState); 126 return pdfGraphicState; 127 } 128 129 namespace { 130 SkPDFObject* create_invert_function() { 131 // Acrobat crashes if we use a type 0 function, kpdf crashes if we use 132 // a type 2 function, so we use a type 4 function. 133 SkAutoTUnref<SkPDFArray> domainAndRange(new SkPDFArray); 134 domainAndRange->reserve(2); 135 domainAndRange->appendInt(0); 136 domainAndRange->appendInt(1); 137 138 static const char psInvert[] = "{1 exch sub}"; 139 // Do not copy the trailing '\0' into the SkData. 140 SkAutoTUnref<SkData> psInvertStream( 141 SkData::NewWithoutCopy(psInvert, strlen(psInvert))); 142 143 SkPDFStream* invertFunction = SkNEW_ARGS( 144 SkPDFStream, (psInvertStream.get())); 145 invertFunction->insertInt("FunctionType", 4); 146 invertFunction->insertObject("Domain", SkRef(domainAndRange.get())); 147 invertFunction->insertObject("Range", domainAndRange.detach()); 148 return invertFunction; 149 } 150 151 template <typename T> void unref(T* ptr) { ptr->unref(); } 152 } // namespace 153 154 SK_DECLARE_STATIC_LAZY_PTR(SkPDFObject, 155 invertFunction, 156 create_invert_function, 157 unref<SkPDFObject>); 158 159 // static 160 SkPDFDict* SkPDFGraphicState::GetSMaskGraphicState(SkPDFFormXObject* sMask, 161 bool invert, 162 SkPDFSMaskMode sMaskMode) { 163 // The practical chances of using the same mask more than once are unlikely 164 // enough that it's not worth canonicalizing. 165 SkAutoTUnref<SkPDFDict> sMaskDict(new SkPDFDict("Mask")); 166 if (sMaskMode == kAlpha_SMaskMode) { 167 sMaskDict->insertName("S", "Alpha"); 168 } else if (sMaskMode == kLuminosity_SMaskMode) { 169 sMaskDict->insertName("S", "Luminosity"); 170 } 171 sMaskDict->insertObjRef("G", SkRef(sMask)); 172 if (invert) { 173 sMaskDict->insertObjRef("TR", SkRef(invertFunction.get())); 174 } 175 176 SkPDFDict* result = new SkPDFDict("ExtGState"); 177 result->insertObject("SMask", sMaskDict.detach()); 178 return result; 179 } 180 181 namespace { 182 SkPDFDict* create_no_smask_graphic_state() { 183 SkPDFDict* noSMaskGS = new SkPDFDict("ExtGState"); 184 noSMaskGS->insertName("SMask", "None"); 185 return noSMaskGS; 186 } 187 } // namespace 188 SK_DECLARE_STATIC_LAZY_PTR(SkPDFDict, 189 noSMaskGraphicState, 190 create_no_smask_graphic_state, 191 unref<SkPDFDict>); 192 193 // static 194 SkPDFDict* SkPDFGraphicState::GetNoSMaskGraphicState() { 195 return SkRef(noSMaskGraphicState.get()); 196 } 197 198 void SkPDFGraphicState::emitObject(SkWStream* stream, 199 const SkPDFObjNumMap& objNumMap, 200 const SkPDFSubstituteMap& substitutes) { 201 SkAutoTUnref<SkPDFDict> dict(SkNEW_ARGS(SkPDFDict, ("ExtGState"))); 202 dict->insertName("Type", "ExtGState"); 203 204 SkScalar alpha = SkIntToScalar(fAlpha) / 0xFF; 205 dict->insertScalar("CA", alpha); 206 dict->insertScalar("ca", alpha); 207 208 SkPaint::Cap strokeCap = (SkPaint::Cap)fStrokeCap; 209 SkPaint::Join strokeJoin = (SkPaint::Join)fStrokeJoin; 210 SkXfermode::Mode xferMode = (SkXfermode::Mode)fMode; 211 212 SK_COMPILE_ASSERT(SkPaint::kButt_Cap == 0, paint_cap_mismatch); 213 SK_COMPILE_ASSERT(SkPaint::kRound_Cap == 1, paint_cap_mismatch); 214 SK_COMPILE_ASSERT(SkPaint::kSquare_Cap == 2, paint_cap_mismatch); 215 SK_COMPILE_ASSERT(SkPaint::kCapCount == 3, paint_cap_mismatch); 216 SkASSERT(strokeCap >= 0 && strokeCap <= 2); 217 dict->insertInt("LC", strokeCap); 218 219 SK_COMPILE_ASSERT(SkPaint::kMiter_Join == 0, paint_join_mismatch); 220 SK_COMPILE_ASSERT(SkPaint::kRound_Join == 1, paint_join_mismatch); 221 SK_COMPILE_ASSERT(SkPaint::kBevel_Join == 2, paint_join_mismatch); 222 SK_COMPILE_ASSERT(SkPaint::kJoinCount == 3, paint_join_mismatch); 223 SkASSERT(strokeJoin >= 0 && strokeJoin <= 2); 224 dict->insertInt("LJ", strokeJoin); 225 226 dict->insertScalar("LW", fStrokeWidth); 227 dict->insertScalar("ML", fStrokeMiter); 228 dict->insertBool("SA", true); // SA = Auto stroke adjustment. 229 dict->insertName("BM", as_blend_mode(xferMode)); 230 dict->emitObject(stream, objNumMap, substitutes); 231 } 232