OLD | NEW |
1 | 1 |
2 /* | 2 /* |
3 * Copyright 2011 Google Inc. | 3 * Copyright 2011 Google Inc. |
4 * | 4 * |
5 * Use of this source code is governed by a BSD-style license that can be | 5 * Use of this source code is governed by a BSD-style license that can be |
6 * found in the LICENSE file. | 6 * found in the LICENSE file. |
7 */ | 7 */ |
8 | 8 |
9 | 9 |
10 #include "SkPDFShader.h" | 10 #include "SkPDFShader.h" |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
44 /* Assumes t + startOffset is on the stack and does a linear interpolation on t | 44 /* Assumes t + startOffset is on the stack and does a linear interpolation on t |
45 between startOffset and endOffset from prevColor to curColor (for each color | 45 between startOffset and endOffset from prevColor to curColor (for each color |
46 component), leaving the result in component order on the stack. It assumes | 46 component), leaving the result in component order on the stack. It assumes |
47 there are always 3 components per color. | 47 there are always 3 components per color. |
48 @param range endOffset - startOffset | 48 @param range endOffset - startOffset |
49 @param curColor[components] The current color components. | 49 @param curColor[components] The current color components. |
50 @param prevColor[components] The previous color components. | 50 @param prevColor[components] The previous color components. |
51 @param result The result ps function. | 51 @param result The result ps function. |
52 */ | 52 */ |
53 static void interpolateColorCode(SkScalar range, SkScalar* curColor, | 53 static void interpolateColorCode(SkScalar range, SkScalar* curColor, |
54 SkScalar* prevColor, SkString* result) { | 54 SkScalar* prevColor, |
| 55 SkDynamicMemoryWStream* result) { |
55 SkASSERT(range != SkIntToScalar(0)); | 56 SkASSERT(range != SkIntToScalar(0)); |
56 static const int kColorComponents = 3; | 57 static const int kColorComponents = 3; |
57 | 58 |
58 // Figure out how to scale each color component. | 59 // Figure out how to scale each color component. |
59 SkScalar multiplier[kColorComponents]; | 60 SkScalar multiplier[kColorComponents]; |
60 for (int i = 0; i < kColorComponents; i++) { | 61 for (int i = 0; i < kColorComponents; i++) { |
61 multiplier[i] = (curColor[i] - prevColor[i]) / range; | 62 multiplier[i] = (curColor[i] - prevColor[i]) / range; |
62 } | 63 } |
63 | 64 |
64 // Calculate when we no longer need to keep a copy of the input parameter t. | 65 // Calculate when we no longer need to keep a copy of the input parameter t. |
65 // If the last component to use t is i, then dupInput[0..i - 1] = true | 66 // If the last component to use t is i, then dupInput[0..i - 1] = true |
66 // and dupInput[i .. components] = false. | 67 // and dupInput[i .. components] = false. |
67 bool dupInput[kColorComponents]; | 68 bool dupInput[kColorComponents]; |
68 dupInput[kColorComponents - 1] = false; | 69 dupInput[kColorComponents - 1] = false; |
69 for (int i = kColorComponents - 2; i >= 0; i--) { | 70 for (int i = kColorComponents - 2; i >= 0; i--) { |
70 dupInput[i] = dupInput[i + 1] || multiplier[i + 1] != 0; | 71 dupInput[i] = dupInput[i + 1] || multiplier[i + 1] != 0; |
71 } | 72 } |
72 | 73 |
73 if (!dupInput[0] && multiplier[0] == 0) { | 74 if (!dupInput[0] && multiplier[0] == 0) { |
74 result->append("pop "); | 75 result->writeText("pop "); |
75 } | 76 } |
76 | 77 |
77 for (int i = 0; i < kColorComponents; i++) { | 78 for (int i = 0; i < kColorComponents; i++) { |
78 // If the next components needs t and this component will consume a | 79 // If the next components needs t and this component will consume a |
79 // copy, make another copy. | 80 // copy, make another copy. |
80 if (dupInput[i] && multiplier[i] != 0) { | 81 if (dupInput[i] && multiplier[i] != 0) { |
81 result->append("dup "); | 82 result->writeText("dup "); |
82 } | 83 } |
83 | 84 |
84 if (multiplier[i] == 0) { | 85 if (multiplier[i] == 0) { |
85 result->appendScalar(prevColor[i]); | 86 SkPDFUtils::AppendScalar(prevColor[i], result); |
86 result->append(" "); | 87 result->writeText(" "); |
87 } else { | 88 } else { |
88 if (multiplier[i] != 1) { | 89 if (multiplier[i] != 1) { |
89 result->appendScalar(multiplier[i]); | 90 SkPDFUtils::AppendScalar(multiplier[i], result); |
90 result->append(" mul "); | 91 result->writeText(" mul "); |
91 } | 92 } |
92 if (prevColor[i] != 0) { | 93 if (prevColor[i] != 0) { |
93 result->appendScalar(prevColor[i]); | 94 SkPDFUtils::AppendScalar(prevColor[i], result); |
94 result->append(" add "); | 95 result->writeText(" add "); |
95 } | 96 } |
96 } | 97 } |
97 | 98 |
98 if (dupInput[i]) { | 99 if (dupInput[i]) { |
99 result->append("exch\n"); | 100 result->writeText("exch\n"); |
100 } | 101 } |
101 } | 102 } |
102 } | 103 } |
103 | 104 |
104 /* Generate Type 4 function code to map t=[0,1) to the passed gradient, | 105 /* Generate Type 4 function code to map t=[0,1) to the passed gradient, |
105 clamping at the edges of the range. The generated code will be of the form: | 106 clamping at the edges of the range. The generated code will be of the form: |
106 if (t < 0) { | 107 if (t < 0) { |
107 return colorData[0][r,g,b]; | 108 return colorData[0][r,g,b]; |
108 } else { | 109 } else { |
109 if (t < info.fColorOffsets[1]) { | 110 if (t < info.fColorOffsets[1]) { |
110 return linearinterpolation(colorData[0][r,g,b], | 111 return linearinterpolation(colorData[0][r,g,b], |
111 colorData[1][r,g,b]); | 112 colorData[1][r,g,b]); |
112 } else { | 113 } else { |
113 if (t < info.fColorOffsets[2]) { | 114 if (t < info.fColorOffsets[2]) { |
114 return linearinterpolation(colorData[1][r,g,b], | 115 return linearinterpolation(colorData[1][r,g,b], |
115 colorData[2][r,g,b]); | 116 colorData[2][r,g,b]); |
116 } else { | 117 } else { |
117 | 118 |
118 ... } else { | 119 ... } else { |
119 return colorData[info.fColorCount - 1][r,g,b]; | 120 return colorData[info.fColorCount - 1][r,g,b]; |
120 } | 121 } |
121 ... | 122 ... |
122 } | 123 } |
123 } | 124 } |
124 */ | 125 */ |
125 static void gradientFunctionCode(const SkShader::GradientInfo& info, | 126 static void gradientFunctionCode(const SkShader::GradientInfo& info, |
126 SkString* result) { | 127 SkDynamicMemoryWStream* result) { |
127 /* We want to linearly interpolate from the previous color to the next. | 128 /* We want to linearly interpolate from the previous color to the next. |
128 Scale the colors from 0..255 to 0..1 and determine the multipliers | 129 Scale the colors from 0..255 to 0..1 and determine the multipliers |
129 for interpolation. | 130 for interpolation. |
130 C{r,g,b}(t, section) = t - offset_(section-1) + t * Multiplier{r,g,b}. | 131 C{r,g,b}(t, section) = t - offset_(section-1) + t * Multiplier{r,g,b}. |
131 */ | 132 */ |
132 static const int kColorComponents = 3; | 133 static const int kColorComponents = 3; |
133 typedef SkScalar ColorTuple[kColorComponents]; | 134 typedef SkScalar ColorTuple[kColorComponents]; |
134 SkAutoSTMalloc<4, ColorTuple> colorDataAlloc(info.fColorCount); | 135 SkAutoSTMalloc<4, ColorTuple> colorDataAlloc(info.fColorCount); |
135 ColorTuple *colorData = colorDataAlloc.get(); | 136 ColorTuple *colorData = colorDataAlloc.get(); |
136 const SkScalar scale = SkScalarInvert(SkIntToScalar(255)); | 137 const SkScalar scale = SkScalarInvert(SkIntToScalar(255)); |
137 for (int i = 0; i < info.fColorCount; i++) { | 138 for (int i = 0; i < info.fColorCount; i++) { |
138 colorData[i][0] = SkScalarMul(SkColorGetR(info.fColors[i]), scale); | 139 colorData[i][0] = SkScalarMul(SkColorGetR(info.fColors[i]), scale); |
139 colorData[i][1] = SkScalarMul(SkColorGetG(info.fColors[i]), scale); | 140 colorData[i][1] = SkScalarMul(SkColorGetG(info.fColors[i]), scale); |
140 colorData[i][2] = SkScalarMul(SkColorGetB(info.fColors[i]), scale); | 141 colorData[i][2] = SkScalarMul(SkColorGetB(info.fColors[i]), scale); |
141 } | 142 } |
142 | 143 |
143 // Clamp the initial color. | 144 // Clamp the initial color. |
144 result->append("dup 0 le {pop "); | 145 result->writeText("dup 0 le {pop "); |
145 result->appendScalar(colorData[0][0]); | 146 SkPDFUtils::AppendScalar(colorData[0][0], result); |
146 result->append(" "); | 147 result->writeText(" "); |
147 result->appendScalar(colorData[0][1]); | 148 SkPDFUtils::AppendScalar(colorData[0][1], result); |
148 result->append(" "); | 149 result->writeText(" "); |
149 result->appendScalar(colorData[0][2]); | 150 SkPDFUtils::AppendScalar(colorData[0][2], result); |
150 result->append(" }\n"); | 151 result->writeText(" }\n"); |
151 | 152 |
152 // The gradient colors. | 153 // The gradient colors. |
153 int gradients = 0; | 154 int gradients = 0; |
154 for (int i = 1 ; i < info.fColorCount; i++) { | 155 for (int i = 1 ; i < info.fColorCount; i++) { |
155 if (info.fColorOffsets[i] == info.fColorOffsets[i - 1]) { | 156 if (info.fColorOffsets[i] == info.fColorOffsets[i - 1]) { |
156 continue; | 157 continue; |
157 } | 158 } |
158 gradients++; | 159 gradients++; |
159 | 160 |
160 result->append("{dup "); | 161 result->writeText("{dup "); |
161 result->appendScalar(info.fColorOffsets[i]); | 162 SkPDFUtils::AppendScalar(info.fColorOffsets[i], result); |
162 result->append(" le {"); | 163 result->writeText(" le {"); |
163 if (info.fColorOffsets[i - 1] != 0) { | 164 if (info.fColorOffsets[i - 1] != 0) { |
164 result->appendScalar(info.fColorOffsets[i - 1]); | 165 SkPDFUtils::AppendScalar(info.fColorOffsets[i - 1], result); |
165 result->append(" sub\n"); | 166 result->writeText(" sub\n"); |
166 } | 167 } |
167 | 168 |
168 interpolateColorCode(info.fColorOffsets[i] - info.fColorOffsets[i - 1], | 169 interpolateColorCode(info.fColorOffsets[i] - info.fColorOffsets[i - 1], |
169 colorData[i], colorData[i - 1], result); | 170 colorData[i], colorData[i - 1], result); |
170 result->append("}\n"); | 171 result->writeText("}\n"); |
171 } | 172 } |
172 | 173 |
173 // Clamp the final color. | 174 // Clamp the final color. |
174 result->append("{pop "); | 175 result->writeText("{pop "); |
175 result->appendScalar(colorData[info.fColorCount - 1][0]); | 176 SkPDFUtils::AppendScalar(colorData[info.fColorCount - 1][0], result); |
176 result->append(" "); | 177 result->writeText(" "); |
177 result->appendScalar(colorData[info.fColorCount - 1][1]); | 178 SkPDFUtils::AppendScalar(colorData[info.fColorCount - 1][1], result); |
178 result->append(" "); | 179 result->writeText(" "); |
179 result->appendScalar(colorData[info.fColorCount - 1][2]); | 180 SkPDFUtils::AppendScalar(colorData[info.fColorCount - 1][2], result); |
180 | 181 |
181 for (int i = 0 ; i < gradients + 1; i++) { | 182 for (int i = 0 ; i < gradients + 1; i++) { |
182 result->append("} ifelse\n"); | 183 result->writeText("} ifelse\n"); |
183 } | 184 } |
184 } | 185 } |
185 | 186 |
186 /* Map a value of t on the stack into [0, 1) for Repeat or Mirror tile mode. */ | 187 /* Map a value of t on the stack into [0, 1) for Repeat or Mirror tile mode. */ |
187 static void tileModeCode(SkShader::TileMode mode, SkString* result) { | 188 static void tileModeCode(SkShader::TileMode mode, |
| 189 SkDynamicMemoryWStream* result) { |
188 if (mode == SkShader::kRepeat_TileMode) { | 190 if (mode == SkShader::kRepeat_TileMode) { |
189 result->append("dup truncate sub\n"); // Get the fractional part. | 191 result->writeText("dup truncate sub\n"); // Get the fractional part. |
190 result->append("dup 0 le {1 add} if\n"); // Map (-1,0) => (0,1) | 192 result->writeText("dup 0 le {1 add} if\n"); // Map (-1,0) => (0,1) |
191 return; | 193 return; |
192 } | 194 } |
193 | 195 |
194 if (mode == SkShader::kMirror_TileMode) { | 196 if (mode == SkShader::kMirror_TileMode) { |
195 // Map t mod 2 into [0, 1, 1, 0]. | 197 // Map t mod 2 into [0, 1, 1, 0]. |
196 // Code Stack | 198 // Code Stack |
197 result->append("abs " // Map negative to positive. | 199 result->writeText("abs " // Map negative to positive. |
198 "dup " // t.s t.s | 200 "dup " // t.s t.s |
199 "truncate " // t.s t | 201 "truncate " // t.s t |
200 "dup " // t.s t t | 202 "dup " // t.s t t |
201 "cvi " // t.s t T | 203 "cvi " // t.s t T |
202 "2 mod " // t.s t (i mod 2) | 204 "2 mod " // t.s t (i mod 2) |
203 "1 eq " // t.s t true|false | 205 "1 eq " // t.s t true|false |
204 "3 1 roll " // true|false t.s t | 206 "3 1 roll " // true|false t.s t |
205 "sub " // true|false 0.s | 207 "sub " // true|false 0.s |
206 "exch " // 0.s true|false | 208 "exch " // 0.s true|false |
207 "{1 exch sub} if\n"); // 1 - 0.s|0.s | 209 "{1 exch sub} if\n"); // 1 - 0.s|0.s |
208 } | 210 } |
209 } | 211 } |
210 | 212 |
211 /** | 213 /** |
212 * Returns PS function code that applies inverse perspective | 214 * Returns PS function code that applies inverse perspective |
213 * to a x, y point. | 215 * to a x, y point. |
214 * The function assumes that the stack has at least two elements, | 216 * The function assumes that the stack has at least two elements, |
215 * and that the top 2 elements are numeric values. | 217 * and that the top 2 elements are numeric values. |
216 * After executing this code on a PS stack, the last 2 elements are updated | 218 * After executing this code on a PS stack, the last 2 elements are updated |
217 * while the rest of the stack is preserved intact. | 219 * while the rest of the stack is preserved intact. |
218 * inversePerspectiveMatrix is the inverse perspective matrix. | 220 * inversePerspectiveMatrix is the inverse perspective matrix. |
219 */ | 221 */ |
220 static SkString apply_perspective_to_coordinates( | 222 static void apply_perspective_to_coordinates( |
221 const SkMatrix& inversePerspectiveMatrix) { | 223 const SkMatrix& inversePerspectiveMatrix, |
222 SkString code; | 224 SkDynamicMemoryWStream* code) { |
223 if (!inversePerspectiveMatrix.hasPerspective()) { | 225 if (!inversePerspectiveMatrix.hasPerspective()) { |
224 return code; | 226 return; |
225 } | 227 } |
226 | 228 |
227 // Perspective matrix should be: | 229 // Perspective matrix should be: |
228 // 1 0 0 | 230 // 1 0 0 |
229 // 0 1 0 | 231 // 0 1 0 |
230 // p0 p1 p2 | 232 // p0 p1 p2 |
231 | 233 |
232 const SkScalar p0 = inversePerspectiveMatrix[SkMatrix::kMPersp0]; | 234 const SkScalar p0 = inversePerspectiveMatrix[SkMatrix::kMPersp0]; |
233 const SkScalar p1 = inversePerspectiveMatrix[SkMatrix::kMPersp1]; | 235 const SkScalar p1 = inversePerspectiveMatrix[SkMatrix::kMPersp1]; |
234 const SkScalar p2 = inversePerspectiveMatrix[SkMatrix::kMPersp2]; | 236 const SkScalar p2 = inversePerspectiveMatrix[SkMatrix::kMPersp2]; |
235 | 237 |
236 // y = y / (p2 + p0 x + p1 y) | 238 // y = y / (p2 + p0 x + p1 y) |
237 // x = x / (p2 + p0 x + p1 y) | 239 // x = x / (p2 + p0 x + p1 y) |
238 | 240 |
239 // Input on stack: x y | 241 // Input on stack: x y |
240 code.append(" dup "); // x y y | 242 code->writeText(" dup "); // x y y |
241 code.appendScalar(p1); // x y y p1 | 243 SkPDFUtils::AppendScalar(p1, code); // x y y p1 |
242 code.append(" mul " // x y y*p1 | 244 code->writeText(" mul " // x y y*p1 |
243 " 2 index "); // x y y*p1 x | 245 " 2 index "); // x y y*p1 x |
244 code.appendScalar(p0); // x y y p1 x p0 | 246 SkPDFUtils::AppendScalar(p0, code); // x y y p1 x p0 |
245 code.append(" mul "); // x y y*p1 x*p0 | 247 code->writeText(" mul "); // x y y*p1 x*p0 |
246 code.appendScalar(p2); // x y y p1 x*p0 p2 | 248 SkPDFUtils::AppendScalar(p2, code); // x y y p1 x*p0 p2 |
247 code.append(" add " // x y y*p1 x*p0+p2 | 249 code->writeText(" add " // x y y*p1 x*p0+p2 |
248 "add " // x y y*p1+x*p0+p2 | 250 "add " // x y y*p1+x*p0+p2 |
249 "3 1 roll " // y*p1+x*p0+p2 x y | 251 "3 1 roll " // y*p1+x*p0+p2 x y |
250 "2 index " // z x y y*p1+x*p0+p2 | 252 "2 index " // z x y y*p1+x*p0+p2 |
251 "div " // y*p1+x*p0+p2 x y/(y*p1+x*p0+p2) | 253 "div " // y*p1+x*p0+p2 x y/(y*p1+x*p0+p2) |
252 "3 1 roll " // y/(y*p1+x*p0+p2) y*p1+x*p0+p2 x | 254 "3 1 roll " // y/(y*p1+x*p0+p2) y*p1+x*p0+p2 x |
253 "exch " // y/(y*p1+x*p0+p2) x y*p1+x*p0+p2 | 255 "exch " // y/(y*p1+x*p0+p2) x y*p1+x*p0+p2 |
254 "div " // y/(y*p1+x*p0+p2) x/(y*p1+x*p0+p2) | 256 "div " // y/(y*p1+x*p0+p2) x/(y*p1+x*p0+p2) |
255 "exch\n"); // x/(y*p1+x*p0+p2) y/(y*p1+x*p0+p2) | 257 "exch\n"); // x/(y*p1+x*p0+p2) y/(y*p1+x*p0+p2) |
256 return code; | |
257 } | 258 } |
258 | 259 |
259 static SkString linearCode(const SkShader::GradientInfo& info, | 260 static void linearCode(const SkShader::GradientInfo& info, |
260 const SkMatrix& perspectiveRemover) { | 261 const SkMatrix& perspectiveRemover, |
261 SkString function("{"); | 262 SkDynamicMemoryWStream* function) { |
| 263 function->writeText("{"); |
262 | 264 |
263 function.append(apply_perspective_to_coordinates(perspectiveRemover)); | 265 apply_perspective_to_coordinates(perspectiveRemover, function); |
264 | 266 |
265 function.append("pop\n"); // Just ditch the y value. | 267 function->writeText("pop\n"); // Just ditch the y value. |
266 tileModeCode(info.fTileMode, &function); | 268 tileModeCode(info.fTileMode, function); |
267 gradientFunctionCode(info, &function); | 269 gradientFunctionCode(info, function); |
268 function.append("}"); | 270 function->writeText("}"); |
269 return function; | |
270 } | 271 } |
271 | 272 |
272 static SkString radialCode(const SkShader::GradientInfo& info, | 273 static void radialCode(const SkShader::GradientInfo& info, |
273 const SkMatrix& perspectiveRemover) { | 274 const SkMatrix& perspectiveRemover, |
274 SkString function("{"); | 275 SkDynamicMemoryWStream* function) { |
| 276 function->writeText("{"); |
275 | 277 |
276 function.append(apply_perspective_to_coordinates(perspectiveRemover)); | 278 apply_perspective_to_coordinates(perspectiveRemover, function); |
277 | 279 |
278 // Find the distance from the origin. | 280 // Find the distance from the origin. |
279 function.append("dup " // x y y | 281 function->writeText("dup " // x y y |
280 "mul " // x y^2 | 282 "mul " // x y^2 |
281 "exch " // y^2 x | 283 "exch " // y^2 x |
282 "dup " // y^2 x x | 284 "dup " // y^2 x x |
283 "mul " // y^2 x^2 | 285 "mul " // y^2 x^2 |
284 "add " // y^2+x^2 | 286 "add " // y^2+x^2 |
285 "sqrt\n"); // sqrt(y^2+x^2) | 287 "sqrt\n"); // sqrt(y^2+x^2) |
286 | 288 |
287 tileModeCode(info.fTileMode, &function); | 289 tileModeCode(info.fTileMode, function); |
288 gradientFunctionCode(info, &function); | 290 gradientFunctionCode(info, function); |
289 function.append("}"); | 291 function->writeText("}"); |
290 return function; | |
291 } | 292 } |
292 | 293 |
293 /* Conical gradient shader, based on the Canvas spec for radial gradients | 294 /* Conical gradient shader, based on the Canvas spec for radial gradients |
294 See: http://www.w3.org/TR/2dcontext/#dom-context-2d-createradialgradient | 295 See: http://www.w3.org/TR/2dcontext/#dom-context-2d-createradialgradient |
295 */ | 296 */ |
296 static SkString twoPointConicalCode(const SkShader::GradientInfo& info, | 297 static void twoPointConicalCode(const SkShader::GradientInfo& info, |
297 const SkMatrix& perspectiveRemover) { | 298 const SkMatrix& perspectiveRemover, |
| 299 SkDynamicMemoryWStream* function) { |
298 SkScalar dx = info.fPoint[1].fX - info.fPoint[0].fX; | 300 SkScalar dx = info.fPoint[1].fX - info.fPoint[0].fX; |
299 SkScalar dy = info.fPoint[1].fY - info.fPoint[0].fY; | 301 SkScalar dy = info.fPoint[1].fY - info.fPoint[0].fY; |
300 SkScalar r0 = info.fRadius[0]; | 302 SkScalar r0 = info.fRadius[0]; |
301 SkScalar dr = info.fRadius[1] - info.fRadius[0]; | 303 SkScalar dr = info.fRadius[1] - info.fRadius[0]; |
302 SkScalar a = SkScalarMul(dx, dx) + SkScalarMul(dy, dy) - | 304 SkScalar a = SkScalarMul(dx, dx) + SkScalarMul(dy, dy) - |
303 SkScalarMul(dr, dr); | 305 SkScalarMul(dr, dr); |
304 | 306 |
305 // First compute t, if the pixel falls outside the cone, then we'll end | 307 // First compute t, if the pixel falls outside the cone, then we'll end |
306 // with 'false' on the stack, otherwise we'll push 'true' with t below it | 308 // with 'false' on the stack, otherwise we'll push 'true' with t below it |
307 | 309 |
308 // We start with a stack of (x y), copy it and then consume one copy in | 310 // We start with a stack of (x y), copy it and then consume one copy in |
309 // order to calculate b and the other to calculate c. | 311 // order to calculate b and the other to calculate c. |
310 SkString function("{"); | 312 function->writeText("{"); |
311 | 313 |
312 function.append(apply_perspective_to_coordinates(perspectiveRemover)); | 314 apply_perspective_to_coordinates(perspectiveRemover, function); |
313 | 315 |
314 function.append("2 copy "); | 316 function->writeText("2 copy "); |
315 | 317 |
316 // Calculate b and b^2; b = -2 * (y * dy + x * dx + r0 * dr). | 318 // Calculate b and b^2; b = -2 * (y * dy + x * dx + r0 * dr). |
317 function.appendScalar(dy); | 319 SkPDFUtils::AppendScalar(dy, function); |
318 function.append(" mul exch "); | 320 function->writeText(" mul exch "); |
319 function.appendScalar(dx); | 321 SkPDFUtils::AppendScalar(dx, function); |
320 function.append(" mul add "); | 322 function->writeText(" mul add "); |
321 function.appendScalar(SkScalarMul(r0, dr)); | 323 SkPDFUtils::AppendScalar(SkScalarMul(r0, dr), function); |
322 function.append(" add -2 mul dup dup mul\n"); | 324 function->writeText(" add -2 mul dup dup mul\n"); |
323 | 325 |
324 // c = x^2 + y^2 + radius0^2 | 326 // c = x^2 + y^2 + radius0^2 |
325 function.append("4 2 roll dup mul exch dup mul add "); | 327 function->writeText("4 2 roll dup mul exch dup mul add "); |
326 function.appendScalar(SkScalarMul(r0, r0)); | 328 SkPDFUtils::AppendScalar(SkScalarMul(r0, r0), function); |
327 function.append(" sub dup 4 1 roll\n"); | 329 function->writeText(" sub dup 4 1 roll\n"); |
328 | 330 |
329 // Contents of the stack at this point: c, b, b^2, c | 331 // Contents of the stack at this point: c, b, b^2, c |
330 | 332 |
331 // if a = 0, then we collapse to a simpler linear case | 333 // if a = 0, then we collapse to a simpler linear case |
332 if (a == 0) { | 334 if (a == 0) { |
333 | 335 |
334 // t = -c/b | 336 // t = -c/b |
335 function.append("pop pop div neg dup "); | 337 function->writeText("pop pop div neg dup "); |
336 | 338 |
337 // compute radius(t) | 339 // compute radius(t) |
338 function.appendScalar(dr); | 340 SkPDFUtils::AppendScalar(dr, function); |
339 function.append(" mul "); | 341 function->writeText(" mul "); |
340 function.appendScalar(r0); | 342 SkPDFUtils::AppendScalar(r0, function); |
341 function.append(" add\n"); | 343 function->writeText(" add\n"); |
342 | 344 |
343 // if r(t) < 0, then it's outside the cone | 345 // if r(t) < 0, then it's outside the cone |
344 function.append("0 lt {pop false} {true} ifelse\n"); | 346 function->writeText("0 lt {pop false} {true} ifelse\n"); |
345 | 347 |
346 } else { | 348 } else { |
347 | 349 |
348 // quadratic case: the Canvas spec wants the largest | 350 // quadratic case: the Canvas spec wants the largest |
349 // root t for which radius(t) > 0 | 351 // root t for which radius(t) > 0 |
350 | 352 |
351 // compute the discriminant (b^2 - 4ac) | 353 // compute the discriminant (b^2 - 4ac) |
352 function.appendScalar(SkScalarMul(SkIntToScalar(4), a)); | 354 SkPDFUtils::AppendScalar(SkScalarMul(SkIntToScalar(4), a), function); |
353 function.append(" mul sub dup\n"); | 355 function->writeText(" mul sub dup\n"); |
354 | 356 |
355 // if d >= 0, proceed | 357 // if d >= 0, proceed |
356 function.append("0 ge {\n"); | 358 function->writeText("0 ge {\n"); |
357 | 359 |
358 // an intermediate value we'll use to compute the roots: | 360 // an intermediate value we'll use to compute the roots: |
359 // q = -0.5 * (b +/- sqrt(d)) | 361 // q = -0.5 * (b +/- sqrt(d)) |
360 function.append("sqrt exch dup 0 lt {exch -1 mul} if"); | 362 function->writeText("sqrt exch dup 0 lt {exch -1 mul} if"); |
361 function.append(" add -0.5 mul dup\n"); | 363 function->writeText(" add -0.5 mul dup\n"); |
362 | 364 |
363 // first root = q / a | 365 // first root = q / a |
364 function.appendScalar(a); | 366 SkPDFUtils::AppendScalar(a, function); |
365 function.append(" div\n"); | 367 function->writeText(" div\n"); |
366 | 368 |
367 // second root = c / q | 369 // second root = c / q |
368 function.append("3 1 roll div\n"); | 370 function->writeText("3 1 roll div\n"); |
369 | 371 |
370 // put the larger root on top of the stack | 372 // put the larger root on top of the stack |
371 function.append("2 copy gt {exch} if\n"); | 373 function->writeText("2 copy gt {exch} if\n"); |
372 | 374 |
373 // compute radius(t) for larger root | 375 // compute radius(t) for larger root |
374 function.append("dup "); | 376 function->writeText("dup "); |
375 function.appendScalar(dr); | 377 SkPDFUtils::AppendScalar(dr, function); |
376 function.append(" mul "); | 378 function->writeText(" mul "); |
377 function.appendScalar(r0); | 379 SkPDFUtils::AppendScalar(r0, function); |
378 function.append(" add\n"); | 380 function->writeText(" add\n"); |
379 | 381 |
380 // if r(t) > 0, we have our t, pop off the smaller root and we're done | 382 // if r(t) > 0, we have our t, pop off the smaller root and we're done |
381 function.append(" 0 gt {exch pop true}\n"); | 383 function->writeText(" 0 gt {exch pop true}\n"); |
382 | 384 |
383 // otherwise, throw out the larger one and try the smaller root | 385 // otherwise, throw out the larger one and try the smaller root |
384 function.append("{pop dup\n"); | 386 function->writeText("{pop dup\n"); |
385 function.appendScalar(dr); | 387 SkPDFUtils::AppendScalar(dr, function); |
386 function.append(" mul "); | 388 function->writeText(" mul "); |
387 function.appendScalar(r0); | 389 SkPDFUtils::AppendScalar(r0, function); |
388 function.append(" add\n"); | 390 function->writeText(" add\n"); |
389 | 391 |
390 // if r(t) < 0, push false, otherwise the smaller root is our t | 392 // if r(t) < 0, push false, otherwise the smaller root is our t |
391 function.append("0 le {pop false} {true} ifelse\n"); | 393 function->writeText("0 le {pop false} {true} ifelse\n"); |
392 function.append("} ifelse\n"); | 394 function->writeText("} ifelse\n"); |
393 | 395 |
394 // d < 0, clear the stack and push false | 396 // d < 0, clear the stack and push false |
395 function.append("} {pop pop pop false} ifelse\n"); | 397 function->writeText("} {pop pop pop false} ifelse\n"); |
396 } | 398 } |
397 | 399 |
398 // if the pixel is in the cone, proceed to compute a color | 400 // if the pixel is in the cone, proceed to compute a color |
399 function.append("{"); | 401 function->writeText("{"); |
400 tileModeCode(info.fTileMode, &function); | 402 tileModeCode(info.fTileMode, function); |
401 gradientFunctionCode(info, &function); | 403 gradientFunctionCode(info, function); |
402 | 404 |
403 // otherwise, just write black | 405 // otherwise, just write black |
404 function.append("} {0 0 0} ifelse }"); | 406 function->writeText("} {0 0 0} ifelse }"); |
405 | |
406 return function; | |
407 } | 407 } |
408 | 408 |
409 static SkString sweepCode(const SkShader::GradientInfo& info, | 409 static void sweepCode(const SkShader::GradientInfo& info, |
410 const SkMatrix& perspectiveRemover) { | 410 const SkMatrix& perspectiveRemover, |
411 SkString function("{exch atan 360 div\n"); | 411 SkDynamicMemoryWStream* function) { |
412 tileModeCode(info.fTileMode, &function); | 412 function->writeText("{exch atan 360 div\n"); |
413 gradientFunctionCode(info, &function); | 413 tileModeCode(info.fTileMode, function); |
414 function.append("}"); | 414 gradientFunctionCode(info, function); |
415 return function; | 415 function->writeText("}"); |
416 } | 416 } |
417 | 417 |
418 static void drawBitmapMatrix(SkCanvas* canvas, const SkBitmap& bm, const SkMatri
x& matrix) { | 418 static void drawBitmapMatrix(SkCanvas* canvas, const SkBitmap& bm, const SkMatri
x& matrix) { |
419 SkAutoCanvasRestore acr(canvas, true); | 419 SkAutoCanvasRestore acr(canvas, true); |
420 canvas->concat(matrix); | 420 canvas->concat(matrix); |
421 canvas->drawBitmap(bm, 0, 0); | 421 canvas->drawBitmap(bm, 0, 0); |
422 } | 422 } |
423 | 423 |
424 class SkPDFShader::State { | 424 class SkPDFShader::State { |
425 public: | 425 public: |
(...skipping 256 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
682 range->reserve(6); | 682 range->reserve(6); |
683 range->appendInt(0); | 683 range->appendInt(0); |
684 range->appendInt(1); | 684 range->appendInt(1); |
685 range->appendInt(0); | 685 range->appendInt(0); |
686 range->appendInt(1); | 686 range->appendInt(1); |
687 range->appendInt(0); | 687 range->appendInt(0); |
688 range->appendInt(1); | 688 range->appendInt(1); |
689 return range; | 689 return range; |
690 } | 690 } |
691 | 691 |
692 static sk_sp<SkPDFStream> make_ps_function(const SkString& psCode, | 692 static sk_sp<SkPDFStream> make_ps_function( |
693 SkPDFArray* domain, | 693 std::unique_ptr<SkStreamAsset> psCode, |
694 sk_sp<SkPDFObject> range) { | 694 SkPDFArray* domain, |
695 SkAutoDataUnref funcData( | 695 sk_sp<SkPDFObject> range) { |
696 SkData::NewWithCopy(psCode.c_str(), psCode.size())); | 696 auto result = sk_make_sp<SkPDFStream>(psCode.get()); |
697 auto result = sk_make_sp<SkPDFStream>(funcData.get()); | |
698 result->insertInt("FunctionType", 4); | 697 result->insertInt("FunctionType", 4); |
699 result->insertObject("Domain", sk_ref_sp(domain)); | 698 result->insertObject("Domain", sk_ref_sp(domain)); |
700 result->insertObject("Range", std::move(range)); | 699 result->insertObject("Range", std::move(range)); |
701 return result; | 700 return result; |
702 } | 701 } |
703 | 702 |
704 SkPDFFunctionShader* SkPDFFunctionShader::Create( | 703 SkPDFFunctionShader* SkPDFFunctionShader::Create( |
705 SkPDFCanon* canon, SkAutoTDelete<SkPDFShader::State>* autoState) { | 704 SkPDFCanon* canon, SkAutoTDelete<SkPDFShader::State>* autoState) { |
706 const SkPDFShader::State& state = **autoState; | 705 const SkPDFShader::State& state = **autoState; |
707 | 706 |
708 SkString (*codeFunction)(const SkShader::GradientInfo& info, | 707 void (*codeFunction)(const SkShader::GradientInfo& info, |
709 const SkMatrix& perspectiveRemover) = nullptr; | 708 const SkMatrix& perspectiveRemover, |
| 709 SkDynamicMemoryWStream* function) = nullptr; |
710 SkPoint transformPoints[2]; | 710 SkPoint transformPoints[2]; |
711 | 711 |
712 // Depending on the type of the gradient, we want to transform the | 712 // Depending on the type of the gradient, we want to transform the |
713 // coordinate space in different ways. | 713 // coordinate space in different ways. |
714 const SkShader::GradientInfo* info = &state.fInfo; | 714 const SkShader::GradientInfo* info = &state.fInfo; |
715 transformPoints[0] = info->fPoint[0]; | 715 transformPoints[0] = info->fPoint[0]; |
716 transformPoints[1] = info->fPoint[1]; | 716 transformPoints[1] = info->fPoint[1]; |
717 switch (state.fType) { | 717 switch (state.fType) { |
718 case SkShader::kLinear_GradientType: | 718 case SkShader::kLinear_GradientType: |
719 codeFunction = &linearCode; | 719 codeFunction = &linearCode; |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
770 return nullptr; | 770 return nullptr; |
771 } | 771 } |
772 | 772 |
773 auto domain = sk_make_sp<SkPDFArray>(); | 773 auto domain = sk_make_sp<SkPDFArray>(); |
774 domain->reserve(4); | 774 domain->reserve(4); |
775 domain->appendScalar(bbox.fLeft); | 775 domain->appendScalar(bbox.fLeft); |
776 domain->appendScalar(bbox.fRight); | 776 domain->appendScalar(bbox.fRight); |
777 domain->appendScalar(bbox.fTop); | 777 domain->appendScalar(bbox.fTop); |
778 domain->appendScalar(bbox.fBottom); | 778 domain->appendScalar(bbox.fBottom); |
779 | 779 |
780 SkString functionCode; | 780 SkDynamicMemoryWStream functionCode; |
781 // The two point radial gradient further references | 781 // The two point radial gradient further references |
782 // state.fInfo | 782 // state.fInfo |
783 // in translating from x, y coordinates to the t parameter. So, we have | 783 // in translating from x, y coordinates to the t parameter. So, we have |
784 // to transform the points and radii according to the calculated matrix. | 784 // to transform the points and radii according to the calculated matrix. |
785 if (state.fType == SkShader::kConical_GradientType) { | 785 if (state.fType == SkShader::kConical_GradientType) { |
786 SkShader::GradientInfo twoPointRadialInfo = *info; | 786 SkShader::GradientInfo twoPointRadialInfo = *info; |
787 SkMatrix inverseMapperMatrix; | 787 SkMatrix inverseMapperMatrix; |
788 if (!mapperMatrix.invert(&inverseMapperMatrix)) { | 788 if (!mapperMatrix.invert(&inverseMapperMatrix)) { |
789 return nullptr; | 789 return nullptr; |
790 } | 790 } |
791 inverseMapperMatrix.mapPoints(twoPointRadialInfo.fPoint, 2); | 791 inverseMapperMatrix.mapPoints(twoPointRadialInfo.fPoint, 2); |
792 twoPointRadialInfo.fRadius[0] = | 792 twoPointRadialInfo.fRadius[0] = |
793 inverseMapperMatrix.mapRadius(info->fRadius[0]); | 793 inverseMapperMatrix.mapRadius(info->fRadius[0]); |
794 twoPointRadialInfo.fRadius[1] = | 794 twoPointRadialInfo.fRadius[1] = |
795 inverseMapperMatrix.mapRadius(info->fRadius[1]); | 795 inverseMapperMatrix.mapRadius(info->fRadius[1]); |
796 functionCode = codeFunction(twoPointRadialInfo, perspectiveInverseOnly); | 796 codeFunction(twoPointRadialInfo, perspectiveInverseOnly, &functionCode); |
797 } else { | 797 } else { |
798 functionCode = codeFunction(*info, perspectiveInverseOnly); | 798 codeFunction(*info, perspectiveInverseOnly, &functionCode); |
799 } | 799 } |
800 | 800 |
801 auto pdfShader = sk_make_sp<SkPDFDict>(); | 801 auto pdfShader = sk_make_sp<SkPDFDict>(); |
802 pdfShader->insertInt("ShadingType", 1); | 802 pdfShader->insertInt("ShadingType", 1); |
803 pdfShader->insertName("ColorSpace", "DeviceRGB"); | 803 pdfShader->insertName("ColorSpace", "DeviceRGB"); |
804 pdfShader->insertObject("Domain", sk_ref_sp(domain.get())); | 804 pdfShader->insertObject("Domain", sk_ref_sp(domain.get())); |
805 | 805 |
806 // Call canon->makeRangeObject() instead of | 806 // Call canon->makeRangeObject() instead of |
807 // SkPDFShader::MakeRangeObject() so that the canon can | 807 // SkPDFShader::MakeRangeObject() so that the canon can |
808 // deduplicate. | 808 // deduplicate. |
809 auto function = make_ps_function(functionCode, domain.get(), | 809 std::unique_ptr<SkStreamAsset> functionStream( |
| 810 functionCode.detachAsStream()); |
| 811 auto function = make_ps_function(std::move(functionStream), domain.get(), |
810 canon->makeRangeObject()); | 812 canon->makeRangeObject()); |
811 pdfShader->insertObjRef("Function", std::move(function)); | 813 pdfShader->insertObjRef("Function", std::move(function)); |
812 | 814 |
813 sk_sp<SkPDFFunctionShader> pdfFunctionShader( | 815 sk_sp<SkPDFFunctionShader> pdfFunctionShader( |
814 new SkPDFFunctionShader(autoState->release())); | 816 new SkPDFFunctionShader(autoState->release())); |
815 pdfFunctionShader->insertInt("PatternType", 2); | 817 pdfFunctionShader->insertInt("PatternType", 2); |
816 pdfFunctionShader->insertObject("Matrix", | 818 pdfFunctionShader->insertObject("Matrix", |
817 SkPDFUtils::MatrixToArray(finalMatrix)); | 819 SkPDFUtils::MatrixToArray(finalMatrix)); |
818 pdfFunctionShader->insertObject("Shading", std::move(pdfShader)); | 820 pdfFunctionShader->insertObject("Shading", std::move(pdfShader)); |
819 | 821 |
(...skipping 405 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1225 return false; | 1227 return false; |
1226 } | 1228 } |
1227 | 1229 |
1228 void SkPDFShader::State::AllocateGradientInfoStorage() { | 1230 void SkPDFShader::State::AllocateGradientInfoStorage() { |
1229 fColorData.set(sk_malloc_throw( | 1231 fColorData.set(sk_malloc_throw( |
1230 fInfo.fColorCount * (sizeof(SkColor) + sizeof(SkScalar)))); | 1232 fInfo.fColorCount * (sizeof(SkColor) + sizeof(SkScalar)))); |
1231 fInfo.fColors = reinterpret_cast<SkColor*>(fColorData.get()); | 1233 fInfo.fColors = reinterpret_cast<SkColor*>(fColorData.get()); |
1232 fInfo.fColorOffsets = | 1234 fInfo.fColorOffsets = |
1233 reinterpret_cast<SkScalar*>(fInfo.fColors + fInfo.fColorCount); | 1235 reinterpret_cast<SkScalar*>(fInfo.fColors + fInfo.fColorCount); |
1234 } | 1236 } |
OLD | NEW |