/* * Spits out a dummy gradient to test blur with shader on paint */ static sk_sp<SkShader> make_radial() { SkPoint pts[2] = { { 0, 0 }, { SkIntToScalar(100), SkIntToScalar(100) } }; SkShader::TileMode tm = SkShader::kClamp_TileMode; const SkColor colors[] = { SK_ColorRED, SK_ColorGREEN, }; const SkScalar pos[] = { SK_Scalar1/4, SK_Scalar1*3/4 }; SkMatrix scale; scale.setScale(0.5f, 0.5f); scale.postTranslate(25.f, 25.f); SkPoint center0, center1; center0.set(SkScalarAve(pts[0].fX, pts[1].fX), SkScalarAve(pts[0].fY, pts[1].fY)); center1.set(SkScalarInterp(pts[0].fX, pts[1].fX, SkIntToScalar(3)/5), SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4)); return SkGradientShader::MakeTwoPointConical(center1, (pts[1].fX - pts[0].fX) / 7, center0, (pts[1].fX - pts[0].fX) / 2, colors, pos, SK_ARRAY_COUNT(colors), tm, 0, &scale); }
void TextArt::EnvelopeWarp::weight(const SkPoint src[], const SkPoint tSrc[], const SkPoint bSrc[], int count, const SkRect& srcBounds, SkPoint dst[]) { for (int i = 0; i < count; i++) { SkScalar origY = src[i].fY; SkScalar origX = src[i].fX; dst[i].fX = bSrc[i].fX; dst[i].fY = origY; if (srcBounds.fBottom > 0) origY -= srcBounds.fBottom; SkScalar k1 = SkScalarAbs( SkScalarDiv(origY, srcBounds.height()) ); dst[i].fY = SkScalarInterp(bSrc[i].fY, tSrc[i].fY, k1); if (xWeightingMode_ & XWeightingMode_Interpolating) { //in Interpolating mode calculate X as interpolation beween Top and Bottom dst[i].fX = SkScalarInterp(bSrc[i].fX, tSrc[i].fX, k1); } } }
static void interp_cubic_coords(const SkScalar* src, SkScalar* dst, SkScalar t) { SkScalar ab = SkScalarInterp(src[0], src[2], t); SkScalar bc = SkScalarInterp(src[2], src[4], t); SkScalar cd = SkScalarInterp(src[4], src[6], t); SkScalar abc = SkScalarInterp(ab, bc, t); SkScalar bcd = SkScalarInterp(bc, cd, t); SkScalar abcd = SkScalarInterp(abc, bcd, t); dst[0] = src[0]; dst[2] = ab; dst[4] = abc; dst[6] = abcd; dst[8] = bcd; dst[10] = cd; dst[12] = src[6]; }
void onDrawContent(SkCanvas* canvas) override { SkPaint paint; paint.setTypeface(fTypeface); paint.setAntiAlias(true); paint.setFilterQuality(kMedium_SkFilterQuality); paint.setTextSize(50); // rough center of each glyph static constexpr auto kMidX = 35; static constexpr auto kMidY = 50; canvas->clear(SK_ColorWHITE); for (int i = 0; i < kNumChars; ++i) { canvas->save(); double rot = SkScalarInterp(fChars[i].fStartRotation, fChars[i].fEndRotation, fCurrTime/kDuration); canvas->translate(fChars[i].fPosition.fX + kMidX, fChars[i].fPosition.fY - kMidY); canvas->rotate(SkRadiansToDegrees(rot)); canvas->translate(-35,+50); canvas->drawString(fChars[i].fChar, 0, 0, paint); canvas->restore(); } }
SkInterpolator::Result SkInterpolator::timeToValues(SkMSec time, SkScalar values[]) const { SkScalar T; int index; SkBool exact; Result result = timeToT(time, &T, &index, &exact); if (values) { const SkScalar* nextSrc = &fValues[index * fElemCount]; if (exact) { memcpy(values, nextSrc, fElemCount * sizeof(SkScalar)); } else { SkASSERT(index > 0); const SkScalar* prevSrc = nextSrc - fElemCount; for (int i = fElemCount - 1; i >= 0; --i) { values[i] = SkScalarInterp(prevSrc[i], nextSrc[i], T); } } } return result; }
static SkScalar eval_cubic(const SkScalar src[], SkScalar t) { SkASSERT(src); SkASSERT(t >= 0 && t <= SK_Scalar1); if (t == 0) { return src[0]; } #ifdef DIRECT_EVAL_OF_POLYNOMIALS SkScalar D = src[0]; SkScalar A = src[6] + 3*(src[2] - src[4]) - D; SkScalar B = 3*(src[4] - src[2] - src[2] + D); SkScalar C = 3*(src[2] - D); return SkScalarMulAdd(SkScalarMulAdd(SkScalarMulAdd(A, t, B), t, C), t, D); #else SkScalar ab = SkScalarInterp(src[0], src[2], t); SkScalar bc = SkScalarInterp(src[2], src[4], t); SkScalar cd = SkScalarInterp(src[4], src[6], t); SkScalar abc = SkScalarInterp(ab, bc, t); SkScalar bcd = SkScalarInterp(bc, cd, t); return SkScalarInterp(abc, bcd, t); #endif }
static SkPoint SkPointInterp(const SkPoint& a, const SkPoint& b, SkScalar t) { return SkMakePoint(SkScalarInterp(a.fX, b.fX, t), SkScalarInterp(a.fY, b.fY, t)); }
static bool chopMonoCubicAtY(SkPoint pts[4], SkScalar y, SkScalar* t) { SkScalar ycrv[4]; ycrv[0] = pts[0].fY - y; ycrv[1] = pts[1].fY - y; ycrv[2] = pts[2].fY - y; ycrv[3] = pts[3].fY - y; #ifdef NEWTON_RAPHSON // Quadratic convergence, typically <= 3 iterations. // Initial guess. // TODO(turk): Check for zero denominator? Shouldn't happen unless the curve // is not only monotonic but degenerate. #ifdef SK_SCALAR_IS_FLOAT SkScalar t1 = ycrv[0] / (ycrv[0] - ycrv[3]); #else // !SK_SCALAR_IS_FLOAT SkScalar t1 = SkDivBits(ycrv[0], ycrv[0] - ycrv[3], 16); #endif // !SK_SCALAR_IS_FLOAT // Newton's iterations. const SkScalar tol = SK_Scalar1 / 16384; // This leaves 2 fixed noise bits. SkScalar t0; const int maxiters = 5; int iters = 0; bool converged; do { t0 = t1; SkScalar y01 = SkScalarInterp(ycrv[0], ycrv[1], t0); SkScalar y12 = SkScalarInterp(ycrv[1], ycrv[2], t0); SkScalar y23 = SkScalarInterp(ycrv[2], ycrv[3], t0); SkScalar y012 = SkScalarInterp(y01, y12, t0); SkScalar y123 = SkScalarInterp(y12, y23, t0); SkScalar y0123 = SkScalarInterp(y012, y123, t0); SkScalar yder = (y123 - y012) * 3; // TODO(turk): check for yder==0: horizontal. #ifdef SK_SCALAR_IS_FLOAT t1 -= y0123 / yder; #else // !SK_SCALAR_IS_FLOAT t1 -= SkDivBits(y0123, yder, 16); #endif // !SK_SCALAR_IS_FLOAT converged = SkScalarAbs(t1 - t0) <= tol; // NaN-safe ++iters; } while (!converged && (iters < maxiters)); *t = t1; // Return the result. // The result might be valid, even if outside of the range [0, 1], but // we never evaluate a Bezier outside this interval, so we return false. if (t1 < 0 || t1 > SK_Scalar1) return false; // This shouldn't happen, but check anyway. return converged; #else // BISECTION // Linear convergence, typically 16 iterations. // Check that the endpoints straddle zero. SkScalar tNeg, tPos; // Negative and positive function parameters. if (ycrv[0] < 0) { if (ycrv[3] < 0) return false; tNeg = 0; tPos = SK_Scalar1; } else if (ycrv[0] > 0) { if (ycrv[3] > 0) return false; tNeg = SK_Scalar1; tPos = 0; } else { *t = 0; return true; } const SkScalar tol = SK_Scalar1 / 65536; // 1 for fixed, 1e-5 for float. int iters = 0; do { SkScalar tMid = (tPos + tNeg) / 2; SkScalar y01 = SkScalarInterp(ycrv[0], ycrv[1], tMid); SkScalar y12 = SkScalarInterp(ycrv[1], ycrv[2], tMid); SkScalar y23 = SkScalarInterp(ycrv[2], ycrv[3], tMid); SkScalar y012 = SkScalarInterp(y01, y12, tMid); SkScalar y123 = SkScalarInterp(y12, y23, tMid); SkScalar y0123 = SkScalarInterp(y012, y123, tMid); if (y0123 == 0) { *t = tMid; return true; } if (y0123 < 0) tNeg = tMid; else tPos = tMid; ++iters; } while (!(SkScalarAbs(tPos - tNeg) <= tol)); // Nan-safe *t = (tNeg + tPos) / 2; return true; #endif // BISECTION }