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 |