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