gfx/skia/trunk/src/utils/SkInterpolator.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

michael@0 1
michael@0 2 /*
michael@0 3 * Copyright 2008 The Android Open Source Project
michael@0 4 *
michael@0 5 * Use of this source code is governed by a BSD-style license that can be
michael@0 6 * found in the LICENSE file.
michael@0 7 */
michael@0 8
michael@0 9
michael@0 10 #include "SkInterpolator.h"
michael@0 11 #include "SkMath.h"
michael@0 12 #include "SkTSearch.h"
michael@0 13
michael@0 14 SkInterpolatorBase::SkInterpolatorBase() {
michael@0 15 fStorage = NULL;
michael@0 16 fTimes = NULL;
michael@0 17 SkDEBUGCODE(fTimesArray = NULL;)
michael@0 18 }
michael@0 19
michael@0 20 SkInterpolatorBase::~SkInterpolatorBase() {
michael@0 21 if (fStorage) {
michael@0 22 sk_free(fStorage);
michael@0 23 }
michael@0 24 }
michael@0 25
michael@0 26 void SkInterpolatorBase::reset(int elemCount, int frameCount) {
michael@0 27 fFlags = 0;
michael@0 28 fElemCount = SkToU8(elemCount);
michael@0 29 fFrameCount = SkToS16(frameCount);
michael@0 30 fRepeat = SK_Scalar1;
michael@0 31 if (fStorage) {
michael@0 32 sk_free(fStorage);
michael@0 33 fStorage = NULL;
michael@0 34 fTimes = NULL;
michael@0 35 SkDEBUGCODE(fTimesArray = NULL);
michael@0 36 }
michael@0 37 }
michael@0 38
michael@0 39 /* Each value[] run is formated as:
michael@0 40 <time (in msec)>
michael@0 41 <blend>
michael@0 42 <data[fElemCount]>
michael@0 43
michael@0 44 Totaling fElemCount+2 entries per keyframe
michael@0 45 */
michael@0 46
michael@0 47 bool SkInterpolatorBase::getDuration(SkMSec* startTime, SkMSec* endTime) const {
michael@0 48 if (fFrameCount == 0) {
michael@0 49 return false;
michael@0 50 }
michael@0 51
michael@0 52 if (startTime) {
michael@0 53 *startTime = fTimes[0].fTime;
michael@0 54 }
michael@0 55 if (endTime) {
michael@0 56 *endTime = fTimes[fFrameCount - 1].fTime;
michael@0 57 }
michael@0 58 return true;
michael@0 59 }
michael@0 60
michael@0 61 SkScalar SkInterpolatorBase::ComputeRelativeT(SkMSec time, SkMSec prevTime,
michael@0 62 SkMSec nextTime, const SkScalar blend[4]) {
michael@0 63 SkASSERT(time > prevTime && time < nextTime);
michael@0 64
michael@0 65 SkScalar t = SkScalarDiv((SkScalar)(time - prevTime),
michael@0 66 (SkScalar)(nextTime - prevTime));
michael@0 67 return blend ?
michael@0 68 SkUnitCubicInterp(t, blend[0], blend[1], blend[2], blend[3]) : t;
michael@0 69 }
michael@0 70
michael@0 71 SkInterpolatorBase::Result SkInterpolatorBase::timeToT(SkMSec time, SkScalar* T,
michael@0 72 int* indexPtr, SkBool* exactPtr) const {
michael@0 73 SkASSERT(fFrameCount > 0);
michael@0 74 Result result = kNormal_Result;
michael@0 75 if (fRepeat != SK_Scalar1) {
michael@0 76 SkMSec startTime = 0, endTime = 0; // initialize to avoid warning
michael@0 77 this->getDuration(&startTime, &endTime);
michael@0 78 SkMSec totalTime = endTime - startTime;
michael@0 79 SkMSec offsetTime = time - startTime;
michael@0 80 endTime = SkScalarFloorToInt(fRepeat * totalTime);
michael@0 81 if (offsetTime >= endTime) {
michael@0 82 SkScalar fraction = SkScalarFraction(fRepeat);
michael@0 83 offsetTime = fraction == 0 && fRepeat > 0 ? totalTime :
michael@0 84 (SkMSec) SkScalarFloorToInt(fraction * totalTime);
michael@0 85 result = kFreezeEnd_Result;
michael@0 86 } else {
michael@0 87 int mirror = fFlags & kMirror;
michael@0 88 offsetTime = offsetTime % (totalTime << mirror);
michael@0 89 if (offsetTime > totalTime) { // can only be true if fMirror is true
michael@0 90 offsetTime = (totalTime << 1) - offsetTime;
michael@0 91 }
michael@0 92 }
michael@0 93 time = offsetTime + startTime;
michael@0 94 }
michael@0 95
michael@0 96 int index = SkTSearch<SkMSec>(&fTimes[0].fTime, fFrameCount, time,
michael@0 97 sizeof(SkTimeCode));
michael@0 98
michael@0 99 bool exact = true;
michael@0 100
michael@0 101 if (index < 0) {
michael@0 102 index = ~index;
michael@0 103 if (index == 0) {
michael@0 104 result = kFreezeStart_Result;
michael@0 105 } else if (index == fFrameCount) {
michael@0 106 if (fFlags & kReset) {
michael@0 107 index = 0;
michael@0 108 } else {
michael@0 109 index -= 1;
michael@0 110 }
michael@0 111 result = kFreezeEnd_Result;
michael@0 112 } else {
michael@0 113 exact = false;
michael@0 114 }
michael@0 115 }
michael@0 116 SkASSERT(index < fFrameCount);
michael@0 117 const SkTimeCode* nextTime = &fTimes[index];
michael@0 118 SkMSec nextT = nextTime[0].fTime;
michael@0 119 if (exact) {
michael@0 120 *T = 0;
michael@0 121 } else {
michael@0 122 SkMSec prevT = nextTime[-1].fTime;
michael@0 123 *T = ComputeRelativeT(time, prevT, nextT, nextTime[-1].fBlend);
michael@0 124 }
michael@0 125 *indexPtr = index;
michael@0 126 *exactPtr = exact;
michael@0 127 return result;
michael@0 128 }
michael@0 129
michael@0 130
michael@0 131 SkInterpolator::SkInterpolator() {
michael@0 132 INHERITED::reset(0, 0);
michael@0 133 fValues = NULL;
michael@0 134 SkDEBUGCODE(fScalarsArray = NULL;)
michael@0 135 }
michael@0 136
michael@0 137 SkInterpolator::SkInterpolator(int elemCount, int frameCount) {
michael@0 138 SkASSERT(elemCount > 0);
michael@0 139 this->reset(elemCount, frameCount);
michael@0 140 }
michael@0 141
michael@0 142 void SkInterpolator::reset(int elemCount, int frameCount) {
michael@0 143 INHERITED::reset(elemCount, frameCount);
michael@0 144 fStorage = sk_malloc_throw((sizeof(SkScalar) * elemCount +
michael@0 145 sizeof(SkTimeCode)) * frameCount);
michael@0 146 fTimes = (SkTimeCode*) fStorage;
michael@0 147 fValues = (SkScalar*) ((char*) fStorage + sizeof(SkTimeCode) * frameCount);
michael@0 148 #ifdef SK_DEBUG
michael@0 149 fTimesArray = (SkTimeCode(*)[10]) fTimes;
michael@0 150 fScalarsArray = (SkScalar(*)[10]) fValues;
michael@0 151 #endif
michael@0 152 }
michael@0 153
michael@0 154 #define SK_Fixed1Third (SK_Fixed1/3)
michael@0 155 #define SK_Fixed2Third (SK_Fixed1*2/3)
michael@0 156
michael@0 157 static const SkScalar gIdentityBlend[4] = {
michael@0 158 0.33333333f, 0.33333333f, 0.66666667f, 0.66666667f
michael@0 159 };
michael@0 160
michael@0 161 bool SkInterpolator::setKeyFrame(int index, SkMSec time,
michael@0 162 const SkScalar values[], const SkScalar blend[4]) {
michael@0 163 SkASSERT(values != NULL);
michael@0 164
michael@0 165 if (blend == NULL) {
michael@0 166 blend = gIdentityBlend;
michael@0 167 }
michael@0 168
michael@0 169 bool success = ~index == SkTSearch<SkMSec>(&fTimes->fTime, index, time,
michael@0 170 sizeof(SkTimeCode));
michael@0 171 SkASSERT(success);
michael@0 172 if (success) {
michael@0 173 SkTimeCode* timeCode = &fTimes[index];
michael@0 174 timeCode->fTime = time;
michael@0 175 memcpy(timeCode->fBlend, blend, sizeof(timeCode->fBlend));
michael@0 176 SkScalar* dst = &fValues[fElemCount * index];
michael@0 177 memcpy(dst, values, fElemCount * sizeof(SkScalar));
michael@0 178 }
michael@0 179 return success;
michael@0 180 }
michael@0 181
michael@0 182 SkInterpolator::Result SkInterpolator::timeToValues(SkMSec time,
michael@0 183 SkScalar values[]) const {
michael@0 184 SkScalar T;
michael@0 185 int index;
michael@0 186 SkBool exact;
michael@0 187 Result result = timeToT(time, &T, &index, &exact);
michael@0 188 if (values) {
michael@0 189 const SkScalar* nextSrc = &fValues[index * fElemCount];
michael@0 190
michael@0 191 if (exact) {
michael@0 192 memcpy(values, nextSrc, fElemCount * sizeof(SkScalar));
michael@0 193 } else {
michael@0 194 SkASSERT(index > 0);
michael@0 195
michael@0 196 const SkScalar* prevSrc = nextSrc - fElemCount;
michael@0 197
michael@0 198 for (int i = fElemCount - 1; i >= 0; --i) {
michael@0 199 values[i] = SkScalarInterp(prevSrc[i], nextSrc[i], T);
michael@0 200 }
michael@0 201 }
michael@0 202 }
michael@0 203 return result;
michael@0 204 }
michael@0 205
michael@0 206 ///////////////////////////////////////////////////////////////////////////////
michael@0 207
michael@0 208 typedef int Dot14;
michael@0 209 #define Dot14_ONE (1 << 14)
michael@0 210 #define Dot14_HALF (1 << 13)
michael@0 211
michael@0 212 #define Dot14ToFloat(x) ((x) / 16384.f)
michael@0 213
michael@0 214 static inline Dot14 Dot14Mul(Dot14 a, Dot14 b) {
michael@0 215 return (a * b + Dot14_HALF) >> 14;
michael@0 216 }
michael@0 217
michael@0 218 static inline Dot14 eval_cubic(Dot14 t, Dot14 A, Dot14 B, Dot14 C) {
michael@0 219 return Dot14Mul(Dot14Mul(Dot14Mul(C, t) + B, t) + A, t);
michael@0 220 }
michael@0 221
michael@0 222 static inline Dot14 pin_and_convert(SkScalar x) {
michael@0 223 if (x <= 0) {
michael@0 224 return 0;
michael@0 225 }
michael@0 226 if (x >= SK_Scalar1) {
michael@0 227 return Dot14_ONE;
michael@0 228 }
michael@0 229 return SkScalarToFixed(x) >> 2;
michael@0 230 }
michael@0 231
michael@0 232 SkScalar SkUnitCubicInterp(SkScalar value, SkScalar bx, SkScalar by,
michael@0 233 SkScalar cx, SkScalar cy) {
michael@0 234 // pin to the unit-square, and convert to 2.14
michael@0 235 Dot14 x = pin_and_convert(value);
michael@0 236
michael@0 237 if (x == 0) return 0;
michael@0 238 if (x == Dot14_ONE) return SK_Scalar1;
michael@0 239
michael@0 240 Dot14 b = pin_and_convert(bx);
michael@0 241 Dot14 c = pin_and_convert(cx);
michael@0 242
michael@0 243 // Now compute our coefficients from the control points
michael@0 244 // t -> 3b
michael@0 245 // t^2 -> 3c - 6b
michael@0 246 // t^3 -> 3b - 3c + 1
michael@0 247 Dot14 A = 3*b;
michael@0 248 Dot14 B = 3*(c - 2*b);
michael@0 249 Dot14 C = 3*(b - c) + Dot14_ONE;
michael@0 250
michael@0 251 // Now search for a t value given x
michael@0 252 Dot14 t = Dot14_HALF;
michael@0 253 Dot14 dt = Dot14_HALF;
michael@0 254 for (int i = 0; i < 13; i++) {
michael@0 255 dt >>= 1;
michael@0 256 Dot14 guess = eval_cubic(t, A, B, C);
michael@0 257 if (x < guess) {
michael@0 258 t -= dt;
michael@0 259 } else {
michael@0 260 t += dt;
michael@0 261 }
michael@0 262 }
michael@0 263
michael@0 264 // Now we have t, so compute the coeff for Y and evaluate
michael@0 265 b = pin_and_convert(by);
michael@0 266 c = pin_and_convert(cy);
michael@0 267 A = 3*b;
michael@0 268 B = 3*(c - 2*b);
michael@0 269 C = 3*(b - c) + Dot14_ONE;
michael@0 270 return SkFixedToScalar(eval_cubic(t, A, B, C) << 2);
michael@0 271 }
michael@0 272
michael@0 273 ///////////////////////////////////////////////////////////////////////////////
michael@0 274 ///////////////////////////////////////////////////////////////////////////////
michael@0 275
michael@0 276 #ifdef SK_DEBUG
michael@0 277
michael@0 278 #ifdef SK_SUPPORT_UNITTEST
michael@0 279 static SkScalar* iset(SkScalar array[3], int a, int b, int c) {
michael@0 280 array[0] = SkIntToScalar(a);
michael@0 281 array[1] = SkIntToScalar(b);
michael@0 282 array[2] = SkIntToScalar(c);
michael@0 283 return array;
michael@0 284 }
michael@0 285 #endif
michael@0 286
michael@0 287 void SkInterpolator::UnitTest() {
michael@0 288 #ifdef SK_SUPPORT_UNITTEST
michael@0 289 SkInterpolator inter(3, 2);
michael@0 290 SkScalar v1[3], v2[3], v[3], vv[3];
michael@0 291 Result result;
michael@0 292
michael@0 293 inter.setKeyFrame(0, 100, iset(v1, 10, 20, 30), 0);
michael@0 294 inter.setKeyFrame(1, 200, iset(v2, 110, 220, 330));
michael@0 295
michael@0 296 result = inter.timeToValues(0, v);
michael@0 297 SkASSERT(result == kFreezeStart_Result);
michael@0 298 SkASSERT(memcmp(v, v1, sizeof(v)) == 0);
michael@0 299
michael@0 300 result = inter.timeToValues(99, v);
michael@0 301 SkASSERT(result == kFreezeStart_Result);
michael@0 302 SkASSERT(memcmp(v, v1, sizeof(v)) == 0);
michael@0 303
michael@0 304 result = inter.timeToValues(100, v);
michael@0 305 SkASSERT(result == kNormal_Result);
michael@0 306 SkASSERT(memcmp(v, v1, sizeof(v)) == 0);
michael@0 307
michael@0 308 result = inter.timeToValues(200, v);
michael@0 309 SkASSERT(result == kNormal_Result);
michael@0 310 SkASSERT(memcmp(v, v2, sizeof(v)) == 0);
michael@0 311
michael@0 312 result = inter.timeToValues(201, v);
michael@0 313 SkASSERT(result == kFreezeEnd_Result);
michael@0 314 SkASSERT(memcmp(v, v2, sizeof(v)) == 0);
michael@0 315
michael@0 316 result = inter.timeToValues(150, v);
michael@0 317 SkASSERT(result == kNormal_Result);
michael@0 318 SkASSERT(memcmp(v, iset(vv, 60, 120, 180), sizeof(v)) == 0);
michael@0 319
michael@0 320 result = inter.timeToValues(125, v);
michael@0 321 SkASSERT(result == kNormal_Result);
michael@0 322 result = inter.timeToValues(175, v);
michael@0 323 SkASSERT(result == kNormal_Result);
michael@0 324 #endif
michael@0 325 }
michael@0 326
michael@0 327 #endif

mercurial