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

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

Issue 29743002: Revert "PDF: support perspective in simple shaders. (this version does not work well with tilling)" (Closed) Base URL: https://skia.googlecode.com/svn/trunk
Patch Set: Created 7 years, 2 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 | Annotate | Revision Log
« no previous file with comments | « src/pdf/SkPDFDevice.cpp ('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 192 matching lines...) Expand 10 before | Expand all | Expand 10 after
203 "cvi " // t.s t T 203 "cvi " // t.s t T
204 "2 mod " // t.s t (i mod 2) 204 "2 mod " // t.s t (i mod 2)
205 "1 eq " // t.s t true|false 205 "1 eq " // t.s t true|false
206 "3 1 roll " // true|false t.s t 206 "3 1 roll " // true|false t.s t
207 "sub " // true|false 0.s 207 "sub " // true|false 0.s
208 "exch " // 0.s true|false 208 "exch " // 0.s true|false
209 "{1 exch sub} if\n"); // 1 - 0.s|0.s 209 "{1 exch sub} if\n"); // 1 - 0.s|0.s
210 } 210 }
211 } 211 }
212 212
213 /** 213 static SkString linearCode(const SkShader::GradientInfo& info) {
214 * Returns PS function code that would apply perspective to a x, y point. 214 SkString function("{pop\n"); // Just ditch the y value.
215 * The function assumes that the stack has at least two elements,
216 * and that the top 2 elements are numeric values.
217 * After ececuting this code on a PS stack, the last 2 elements are updated
218 * while the rest of the stack is preserved intact.
219 * xy2xy is the inverse perspective matrix.
220 */
221 static SkString apply_perspective_to_coordinates(
222 const SkMatrix& inversePerspectiveMatrix) {
223 SkString code;
224 if (!inversePerspectiveMatrix.hasPerspective()) {
225 return code;
226 }
227
228 // Perspective matrix should be:
229 // 1 0 0
230 // 0 1 0
231 // p0 p1 p2
232
233 SkScalar p0 = inversePerspectiveMatrix[SkMatrix::kMPersp0];
234 SkScalar p1 = inversePerspectiveMatrix[SkMatrix::kMPersp1];
235 SkScalar p2 = inversePerspectiveMatrix[SkMatrix::kMPersp2];
236
237 // y = y / (p2 + p0 x + p1 y)
238 // x = x / (p2 + p0 x + p1 y)
239
240 // Input on stack: x y
241 code.append("dup "); // x y y
242 code.appendScalar(p1); // x y y p1
243 code.append(" mul " // x y y*p1
244 " 2 index "); // x y y*p1 x
245 code.appendScalar(p0); // x y y p1 x p0
246 code.append(" mul "); // x y y*p1 x*p0
247 code.appendScalar(p2); // x y y p1 x*p0 p2
248 code.append("add " // x y y*p1 x*p0+p2
249 "add " // x y y*p1+x*p0+p2
250 "1 index " // x y y*p1+x*p0+p2 y
251 "1 index " // x y y*p1+x*p0+p2 y y*p1+x*p0+p2
252 "div " // x y y*p1+x*p0+p2 y/(y*p1+x*p0+p2)
253 "4 1 roll " // y/(y*p1+x*p0+p2) x y y*p1+x*p0+p2
254 "exch " // y/(y*p1+x*p0+p2) x y*p1+x*p0+p2 y
255 "pop " // 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)
257 "exch\n"); // x/(y*p1+x*p0+p2) y/(y*p1+x*p0+p2)
258
259 return code;
260 }
261
262 static SkString linearCode(const SkShader::GradientInfo& info,
263 const SkMatrix& perspectiveRemover) {
264 SkString function("{");
265
266 function.append(apply_perspective_to_coordinates(perspectiveRemover));
267
268 function.append("pop\n"); // Just ditch the y value.
269 tileModeCode(info.fTileMode, &function); 215 tileModeCode(info.fTileMode, &function);
270 gradientFunctionCode(info, &function); 216 gradientFunctionCode(info, &function);
271 function.append("}"); 217 function.append("}");
272 return function; 218 return function;
273 } 219 }
274 220
275 static SkString radialCode(const SkShader::GradientInfo& info, 221 static SkString radialCode(const SkShader::GradientInfo& info) {
276 const SkMatrix& perspectiveRemover) {
277 SkString function("{"); 222 SkString function("{");
278
279 function.append(apply_perspective_to_coordinates(perspectiveRemover));
280
281 // Find the distance from the origin. 223 // Find the distance from the origin.
282 function.append("dup " // x y y 224 function.append("dup " // x y y
283 "mul " // x y^2 225 "mul " // x y^2
284 "exch " // y^2 x 226 "exch " // y^2 x
285 "dup " // y^2 x x 227 "dup " // y^2 x x
286 "mul " // y^2 x^2 228 "mul " // y^2 x^2
287 "add " // y^2+x^2 229 "add " // y^2+x^2
288 "sqrt\n"); // sqrt(y^2+x^2) 230 "sqrt\n"); // sqrt(y^2+x^2)
289 231
290 tileModeCode(info.fTileMode, &function); 232 tileModeCode(info.fTileMode, &function);
291 gradientFunctionCode(info, &function); 233 gradientFunctionCode(info, &function);
292 function.append("}"); 234 function.append("}");
293 return function; 235 return function;
294 } 236 }
295 237
296 /* The math here is all based on the description in Two_Point_Radial_Gradient, 238 /* The math here is all based on the description in Two_Point_Radial_Gradient,
297 with one simplification, the coordinate space has been scaled so that 239 with one simplification, the coordinate space has been scaled so that
298 Dr = 1. This means we don't need to scale the entire equation by 1/Dr^2. 240 Dr = 1. This means we don't need to scale the entire equation by 1/Dr^2.
299 */ 241 */
300 static SkString twoPointRadialCode(const SkShader::GradientInfo& info, 242 static SkString twoPointRadialCode(const SkShader::GradientInfo& info) {
301 const SkMatrix& perspectiveRemover) {
302 SkScalar dx = info.fPoint[0].fX - info.fPoint[1].fX; 243 SkScalar dx = info.fPoint[0].fX - info.fPoint[1].fX;
303 SkScalar dy = info.fPoint[0].fY - info.fPoint[1].fY; 244 SkScalar dy = info.fPoint[0].fY - info.fPoint[1].fY;
304 SkScalar sr = info.fRadius[0]; 245 SkScalar sr = info.fRadius[0];
305 SkScalar a = SkScalarMul(dx, dx) + SkScalarMul(dy, dy) - SK_Scalar1; 246 SkScalar a = SkScalarMul(dx, dx) + SkScalarMul(dy, dy) - SK_Scalar1;
306 bool posRoot = info.fRadius[1] > info.fRadius[0]; 247 bool posRoot = info.fRadius[1] > info.fRadius[0];
307 248
308 // We start with a stack of (x y), copy it and then consume one copy in 249 // 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. 250 // order to calculate b and the other to calculate c.
310 SkString function("{"); 251 SkString function("{");
311
312 function.append(apply_perspective_to_coordinates(perspectiveRemover));
313
314 function.append("2 copy "); 252 function.append("2 copy ");
315 253
316 // Calculate -b and b^2. 254 // Calculate -b and b^2.
317 function.appendScalar(dy); 255 function.appendScalar(dy);
318 function.append(" mul exch "); 256 function.append(" mul exch ");
319 function.appendScalar(dx); 257 function.appendScalar(dx);
320 function.append(" mul add "); 258 function.append(" mul add ");
321 function.appendScalar(sr); 259 function.appendScalar(sr);
322 function.append(" sub 2 mul neg dup dup mul\n"); 260 function.append(" sub 2 mul neg dup dup mul\n");
323 261
(...skipping 17 matching lines...) Expand all
341 279
342 tileModeCode(info.fTileMode, &function); 280 tileModeCode(info.fTileMode, &function);
343 gradientFunctionCode(info, &function); 281 gradientFunctionCode(info, &function);
344 function.append("}"); 282 function.append("}");
345 return function; 283 return function;
346 } 284 }
347 285
348 /* Conical gradient shader, based on the Canvas spec for radial gradients 286 /* Conical gradient shader, based on the Canvas spec for radial gradients
349 See: http://www.w3.org/TR/2dcontext/#dom-context-2d-createradialgradient 287 See: http://www.w3.org/TR/2dcontext/#dom-context-2d-createradialgradient
350 */ 288 */
351 static SkString twoPointConicalCode(const SkShader::GradientInfo& info, 289 static SkString twoPointConicalCode(const SkShader::GradientInfo& info) {
352 const SkMatrix& perspectiveRemover) {
353 SkScalar dx = info.fPoint[1].fX - info.fPoint[0].fX; 290 SkScalar dx = info.fPoint[1].fX - info.fPoint[0].fX;
354 SkScalar dy = info.fPoint[1].fY - info.fPoint[0].fY; 291 SkScalar dy = info.fPoint[1].fY - info.fPoint[0].fY;
355 SkScalar r0 = info.fRadius[0]; 292 SkScalar r0 = info.fRadius[0];
356 SkScalar dr = info.fRadius[1] - info.fRadius[0]; 293 SkScalar dr = info.fRadius[1] - info.fRadius[0];
357 SkScalar a = SkScalarMul(dx, dx) + SkScalarMul(dy, dy) - 294 SkScalar a = SkScalarMul(dx, dx) + SkScalarMul(dy, dy) -
358 SkScalarMul(dr, dr); 295 SkScalarMul(dr, dr);
359 296
360 // First compute t, if the pixel falls outside the cone, then we'll end 297 // First compute t, if the pixel falls outside the cone, then we'll end
361 // with 'false' on the stack, otherwise we'll push 'true' with t below it 298 // with 'false' on the stack, otherwise we'll push 'true' with t below it
362 299
363 // We start with a stack of (x y), copy it and then consume one copy in 300 // We start with a stack of (x y), copy it and then consume one copy in
364 // order to calculate b and the other to calculate c. 301 // order to calculate b and the other to calculate c.
365 SkString function("{"); 302 SkString function("{");
366
367 function.append(apply_perspective_to_coordinates(perspectiveRemover));
368
369 function.append("2 copy "); 303 function.append("2 copy ");
370 304
371 // Calculate b and b^2; b = -2 * (y * dy + x * dx + r0 * dr). 305 // Calculate b and b^2; b = -2 * (y * dy + x * dx + r0 * dr).
372 function.appendScalar(dy); 306 function.appendScalar(dy);
373 function.append(" mul exch "); 307 function.append(" mul exch ");
374 function.appendScalar(dx); 308 function.appendScalar(dx);
375 function.append(" mul add "); 309 function.append(" mul add ");
376 function.appendScalar(SkScalarMul(r0, dr)); 310 function.appendScalar(SkScalarMul(r0, dr));
377 function.append(" add -2 mul dup dup mul\n"); 311 function.append(" add -2 mul dup dup mul\n");
378 312
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
454 function.append("{"); 388 function.append("{");
455 tileModeCode(info.fTileMode, &function); 389 tileModeCode(info.fTileMode, &function);
456 gradientFunctionCode(info, &function); 390 gradientFunctionCode(info, &function);
457 391
458 // otherwise, just write black 392 // otherwise, just write black
459 function.append("} {0 0 0} ifelse }"); 393 function.append("} {0 0 0} ifelse }");
460 394
461 return function; 395 return function;
462 } 396 }
463 397
464 static SkString sweepCode(const SkShader::GradientInfo& info, 398 static SkString sweepCode(const SkShader::GradientInfo& info) {
465 const SkMatrix& perspectiveRemover) {
466 SkString function("{exch atan 360 div\n"); 399 SkString function("{exch atan 360 div\n");
467 tileModeCode(info.fTileMode, &function); 400 tileModeCode(info.fTileMode, &function);
468 gradientFunctionCode(info, &function); 401 gradientFunctionCode(info, &function);
469 function.append("}"); 402 function.append("}");
470 return function; 403 return function;
471 } 404 }
472 405
473 class SkPDFShader::State { 406 class SkPDFShader::State {
474 public: 407 public:
475 SkShader::GradientType fType; 408 SkShader::GradientType fType;
(...skipping 309 matching lines...) Expand 10 before | Expand all | Expand 10 after
785 get_gradient_resource_dict(fColorShader.get(), alphaGs.get())); 718 get_gradient_resource_dict(fColorShader.get(), alphaGs.get()));
786 719
787 SkAutoTUnref<SkStream> colorStream( 720 SkAutoTUnref<SkStream> colorStream(
788 create_pattern_fill_content(0, bbox)); 721 create_pattern_fill_content(0, bbox));
789 setData(colorStream.get()); 722 setData(colorStream.get());
790 723
791 populate_tiling_pattern_dict(this, bbox, fResourceDict.get(), 724 populate_tiling_pattern_dict(this, bbox, fResourceDict.get(),
792 SkMatrix::I()); 725 SkMatrix::I());
793 } 726 }
794 727
795 // Finds affine and persp such that in = affine * persp.
796 // but it returns the inverse of perspective matrix.
797 static bool split_perspective(const SkMatrix in, SkMatrix* affine,
798 SkMatrix* perspectiveInverse) {
799 const SkScalar p2 = in[SkMatrix::kMPersp2];
800
801 if (SkScalarNearlyZero(p2)) {
802 return false;
803 }
804
805 const SkScalar zero = SkIntToScalar(0);
806 const SkScalar one = SkIntToScalar(1);
807
808 const SkScalar sx = in[SkMatrix::kMScaleX];
809 const SkScalar kx = in[SkMatrix::kMSkewX];
810 const SkScalar tx = in[SkMatrix::kMTransX];
811 const SkScalar ky = in[SkMatrix::kMSkewY];
812 const SkScalar sy = in[SkMatrix::kMScaleY];
813 const SkScalar ty = in[SkMatrix::kMTransY];
814 const SkScalar p0 = in[SkMatrix::kMPersp0];
815 const SkScalar p1 = in[SkMatrix::kMPersp1];
816
817 // Perspective matrix would be:
818 // 1 0 0
819 // 0 1 0
820 // p0 p1 p2
821 // But we need the inverse of persp.
822 perspectiveInverse->setAll(one, zero, zero,
823 zero, one, zero,
824 -p0 / p2, -p1/p2, 1/p2);
825
826 affine->setAll(sx - p0 * tx / p2, kx - p1 * tx / p2, tx / p2,
827 ky - p0 * ty / p2, sy - p1 * ty / p2, ty / p2,
828 zero, zero, one);
829
830 return true;
831 }
832
833 SkPDFFunctionShader::SkPDFFunctionShader(SkPDFShader::State* state) 728 SkPDFFunctionShader::SkPDFFunctionShader(SkPDFShader::State* state)
834 : SkPDFDict("Pattern"), 729 : SkPDFDict("Pattern"),
835 fState(state) { 730 fState(state) {
836 SkString (*codeFunction)(const SkShader::GradientInfo& info, 731 SkString (*codeFunction)(const SkShader::GradientInfo& info) = NULL;
837 const SkMatrix& perspectiveRemover) = NULL;
838 SkPoint transformPoints[2]; 732 SkPoint transformPoints[2];
839 733
840 // Depending on the type of the gradient, we want to transform the 734 // Depending on the type of the gradient, we want to transform the
841 // coordinate space in different ways. 735 // coordinate space in different ways.
842 const SkShader::GradientInfo* info = &fState.get()->fInfo; 736 const SkShader::GradientInfo* info = &fState.get()->fInfo;
843 transformPoints[0] = info->fPoint[0]; 737 transformPoints[0] = info->fPoint[0];
844 transformPoints[1] = info->fPoint[1]; 738 transformPoints[1] = info->fPoint[1];
845 switch (fState.get()->fType) { 739 switch (fState.get()->fType) {
846 case SkShader::kLinear_GradientType: 740 case SkShader::kLinear_GradientType:
847 codeFunction = &linearCode; 741 codeFunction = &linearCode;
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
879 default: 773 default:
880 return; 774 return;
881 } 775 }
882 776
883 // Move any scaling (assuming a unit gradient) or translation 777 // Move any scaling (assuming a unit gradient) or translation
884 // (and rotation for linear gradient), of the final gradient from 778 // (and rotation for linear gradient), of the final gradient from
885 // info->fPoints to the matrix (updating bbox appropriately). Now 779 // info->fPoints to the matrix (updating bbox appropriately). Now
886 // the gradient can be drawn on on the unit segment. 780 // the gradient can be drawn on on the unit segment.
887 SkMatrix mapperMatrix; 781 SkMatrix mapperMatrix;
888 unitToPointsMatrix(transformPoints, &mapperMatrix); 782 unitToPointsMatrix(transformPoints, &mapperMatrix);
889
890 SkMatrix perspectiveInverseOnly = SkMatrix::I();
891
892 SkMatrix finalMatrix = fState.get()->fCanvasTransform; 783 SkMatrix finalMatrix = fState.get()->fCanvasTransform;
893 finalMatrix.preConcat(fState.get()->fShaderTransform); 784 finalMatrix.preConcat(fState.get()->fShaderTransform);
894
895 // Preserves as much as posible in the final matrix, and only removes
896 // the perspective. The inverse of the perspective is stored in
897 // perspectiveInverseOnly matrix and has 3 useful numbers
898 // (p0, p1, p2), while everything else is either 0 or 1.
899 // In this way the shader will handle it eficiently, with minimal code.
900 if (finalMatrix.hasPerspective()) {
901 if (!split_perspective(finalMatrix,
902 &finalMatrix, &perspectiveInverseOnly)) {
903 return;
904 }
905 }
906
907 finalMatrix.preConcat(mapperMatrix); 785 finalMatrix.preConcat(mapperMatrix);
908 786
909 SkRect bbox; 787 SkRect bbox;
910 bbox.set(fState.get()->fBBox); 788 bbox.set(fState.get()->fBBox);
911 if (!inverseTransformBBox(finalMatrix, &bbox)) { 789 if (!inverseTransformBBox(finalMatrix, &bbox)) {
912 return; 790 return;
913 } 791 }
914 792
915 SkAutoTUnref<SkPDFArray> domain(new SkPDFArray); 793 SkAutoTUnref<SkPDFArray> domain(new SkPDFArray);
916 domain->reserve(4); 794 domain->reserve(4);
(...skipping 10 matching lines...) Expand all
927 SkShader::GradientInfo twoPointRadialInfo = *info; 805 SkShader::GradientInfo twoPointRadialInfo = *info;
928 SkMatrix inverseMapperMatrix; 806 SkMatrix inverseMapperMatrix;
929 if (!mapperMatrix.invert(&inverseMapperMatrix)) { 807 if (!mapperMatrix.invert(&inverseMapperMatrix)) {
930 return; 808 return;
931 } 809 }
932 inverseMapperMatrix.mapPoints(twoPointRadialInfo.fPoint, 2); 810 inverseMapperMatrix.mapPoints(twoPointRadialInfo.fPoint, 2);
933 twoPointRadialInfo.fRadius[0] = 811 twoPointRadialInfo.fRadius[0] =
934 inverseMapperMatrix.mapRadius(info->fRadius[0]); 812 inverseMapperMatrix.mapRadius(info->fRadius[0]);
935 twoPointRadialInfo.fRadius[1] = 813 twoPointRadialInfo.fRadius[1] =
936 inverseMapperMatrix.mapRadius(info->fRadius[1]); 814 inverseMapperMatrix.mapRadius(info->fRadius[1]);
937 functionCode = codeFunction(twoPointRadialInfo, perspectiveInverseOnly); 815 functionCode = codeFunction(twoPointRadialInfo);
938 } else { 816 } else {
939 functionCode = codeFunction(*info, perspectiveInverseOnly); 817 functionCode = codeFunction(*info);
940 } 818 }
941 819
942 SkAutoTUnref<SkPDFDict> pdfShader(new SkPDFDict); 820 SkAutoTUnref<SkPDFDict> pdfShader(new SkPDFDict);
943 pdfShader->insertInt("ShadingType", 1); 821 pdfShader->insertInt("ShadingType", 1);
944 pdfShader->insertName("ColorSpace", "DeviceRGB"); 822 pdfShader->insertName("ColorSpace", "DeviceRGB");
945 pdfShader->insert("Domain", domain.get()); 823 pdfShader->insert("Domain", domain.get());
946 824
947 SkPDFStream* function = makePSFunction(functionCode, domain.get()); 825 SkPDFStream* function = makePSFunction(functionCode, domain.get());
948 pdfShader->insert("Function", new SkPDFObjRef(function))->unref(); 826 pdfShader->insert("Function", new SkPDFObjRef(function))->unref();
949 fResources.push(function); // Pass ownership to resource list. 827 fResources.push(function); // Pass ownership to resource list.
(...skipping 390 matching lines...) Expand 10 before | Expand all | Expand 10 after
1340 return false; 1218 return false;
1341 } 1219 }
1342 1220
1343 void SkPDFShader::State::AllocateGradientInfoStorage() { 1221 void SkPDFShader::State::AllocateGradientInfoStorage() {
1344 fColorData.set(sk_malloc_throw( 1222 fColorData.set(sk_malloc_throw(
1345 fInfo.fColorCount * (sizeof(SkColor) + sizeof(SkScalar)))); 1223 fInfo.fColorCount * (sizeof(SkColor) + sizeof(SkScalar))));
1346 fInfo.fColors = reinterpret_cast<SkColor*>(fColorData.get()); 1224 fInfo.fColors = reinterpret_cast<SkColor*>(fColorData.get());
1347 fInfo.fColorOffsets = 1225 fInfo.fColorOffsets =
1348 reinterpret_cast<SkScalar*>(fInfo.fColors + fInfo.fColorCount); 1226 reinterpret_cast<SkScalar*>(fInfo.fColors + fInfo.fColorCount);
1349 } 1227 }
OLDNEW
« no previous file with comments | « src/pdf/SkPDFDevice.cpp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698