| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2011 Google Inc. | 2 * Copyright 2011 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 #include "SkData.h" | 8 #include "SkData.h" |
| 9 #include "SkLazyPtr.h" | 9 #include "SkLazyPtr.h" |
| 10 #include "SkPDFCanon.h" | 10 #include "SkPDFCanon.h" |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 63 return "Normal"; | 63 return "Normal"; |
| 64 | 64 |
| 65 // TODO(vandebo): Figure out if we can support more of these modes. | 65 // TODO(vandebo): Figure out if we can support more of these modes. |
| 66 case SkXfermode::kXor_Mode: | 66 case SkXfermode::kXor_Mode: |
| 67 case SkXfermode::kPlus_Mode: | 67 case SkXfermode::kPlus_Mode: |
| 68 return NULL; | 68 return NULL; |
| 69 } | 69 } |
| 70 return NULL; | 70 return NULL; |
| 71 } | 71 } |
| 72 | 72 |
| 73 static bool equivalent(const SkPaint& a, const SkPaint& b) { | 73 // If a SkXfermode is unsupported in PDF, this function returns |
| 74 // We're only interested in some fields of the SkPaint, so we have | 74 // SrcOver, otherwise, it returns that Xfermode as a Mode. |
| 75 // a custom equality function. | 75 static SkXfermode::Mode mode_for_pdf(const SkXfermode* xfermode) { |
| 76 if (SkColorGetA(a.getColor()) != SkColorGetA(b.getColor()) || | 76 SkXfermode::Mode mode = SkXfermode::kSrcOver_Mode; |
| 77 a.getStrokeCap() != b.getStrokeCap() || | 77 if (xfermode) { |
| 78 a.getStrokeJoin() != b.getStrokeJoin() || | 78 xfermode->asMode(&mode); |
| 79 a.getStrokeWidth() != b.getStrokeWidth() || | |
| 80 a.getStrokeMiter() != b.getStrokeMiter()) { | |
| 81 return false; | |
| 82 } | 79 } |
| 83 | 80 switch (mode) { |
| 84 SkXfermode::Mode aXfermodeName = SkXfermode::kSrcOver_Mode; | 81 case SkXfermode::kSrcOver_Mode: |
| 85 SkXfermode* aXfermode = a.getXfermode(); | 82 case SkXfermode::kMultiply_Mode: |
| 86 if (aXfermode) { | 83 case SkXfermode::kScreen_Mode: |
| 87 aXfermode->asMode(&aXfermodeName); | 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. |
| 88 } | 101 } |
| 89 if (aXfermodeName < 0 || aXfermodeName > SkXfermode::kLastMode || | |
| 90 as_blend_mode(aXfermodeName) == NULL) { | |
| 91 aXfermodeName = SkXfermode::kSrcOver_Mode; | |
| 92 } | |
| 93 const char* aXfermodeString = as_blend_mode(aXfermodeName); | |
| 94 SkASSERT(aXfermodeString != NULL); | |
| 95 | |
| 96 SkXfermode::Mode bXfermodeName = SkXfermode::kSrcOver_Mode; | |
| 97 SkXfermode* bXfermode = b.getXfermode(); | |
| 98 if (bXfermode) { | |
| 99 bXfermode->asMode(&bXfermodeName); | |
| 100 } | |
| 101 if (bXfermodeName < 0 || bXfermodeName > SkXfermode::kLastMode || | |
| 102 as_blend_mode(bXfermodeName) == NULL) { | |
| 103 bXfermodeName = SkXfermode::kSrcOver_Mode; | |
| 104 } | |
| 105 const char* bXfermodeString = as_blend_mode(bXfermodeName); | |
| 106 SkASSERT(bXfermodeString != NULL); | |
| 107 | |
| 108 return strcmp(aXfermodeString, bXfermodeString) == 0; | |
| 109 } | 102 } |
| 110 | 103 |
| 111 bool SkPDFGraphicState::equals(const SkPaint& paint) const { | 104 SkPDFGraphicState::SkPDFGraphicState(const SkPaint& p) |
| 112 return equivalent(paint, fPaint); | 105 : fStrokeWidth(p.getStrokeWidth()) |
| 113 } | 106 , fStrokeMiter(p.getStrokeMiter()) |
| 114 | 107 , fAlpha(p.getAlpha()) |
| 115 SkPDFGraphicState::~SkPDFGraphicState() {} | 108 , fStrokeCap(SkToU8(p.getStrokeCap())) |
| 116 | 109 , fStrokeJoin(SkToU8(p.getStrokeJoin())) |
| 117 void SkPDFGraphicState::emitObject(SkWStream* stream, | 110 , fMode(SkToU8(mode_for_pdf(p.getXfermode()))) {} |
| 118 const SkPDFObjNumMap& objNumMap, | |
| 119 const SkPDFSubstituteMap& substitutes) { | |
| 120 populateDict(); | |
| 121 SkPDFDict::emitObject(stream, objNumMap, substitutes); | |
| 122 } | |
| 123 | 111 |
| 124 // static | 112 // static |
| 125 SkPDFGraphicState* SkPDFGraphicState::GetGraphicStateForPaint( | 113 SkPDFGraphicState* SkPDFGraphicState::GetGraphicStateForPaint( |
| 126 SkPDFCanon* canon, const SkPaint& paint) { | 114 SkPDFCanon* canon, const SkPaint& paint) { |
| 127 SkASSERT(canon); | 115 SkASSERT(canon); |
| 128 SkPDFGraphicState* pdfGraphicState = canon->findGraphicState(paint); | 116 SkPDFGraphicState key(paint); |
| 129 if (pdfGraphicState) { | 117 if (const SkPDFGraphicState* canonGS = canon->findGraphicState(key)) { |
| 130 return SkRef(pdfGraphicState); | 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)); |
| 131 } | 123 } |
| 132 pdfGraphicState = new SkPDFGraphicState(paint); | 124 SkPDFGraphicState* pdfGraphicState = new SkPDFGraphicState(paint); |
| 133 canon->addGraphicState(pdfGraphicState); | 125 canon->addGraphicState(pdfGraphicState); |
| 134 return pdfGraphicState; | 126 return pdfGraphicState; |
| 135 } | 127 } |
| 136 | 128 |
| 137 namespace { | 129 namespace { |
| 138 SkPDFObject* create_invert_function() { | 130 SkPDFObject* create_invert_function() { |
| 139 // Acrobat crashes if we use a type 0 function, kpdf crashes if we use | 131 // Acrobat crashes if we use a type 0 function, kpdf crashes if we use |
| 140 // a type 2 function, so we use a type 4 function. | 132 // a type 2 function, so we use a type 4 function. |
| 141 SkAutoTUnref<SkPDFArray> domainAndRange(new SkPDFArray); | 133 SkAutoTUnref<SkPDFArray> domainAndRange(new SkPDFArray); |
| 142 domainAndRange->reserve(2); | 134 domainAndRange->reserve(2); |
| 143 domainAndRange->appendInt(0); | 135 domainAndRange->appendInt(0); |
| 144 domainAndRange->appendInt(1); | 136 domainAndRange->appendInt(1); |
| 145 | 137 |
| 146 static const char psInvert[] = "{1 exch sub}"; | 138 static const char psInvert[] = "{1 exch sub}"; |
| 147 // Do not copy the trailing '\0' into the SkData. | 139 // Do not copy the trailing '\0' into the SkData. |
| 148 SkAutoTUnref<SkData> psInvertStream( | 140 SkAutoTUnref<SkData> psInvertStream( |
| 149 SkData::NewWithoutCopy(psInvert, strlen(psInvert))); | 141 SkData::NewWithoutCopy(psInvert, strlen(psInvert))); |
| 150 | 142 |
| 151 SkPDFStream* invertFunction = SkNEW_ARGS( | 143 SkPDFStream* invertFunction = SkNEW_ARGS( |
| 152 SkPDFStream, (psInvertStream.get())); | 144 SkPDFStream, (psInvertStream.get())); |
| 153 invertFunction->insertInt("FunctionType", 4); | 145 invertFunction->insertInt("FunctionType", 4); |
| 154 invertFunction->insert("Domain", domainAndRange.get()); | 146 invertFunction->insert("Domain", domainAndRange.get()); |
| 155 invertFunction->insert("Range", domainAndRange.get()); | 147 invertFunction->insert("Range", domainAndRange.get()); |
| 156 return invertFunction; | 148 return invertFunction; |
| 157 } | 149 } |
| 158 | 150 |
| 159 template <typename T> void unref(T* ptr) { ptr->unref(); } | 151 template <typename T> void unref(T* ptr) { ptr->unref(); } |
| 160 } // namespace | 152 } // namespace |
| 161 | 153 |
| 162 SK_DECLARE_STATIC_LAZY_PTR(SkPDFObject, invertFunction, | 154 SK_DECLARE_STATIC_LAZY_PTR(SkPDFObject, |
| 163 create_invert_function, unref<SkPDFObject>); | 155 invertFunction, |
| 156 create_invert_function, |
| 157 unref<SkPDFObject>); |
| 164 | 158 |
| 165 // static | 159 // static |
| 166 SkPDFGraphicState* SkPDFGraphicState::GetSMaskGraphicState( | 160 SkPDFDict* SkPDFGraphicState::GetSMaskGraphicState(SkPDFFormXObject* sMask, |
| 167 SkPDFFormXObject* sMask, bool invert, SkPDFSMaskMode sMaskMode) { | 161 bool invert, |
| 162 SkPDFSMaskMode sMaskMode) { |
| 168 // The practical chances of using the same mask more than once are unlikely | 163 // The practical chances of using the same mask more than once are unlikely |
| 169 // enough that it's not worth canonicalizing. | 164 // enough that it's not worth canonicalizing. |
| 170 SkAutoTUnref<SkPDFDict> sMaskDict(new SkPDFDict("Mask")); | 165 SkAutoTUnref<SkPDFDict> sMaskDict(new SkPDFDict("Mask")); |
| 171 if (sMaskMode == kAlpha_SMaskMode) { | 166 if (sMaskMode == kAlpha_SMaskMode) { |
| 172 sMaskDict->insertName("S", "Alpha"); | 167 sMaskDict->insertName("S", "Alpha"); |
| 173 } else if (sMaskMode == kLuminosity_SMaskMode) { | 168 } else if (sMaskMode == kLuminosity_SMaskMode) { |
| 174 sMaskDict->insertName("S", "Luminosity"); | 169 sMaskDict->insertName("S", "Luminosity"); |
| 175 } | 170 } |
| 176 sMaskDict->insert("G", new SkPDFObjRef(sMask))->unref(); | 171 sMaskDict->insert("G", new SkPDFObjRef(sMask))->unref(); |
| 177 | |
| 178 SkPDFGraphicState* result = new SkPDFGraphicState; | |
| 179 result->fPopulated = true; | |
| 180 result->insertName("Type", "ExtGState"); | |
| 181 result->insert("SMask", sMaskDict.get()); | |
| 182 | |
| 183 if (invert) { | 172 if (invert) { |
| 184 sMaskDict->insert("TR", new SkPDFObjRef(invertFunction.get()))->unref(); | 173 sMaskDict->insert("TR", new SkPDFObjRef(invertFunction.get()))->unref(); |
| 185 } | 174 } |
| 186 | 175 |
| 176 SkPDFDict* result = new SkPDFDict("ExtGState"); |
| 177 result->insert("SMask", sMaskDict.get()); |
| 187 return result; | 178 return result; |
| 188 } | 179 } |
| 189 | 180 |
| 190 SkPDFGraphicState* SkPDFGraphicState::CreateNoSMaskGraphicState() { | 181 namespace { |
| 191 SkPDFGraphicState* noSMaskGS = SkNEW(SkPDFGraphicState); | 182 SkPDFDict* create_no_smask_graphic_state() { |
| 192 noSMaskGS->fPopulated = true; | 183 SkPDFDict* noSMaskGS = new SkPDFDict("ExtGState"); |
| 193 noSMaskGS->insertName("Type", "ExtGState"); | |
| 194 noSMaskGS->insertName("SMask", "None"); | 184 noSMaskGS->insertName("SMask", "None"); |
| 195 return noSMaskGS; | 185 return noSMaskGS; |
| 196 } | 186 } |
| 197 | 187 } // namespace |
| 198 SK_DECLARE_STATIC_LAZY_PTR( | 188 SK_DECLARE_STATIC_LAZY_PTR(SkPDFDict, |
| 199 SkPDFGraphicState, noSMaskGraphicState, | 189 noSMaskGraphicState, |
| 200 SkPDFGraphicState::CreateNoSMaskGraphicState, unref<SkPDFGraphicState>); | 190 create_no_smask_graphic_state, |
| 191 unref<SkPDFDict>); |
| 201 | 192 |
| 202 // static | 193 // static |
| 203 SkPDFGraphicState* SkPDFGraphicState::GetNoSMaskGraphicState() { | 194 SkPDFDict* SkPDFGraphicState::GetNoSMaskGraphicState() { |
| 204 return SkRef(noSMaskGraphicState.get()); | 195 return SkRef(noSMaskGraphicState.get()); |
| 205 } | 196 } |
| 206 | 197 |
| 207 SkPDFGraphicState::SkPDFGraphicState() | 198 void SkPDFGraphicState::emitObject(SkWStream* stream, |
| 208 : fPopulated(false) {} | 199 const SkPDFObjNumMap& objNumMap, |
| 200 const SkPDFSubstituteMap& substitutes) { |
| 201 SkAutoTUnref<SkPDFDict> dict(SkNEW_ARGS(SkPDFDict, ("ExtGState"))); |
| 202 dict->insertName("Type", "ExtGState"); |
| 209 | 203 |
| 210 SkPDFGraphicState::SkPDFGraphicState(const SkPaint& paint) | 204 SkAutoTUnref<SkPDFScalar> alpha(new SkPDFScalar(SkScalarDiv(fAlpha, 0xFF))); |
| 211 : fPaint(paint), fPopulated(false) {} | 205 dict->insert("CA", alpha.get()); |
| 206 dict->insert("ca", alpha.get()); |
| 212 | 207 |
| 213 // populateDict and operator== have to stay in sync with each other. | 208 SkPaint::Cap strokeCap = (SkPaint::Cap)fStrokeCap; |
| 214 void SkPDFGraphicState::populateDict() { | 209 SkPaint::Join strokeJoin = (SkPaint::Join)fStrokeJoin; |
| 215 if (!fPopulated) { | 210 SkXfermode::Mode xferMode = (SkXfermode::Mode)fMode; |
| 216 fPopulated = true; | |
| 217 insertName("Type", "ExtGState"); | |
| 218 | 211 |
| 219 SkAutoTUnref<SkPDFScalar> alpha( | 212 SK_COMPILE_ASSERT(SkPaint::kButt_Cap == 0, paint_cap_mismatch); |
| 220 new SkPDFScalar(SkScalarDiv(fPaint.getAlpha(), 0xFF))); | 213 SK_COMPILE_ASSERT(SkPaint::kRound_Cap == 1, paint_cap_mismatch); |
| 221 insert("CA", alpha.get()); | 214 SK_COMPILE_ASSERT(SkPaint::kSquare_Cap == 2, paint_cap_mismatch); |
| 222 insert("ca", alpha.get()); | 215 SK_COMPILE_ASSERT(SkPaint::kCapCount == 3, paint_cap_mismatch); |
| 216 SkASSERT(strokeCap >= 0 && strokeCap <= 2); |
| 217 dict->insertInt("LC", strokeCap); |
| 223 | 218 |
| 224 SK_COMPILE_ASSERT(SkPaint::kButt_Cap == 0, paint_cap_mismatch); | 219 SK_COMPILE_ASSERT(SkPaint::kMiter_Join == 0, paint_join_mismatch); |
| 225 SK_COMPILE_ASSERT(SkPaint::kRound_Cap == 1, paint_cap_mismatch); | 220 SK_COMPILE_ASSERT(SkPaint::kRound_Join == 1, paint_join_mismatch); |
| 226 SK_COMPILE_ASSERT(SkPaint::kSquare_Cap == 2, paint_cap_mismatch); | 221 SK_COMPILE_ASSERT(SkPaint::kBevel_Join == 2, paint_join_mismatch); |
| 227 SK_COMPILE_ASSERT(SkPaint::kCapCount == 3, paint_cap_mismatch); | 222 SK_COMPILE_ASSERT(SkPaint::kJoinCount == 3, paint_join_mismatch); |
| 228 SkASSERT(fPaint.getStrokeCap() >= 0 && fPaint.getStrokeCap() <= 2); | 223 SkASSERT(strokeJoin >= 0 && strokeJoin <= 2); |
| 229 insertInt("LC", fPaint.getStrokeCap()); | 224 dict->insertInt("LJ", strokeJoin); |
| 230 | 225 |
| 231 SK_COMPILE_ASSERT(SkPaint::kMiter_Join == 0, paint_join_mismatch); | 226 dict->insertScalar("LW", fStrokeWidth); |
| 232 SK_COMPILE_ASSERT(SkPaint::kRound_Join == 1, paint_join_mismatch); | 227 dict->insertScalar("ML", fStrokeMiter); |
| 233 SK_COMPILE_ASSERT(SkPaint::kBevel_Join == 2, paint_join_mismatch); | 228 // SA = Auto stroke adjustment. |
| 234 SK_COMPILE_ASSERT(SkPaint::kJoinCount == 3, paint_join_mismatch); | 229 dict->insert("SA", new SkPDFBool(true))->unref(); |
| 235 SkASSERT(fPaint.getStrokeJoin() >= 0 && fPaint.getStrokeJoin() <= 2); | 230 dict->insertName("BM", as_blend_mode(xferMode)); |
| 236 insertInt("LJ", fPaint.getStrokeJoin()); | 231 dict->emitObject(stream, objNumMap, substitutes); |
| 237 | |
| 238 insertScalar("LW", fPaint.getStrokeWidth()); | |
| 239 insertScalar("ML", fPaint.getStrokeMiter()); | |
| 240 insert("SA", new SkPDFBool(true))->unref(); // Auto stroke adjustment. | |
| 241 | |
| 242 SkXfermode::Mode xfermode = SkXfermode::kSrcOver_Mode; | |
| 243 // If asMode fails, default to kSrcOver_Mode. | |
| 244 if (fPaint.getXfermode()) | |
| 245 fPaint.getXfermode()->asMode(&xfermode); | |
| 246 // If we don't support the mode, just use kSrcOver_Mode. | |
| 247 if (xfermode < 0 || xfermode > SkXfermode::kLastMode || | |
| 248 as_blend_mode(xfermode) == NULL) { | |
| 249 xfermode = SkXfermode::kSrcOver_Mode; | |
| 250 NOT_IMPLEMENTED("unsupported xfermode", false); | |
| 251 } | |
| 252 insertName("BM", as_blend_mode(xfermode)); | |
| 253 } | |
| 254 } | 232 } |
| OLD | NEW |