/* * Copyright (C) 2008 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "SkiaInterpolator.h" #include "include/core/SkScalar.h" #include "include/core/SkTypes.h" #include #include #include typedef int Dot14; #define Dot14_ONE (1 << 14) #define Dot14_HALF (1 << 13) #define Dot14ToFloat(x) ((x) / 16384.f) static inline Dot14 Dot14Mul(Dot14 a, Dot14 b) { return (a * b + Dot14_HALF) >> 14; } static inline Dot14 eval_cubic(Dot14 t, Dot14 A, Dot14 B, Dot14 C) { return Dot14Mul(Dot14Mul(Dot14Mul(C, t) + B, t) + A, t); } static inline Dot14 pin_and_convert(float x) { if (x <= 0) { return 0; } if (x >= 1.0f) { return Dot14_ONE; } return static_cast(x * Dot14_ONE); } static float SkUnitCubicInterp(float value, float bx, float by, float cx, float cy) { // pin to the unit-square, and convert to 2.14 Dot14 x = pin_and_convert(value); if (x == 0) return 0.0f; if (x == Dot14_ONE) return 1.0f; Dot14 b = pin_and_convert(bx); Dot14 c = pin_and_convert(cx); // Now compute our coefficients from the control points // t -> 3b // t^2 -> 3c - 6b // t^3 -> 3b - 3c + 1 Dot14 A = 3 * b; Dot14 B = 3 * (c - 2 * b); Dot14 C = 3 * (b - c) + Dot14_ONE; // Now search for a t value given x Dot14 t = Dot14_HALF; Dot14 dt = Dot14_HALF; for (int i = 0; i < 13; i++) { dt >>= 1; Dot14 guess = eval_cubic(t, A, B, C); if (x < guess) { t -= dt; } else { t += dt; } } // Now we have t, so compute the coeff for Y and evaluate b = pin_and_convert(by); c = pin_and_convert(cy); A = 3 * b; B = 3 * (c - 2 * b); C = 3 * (b - c) + Dot14_ONE; return Dot14ToFloat(eval_cubic(t, A, B, C)); } /////////////////////////////////////////////////////////////////////////////////////////////////// SkiaInterpolatorBase::SkiaInterpolatorBase() { fStorage = nullptr; fTimes = nullptr; } SkiaInterpolatorBase::~SkiaInterpolatorBase() { if (fStorage) { free(fStorage); } } void SkiaInterpolatorBase::reset(int elemCount, int frameCount) { fFlags = 0; fElemCount = static_cast(elemCount); fFrameCount = static_cast(frameCount); fRepeat = 1.0f; if (fStorage) { free(fStorage); fStorage = nullptr; fTimes = nullptr; } } /* Each value[] run is formatted as: