Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2)

Side by Side Diff: src/pdf/SkPDFShader.cpp

Issue 1833793002: SkPDF: speed up SkPDFShader generation. (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/pdf/SkPDFDocument.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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 }
OLDNEW
« no previous file with comments | « src/pdf/SkPDFDocument.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698