/* This works -- more needs to be done to see if it is performant on all platforms. To use this to measure parts of quads requires recomputing everything -- perhaps a chop-like interface can start from a larger measurement and get two new measurements with one call here. */ static SkScalar compute_quad_len(const SkPoint pts[3]) { SkPoint a,b; a.fX = pts[0].fX - 2 * pts[1].fX + pts[2].fX; a.fY = pts[0].fY - 2 * pts[1].fY + pts[2].fY; SkScalar A = 4 * (a.fX * a.fX + a.fY * a.fY); if (0 == A) { a = pts[2] - pts[0]; return a.length(); } b.fX = 2 * (pts[1].fX - pts[0].fX); b.fY = 2 * (pts[1].fY - pts[0].fY); SkScalar B = 4 * (a.fX * b.fX + a.fY * b.fY); SkScalar C = b.fX * b.fX + b.fY * b.fY; SkScalar Sabc = 2 * SkScalarSqrt(A + B + C); SkScalar A_2 = SkScalarSqrt(A); SkScalar A_32 = 2 * A * A_2; SkScalar C_2 = 2 * SkScalarSqrt(C); SkScalar BA = B / A_2; if (0 == BA + C_2) { return quad_folded_len(pts); } SkScalar J = A_32 * Sabc + A_2 * B * (Sabc - C_2); SkScalar K = 4 * C * A - B * B; SkScalar L = (2 * A_2 + BA + Sabc) / (BA + C_2); if (L <= 0) { return quad_folded_len(pts); } SkScalar M = SkScalarLog(L); SkScalar result = (J + K * M) / (4 * A_32); SkASSERT(SkScalarIsFinite(result)); return result; }
static inline SkScalar scalar_log2(SkScalar x) { static const SkScalar log2_conversion_factor = SkScalarInvert(SkScalarLog(2)); return SkScalarLog(x) * log2_conversion_factor; }
void SkDisplayMath::executeFunction(SkDisplayable* target, int index, SkTDArray<SkScriptValue>& parameters, SkDisplayTypes type, SkScriptValue* scriptValue) { if (scriptValue == NULL) return; SkASSERT(target == this); SkScriptValue* array = parameters.begin(); SkScriptValue* end = parameters.end(); SkScalar input = parameters[0].fOperand.fScalar; SkScalar scalarResult; switch (index) { case SK_FUNCTION(abs): scalarResult = SkScalarAbs(input); break; case SK_FUNCTION(acos): scalarResult = SkScalarACos(input); break; case SK_FUNCTION(asin): scalarResult = SkScalarASin(input); break; case SK_FUNCTION(atan): scalarResult = SkScalarATan2(input, SK_Scalar1); break; case SK_FUNCTION(atan2): scalarResult = SkScalarATan2(input, parameters[1].fOperand.fScalar); break; case SK_FUNCTION(ceil): scalarResult = SkIntToScalar(SkScalarCeil(input)); break; case SK_FUNCTION(cos): scalarResult = SkScalarCos(input); break; case SK_FUNCTION(exp): scalarResult = SkScalarExp(input); break; case SK_FUNCTION(floor): scalarResult = SkIntToScalar(SkScalarFloor(input)); break; case SK_FUNCTION(log): scalarResult = SkScalarLog(input); break; case SK_FUNCTION(max): scalarResult = -SK_ScalarMax; while (array < end) { scalarResult = SkMaxScalar(scalarResult, array->fOperand.fScalar); array++; } break; case SK_FUNCTION(min): scalarResult = SK_ScalarMax; while (array < end) { scalarResult = SkMinScalar(scalarResult, array->fOperand.fScalar); array++; } break; case SK_FUNCTION(pow): // not the greatest -- but use x^y = e^(y * ln(x)) scalarResult = SkScalarLog(input); scalarResult = SkScalarMul(parameters[1].fOperand.fScalar, scalarResult); scalarResult = SkScalarExp(scalarResult); break; case SK_FUNCTION(random): scalarResult = fRandom.nextUScalar1(); break; case SK_FUNCTION(round): scalarResult = SkIntToScalar(SkScalarRound(input)); break; case SK_FUNCTION(sin): scalarResult = SkScalarSin(input); break; case SK_FUNCTION(sqrt): { SkASSERT(parameters.count() == 1); SkASSERT(type == SkType_Float); scalarResult = SkScalarSqrt(input); } break; case SK_FUNCTION(tan): scalarResult = SkScalarTan(input); break; default: SkASSERT(0); scalarResult = SK_ScalarNaN; } scriptValue->fOperand.fScalar = scalarResult; scriptValue->fType = SkType_Float; }