static SkString sweepCode(const SkShader::GradientInfo& info) { SkString function("{exch atan 360 div\n"); tileModeCode(info.fTileMode, &function); gradientFunctionCode(info, &function); function.append("}"); return function; }
static SkString linearCode(const SkShader::GradientInfo& info) { SkString function("{pop\n"); // Just ditch the y value. tileModeCode(info.fTileMode, &function); gradientFunctionCode(info, &function); function.append("}"); return function; }
static void sweepCode(const SkShader::GradientInfo& info, const SkMatrix& perspectiveRemover, SkDynamicMemoryWStream* function) { function->writeText("{exch atan 360 div\n"); tileModeCode((SkTileMode)info.fTileMode, function); gradient_function_code(info, function); function->writeText("}"); }
static SkString linearCode(const SkShader::GradientInfo& info, const SkMatrix& perspectiveRemover) { SkString function("{"); function.append(apply_perspective_to_coordinates(perspectiveRemover)); function.append("pop\n"); // Just ditch the y value. tileModeCode(info.fTileMode, &function); gradientFunctionCode(info, &function); function.append("}"); return function; }
static void linearCode(const SkShader::GradientInfo& info, const SkMatrix& perspectiveRemover, SkDynamicMemoryWStream* function) { function->writeText("{"); apply_perspective_to_coordinates(perspectiveRemover, function); function->writeText("pop\n"); // Just ditch the y value. tileModeCode((SkTileMode)info.fTileMode, function); gradient_function_code(info, function); function->writeText("}"); }
static SkString radialCode(const SkShader::GradientInfo& info) { SkString function("{"); // Find the distance from the origin. function.append("dup " // x y y "mul " // x y^2 "exch " // y^2 x "dup " // y^2 x x "mul " // y^2 x^2 "add " // y^2+x^2 "sqrt\n"); // sqrt(y^2+x^2) tileModeCode(info.fTileMode, &function); gradientFunctionCode(info, &function); function.append("}"); return function; }
/* The math here is all based on the description in Two_Point_Radial_Gradient, with one simplification, the coordinate space has been scaled so that Dr = 1. This means we don't need to scale the entire equation by 1/Dr^2. */ static SkString twoPointRadialCode(const SkShader::GradientInfo& info, const SkMatrix& perspectiveRemover) { SkScalar dx = info.fPoint[0].fX - info.fPoint[1].fX; SkScalar dy = info.fPoint[0].fY - info.fPoint[1].fY; SkScalar sr = info.fRadius[0]; SkScalar a = SkScalarMul(dx, dx) + SkScalarMul(dy, dy) - SK_Scalar1; bool posRoot = info.fRadius[1] > info.fRadius[0]; // We start with a stack of (x y), copy it and then consume one copy in // order to calculate b and the other to calculate c. SkString function("{"); function.append(apply_perspective_to_coordinates(perspectiveRemover)); function.append("2 copy "); // Calculate -b and b^2. function.appendScalar(dy); function.append(" mul exch "); function.appendScalar(dx); function.append(" mul add "); function.appendScalar(sr); function.append(" sub 2 mul neg dup dup mul\n"); // Calculate c function.append("4 2 roll dup mul exch dup mul add "); function.appendScalar(SkScalarMul(sr, sr)); function.append(" sub\n"); // Calculate the determinate function.appendScalar(SkScalarMul(SkIntToScalar(4), a)); function.append(" mul sub abs sqrt\n"); // And then the final value of t. if (posRoot) { function.append("sub "); } else { function.append("add "); } function.appendScalar(SkScalarMul(SkIntToScalar(2), a)); function.append(" div\n"); tileModeCode(info.fTileMode, &function); gradientFunctionCode(info, &function); function.append("}"); return function; }
static SkString radialCode(const SkShader::GradientInfo& info, const SkMatrix& perspectiveRemover) { SkString function("{"); function.append(apply_perspective_to_coordinates(perspectiveRemover)); // Find the distance from the origin. function.append("dup " // x y y "mul " // x y^2 "exch " // y^2 x "dup " // y^2 x x "mul " // y^2 x^2 "add " // y^2+x^2 "sqrt\n"); // sqrt(y^2+x^2) tileModeCode(info.fTileMode, &function); gradientFunctionCode(info, &function); function.append("}"); return function; }
static void radialCode(const SkShader::GradientInfo& info, const SkMatrix& perspectiveRemover, SkDynamicMemoryWStream* function) { function->writeText("{"); apply_perspective_to_coordinates(perspectiveRemover, function); // Find the distance from the origin. function->writeText("dup " // x y y "mul " // x y^2 "exch " // y^2 x "dup " // y^2 x x "mul " // y^2 x^2 "add " // y^2+x^2 "sqrt\n"); // sqrt(y^2+x^2) tileModeCode((SkTileMode)info.fTileMode, function); gradient_function_code(info, function); function->writeText("}"); }
/* Conical gradient shader, based on the Canvas spec for radial gradients See: http://www.w3.org/TR/2dcontext/#dom-context-2d-createradialgradient */ static SkString twoPointConicalCode(const SkShader::GradientInfo& info, const SkMatrix& perspectiveRemover) { SkScalar dx = info.fPoint[1].fX - info.fPoint[0].fX; SkScalar dy = info.fPoint[1].fY - info.fPoint[0].fY; SkScalar r0 = info.fRadius[0]; SkScalar dr = info.fRadius[1] - info.fRadius[0]; SkScalar a = SkScalarMul(dx, dx) + SkScalarMul(dy, dy) - SkScalarMul(dr, dr); // First compute t, if the pixel falls outside the cone, then we'll end // with 'false' on the stack, otherwise we'll push 'true' with t below it // We start with a stack of (x y), copy it and then consume one copy in // order to calculate b and the other to calculate c. SkString function("{"); function.append(apply_perspective_to_coordinates(perspectiveRemover)); function.append("2 copy "); // Calculate b and b^2; b = -2 * (y * dy + x * dx + r0 * dr). function.appendScalar(dy); function.append(" mul exch "); function.appendScalar(dx); function.append(" mul add "); function.appendScalar(SkScalarMul(r0, dr)); function.append(" add -2 mul dup dup mul\n"); // c = x^2 + y^2 + radius0^2 function.append("4 2 roll dup mul exch dup mul add "); function.appendScalar(SkScalarMul(r0, r0)); function.append(" sub dup 4 1 roll\n"); // Contents of the stack at this point: c, b, b^2, c // if a = 0, then we collapse to a simpler linear case if (a == 0) { // t = -c/b function.append("pop pop div neg dup "); // compute radius(t) function.appendScalar(dr); function.append(" mul "); function.appendScalar(r0); function.append(" add\n"); // if r(t) < 0, then it's outside the cone function.append("0 lt {pop false} {true} ifelse\n"); } else { // quadratic case: the Canvas spec wants the largest // root t for which radius(t) > 0 // compute the discriminant (b^2 - 4ac) function.appendScalar(SkScalarMul(SkIntToScalar(4), a)); function.append(" mul sub dup\n"); // if d >= 0, proceed function.append("0 ge {\n"); // an intermediate value we'll use to compute the roots: // q = -0.5 * (b +/- sqrt(d)) function.append("sqrt exch dup 0 lt {exch -1 mul} if"); function.append(" add -0.5 mul dup\n"); // first root = q / a function.appendScalar(a); function.append(" div\n"); // second root = c / q function.append("3 1 roll div\n"); // put the larger root on top of the stack function.append("2 copy gt {exch} if\n"); // compute radius(t) for larger root function.append("dup "); function.appendScalar(dr); function.append(" mul "); function.appendScalar(r0); function.append(" add\n"); // if r(t) > 0, we have our t, pop off the smaller root and we're done function.append(" 0 gt {exch pop true}\n"); // otherwise, throw out the larger one and try the smaller root function.append("{pop dup\n"); function.appendScalar(dr); function.append(" mul "); function.appendScalar(r0); function.append(" add\n"); // if r(t) < 0, push false, otherwise the smaller root is our t function.append("0 le {pop false} {true} ifelse\n"); function.append("} ifelse\n"); // d < 0, clear the stack and push false function.append("} {pop pop pop false} ifelse\n"); } // if the pixel is in the cone, proceed to compute a color function.append("{"); tileModeCode(info.fTileMode, &function); gradientFunctionCode(info, &function); // otherwise, just write black function.append("} {0 0 0} ifelse }"); return function; }