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 "SkPDFCanon.h" |
9 #include "SkPDFFormXObject.h" | 10 #include "SkPDFFormXObject.h" |
10 #include "SkPDFGraphicState.h" | 11 #include "SkPDFGraphicState.h" |
11 #include "SkPDFUtils.h" | 12 #include "SkPDFUtils.h" |
12 #include "SkTypes.h" | 13 #include "SkTypes.h" |
13 | 14 |
14 static const char* blend_mode_from_xfermode(SkXfermode::Mode mode) { | 15 static const char* as_blend_mode(SkXfermode::Mode mode) { |
15 switch (mode) { | 16 switch (mode) { |
16 case SkXfermode::kSrcOver_Mode: return "Normal"; | 17 case SkXfermode::kSrcOver_Mode: |
17 case SkXfermode::kMultiply_Mode: return "Multiply"; | 18 return "Normal"; |
18 case SkXfermode::kScreen_Mode: return "Screen"; | 19 case SkXfermode::kMultiply_Mode: |
19 case SkXfermode::kOverlay_Mode: return "Overlay"; | 20 return "Multiply"; |
20 case SkXfermode::kDarken_Mode: return "Darken"; | 21 case SkXfermode::kScreen_Mode: |
21 case SkXfermode::kLighten_Mode: return "Lighten"; | 22 return "Screen"; |
22 case SkXfermode::kColorDodge_Mode: return "ColorDodge"; | 23 case SkXfermode::kOverlay_Mode: |
23 case SkXfermode::kColorBurn_Mode: return "ColorBurn"; | 24 return "Overlay"; |
24 case SkXfermode::kHardLight_Mode: return "HardLight"; | 25 case SkXfermode::kDarken_Mode: |
25 case SkXfermode::kSoftLight_Mode: return "SoftLight"; | 26 return "Darken"; |
26 case SkXfermode::kDifference_Mode: return "Difference"; | 27 case SkXfermode::kLighten_Mode: |
27 case SkXfermode::kExclusion_Mode: return "Exclusion"; | 28 return "Lighten"; |
28 case SkXfermode::kHue_Mode: return "Hue"; | 29 case SkXfermode::kColorDodge_Mode: |
29 case SkXfermode::kSaturation_Mode: return "Saturation"; | 30 return "ColorDodge"; |
30 case SkXfermode::kColor_Mode: return "Color"; | 31 case SkXfermode::kColorBurn_Mode: |
31 case SkXfermode::kLuminosity_Mode: return "Luminosity"; | 32 return "ColorBurn"; |
| 33 case SkXfermode::kHardLight_Mode: |
| 34 return "HardLight"; |
| 35 case SkXfermode::kSoftLight_Mode: |
| 36 return "SoftLight"; |
| 37 case SkXfermode::kDifference_Mode: |
| 38 return "Difference"; |
| 39 case SkXfermode::kExclusion_Mode: |
| 40 return "Exclusion"; |
| 41 case SkXfermode::kHue_Mode: |
| 42 return "Hue"; |
| 43 case SkXfermode::kSaturation_Mode: |
| 44 return "Saturation"; |
| 45 case SkXfermode::kColor_Mode: |
| 46 return "Color"; |
| 47 case SkXfermode::kLuminosity_Mode: |
| 48 return "Luminosity"; |
32 | 49 |
33 // These are handled in SkPDFDevice::setUpContentEntry. | 50 // These are handled in SkPDFDevice::setUpContentEntry. |
34 case SkXfermode::kClear_Mode: | 51 case SkXfermode::kClear_Mode: |
35 case SkXfermode::kSrc_Mode: | 52 case SkXfermode::kSrc_Mode: |
36 case SkXfermode::kDst_Mode: | 53 case SkXfermode::kDst_Mode: |
37 case SkXfermode::kDstOver_Mode: | 54 case SkXfermode::kDstOver_Mode: |
38 case SkXfermode::kSrcIn_Mode: | 55 case SkXfermode::kSrcIn_Mode: |
39 case SkXfermode::kDstIn_Mode: | 56 case SkXfermode::kDstIn_Mode: |
40 case SkXfermode::kSrcOut_Mode: | 57 case SkXfermode::kSrcOut_Mode: |
41 case SkXfermode::kDstOut_Mode: | 58 case SkXfermode::kDstOut_Mode: |
42 case SkXfermode::kSrcATop_Mode: | 59 case SkXfermode::kSrcATop_Mode: |
43 case SkXfermode::kDstATop_Mode: | 60 case SkXfermode::kDstATop_Mode: |
44 case SkXfermode::kModulate_Mode: | 61 case SkXfermode::kModulate_Mode: |
45 return "Normal"; | 62 return "Normal"; |
46 | 63 |
47 // TODO(vandebo): Figure out if we can support more of these modes. | 64 // TODO(vandebo): Figure out if we can support more of these modes. |
48 case SkXfermode::kXor_Mode: | 65 case SkXfermode::kXor_Mode: |
49 case SkXfermode::kPlus_Mode: | 66 case SkXfermode::kPlus_Mode: |
50 return NULL; | 67 return NULL; |
51 } | 68 } |
52 return NULL; | 69 return NULL; |
53 } | 70 } |
54 | 71 |
| 72 static bool equivalent(const SkPaint& a, const SkPaint& b) { |
| 73 // We're only interested in some fields of the SkPaint, so we have |
| 74 // a custom equality function. |
| 75 if (SkColorGetA(a.getColor()) != SkColorGetA(b.getColor()) || |
| 76 a.getStrokeCap() != b.getStrokeCap() || |
| 77 a.getStrokeJoin() != b.getStrokeJoin() || |
| 78 a.getStrokeWidth() != b.getStrokeWidth() || |
| 79 a.getStrokeMiter() != b.getStrokeMiter()) { |
| 80 return false; |
| 81 } |
| 82 |
| 83 SkXfermode::Mode aXfermodeName = SkXfermode::kSrcOver_Mode; |
| 84 SkXfermode* aXfermode = a.getXfermode(); |
| 85 if (aXfermode) { |
| 86 aXfermode->asMode(&aXfermodeName); |
| 87 } |
| 88 if (aXfermodeName < 0 || aXfermodeName > SkXfermode::kLastMode || |
| 89 as_blend_mode(aXfermodeName) == NULL) { |
| 90 aXfermodeName = SkXfermode::kSrcOver_Mode; |
| 91 } |
| 92 const char* aXfermodeString = as_blend_mode(aXfermodeName); |
| 93 SkASSERT(aXfermodeString != NULL); |
| 94 |
| 95 SkXfermode::Mode bXfermodeName = SkXfermode::kSrcOver_Mode; |
| 96 SkXfermode* bXfermode = b.getXfermode(); |
| 97 if (bXfermode) { |
| 98 bXfermode->asMode(&bXfermodeName); |
| 99 } |
| 100 if (bXfermodeName < 0 || bXfermodeName > SkXfermode::kLastMode || |
| 101 as_blend_mode(bXfermodeName) == NULL) { |
| 102 bXfermodeName = SkXfermode::kSrcOver_Mode; |
| 103 } |
| 104 const char* bXfermodeString = as_blend_mode(bXfermodeName); |
| 105 SkASSERT(bXfermodeString != NULL); |
| 106 |
| 107 return strcmp(aXfermodeString, bXfermodeString) == 0; |
| 108 } |
| 109 |
| 110 bool SkPDFGraphicState::equals(const SkPaint& paint) const { |
| 111 return equivalent(paint, fPaint); |
| 112 } |
| 113 |
55 SkPDFGraphicState::~SkPDFGraphicState() { | 114 SkPDFGraphicState::~SkPDFGraphicState() { |
56 SkAutoMutexAcquire lock(CanonicalPaintsMutex()); | 115 SkAutoMutexAcquire lock(SkPDFCanon::GetPaintMutex()); |
57 if (!fSMask) { | 116 if (!fSMask) { |
58 int index = Find(fPaint); | 117 SkPDFCanon::GetCanon().removeGraphicState(this); |
59 SkASSERT(index >= 0); | |
60 SkASSERT(CanonicalPaints()[index].fGraphicState == this); | |
61 CanonicalPaints().removeShuffle(index); | |
62 } | 118 } |
63 fResources.unrefAll(); | 119 fResources.unrefAll(); |
64 } | 120 } |
65 | 121 |
66 void SkPDFGraphicState::getResources( | 122 void SkPDFGraphicState::getResources( |
67 const SkTSet<SkPDFObject*>& knownResourceObjects, | 123 const SkTSet<SkPDFObject*>& knownResourceObjects, |
68 SkTSet<SkPDFObject*>* newResourceObjects) { | 124 SkTSet<SkPDFObject*>* newResourceObjects) { |
69 GetResourcesHelper(&fResources, knownResourceObjects, newResourceObjects); | 125 GetResourcesHelper(&fResources, knownResourceObjects, newResourceObjects); |
70 } | 126 } |
71 | 127 |
72 void SkPDFGraphicState::emitObject(SkWStream* stream, SkPDFCatalog* catalog) { | 128 void SkPDFGraphicState::emitObject(SkWStream* stream, SkPDFCatalog* catalog) { |
73 populateDict(); | 129 populateDict(); |
74 SkPDFDict::emitObject(stream, catalog); | 130 SkPDFDict::emitObject(stream, catalog); |
75 } | 131 } |
76 | 132 |
77 // static | 133 // static |
78 SkTDArray<SkPDFGraphicState::GSCanonicalEntry>& SkPDFGraphicState::CanonicalPain
ts() { | 134 SkPDFGraphicState* SkPDFGraphicState::GetGraphicStateForPaint( |
79 CanonicalPaintsMutex().assertHeld(); | 135 const SkPaint& paint) { |
80 static SkTDArray<SkPDFGraphicState::GSCanonicalEntry> gCanonicalPaints; | 136 SkAutoMutexAcquire lock(SkPDFCanon::GetPaintMutex()); |
81 return gCanonicalPaints; | 137 SkPDFGraphicState* pdfGraphicState = |
82 } | 138 SkPDFCanon::GetCanon().findGraphicState(paint); |
83 | 139 if (pdfGraphicState) { |
84 SK_DECLARE_STATIC_MUTEX(gCanonicalPaintsMutex); | 140 return SkRef(pdfGraphicState); |
85 // static | |
86 SkBaseMutex& SkPDFGraphicState::CanonicalPaintsMutex() { | |
87 return gCanonicalPaintsMutex; | |
88 } | |
89 | |
90 // static | |
91 SkPDFGraphicState* SkPDFGraphicState::GetGraphicStateForPaint(const SkPaint& pai
nt) { | |
92 SkAutoMutexAcquire lock(CanonicalPaintsMutex()); | |
93 int index = Find(paint); | |
94 if (index >= 0) { | |
95 CanonicalPaints()[index].fGraphicState->ref(); | |
96 return CanonicalPaints()[index].fGraphicState; | |
97 } | 141 } |
98 GSCanonicalEntry newEntry(new SkPDFGraphicState(paint)); | 142 pdfGraphicState = new SkPDFGraphicState(paint); |
99 CanonicalPaints().push(newEntry); | 143 SkPDFCanon::GetCanon().addGraphicState(pdfGraphicState); |
100 return newEntry.fGraphicState; | 144 return pdfGraphicState; |
101 } | 145 } |
102 | 146 |
103 // static | 147 // static |
104 SkPDFObject* SkPDFGraphicState::GetInvertFunction() { | 148 SkPDFObject* SkPDFGraphicState::GetInvertFunction() { |
105 // This assumes that canonicalPaintsMutex is held. | 149 // This assumes that canonicalPaintsMutex is held. |
106 CanonicalPaintsMutex().assertHeld(); | 150 SkPDFCanon::GetPaintMutex().assertHeld(); |
107 static SkPDFStream* invertFunction = NULL; | 151 static SkPDFStream* invertFunction = NULL; |
108 if (!invertFunction) { | 152 if (!invertFunction) { |
109 // Acrobat crashes if we use a type 0 function, kpdf crashes if we use | 153 // Acrobat crashes if we use a type 0 function, kpdf crashes if we use |
110 // a type 2 function, so we use a type 4 function. | 154 // a type 2 function, so we use a type 4 function. |
111 SkAutoTUnref<SkPDFArray> domainAndRange(new SkPDFArray); | 155 SkAutoTUnref<SkPDFArray> domainAndRange(new SkPDFArray); |
112 domainAndRange->reserve(2); | 156 domainAndRange->reserve(2); |
113 domainAndRange->appendInt(0); | 157 domainAndRange->appendInt(0); |
114 domainAndRange->appendInt(1); | 158 domainAndRange->appendInt(1); |
115 | 159 |
116 static const char psInvert[] = "{1 exch sub}"; | 160 static const char psInvert[] = "{1 exch sub}"; |
117 // Do not copy the trailing '\0' into the SkData. | 161 // Do not copy the trailing '\0' into the SkData. |
118 SkAutoTUnref<SkData> psInvertStream( | 162 SkAutoTUnref<SkData> psInvertStream( |
119 SkData::NewWithoutCopy(psInvert, strlen(psInvert))); | 163 SkData::NewWithoutCopy(psInvert, strlen(psInvert))); |
120 | 164 |
121 invertFunction = new SkPDFStream(psInvertStream.get()); | 165 invertFunction = new SkPDFStream(psInvertStream.get()); |
122 invertFunction->insertInt("FunctionType", 4); | 166 invertFunction->insertInt("FunctionType", 4); |
123 invertFunction->insert("Domain", domainAndRange.get()); | 167 invertFunction->insert("Domain", domainAndRange.get()); |
124 invertFunction->insert("Range", domainAndRange.get()); | 168 invertFunction->insert("Range", domainAndRange.get()); |
125 } | 169 } |
126 return invertFunction; | 170 return invertFunction; |
127 } | 171 } |
128 | 172 |
129 // static | 173 // static |
130 SkPDFGraphicState* SkPDFGraphicState::GetSMaskGraphicState( | 174 SkPDFGraphicState* SkPDFGraphicState::GetSMaskGraphicState( |
131 SkPDFFormXObject* sMask, bool invert, SkPDFSMaskMode sMaskMode) { | 175 SkPDFFormXObject* sMask, bool invert, SkPDFSMaskMode sMaskMode) { |
132 // The practical chances of using the same mask more than once are unlikely | 176 // The practical chances of using the same mask more than once are unlikely |
133 // enough that it's not worth canonicalizing. | 177 // enough that it's not worth canonicalizing. |
134 SkAutoMutexAcquire lock(CanonicalPaintsMutex()); | 178 SkAutoMutexAcquire lock(SkPDFCanon::GetPaintMutex()); |
135 | |
136 SkAutoTUnref<SkPDFDict> sMaskDict(new SkPDFDict("Mask")); | 179 SkAutoTUnref<SkPDFDict> sMaskDict(new SkPDFDict("Mask")); |
137 if (sMaskMode == kAlpha_SMaskMode) { | 180 if (sMaskMode == kAlpha_SMaskMode) { |
138 sMaskDict->insertName("S", "Alpha"); | 181 sMaskDict->insertName("S", "Alpha"); |
139 } else if (sMaskMode == kLuminosity_SMaskMode) { | 182 } else if (sMaskMode == kLuminosity_SMaskMode) { |
140 sMaskDict->insertName("S", "Luminosity"); | 183 sMaskDict->insertName("S", "Luminosity"); |
141 } | 184 } |
142 sMaskDict->insert("G", new SkPDFObjRef(sMask))->unref(); | 185 sMaskDict->insert("G", new SkPDFObjRef(sMask))->unref(); |
143 | 186 |
144 SkPDFGraphicState* result = new SkPDFGraphicState; | 187 SkPDFGraphicState* result = new SkPDFGraphicState; |
145 result->fPopulated = true; | 188 result->fPopulated = true; |
146 result->fSMask = true; | 189 result->fSMask = true; |
147 result->insertName("Type", "ExtGState"); | 190 result->insertName("Type", "ExtGState"); |
148 result->insert("SMask", sMaskDict.get()); | 191 result->insert("SMask", sMaskDict.get()); |
149 result->fResources.push(sMask); | 192 result->fResources.push(sMask); |
150 sMask->ref(); | 193 sMask->ref(); |
151 | 194 |
152 if (invert) { | 195 if (invert) { |
153 SkPDFObject* invertFunction = GetInvertFunction(); | 196 SkPDFObject* invertFunction = GetInvertFunction(); |
154 result->fResources.push(invertFunction); | 197 result->fResources.push(invertFunction); |
155 invertFunction->ref(); | 198 invertFunction->ref(); |
156 sMaskDict->insert("TR", new SkPDFObjRef(invertFunction))->unref(); | 199 sMaskDict->insert("TR", new SkPDFObjRef(invertFunction))->unref(); |
157 } | 200 } |
158 | 201 |
159 return result; | 202 return result; |
160 } | 203 } |
161 | 204 |
162 // static | 205 // static |
163 SkPDFGraphicState* SkPDFGraphicState::GetNoSMaskGraphicState() { | 206 SkPDFGraphicState* SkPDFGraphicState::GetNoSMaskGraphicState() { |
164 SkAutoMutexAcquire lock(CanonicalPaintsMutex()); | 207 SkAutoMutexAcquire lock(SkPDFCanon::GetPaintMutex()); |
165 static SkPDFGraphicState* noSMaskGS = NULL; | 208 static SkPDFGraphicState* noSMaskGS = NULL; |
166 if (!noSMaskGS) { | 209 if (!noSMaskGS) { |
167 noSMaskGS = new SkPDFGraphicState; | 210 noSMaskGS = new SkPDFGraphicState; |
168 noSMaskGS->fPopulated = true; | 211 noSMaskGS->fPopulated = true; |
169 noSMaskGS->fSMask = true; | 212 noSMaskGS->fSMask = true; |
170 noSMaskGS->insertName("Type", "ExtGState"); | 213 noSMaskGS->insertName("Type", "ExtGState"); |
171 noSMaskGS->insertName("SMask", "None"); | 214 noSMaskGS->insertName("SMask", "None"); |
172 } | 215 } |
173 noSMaskGS->ref(); | 216 noSMaskGS->ref(); |
174 return noSMaskGS; | 217 return noSMaskGS; |
175 } | 218 } |
176 | 219 |
177 // static | |
178 int SkPDFGraphicState::Find(const SkPaint& paint) { | |
179 CanonicalPaintsMutex().assertHeld(); | |
180 GSCanonicalEntry search(&paint); | |
181 return CanonicalPaints().find(search); | |
182 } | |
183 | |
184 SkPDFGraphicState::SkPDFGraphicState() | 220 SkPDFGraphicState::SkPDFGraphicState() |
185 : fPopulated(false), | 221 : fPopulated(false), |
186 fSMask(false) { | 222 fSMask(false) { |
187 } | 223 } |
188 | 224 |
189 SkPDFGraphicState::SkPDFGraphicState(const SkPaint& paint) | 225 SkPDFGraphicState::SkPDFGraphicState(const SkPaint& paint) |
190 : fPaint(paint), | 226 : fPaint(paint), |
191 fPopulated(false), | 227 fPopulated(false), |
192 fSMask(false) { | 228 fSMask(false) { |
193 } | 229 } |
(...skipping 26 matching lines...) Expand all Loading... |
220 insertScalar("LW", fPaint.getStrokeWidth()); | 256 insertScalar("LW", fPaint.getStrokeWidth()); |
221 insertScalar("ML", fPaint.getStrokeMiter()); | 257 insertScalar("ML", fPaint.getStrokeMiter()); |
222 insert("SA", new SkPDFBool(true))->unref(); // Auto stroke adjustment. | 258 insert("SA", new SkPDFBool(true))->unref(); // Auto stroke adjustment. |
223 | 259 |
224 SkXfermode::Mode xfermode = SkXfermode::kSrcOver_Mode; | 260 SkXfermode::Mode xfermode = SkXfermode::kSrcOver_Mode; |
225 // If asMode fails, default to kSrcOver_Mode. | 261 // If asMode fails, default to kSrcOver_Mode. |
226 if (fPaint.getXfermode()) | 262 if (fPaint.getXfermode()) |
227 fPaint.getXfermode()->asMode(&xfermode); | 263 fPaint.getXfermode()->asMode(&xfermode); |
228 // If we don't support the mode, just use kSrcOver_Mode. | 264 // If we don't support the mode, just use kSrcOver_Mode. |
229 if (xfermode < 0 || xfermode > SkXfermode::kLastMode || | 265 if (xfermode < 0 || xfermode > SkXfermode::kLastMode || |
230 blend_mode_from_xfermode(xfermode) == NULL) { | 266 as_blend_mode(xfermode) == NULL) { |
231 xfermode = SkXfermode::kSrcOver_Mode; | 267 xfermode = SkXfermode::kSrcOver_Mode; |
232 NOT_IMPLEMENTED("unsupported xfermode", false); | 268 NOT_IMPLEMENTED("unsupported xfermode", false); |
233 } | 269 } |
234 insertName("BM", blend_mode_from_xfermode(xfermode)); | 270 insertName("BM", as_blend_mode(xfermode)); |
235 } | 271 } |
236 } | 272 } |
237 | 273 |
238 // We're only interested in some fields of the SkPaint, so we have a custom | |
239 // operator== function. | |
240 bool SkPDFGraphicState::GSCanonicalEntry::operator==( | |
241 const SkPDFGraphicState::GSCanonicalEntry& gs) const { | |
242 const SkPaint* a = fPaint; | |
243 const SkPaint* b = gs.fPaint; | |
244 SkASSERT(a != NULL); | |
245 SkASSERT(b != NULL); | |
246 | |
247 if (SkColorGetA(a->getColor()) != SkColorGetA(b->getColor()) || | |
248 a->getStrokeCap() != b->getStrokeCap() || | |
249 a->getStrokeJoin() != b->getStrokeJoin() || | |
250 a->getStrokeWidth() != b->getStrokeWidth() || | |
251 a->getStrokeMiter() != b->getStrokeMiter()) { | |
252 return false; | |
253 } | |
254 | |
255 SkXfermode::Mode aXfermodeName = SkXfermode::kSrcOver_Mode; | |
256 SkXfermode* aXfermode = a->getXfermode(); | |
257 if (aXfermode) { | |
258 aXfermode->asMode(&aXfermodeName); | |
259 } | |
260 if (aXfermodeName < 0 || aXfermodeName > SkXfermode::kLastMode || | |
261 blend_mode_from_xfermode(aXfermodeName) == NULL) { | |
262 aXfermodeName = SkXfermode::kSrcOver_Mode; | |
263 } | |
264 const char* aXfermodeString = blend_mode_from_xfermode(aXfermodeName); | |
265 SkASSERT(aXfermodeString != NULL); | |
266 | |
267 SkXfermode::Mode bXfermodeName = SkXfermode::kSrcOver_Mode; | |
268 SkXfermode* bXfermode = b->getXfermode(); | |
269 if (bXfermode) { | |
270 bXfermode->asMode(&bXfermodeName); | |
271 } | |
272 if (bXfermodeName < 0 || bXfermodeName > SkXfermode::kLastMode || | |
273 blend_mode_from_xfermode(bXfermodeName) == NULL) { | |
274 bXfermodeName = SkXfermode::kSrcOver_Mode; | |
275 } | |
276 const char* bXfermodeString = blend_mode_from_xfermode(bXfermodeName); | |
277 SkASSERT(bXfermodeString != NULL); | |
278 | |
279 return strcmp(aXfermodeString, bXfermodeString) == 0; | |
280 } | |
OLD | NEW |