grab from latest android
git-svn-id: http://skia.googlecode.com/svn/trunk@27 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/utils/SkCamera.cpp b/src/utils/SkCamera.cpp
new file mode 100644
index 0000000..b02499f
--- /dev/null
+++ b/src/utils/SkCamera.cpp
@@ -0,0 +1,449 @@
+/* libs/graphics/effects/SkCamera.cpp
+**
+** Copyright 2006, 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 "SkCamera.h"
+
+static SkScalar SkScalarDotDiv(int count, const SkScalar a[], int step_a,
+ const SkScalar b[], int step_b,
+ SkScalar denom)
+{
+#ifdef SK_SCALAR_IS_FLOAT
+ float prod = 0;
+ for (int i = 0; i < count; i++)
+ {
+ prod += a[0] * b[0];
+ a += step_a;
+ b += step_b;
+ }
+ return prod / denom;
+#else
+ Sk64 prod, tmp;
+
+ prod.set(0);
+ for (int i = 0; i < count; i++)
+ {
+ tmp.setMul(a[0], b[0]);
+ prod.add(tmp);
+ a += step_a;
+ b += step_b;
+ }
+ prod.div(denom, Sk64::kRound_DivOption);
+ return prod.get32();
+#endif
+}
+
+static SkScalar SkScalarDot(int count, const SkScalar a[], int step_a,
+ const SkScalar b[], int step_b)
+{
+#ifdef SK_SCALAR_IS_FLOAT
+ float prod = 0;
+ for (int i = 0; i < count; i++)
+ {
+ prod += a[0] * b[0];
+ a += step_a;
+ b += step_b;
+ }
+ return prod;
+#else
+ Sk64 prod, tmp;
+
+ prod.set(0);
+ for (int i = 0; i < count; i++)
+ {
+ tmp.setMul(a[0], b[0]);
+ prod.add(tmp);
+ a += step_a;
+ b += step_b;
+ }
+ return prod.getFixed();
+#endif
+}
+
+//////////////////////////////////////////////////////////////////////////
+
+SkUnitScalar SkPoint3D::normalize(SkUnit3D* unit) const
+{
+#ifdef SK_SCALAR_IS_FLOAT
+ float mag = sk_float_sqrt(fX*fX + fY*fY + fZ*fZ);
+ if (mag)
+ {
+ float scale = 1.0f / mag;
+ unit->fX = fX * scale;
+ unit->fY = fY * scale;
+ unit->fZ = fZ * scale;
+ }
+#else
+ Sk64 tmp1, tmp2;
+
+ tmp1.setMul(fX, fX);
+ tmp2.setMul(fY, fY);
+ tmp1.add(tmp2);
+ tmp2.setMul(fZ, fZ);
+ tmp1.add(tmp2);
+
+ SkFixed mag = tmp1.getSqrt();
+ if (mag)
+ {
+ // what if mag < SK_Fixed1 ??? we will underflow the fixdiv
+ SkFixed scale = SkFixedDiv(SK_Fract1, mag);
+ unit->fX = SkFixedMul(fX, scale);
+ unit->fY = SkFixedMul(fY, scale);
+ unit->fZ = SkFixedMul(fZ, scale);
+ }
+#endif
+ return mag;
+}
+
+SkUnitScalar SkUnit3D::Dot(const SkUnit3D& a, const SkUnit3D& b)
+{
+ return SkUnitScalarMul(a.fX, b.fX) +
+ SkUnitScalarMul(a.fY, b.fY) +
+ SkUnitScalarMul(a.fZ, b.fZ);
+}
+
+void SkUnit3D::Cross(const SkUnit3D& a, const SkUnit3D& b, SkUnit3D* cross)
+{
+ SkASSERT(cross);
+
+ // use x,y,z, in case &a == cross or &b == cross
+
+
+ SkScalar x = SkUnitScalarMul(a.fY, b.fZ) - SkUnitScalarMul(a.fZ, b.fY);
+ SkScalar y = SkUnitScalarMul(a.fZ, b.fX) - SkUnitScalarMul(a.fX, b.fY);
+ SkScalar z = SkUnitScalarMul(a.fX, b.fY) - SkUnitScalarMul(a.fY, b.fX);
+
+ cross->set(x, y, z);
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+SkPatch3D::SkPatch3D()
+{
+ this->reset();
+}
+
+void SkPatch3D::reset()
+{
+ fOrigin.set(0, 0, 0);
+ fU.set(SK_Scalar1, 0, 0);
+ fV.set(0, -SK_Scalar1, 0);
+}
+
+void SkPatch3D::transform(const SkMatrix3D& m, SkPatch3D* dst) const
+{
+ if (dst == NULL)
+ dst = (SkPatch3D*)this;
+
+ m.mapVector(fU, &dst->fU);
+ m.mapVector(fV, &dst->fV);
+ m.mapPoint(fOrigin, &dst->fOrigin);
+}
+
+SkScalar SkPatch3D::dotWith(SkScalar dx, SkScalar dy, SkScalar dz) const
+{
+ SkScalar cx = SkScalarMul(fU.fY, fV.fZ) - SkScalarMul(fU.fZ, fV.fY);
+ SkScalar cy = SkScalarMul(fU.fZ, fV.fX) - SkScalarMul(fU.fX, fV.fY);
+ SkScalar cz = SkScalarMul(fU.fX, fV.fY) - SkScalarMul(fU.fY, fV.fX);
+
+ return SkScalarMul(cx, dx) + SkScalarMul(cy, dy) + SkScalarMul(cz, dz);
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+void SkMatrix3D::reset()
+{
+ memset(fMat, 0, sizeof(fMat));
+ fMat[0][0] = fMat[1][1] = fMat[2][2] = SK_Scalar1;
+}
+
+void SkMatrix3D::setTranslate(SkScalar x, SkScalar y, SkScalar z)
+{
+ memset(fMat, 0, sizeof(fMat));
+ fMat[0][0] = x;
+ fMat[1][1] = y;
+ fMat[2][2] = z;
+}
+
+void SkMatrix3D::setRotateX(SkScalar degX)
+{
+ SkScalar s, c;
+
+ s = SkScalarSinCos(SkDegreesToRadians(degX), &c);
+ this->setRow(0, SK_Scalar1, 0, 0);
+ this->setRow(1, 0, c, -s);
+ this->setRow(2, 0, s, c);
+}
+
+void SkMatrix3D::setRotateY(SkScalar degY)
+{
+ SkScalar s, c;
+
+ s = SkScalarSinCos(SkDegreesToRadians(degY), &c);
+ this->setRow(0, c, 0, -s);
+ this->setRow(1, 0, SK_Scalar1, 0);
+ this->setRow(2, s, 0, c);
+}
+
+void SkMatrix3D::setRotateZ(SkScalar degZ)
+{
+ SkScalar s, c;
+
+ s = SkScalarSinCos(SkDegreesToRadians(degZ), &c);
+ this->setRow(0, c, -s, 0);
+ this->setRow(1, s, c, 0);
+ this->setRow(2, 0, 0, SK_Scalar1);
+}
+
+void SkMatrix3D::preTranslate(SkScalar x, SkScalar y, SkScalar z)
+{
+ SkScalar col[3] = { x, y, z};
+
+ for (int i = 0; i < 3; i++)
+ fMat[i][3] += SkScalarDot(3, &fMat[i][0], 1, col, 1);
+}
+
+void SkMatrix3D::preRotateX(SkScalar degX)
+{
+ SkMatrix3D m;
+ m.setRotateX(degX);
+ this->setConcat(*this, m);
+}
+
+void SkMatrix3D::preRotateY(SkScalar degY)
+{
+ SkMatrix3D m;
+ m.setRotateY(degY);
+ this->setConcat(*this, m);
+}
+
+void SkMatrix3D::preRotateZ(SkScalar degZ)
+{
+ SkMatrix3D m;
+ m.setRotateZ(degZ);
+ this->setConcat(*this, m);
+}
+
+void SkMatrix3D::setConcat(const SkMatrix3D& a, const SkMatrix3D& b)
+{
+ SkMatrix3D tmp;
+ SkMatrix3D* c = this;
+
+ if (this == &a || this == &b)
+ c = &tmp;
+
+ for (int i = 0; i < 3; i++) {
+ for (int j = 0; j < 3; j++)
+ c->fMat[i][j] = SkScalarDot(3, &a.fMat[i][0], 1, &b.fMat[0][j], 4);
+ c->fMat[i][3] = SkScalarDot(3, &a.fMat[i][0], 1, &b.fMat[0][3], 4) + a.fMat[i][3];
+ }
+
+ if (c == &tmp)
+ *this = tmp;
+}
+
+void SkMatrix3D::mapPoint(const SkPoint3D& src, SkPoint3D* dst) const
+{
+ SkScalar x = SkScalarDot(3, &fMat[0][0], 1, &src.fX, 1) + fMat[0][3];
+ SkScalar y = SkScalarDot(3, &fMat[1][0], 1, &src.fX, 1) + fMat[1][3];
+ SkScalar z = SkScalarDot(3, &fMat[2][0], 1, &src.fX, 1) + fMat[2][3];
+ dst->set(x, y, z);
+}
+
+void SkMatrix3D::mapVector(const SkVector3D& src, SkVector3D* dst) const
+{
+ SkScalar x = SkScalarDot(3, &fMat[0][0], 1, &src.fX, 1);
+ SkScalar y = SkScalarDot(3, &fMat[1][0], 1, &src.fX, 1);
+ SkScalar z = SkScalarDot(3, &fMat[2][0], 1, &src.fX, 1);
+ dst->set(x, y, z);
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+SkCamera3D::SkCamera3D()
+{
+ this->reset();
+}
+
+void SkCamera3D::reset()
+{
+ fLocation.set(0, 0, -SkIntToScalar(576)); // 8 inches backward
+ fAxis.set(0, 0, SK_Scalar1); // forward
+ fZenith.set(0, -SK_Scalar1, 0); // up
+
+ fObserver.set(0, 0, fLocation.fZ);
+
+ fNeedToUpdate = true;
+}
+
+void SkCamera3D::update()
+{
+ fNeedToUpdate = true;
+}
+
+void SkCamera3D::doUpdate() const
+{
+ SkUnit3D axis, zenith, cross;
+
+ fAxis.normalize(&axis);
+
+ {
+ SkScalar dot = SkUnit3D::Dot(*(const SkUnit3D*)(const void*)&fZenith, axis);
+
+ zenith.fX = fZenith.fX - SkUnitScalarMul(dot, axis.fX);
+ zenith.fY = fZenith.fY - SkUnitScalarMul(dot, axis.fY);
+ zenith.fZ = fZenith.fZ - SkUnitScalarMul(dot, axis.fZ);
+
+ (void)((SkPoint3D*)(void*)&zenith)->normalize(&zenith);
+ }
+
+ SkUnit3D::Cross(axis, zenith, &cross);
+
+ {
+ SkMatrix* orien = &fOrientation;
+ SkScalar x = fObserver.fX;
+ SkScalar y = fObserver.fY;
+ SkScalar z = fObserver.fZ;
+
+ orien->set(SkMatrix::kMScaleX, SkUnitScalarMul(x, axis.fX) - SkUnitScalarMul(z, cross.fX));
+ orien->set(SkMatrix::kMSkewX, SkUnitScalarMul(x, axis.fY) - SkUnitScalarMul(z, cross.fY));
+ orien->set(SkMatrix::kMTransX, SkUnitScalarMul(x, axis.fZ) - SkUnitScalarMul(z, cross.fZ));
+ orien->set(SkMatrix::kMSkewY, SkUnitScalarMul(y, axis.fX) - SkUnitScalarMul(z, zenith.fX));
+ orien->set(SkMatrix::kMScaleY, SkUnitScalarMul(y, axis.fY) - SkUnitScalarMul(z, zenith.fY));
+ orien->set(SkMatrix::kMTransY, SkUnitScalarMul(y, axis.fZ) - SkUnitScalarMul(z, zenith.fZ));
+ orien->set(SkMatrix::kMPersp0, axis.fX);
+ orien->set(SkMatrix::kMPersp1, axis.fY);
+ orien->set(SkMatrix::kMPersp2, axis.fZ);
+ }
+}
+
+void SkCamera3D::patchToMatrix(const SkPatch3D& quilt, SkMatrix* matrix) const
+{
+ if (fNeedToUpdate)
+ {
+ this->doUpdate();
+ fNeedToUpdate = false;
+ }
+
+ const SkScalar* mapPtr = (const SkScalar*)(const void*)&fOrientation;
+ const SkScalar* patchPtr;
+ SkPoint3D diff;
+ SkScalar dot;
+
+ diff.fX = quilt.fOrigin.fX - fLocation.fX;
+ diff.fY = quilt.fOrigin.fY - fLocation.fY;
+ diff.fZ = quilt.fOrigin.fZ - fLocation.fZ;
+
+ dot = SkUnit3D::Dot(*(const SkUnit3D*)(const void*)&diff,
+ *(const SkUnit3D*)(((const SkScalar*)(const void*)&fOrientation) + 6));
+
+ patchPtr = (const SkScalar*)&quilt;
+ matrix->set(SkMatrix::kMScaleX, SkScalarDotDiv(3, patchPtr, 1, mapPtr, 1, dot));
+ matrix->set(SkMatrix::kMSkewY, SkScalarDotDiv(3, patchPtr, 1, mapPtr+3, 1, dot));
+ matrix->set(SkMatrix::kMPersp0, SkScalarDotDiv(3, patchPtr, 1, mapPtr+6, 1, dot));
+
+ patchPtr += 3;
+ matrix->set(SkMatrix::kMSkewX, SkScalarDotDiv(3, patchPtr, 1, mapPtr, 1, dot));
+ matrix->set(SkMatrix::kMScaleY, SkScalarDotDiv(3, patchPtr, 1, mapPtr+3, 1, dot));
+ matrix->set(SkMatrix::kMPersp1, SkScalarDotDiv(3, patchPtr, 1, mapPtr+6, 1, dot));
+
+ patchPtr = (const SkScalar*)(const void*)&diff;
+ matrix->set(SkMatrix::kMTransX, SkScalarDotDiv(3, patchPtr, 1, mapPtr, 1, dot));
+ matrix->set(SkMatrix::kMTransY, SkScalarDotDiv(3, patchPtr, 1, mapPtr+3, 1, dot));
+ matrix->set(SkMatrix::kMPersp2, SK_UnitScalar1);
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+Sk3DView::Sk3DView()
+{
+ fInitialRec.fMatrix.reset();
+ fRec = &fInitialRec;
+}
+
+Sk3DView::~Sk3DView()
+{
+ Rec* rec = fRec;
+ while (rec != &fInitialRec) {
+ Rec* next = rec->fNext;
+ SkDELETE(rec);
+ rec = next;
+ }
+}
+
+void Sk3DView::save()
+{
+ Rec* rec = SkNEW(Rec);
+ rec->fNext = fRec;
+ rec->fMatrix = fRec->fMatrix;
+ fRec = rec;
+}
+
+void Sk3DView::restore()
+{
+ SkASSERT(fRec != &fInitialRec);
+ Rec* next = fRec->fNext;
+ SkDELETE(fRec);
+ fRec = next;
+}
+
+void Sk3DView::translate(SkScalar x, SkScalar y, SkScalar z)
+{
+ fRec->fMatrix.preTranslate(x, y, z);
+}
+
+void Sk3DView::rotateX(SkScalar deg)
+{
+ fRec->fMatrix.preRotateX(deg);
+}
+
+void Sk3DView::rotateY(SkScalar deg)
+{
+ fRec->fMatrix.preRotateY(deg);
+}
+
+void Sk3DView::rotateZ(SkScalar deg)
+{
+ fRec->fMatrix.preRotateZ(deg);
+}
+
+SkScalar Sk3DView::dotWithNormal(SkScalar x, SkScalar y, SkScalar z) const
+{
+ SkPatch3D patch;
+ patch.transform(fRec->fMatrix);
+ return patch.dotWith(x, y, z);
+}
+
+void Sk3DView::getMatrix(SkMatrix* matrix) const
+{
+ if (matrix != NULL)
+ {
+ SkPatch3D patch;
+ patch.transform(fRec->fMatrix);
+ fCamera.patchToMatrix(patch, matrix);
+ }
+}
+
+#include "SkCanvas.h"
+
+void Sk3DView::applyToCanvas(SkCanvas* canvas) const
+{
+ SkMatrix matrix;
+
+ this->getMatrix(&matrix);
+ canvas->concat(matrix);
+}
+
diff --git a/src/utils/SkColorMatrix.cpp b/src/utils/SkColorMatrix.cpp
new file mode 100644
index 0000000..0a20990
--- /dev/null
+++ b/src/utils/SkColorMatrix.cpp
@@ -0,0 +1,165 @@
+#include "SkColorMatrix.h"
+
+#define kRScale 0
+#define kGScale 6
+#define kBScale 12
+#define kAScale 18
+
+void SkColorMatrix::setIdentity()
+{
+ memset(fMat, 0, sizeof(fMat));
+ fMat[kRScale] = fMat[kGScale] = fMat[kBScale] = fMat[kAScale] = SK_Scalar1;
+}
+
+void SkColorMatrix::setScale(SkScalar rScale, SkScalar gScale, SkScalar bScale,
+ SkScalar aScale)
+{
+ memset(fMat, 0, sizeof(fMat));
+ fMat[kRScale] = rScale;
+ fMat[kGScale] = gScale;
+ fMat[kBScale] = bScale;
+ fMat[kAScale] = aScale;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void SkColorMatrix::setRotate(Axis axis, SkScalar degrees)
+{
+ SkScalar S, C;
+
+ S = SkScalarSinCos(SkDegreesToRadians(degrees), &C);
+
+ this->setSinCos(axis, S, C);
+}
+
+void SkColorMatrix::setSinCos(Axis axis, SkScalar sine, SkScalar cosine)
+{
+ SkASSERT((unsigned)axis < 3);
+
+ static const uint8_t gRotateIndex[] = {
+ 6, 7, 11, 12,
+ 0, 2, 15, 17,
+ 0, 1, 5, 6,
+ };
+ const uint8_t* index = gRotateIndex + axis * 4;
+
+ this->setIdentity();
+ fMat[index[0]] = cosine;
+ fMat[index[1]] = sine;
+ fMat[index[2]] = -sine;
+ fMat[index[3]] = cosine;
+}
+
+void SkColorMatrix::preRotate(Axis axis, SkScalar degrees)
+{
+ SkColorMatrix tmp;
+ tmp.setRotate(axis, degrees);
+ this->preConcat(tmp);
+}
+
+void SkColorMatrix::postRotate(Axis axis, SkScalar degrees)
+{
+ SkColorMatrix tmp;
+ tmp.setRotate(axis, degrees);
+ this->postConcat(tmp);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void SkColorMatrix::setConcat(const SkColorMatrix& matA,
+ const SkColorMatrix& matB)
+{
+ SkScalar tmp[20];
+ SkScalar* result = fMat;
+
+ if (&matA == this || &matB == this)
+ result = tmp;
+
+ const SkScalar* a = matA.fMat;
+ const SkScalar* b = matB.fMat;
+
+ int index = 0;
+ for (int j = 0; j < 20; j += 5)
+ {
+ for (int i = 0; i < 4; i++)
+ {
+ result[index++] = SkScalarMul(a[j + 0], b[i + 0]) +
+ SkScalarMul(a[j + 1], b[i + 5]) +
+ SkScalarMul(a[j + 2], b[i + 10]) +
+ SkScalarMul(a[j + 3], b[i + 15]);
+ }
+ result[index++] = SkScalarMul(a[j + 0], b[4]) +
+ SkScalarMul(a[j + 1], b[9]) +
+ SkScalarMul(a[j + 2], b[14]) +
+ SkScalarMul(a[j + 3], b[19]) +
+ a[j + 4];
+ }
+
+ if (fMat != result)
+ memcpy(fMat, result, sizeof(fMat));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static void setrow(SkScalar row[], SkScalar r, SkScalar g, SkScalar b)
+{
+ row[0] = r;
+ row[1] = g;
+ row[2] = b;
+}
+
+static const SkScalar kHueR = SkFloatToScalar(0.213f);
+static const SkScalar kHueG = SkFloatToScalar(0.715f);
+static const SkScalar kHueB = SkFloatToScalar(0.072f);
+
+void SkColorMatrix::setSaturation(SkScalar sat)
+{
+ memset(fMat, 0, sizeof(fMat));
+
+ const SkScalar R = SkScalarMul(kHueR, SK_Scalar1 - sat);
+ const SkScalar G = SkScalarMul(kHueG, SK_Scalar1 - sat);
+ const SkScalar B = SkScalarMul(kHueB, SK_Scalar1 - sat);
+
+ setrow(fMat + 0, R + sat, G, B);
+ setrow(fMat + 5, R, G + sat, B);
+ setrow(fMat + 10, R, G, B + sat);
+ fMat[18] = SK_Scalar1;
+}
+
+static const SkScalar kR2Y = SkFloatToScalar(0.299f);
+static const SkScalar kG2Y = SkFloatToScalar(0.587f);
+static const SkScalar kB2Y = SkFloatToScalar(0.114f);
+
+static const SkScalar kR2U = SkFloatToScalar(-0.16874f);
+static const SkScalar kG2U = SkFloatToScalar(-0.33126f);
+static const SkScalar kB2U = SkFloatToScalar(0.5f);
+
+static const SkScalar kR2V = SkFloatToScalar(0.5f);
+static const SkScalar kG2V = SkFloatToScalar(-0.41869f);
+static const SkScalar kB2V = SkFloatToScalar(-0.08131f);
+
+void SkColorMatrix::setRGB2YUV()
+{
+ memset(fMat, 0, sizeof(fMat));
+
+ setrow(fMat + 0, kR2Y, kG2Y, kB2Y);
+ setrow(fMat + 5, kR2U, kG2U, kB2U);
+ setrow(fMat + 10, kR2V, kG2V, kB2V);
+ fMat[18] = SK_Scalar1;
+}
+
+static const SkScalar kV2R = SkFloatToScalar(1.402f);
+static const SkScalar kU2G = SkFloatToScalar(-0.34414f);
+static const SkScalar kV2G = SkFloatToScalar(-0.71414f);
+static const SkScalar kU2B = SkFloatToScalar(1.772f);
+
+void SkColorMatrix::setYUV2RGB()
+{
+ memset(fMat, 0, sizeof(fMat));
+
+ setrow(fMat + 0, SK_Scalar1, 0, kV2R);
+ setrow(fMat + 5, SK_Scalar1, kU2G, kV2G);
+ setrow(fMat + 10, SK_Scalar1, kU2B, 0);
+ fMat[18] = SK_Scalar1;
+}
+
diff --git a/src/utils/SkCullPoints.cpp b/src/utils/SkCullPoints.cpp
new file mode 100644
index 0000000..23d00b6
--- /dev/null
+++ b/src/utils/SkCullPoints.cpp
@@ -0,0 +1,168 @@
+/* libs/graphics/effects/SkCullPoints.cpp
+**
+** Copyright 2006, 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 "SkCullPoints.h"
+#include "Sk64.h"
+
+static bool cross_product_is_neg(const SkIPoint& v, int dx, int dy)
+{
+#if 0
+ return v.fX * dy - v.fY * dx < 0;
+#else
+ Sk64 tmp0, tmp1;
+
+ tmp0.setMul(v.fX, dy);
+ tmp1.setMul(dx, v.fY);
+ tmp0.sub(tmp1);
+ return tmp0.isNeg();
+#endif
+}
+
+bool SkCullPoints::sect_test(int x0, int y0, int x1, int y1) const
+{
+ const SkIRect& r = fR;
+
+ if (x0 < r.fLeft && x1 < r.fLeft ||
+ x0 > r.fRight && x1 > r.fRight ||
+ y0 < r.fTop && y1 < r.fTop ||
+ y0 > r.fBottom && y1 > r.fBottom)
+ return false;
+
+ // since the crossprod test is a little expensive, check for easy-in cases first
+ if (r.contains(x0, y0) || r.contains(x1, y1))
+ return true;
+
+ // At this point we're not sure, so we do a crossprod test
+ SkIPoint vec;
+ const SkIPoint* rAsQuad = fAsQuad;
+
+ vec.set(x1 - x0, y1 - y0);
+ bool isNeg = cross_product_is_neg(vec, x0 - rAsQuad[0].fX, y0 - rAsQuad[0].fY);
+ for (int i = 1; i < 4; i++) {
+ if (cross_product_is_neg(vec, x0 - rAsQuad[i].fX, y0 - rAsQuad[i].fY) != isNeg)
+ {
+ return true;
+ }
+ }
+ return false; // we didn't intersect
+}
+
+static void toQuad(const SkIRect& r, SkIPoint quad[4])
+{
+ SkASSERT(quad);
+
+ quad[0].set(r.fLeft, r.fTop);
+ quad[1].set(r.fRight, r.fTop);
+ quad[2].set(r.fRight, r.fBottom);
+ quad[3].set(r.fLeft, r.fBottom);
+}
+
+SkCullPoints::SkCullPoints()
+{
+ SkIRect r;
+ r.setEmpty();
+ this->reset(r);
+}
+
+SkCullPoints::SkCullPoints(const SkIRect& r)
+{
+ this->reset(r);
+}
+
+void SkCullPoints::reset(const SkIRect& r)
+{
+ fR = r;
+ toQuad(fR, fAsQuad);
+ fPrevPt.set(0, 0);
+ fPrevResult = kNo_Result;
+}
+
+void SkCullPoints::moveTo(int x, int y)
+{
+ fPrevPt.set(x, y);
+ fPrevResult = kNo_Result; // so we trigger a movetolineto later
+}
+
+SkCullPoints::LineToResult SkCullPoints::lineTo(int x, int y, SkIPoint line[])
+{
+ SkASSERT(line != NULL);
+
+ LineToResult result = kNo_Result;
+ int x0 = fPrevPt.fX;
+ int y0 = fPrevPt.fY;
+
+ // need to upgrade sect_test to chop the result
+ // and to correctly return kLineTo_Result when the result is connected
+ // to the previous call-out
+ if (this->sect_test(x0, y0, x, y))
+ {
+ line[0].set(x0, y0);
+ line[1].set(x, y);
+
+ if (fPrevResult != kNo_Result && fPrevPt.equals(x0, y0))
+ result = kLineTo_Result;
+ else
+ result = kMoveToLineTo_Result;
+ }
+
+ fPrevPt.set(x, y);
+ fPrevResult = result;
+
+ return result;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+#include "SkPath.h"
+
+SkCullPointsPath::SkCullPointsPath()
+ : fCP(), fPath(NULL)
+{
+}
+
+SkCullPointsPath::SkCullPointsPath(const SkIRect& r, SkPath* dst)
+ : fCP(r), fPath(dst)
+{
+}
+
+void SkCullPointsPath::reset(const SkIRect& r, SkPath* dst)
+{
+ fCP.reset(r);
+ fPath = dst;
+}
+
+void SkCullPointsPath::moveTo(int x, int y)
+{
+ fCP.moveTo(x, y);
+}
+
+void SkCullPointsPath::lineTo(int x, int y)
+{
+ SkIPoint pts[2];
+
+ switch (fCP.lineTo(x, y, pts)) {
+ case SkCullPoints::kMoveToLineTo_Result:
+ fPath->moveTo(SkIntToScalar(pts[0].fX), SkIntToScalar(pts[0].fY));
+ // fall through to the lineto case
+ case SkCullPoints::kLineTo_Result:
+ fPath->lineTo(SkIntToScalar(pts[1].fX), SkIntToScalar(pts[1].fY));
+ break;
+ default:
+ break;
+ }
+}
+
diff --git a/src/utils/SkDumpCanvas.cpp b/src/utils/SkDumpCanvas.cpp
new file mode 100644
index 0000000..fb203ef
--- /dev/null
+++ b/src/utils/SkDumpCanvas.cpp
@@ -0,0 +1,398 @@
+#include "SkDumpCanvas.h"
+#include "SkPixelRef.h"
+#include "SkString.h"
+#include <stdarg.h>
+
+// needed just to know that these are all subclassed from SkFlattenable
+#include "SkShader.h"
+#include "SkPathEffect.h"
+#include "SkXfermode.h"
+#include "SkColorFilter.h"
+#include "SkPathEffect.h"
+#include "SkMaskFilter.h"
+
+static void toString(const SkRect& r, SkString* str) {
+ str->printf("[(%g %g) %g %g]",
+ SkScalarToFloat(r.fLeft), SkScalarToFloat(r.fTop),
+ SkScalarToFloat(r.width()), SkScalarToFloat(r.height()));
+}
+
+static void toString(const SkIRect& r, SkString* str) {
+ str->printf("[(%d %d) %d %d]", r.fLeft, r.fTop, r.width(), r.height());
+}
+
+static void toString(const SkPath& path, SkString* str) {
+ if (path.isEmpty()) {
+ str->set("path:empty");
+ } else {
+ SkRect bounds;
+ path.computeBounds(&bounds, SkPath::kFast_BoundsType);
+ toString(bounds, str);
+ str->append("]");
+ str->prepend("path:[");
+ }
+}
+
+static const char* toString(SkRegion::Op op) {
+ static const char* gOpNames[] = {
+ "DIFF", "SECT", "UNION", "XOR", "RDIFF", "REPLACE"
+ };
+ return gOpNames[op];
+}
+
+static void toString(const SkRegion& rgn, SkString* str) {
+ toString(rgn.getBounds(), str);
+ str->prepend("Region:[");
+ str->append("]");
+ if (rgn.isComplex()) {
+ str->append(".complex");
+ }
+}
+
+static const char* toString(SkCanvas::VertexMode vm) {
+ static const char* gVMNames[] = {
+ "TRIANGLES", "STRIP", "FAN"
+ };
+ return gVMNames[vm];
+}
+
+static const char* toString(SkCanvas::PointMode pm) {
+ static const char* gPMNames[] = {
+ "POINTS", "LINES", "POLYGON"
+ };
+ return gPMNames[pm];
+}
+
+static const char* toString(SkBitmap::Config config) {
+ static const char* gConfigNames[] = {
+ "NONE", "A1", "A8", "INDEX8", "565", "4444", "8888", "RLE"
+ };
+ return gConfigNames[config];
+}
+
+static void toString(const SkBitmap& bm, SkString* str) {
+ str->printf("bitmap:[%d %d] %s", bm.width(), bm.height(),
+ toString(bm.config()));
+
+ SkPixelRef* pr = bm.pixelRef();
+ if (NULL == pr) {
+ // show null or the explicit pixel address (rare)
+ str->appendf(" pixels:%p", bm.getPixels());
+ } else {
+ const char* uri = pr->getURI();
+ if (uri) {
+ str->appendf(" uri:\"%s\"", uri);
+ } else {
+ str->appendf(" pixelref:%p", pr);
+ }
+ }
+}
+
+static void toString(const void* text, size_t len, SkPaint::TextEncoding enc,
+ SkString* str) {
+ switch (enc) {
+ case SkPaint::kUTF8_TextEncoding:
+ str->printf("\"%.*s\"%s", SkMax32(len, 32), text,
+ len > 32 ? "..." : "");
+ break;
+ case SkPaint::kUTF16_TextEncoding:
+ str->printf("\"%.*S\"%s", SkMax32(len, 32), text,
+ len > 64 ? "..." : "");
+ break;
+ case SkPaint::kGlyphID_TextEncoding:
+ str->set("<glyphs>");
+ break;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+SkDumpCanvas::SkDumpCanvas(Dumper* dumper) {
+ dumper->safeRef();
+ fDumper = dumper;
+
+ static const int WIDE_OPEN = 16384;
+ SkBitmap emptyBitmap;
+
+ emptyBitmap.setConfig(SkBitmap::kNo_Config, WIDE_OPEN, WIDE_OPEN);
+ this->setBitmapDevice(emptyBitmap);
+}
+
+SkDumpCanvas::~SkDumpCanvas() {
+ fDumper->safeUnref();
+}
+
+void SkDumpCanvas::dump(Verb verb, const SkPaint* paint,
+ const char format[], ...) {
+ static const size_t BUFFER_SIZE = 1024;
+
+ char buffer[BUFFER_SIZE];
+ va_list args;
+ va_start(args, format);
+ vsnprintf(buffer, BUFFER_SIZE, format, args);
+ va_end(args);
+
+ if (fDumper) {
+ fDumper->dump(this, verb, buffer, paint);
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+int SkDumpCanvas::save(SaveFlags flags) {
+ this->dump(kSave_Verb, NULL, "save(0x%X)", flags);
+ return this->INHERITED::save(flags);
+}
+
+int SkDumpCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
+ SaveFlags flags) {
+ this->dump(kSave_Verb, paint, "saveLayer(0x%X)", flags);
+ return this->INHERITED::saveLayer(bounds, paint, flags);
+}
+
+void SkDumpCanvas::restore() {
+ this->INHERITED::restore();
+ this->dump(kRestore_Verb, NULL, "restore");
+}
+
+bool SkDumpCanvas::translate(SkScalar dx, SkScalar dy) {
+ this->dump(kMatrix_Verb, NULL, "translate(%g %g)",
+ SkScalarToFloat(dx), SkScalarToFloat(dy));
+ return this->INHERITED::translate(dx, dy);
+}
+
+bool SkDumpCanvas::scale(SkScalar sx, SkScalar sy) {
+ this->dump(kMatrix_Verb, NULL, "scale(%g %g)",
+ SkScalarToFloat(sx), SkScalarToFloat(sy));
+ return this->INHERITED::scale(sx, sy);
+}
+
+bool SkDumpCanvas::rotate(SkScalar degrees) {
+ this->dump(kMatrix_Verb, NULL, "rotate(%g)", SkScalarToFloat(degrees));
+ return this->INHERITED::rotate(degrees);
+}
+
+bool SkDumpCanvas::skew(SkScalar sx, SkScalar sy) {
+ this->dump(kMatrix_Verb, NULL, "skew(%g %g)",
+ SkScalarToFloat(sx), SkScalarToFloat(sy));
+ return this->INHERITED::skew(sx, sy);
+}
+
+bool SkDumpCanvas::concat(const SkMatrix& matrix) {
+ SkString str;
+ matrix.toDumpString(&str);
+ this->dump(kMatrix_Verb, NULL, "concat(%s)", str.c_str());
+ return this->INHERITED::concat(matrix);
+}
+
+void SkDumpCanvas::setMatrix(const SkMatrix& matrix) {
+ SkString str;
+ matrix.toDumpString(&str);
+ this->dump(kMatrix_Verb, NULL, "setMatrix(%s)", str.c_str());
+ this->INHERITED::setMatrix(matrix);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+bool SkDumpCanvas::clipRect(const SkRect& rect, SkRegion::Op op) {
+ SkString str;
+ toString(rect, &str);
+ this->dump(kClip_Verb, NULL, "clipRect(%s %s)", str.c_str(), toString(op));
+ return this->INHERITED::clipRect(rect, op);
+}
+
+bool SkDumpCanvas::clipPath(const SkPath& path, SkRegion::Op op) {
+ SkString str;
+ toString(path, &str);
+ this->dump(kClip_Verb, NULL, "clipPath(%s %s)", str.c_str(), toString(op));
+ return this->INHERITED::clipPath(path, op);
+}
+
+bool SkDumpCanvas::clipRegion(const SkRegion& deviceRgn, SkRegion::Op op) {
+ SkString str;
+ toString(deviceRgn, &str);
+ this->dump(kClip_Verb, NULL, "clipRegion(%s %s)", str.c_str(),
+ toString(op));
+ return this->INHERITED::clipRegion(deviceRgn, op);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void SkDumpCanvas::drawPaint(const SkPaint& paint) {
+ this->dump(kDrawPaint_Verb, &paint, "drawPaint()");
+}
+
+void SkDumpCanvas::drawPoints(PointMode mode, size_t count,
+ const SkPoint pts[], const SkPaint& paint) {
+ this->dump(kDrawPoints_Verb, &paint, "drawPoints(%s, %d)", toString(mode),
+ count);
+}
+
+void SkDumpCanvas::drawRect(const SkRect& rect, const SkPaint& paint) {
+ SkString str;
+ toString(rect, &str);
+ this->dump(kDrawRect_Verb, &paint, "drawRect(%s)", str.c_str());
+}
+
+void SkDumpCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
+ SkString str;
+ toString(path, &str);
+ this->dump(kDrawPath_Verb, &paint, "drawPath(%s)", str.c_str());
+}
+
+void SkDumpCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y,
+ const SkPaint* paint) {
+ SkString str;
+ toString(bitmap, &str);
+ this->dump(kDrawBitmap_Verb, paint, "drawBitmap(%s (%g %g))", str.c_str(),
+ SkScalarToFloat(x), SkScalarToFloat(y));
+}
+
+void SkDumpCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect* src,
+ const SkRect& dst, const SkPaint* paint) {
+ SkString bs, rs;
+ toString(bitmap, &bs);
+ toString(dst, &rs);
+ // show the src-rect only if its not everything
+ if (src && (src->fLeft > 0 || src->fTop > 0 ||
+ src->fRight < bitmap.width() ||
+ src->fBottom < bitmap.height())) {
+ SkString ss;
+ toString(*src, &ss);
+ rs.prependf("%s ", ss.c_str());
+ }
+
+ this->dump(kDrawBitmap_Verb, paint, "drawBitmapRect(%s %s)",
+ bs.c_str(), rs.c_str());
+}
+
+void SkDumpCanvas::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& m,
+ const SkPaint* paint) {
+ SkString bs, ms;
+ toString(bitmap, &bs);
+ m.toDumpString(&ms);
+ this->dump(kDrawBitmap_Verb, paint, "drawBitmapMatrix(%s %s)",
+ bs.c_str(), ms.c_str());
+}
+
+void SkDumpCanvas::drawSprite(const SkBitmap& bitmap, int x, int y,
+ const SkPaint* paint) {
+ SkString str;
+ toString(bitmap, &str);
+ this->dump(kDrawBitmap_Verb, paint, "drawSprite(%s (%d %d))", str.c_str(),
+ x, y);
+}
+
+void SkDumpCanvas::drawText(const void* text, size_t byteLength, SkScalar x,
+ SkScalar y, const SkPaint& paint) {
+ SkString str;
+ toString(text, byteLength, paint.getTextEncoding(), &str);
+ this->dump(kDrawText_Verb, &paint, "drawText(%s [%d] (%g %g))", str.c_str(),
+ byteLength, SkScalarToFloat(x), SkScalarToFloat(y));
+}
+
+void SkDumpCanvas::drawPosText(const void* text, size_t byteLength,
+ const SkPoint pos[], const SkPaint& paint) {
+ SkString str;
+ toString(text, byteLength, paint.getTextEncoding(), &str);
+ this->dump(kDrawText_Verb, &paint, "drawPosText(%s [%d] (%g %g ...))",
+ str.c_str(), byteLength, SkScalarToFloat(pos[0].fX),
+ SkScalarToFloat(pos[0].fY));
+}
+
+void SkDumpCanvas::drawPosTextH(const void* text, size_t byteLength,
+ const SkScalar xpos[], SkScalar constY,
+ const SkPaint& paint) {
+ SkString str;
+ toString(text, byteLength, paint.getTextEncoding(), &str);
+ this->dump(kDrawText_Verb, &paint, "drawPosTextH(%s [%d] (%g %g ...))",
+ str.c_str(), byteLength, SkScalarToFloat(xpos[0]),
+ SkScalarToFloat(constY));
+}
+
+void SkDumpCanvas::drawTextOnPath(const void* text, size_t byteLength,
+ const SkPath& path, const SkMatrix* matrix,
+ const SkPaint& paint) {
+ SkString str;
+ toString(text, byteLength, paint.getTextEncoding(), &str);
+ this->dump(kDrawText_Verb, &paint, "drawTextOnPath(%s [%d])",
+ str.c_str(), byteLength);
+}
+
+void SkDumpCanvas::drawPicture(SkPicture& picture) {
+ this->dump(kDrawPicture_Verb, NULL, "drawPicture(%p)", &picture);
+}
+
+void SkDumpCanvas::drawVertices(VertexMode vmode, int vertexCount,
+ const SkPoint vertices[], const SkPoint texs[],
+ const SkColor colors[], SkXfermode* xmode,
+ const uint16_t indices[], int indexCount,
+ const SkPaint& paint) {
+ this->dump(kDrawVertices_Verb, &paint, "drawVertices(%s [%d] [%g %g ...]",
+ toString(vmode), vertexCount, SkScalarToFloat(vertices[0].fX),
+ SkScalarToFloat(vertices[0].fY));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+
+SkFormatDumper::SkFormatDumper(void (*proc)(const char*, void*), void* refcon) {
+ fProc = proc;
+ fRefcon = refcon;
+}
+
+static void appendPtr(SkString* str, const void* ptr, const char name[]) {
+ if (ptr) {
+ str->appendf(" %s:%p", name, ptr);
+ }
+}
+
+static void appendFlattenable(SkString* str, const SkFlattenable* ptr,
+ const char name[]) {
+ if (ptr) {
+ SkString info;
+ if (ptr->toDumpString(&info)) {
+ str->appendf(" %s", info.c_str());
+ } else {
+ str->appendf(" %s:%p", name, ptr);
+ }
+ }
+}
+
+void SkFormatDumper::dump(SkDumpCanvas* canvas, SkDumpCanvas::Verb verb,
+ const char str[], const SkPaint* p) {
+ SkString msg, tab;
+ const int level = canvas->getSaveCount() - 1;
+ SkASSERT(level >= 0);
+ for (int i = 0; i < level; i++) {
+ tab.append("\t");
+ }
+ msg.printf("%s%s", tab.c_str(), str);
+
+ if (p) {
+ msg.appendf(" color:0x%08X flags:%X", p->getColor(), p->getFlags());
+ appendFlattenable(&msg, p->getShader(), "shader");
+ appendFlattenable(&msg, p->getXfermode(), "xfermode");
+ appendFlattenable(&msg, p->getPathEffect(), "pathEffect");
+ appendFlattenable(&msg, p->getMaskFilter(), "maskFilter");
+ appendFlattenable(&msg, p->getPathEffect(), "pathEffect");
+ appendFlattenable(&msg, p->getColorFilter(), "filter");
+
+ if (SkDumpCanvas::kDrawText_Verb == verb) {
+ msg.appendf(" textSize:%g", SkScalarToFloat(p->getTextSize()));
+ appendPtr(&msg, p->getTypeface(), "typeface");
+ }
+ }
+
+ fProc(msg.c_str(), fRefcon);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static void dumpToDebugf(const char text[], void*) {
+ SkDebugf("%s\n", text);
+}
+
+SkDebugfDumper::SkDebugfDumper() : INHERITED(dumpToDebugf, NULL) {}
+
+
diff --git a/src/utils/SkInterpolator.cpp b/src/utils/SkInterpolator.cpp
new file mode 100644
index 0000000..e4ecd95
--- /dev/null
+++ b/src/utils/SkInterpolator.cpp
@@ -0,0 +1,339 @@
+/*
+ * Copyright (C) 2006-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 "SkInterpolator.h"
+#include "SkMath.h"
+#include "SkTSearch.h"
+
+SkInterpolatorBase::SkInterpolatorBase() {
+ fStorage = NULL;
+ fTimes = NULL;
+ SkDEBUGCODE(fTimesArray = NULL;)
+}
+
+SkInterpolatorBase::~SkInterpolatorBase() {
+ if (fStorage) {
+ sk_free(fStorage);
+ }
+}
+
+void SkInterpolatorBase::reset(int elemCount, int frameCount) {
+ fFlags = 0;
+ fElemCount = SkToU8(elemCount);
+ fFrameCount = SkToS16(frameCount);
+ fRepeat = SK_Scalar1;
+ if (fStorage) {
+ sk_free(fStorage);
+ fStorage = NULL;
+ fTimes = NULL;
+ SkDEBUGCODE(fTimesArray = NULL);
+ }
+}
+
+/* Each value[] run is formated as:
+ <time (in msec)>
+ <blend>
+ <data[fElemCount]>
+
+ Totaling fElemCount+2 entries per keyframe
+*/
+
+bool SkInterpolatorBase::getDuration(SkMSec* startTime, SkMSec* endTime) const {
+ if (fFrameCount == 0) {
+ return false;
+ }
+
+ if (startTime) {
+ *startTime = fTimes[0].fTime;
+ }
+ if (endTime) {
+ *endTime = fTimes[fFrameCount - 1].fTime;
+ }
+ return true;
+}
+
+SkScalar SkInterpolatorBase::ComputeRelativeT(SkMSec time, SkMSec prevTime,
+ SkMSec nextTime, const SkScalar blend[4]) {
+ SkASSERT(time > prevTime && time < nextTime);
+
+ SkScalar t = SkScalarDiv((SkScalar)(time - prevTime),
+ (SkScalar)(nextTime - prevTime));
+ return blend ?
+ SkUnitCubicInterp(t, blend[0], blend[1], blend[2], blend[3]) : t;
+}
+
+SkInterpolatorBase::Result SkInterpolatorBase::timeToT(SkMSec time, SkScalar* T,
+ int* indexPtr, SkBool* exactPtr) const {
+ SkASSERT(fFrameCount > 0);
+ Result result = kNormal_Result;
+ if (fRepeat != SK_Scalar1) {
+ SkMSec startTime, endTime;
+ this->getDuration(&startTime, &endTime);
+ SkMSec totalTime = endTime - startTime;
+ SkMSec offsetTime = time - startTime;
+ endTime = SkScalarMulFloor(fRepeat, totalTime);
+ if (offsetTime >= endTime) {
+ SkScalar fraction = SkScalarFraction(fRepeat);
+ offsetTime = fraction == 0 && fRepeat > 0 ? totalTime :
+ SkScalarMulFloor(fraction, totalTime);
+ result = kFreezeEnd_Result;
+ } else {
+ int mirror = fFlags & kMirror;
+ offsetTime = offsetTime % (totalTime << mirror);
+ if (offsetTime > totalTime) { // can only be true if fMirror is true
+ offsetTime = (totalTime << 1) - offsetTime;
+ }
+ }
+ time = offsetTime + startTime;
+ }
+
+ int index = SkTSearch<SkMSec>(&fTimes[0].fTime, fFrameCount, time,
+ sizeof(SkTimeCode));
+
+ bool exact = true;
+
+ if (index < 0) {
+ index = ~index;
+ if (index == 0) {
+ result = kFreezeStart_Result;
+ } else if (index == fFrameCount) {
+ if (fFlags & kReset) {
+ index = 0;
+ } else {
+ index -= 1;
+ }
+ result = kFreezeEnd_Result;
+ } else {
+ exact = false;
+ }
+ }
+ SkASSERT(index < fFrameCount);
+ const SkTimeCode* nextTime = &fTimes[index];
+ SkMSec nextT = nextTime[0].fTime;
+ if (exact) {
+ *T = 0;
+ } else {
+ SkMSec prevT = nextTime[-1].fTime;
+ *T = ComputeRelativeT(time, prevT, nextT, nextTime[-1].fBlend);
+ }
+ *indexPtr = index;
+ *exactPtr = exact;
+ return result;
+}
+
+
+SkInterpolator::SkInterpolator() {
+ INHERITED::reset(0, 0);
+ fValues = NULL;
+ SkDEBUGCODE(fScalarsArray = NULL;)
+}
+
+SkInterpolator::SkInterpolator(int elemCount, int frameCount) {
+ SkASSERT(elemCount > 0);
+ this->reset(elemCount, frameCount);
+}
+
+void SkInterpolator::reset(int elemCount, int frameCount) {
+ INHERITED::reset(elemCount, frameCount);
+ fStorage = sk_malloc_throw((sizeof(SkScalar) * elemCount +
+ sizeof(SkTimeCode)) * frameCount);
+ fTimes = (SkTimeCode*) fStorage;
+ fValues = (SkScalar*) ((char*) fStorage + sizeof(SkTimeCode) * frameCount);
+#ifdef SK_DEBUG
+ fTimesArray = (SkTimeCode(*)[10]) fTimes;
+ fScalarsArray = (SkScalar(*)[10]) fValues;
+#endif
+}
+
+#define SK_Fixed1Third (SK_Fixed1/3)
+#define SK_Fixed2Third (SK_Fixed1*2/3)
+
+static const SkScalar gIdentityBlend[4] = {
+#ifdef SK_SCALAR_IS_FLOAT
+ 0.33333333f, 0.33333333f, 0.66666667f, 0.66666667f
+#else
+ SK_Fixed1Third, SK_Fixed1Third, SK_Fixed2Third, SK_Fixed2Third
+#endif
+};
+
+bool SkInterpolator::setKeyFrame(int index, SkMSec time,
+ const SkScalar values[], const SkScalar blend[4]) {
+ SkASSERT(values != NULL);
+
+ if (blend == NULL) {
+ blend = gIdentityBlend;
+ }
+
+ bool success = ~index == SkTSearch<SkMSec>(&fTimes->fTime, index, time,
+ sizeof(SkTimeCode));
+ SkASSERT(success);
+ if (success) {
+ SkTimeCode* timeCode = &fTimes[index];
+ timeCode->fTime = time;
+ memcpy(timeCode->fBlend, blend, sizeof(timeCode->fBlend));
+ SkScalar* dst = &fValues[fElemCount * index];
+ memcpy(dst, values, fElemCount * sizeof(SkScalar));
+ }
+ return success;
+}
+
+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;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+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(SkScalar x) {
+ if (x <= 0) {
+ return 0;
+ }
+ if (x >= SK_Scalar1) {
+ return Dot14_ONE;
+ }
+ return SkScalarToFixed(x) >> 2;
+}
+
+SkScalar SkUnitCubicInterp(SkScalar value, SkScalar bx, SkScalar by,
+ SkScalar cx, SkScalar cy) {
+ // pin to the unit-square, and convert to 2.14
+ Dot14 x = pin_and_convert(value);
+
+ if (x == 0) return 0;
+ if (x == Dot14_ONE) return SK_Scalar1;
+
+ 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 SkFixedToScalar(eval_cubic(t, A, B, C) << 2);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+
+#ifdef SK_DEBUG
+
+#ifdef SK_SUPPORT_UNITTEST
+ static SkScalar* iset(SkScalar array[3], int a, int b, int c) {
+ array[0] = SkIntToScalar(a);
+ array[1] = SkIntToScalar(b);
+ array[2] = SkIntToScalar(c);
+ return array;
+ }
+#endif
+
+void SkInterpolator::UnitTest() {
+#ifdef SK_SUPPORT_UNITTEST
+ SkInterpolator inter(3, 2);
+ SkScalar v1[3], v2[3], v[3], vv[3];
+ Result result;
+
+ inter.setKeyFrame(0, 100, iset(v1, 10, 20, 30), 0);
+ inter.setKeyFrame(1, 200, iset(v2, 110, 220, 330));
+
+ result = inter.timeToValues(0, v);
+ SkASSERT(result == kFreezeStart_Result);
+ SkASSERT(memcmp(v, v1, sizeof(v)) == 0);
+
+ result = inter.timeToValues(99, v);
+ SkASSERT(result == kFreezeStart_Result);
+ SkASSERT(memcmp(v, v1, sizeof(v)) == 0);
+
+ result = inter.timeToValues(100, v);
+ SkASSERT(result == kNormal_Result);
+ SkASSERT(memcmp(v, v1, sizeof(v)) == 0);
+
+ result = inter.timeToValues(200, v);
+ SkASSERT(result == kNormal_Result);
+ SkASSERT(memcmp(v, v2, sizeof(v)) == 0);
+
+ result = inter.timeToValues(201, v);
+ SkASSERT(result == kFreezeEnd_Result);
+ SkASSERT(memcmp(v, v2, sizeof(v)) == 0);
+
+ result = inter.timeToValues(150, v);
+ SkASSERT(result == kNormal_Result);
+ SkASSERT(memcmp(v, iset(vv, 60, 120, 180), sizeof(v)) == 0);
+
+ result = inter.timeToValues(125, v);
+ SkASSERT(result == kNormal_Result);
+ result = inter.timeToValues(175, v);
+ SkASSERT(result == kNormal_Result);
+#endif
+}
+
+#endif
+
diff --git a/src/utils/SkNinePatch.cpp b/src/utils/SkNinePatch.cpp
new file mode 100644
index 0000000..b8e11fb
--- /dev/null
+++ b/src/utils/SkNinePatch.cpp
@@ -0,0 +1,287 @@
+/*
+** Copyright 2006, 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 "SkNinePatch.h"
+#include "SkCanvas.h"
+#include "SkShader.h"
+
+static const uint16_t g3x3Indices[] = {
+ 0, 5, 1, 0, 4, 5,
+ 1, 6, 2, 1, 5, 6,
+ 2, 7, 3, 2, 6, 7,
+
+ 4, 9, 5, 4, 8, 9,
+ 5, 10, 6, 5, 9, 10,
+ 6, 11, 7, 6, 10, 11,
+
+ 8, 13, 9, 8, 12, 13,
+ 9, 14, 10, 9, 13, 14,
+ 10, 15, 11, 10, 14, 15
+};
+
+static int fillIndices(uint16_t indices[], int xCount, int yCount) {
+ uint16_t* startIndices = indices;
+
+ int n = 0;
+ for (int y = 0; y < yCount; y++) {
+ for (int x = 0; x < xCount; x++) {
+ *indices++ = n;
+ *indices++ = n + xCount + 2;
+ *indices++ = n + 1;
+
+ *indices++ = n;
+ *indices++ = n + xCount + 1;
+ *indices++ = n + xCount + 2;
+
+ n += 1;
+ }
+ n += 1;
+ }
+ return indices - startIndices;
+}
+
+static void fillRow(SkPoint verts[], SkPoint texs[],
+ const SkScalar vy, const SkScalar ty,
+ const SkRect& bounds, const int32_t xDivs[], int numXDivs,
+ const SkScalar stretchX, int width) {
+ SkScalar vx = bounds.fLeft;
+ verts->set(vx, vy); verts++;
+ texs->set(0, ty); texs++;
+ for (int x = 0; x < numXDivs; x++) {
+ SkScalar tx = SkIntToScalar(xDivs[x]);
+ if (x & 1) {
+ vx += stretchX;
+ } else {
+ vx += tx;
+ }
+ verts->set(vx, vy); verts++;
+ texs->set(tx, ty); texs++;
+ }
+ verts->set(bounds.fRight, vy); verts++;
+ texs->set(SkIntToScalar(width), ty); texs++;
+}
+
+struct Mesh {
+ const SkPoint* fVerts;
+ const SkPoint* fTexs;
+ const SkColor* fColors;
+ const uint16_t* fIndices;
+};
+
+void SkNinePatch::DrawMesh(SkCanvas* canvas, const SkRect& bounds,
+ const SkBitmap& bitmap,
+ const int32_t xDivs[], int numXDivs,
+ const int32_t yDivs[], int numYDivs,
+ const SkPaint* paint) {
+ if (bounds.isEmpty() || bitmap.width() == 0 || bitmap.height() == 0) {
+ return;
+ }
+
+ // should try a quick-reject test before calling lockPixels
+ SkAutoLockPixels alp(bitmap);
+ // after the lock, it is valid to check
+ if (!bitmap.readyToDraw()) {
+ return;
+ }
+
+ // check for degenerate divs (just an optimization, not required)
+ {
+ int i;
+ int zeros = 0;
+ for (i = 0; i < numYDivs && yDivs[i] == 0; i++) {
+ zeros += 1;
+ }
+ numYDivs -= zeros;
+ yDivs += zeros;
+ for (i = numYDivs - 1; i >= 0 && yDivs[i] == bitmap.height(); --i) {
+ numYDivs -= 1;
+ }
+ }
+
+ Mesh mesh;
+
+ const int numXStretch = (numXDivs + 1) >> 1;
+ const int numYStretch = (numYDivs + 1) >> 1;
+
+ if (numXStretch < 1 && numYStretch < 1) {
+ BITMAP_RECT:
+// SkDebugf("------ drawasamesh revert to bitmaprect\n");
+ canvas->drawBitmapRect(bitmap, NULL, bounds, paint);
+ return;
+ }
+
+ if (false) {
+ int i;
+ for (i = 0; i < numXDivs; i++) {
+ SkDebugf("--- xdivs[%d] %d\n", i, xDivs[i]);
+ }
+ for (i = 0; i < numYDivs; i++) {
+ SkDebugf("--- ydivs[%d] %d\n", i, yDivs[i]);
+ }
+ }
+
+ SkScalar stretchX = 0, stretchY = 0;
+
+ if (numXStretch > 0) {
+ int stretchSize = 0;
+ for (int i = 1; i < numXDivs; i += 2) {
+ stretchSize += xDivs[i] - xDivs[i-1];
+ }
+ int fixed = bitmap.width() - stretchSize;
+ stretchX = (bounds.width() - SkIntToScalar(fixed)) / numXStretch;
+ if (stretchX < 0) {
+ goto BITMAP_RECT;
+ }
+ }
+
+ if (numYStretch > 0) {
+ int stretchSize = 0;
+ for (int i = 1; i < numYDivs; i += 2) {
+ stretchSize += yDivs[i] - yDivs[i-1];
+ }
+ int fixed = bitmap.height() - stretchSize;
+ stretchY = (bounds.height() - SkIntToScalar(fixed)) / numYStretch;
+ if (stretchY < 0) {
+ goto BITMAP_RECT;
+ }
+ }
+
+#if 0
+ SkDebugf("---- drawasamesh [%d %d] -> [%g %g] <%d %d> (%g %g)\n",
+ bitmap.width(), bitmap.height(),
+ SkScalarToFloat(bounds.width()), SkScalarToFloat(bounds.height()),
+ numXDivs + 1, numYDivs + 1,
+ SkScalarToFloat(stretchX), SkScalarToFloat(stretchY));
+#endif
+
+ const int vCount = (numXDivs + 2) * (numYDivs + 2);
+ // number of celss * 2 (tris per cell) * 3 (verts per tri)
+ const int indexCount = (numXDivs + 1) * (numYDivs + 1) * 2 * 3;
+ // allocate 2 times, one for verts, one for texs, plus indices
+ SkAutoMalloc storage(vCount * sizeof(SkPoint) * 2 +
+ indexCount * sizeof(uint16_t));
+ SkPoint* verts = (SkPoint*)storage.get();
+ SkPoint* texs = verts + vCount;
+ uint16_t* indices = (uint16_t*)(texs + vCount);
+
+ mesh.fVerts = verts;
+ mesh.fTexs = texs;
+ mesh.fColors = NULL;
+ mesh.fIndices = NULL;
+
+ // we use <= for YDivs, since the prebuild indices work for 3x2 and 3x1 too
+ if (numXDivs == 2 && numYDivs <= 2) {
+ mesh.fIndices = g3x3Indices;
+ } else {
+ int n = fillIndices(indices, numXDivs + 1, numYDivs + 1);
+ SkASSERT(n == indexCount);
+ mesh.fIndices = indices;
+ }
+
+ SkScalar vy = bounds.fTop;
+ fillRow(verts, texs, vy, 0, bounds, xDivs, numXDivs,
+ stretchX, bitmap.width());
+ verts += numXDivs + 2;
+ texs += numXDivs + 2;
+ for (int y = 0; y < numYDivs; y++) {
+ const SkScalar ty = SkIntToScalar(yDivs[y]);
+ if (y & 1) {
+ vy += stretchY;
+ } else {
+ vy += ty;
+ }
+ fillRow(verts, texs, vy, ty, bounds, xDivs, numXDivs,
+ stretchX, bitmap.width());
+ verts += numXDivs + 2;
+ texs += numXDivs + 2;
+ }
+ fillRow(verts, texs, bounds.fBottom, SkIntToScalar(bitmap.height()),
+ bounds, xDivs, numXDivs, stretchX, bitmap.width());
+
+ SkShader* shader = SkShader::CreateBitmapShader(bitmap,
+ SkShader::kClamp_TileMode,
+ SkShader::kClamp_TileMode);
+ SkPaint p;
+ if (paint) {
+ p = *paint;
+ }
+ p.setShader(shader)->unref();
+ canvas->drawVertices(SkCanvas::kTriangles_VertexMode, vCount,
+ mesh.fVerts, mesh.fTexs, mesh.fColors, NULL,
+ mesh.fIndices, indexCount, p);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static void drawNineViaRects(SkCanvas* canvas, const SkRect& dst,
+ const SkBitmap& bitmap, const SkIRect& margins,
+ const SkPaint* paint) {
+ const int32_t srcX[4] = {
+ 0, margins.fLeft, bitmap.width() - margins.fRight, bitmap.width()
+ };
+ const int32_t srcY[4] = {
+ 0, margins.fTop, bitmap.height() - margins.fBottom, bitmap.height()
+ };
+ const SkScalar dstX[4] = {
+ dst.fLeft, dst.fLeft + SkIntToScalar(margins.fLeft),
+ dst.fRight - SkIntToScalar(margins.fRight), dst.fRight
+ };
+ const SkScalar dstY[4] = {
+ dst.fTop, dst.fTop + SkIntToScalar(margins.fTop),
+ dst.fBottom - SkIntToScalar(margins.fBottom), dst.fBottom
+ };
+
+ SkIRect s;
+ SkRect d;
+ for (int y = 0; y < 3; y++) {
+ s.fTop = srcY[y];
+ s.fBottom = srcY[y+1];
+ d.fTop = dstY[y];
+ d.fBottom = dstY[y+1];
+ for (int x = 0; x < 3; x++) {
+ s.fLeft = srcX[x];
+ s.fRight = srcX[x+1];
+ d.fLeft = dstX[x];
+ d.fRight = dstX[x+1];
+ canvas->drawBitmapRect(bitmap, &s, d, paint);
+ }
+ }
+}
+
+void SkNinePatch::DrawNine(SkCanvas* canvas, const SkRect& bounds,
+ const SkBitmap& bitmap, const SkIRect& margins,
+ const SkPaint* paint) {
+ /** Our vertices code has numerical precision problems if the transformed
+ coordinates land directly on a 1/2 pixel boundary. To work around that
+ for now, we only take the vertices case if we are in opengl. Also,
+ when not in GL, the vertices impl is slower (more math) than calling
+ the viaRects code.
+ */
+ if (canvas->getViewport(NULL)) { // returns true for OpenGL
+ int32_t xDivs[2];
+ int32_t yDivs[2];
+
+ xDivs[0] = margins.fLeft;
+ xDivs[1] = bitmap.width() - margins.fRight;
+ yDivs[0] = margins.fTop;
+ yDivs[1] = bitmap.height() - margins.fBottom;
+
+ SkNinePatch::DrawMesh(canvas, bounds, bitmap,
+ xDivs, 2, yDivs, 2, paint);
+ } else {
+ drawNineViaRects(canvas, bounds, bitmap, margins, paint);
+ }
+}
diff --git a/src/utils/SkProxyCanvas.cpp b/src/utils/SkProxyCanvas.cpp
new file mode 100644
index 0000000..2a02b45
--- /dev/null
+++ b/src/utils/SkProxyCanvas.cpp
@@ -0,0 +1,162 @@
+#include "SkProxyCanvas.h"
+
+SkProxyCanvas::SkProxyCanvas(SkCanvas* proxy) : fProxy(proxy) {
+ fProxy->safeRef();
+}
+
+SkProxyCanvas::~SkProxyCanvas() {
+ fProxy->safeUnref();
+}
+
+void SkProxyCanvas::setProxy(SkCanvas* proxy) {
+ SkRefCnt_SafeAssign(fProxy, proxy);
+}
+
+///////////////////////////////// Overrides ///////////
+
+bool SkProxyCanvas::getViewport(SkIPoint* size) const {
+ return fProxy->getViewport(size);
+}
+
+bool SkProxyCanvas::setViewport(int x, int y) {
+ return fProxy->setViewport(x, y);
+}
+
+SkDevice* SkProxyCanvas::setBitmapDevice(const SkBitmap& bitmap) {
+ return fProxy->setBitmapDevice(bitmap);
+}
+
+int SkProxyCanvas::save(SaveFlags flags) {
+ return fProxy->save(flags);
+}
+
+int SkProxyCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
+ SaveFlags flags) {
+ return fProxy->saveLayer(bounds, paint, flags);
+}
+
+void SkProxyCanvas::restore() {
+ fProxy->restore();
+}
+
+bool SkProxyCanvas::translate(SkScalar dx, SkScalar dy) {
+ return fProxy->translate(dx, dy);
+}
+
+bool SkProxyCanvas::scale(SkScalar sx, SkScalar sy) {
+ return fProxy->scale(sx, sy);
+}
+
+bool SkProxyCanvas::rotate(SkScalar degrees) {
+ return fProxy->rotate(degrees);
+}
+
+bool SkProxyCanvas::skew(SkScalar sx, SkScalar sy) {
+ return fProxy->skew(sx, sy);
+}
+
+bool SkProxyCanvas::concat(const SkMatrix& matrix) {
+ return fProxy->concat(matrix);
+}
+
+void SkProxyCanvas::setMatrix(const SkMatrix& matrix) {
+ fProxy->setMatrix(matrix);
+}
+
+bool SkProxyCanvas::clipRect(const SkRect& rect, SkRegion::Op op) {
+ return fProxy->clipRect(rect, op);
+}
+
+bool SkProxyCanvas::clipPath(const SkPath& path, SkRegion::Op op) {
+ return fProxy->clipPath(path, op);
+}
+
+bool SkProxyCanvas::clipRegion(const SkRegion& deviceRgn, SkRegion::Op op) {
+ return fProxy->clipRegion(deviceRgn, op);
+}
+
+void SkProxyCanvas::drawPaint(const SkPaint& paint) {
+ fProxy->drawPaint(paint);
+}
+
+void SkProxyCanvas::drawPoints(PointMode mode, size_t count,
+ const SkPoint pts[], const SkPaint& paint) {
+ fProxy->drawPoints(mode, count, pts, paint);
+}
+
+void SkProxyCanvas::drawRect(const SkRect& rect, const SkPaint& paint) {
+ fProxy->drawRect(rect, paint);
+}
+
+void SkProxyCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
+ fProxy->drawPath(path, paint);
+}
+
+void SkProxyCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y,
+ const SkPaint* paint) {
+ fProxy->drawBitmap(bitmap, x, y, paint);
+}
+
+void SkProxyCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect* src,
+ const SkRect& dst, const SkPaint* paint) {
+ fProxy->drawBitmapRect(bitmap, src, dst, paint);
+}
+
+void SkProxyCanvas::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& m,
+ const SkPaint* paint) {
+ fProxy->drawBitmapMatrix(bitmap, m, paint);
+}
+
+void SkProxyCanvas::drawSprite(const SkBitmap& bitmap, int x, int y,
+ const SkPaint* paint) {
+ fProxy->drawSprite(bitmap, x, y, paint);
+}
+
+void SkProxyCanvas::drawText(const void* text, size_t byteLength, SkScalar x,
+ SkScalar y, const SkPaint& paint) {
+ fProxy->drawText(text, byteLength, x, y, paint);
+}
+
+void SkProxyCanvas::drawPosText(const void* text, size_t byteLength,
+ const SkPoint pos[], const SkPaint& paint) {
+ fProxy->drawPosText(text, byteLength, pos, paint);
+}
+
+void SkProxyCanvas::drawPosTextH(const void* text, size_t byteLength,
+ const SkScalar xpos[], SkScalar constY,
+ const SkPaint& paint) {
+ fProxy->drawPosTextH(text, byteLength, xpos, constY, paint);
+}
+
+void SkProxyCanvas::drawTextOnPath(const void* text, size_t byteLength,
+ const SkPath& path, const SkMatrix* matrix,
+ const SkPaint& paint) {
+ fProxy->drawTextOnPath(text, byteLength, path, matrix, paint);
+}
+
+void SkProxyCanvas::drawPicture(SkPicture& picture) {
+ fProxy->drawPicture(picture);
+}
+
+void SkProxyCanvas::drawVertices(VertexMode vmode, int vertexCount,
+ const SkPoint vertices[], const SkPoint texs[],
+ const SkColor colors[], SkXfermode* xmode,
+ const uint16_t indices[], int indexCount,
+ const SkPaint& paint) {
+ fProxy->drawVertices(vmode, vertexCount, vertices, texs, colors,
+ xmode, indices, indexCount, paint);
+}
+
+SkBounder* SkProxyCanvas::setBounder(SkBounder* bounder) {
+ return fProxy->setBounder(bounder);
+}
+
+SkDrawFilter* SkProxyCanvas::setDrawFilter(SkDrawFilter* filter) {
+ return fProxy->setDrawFilter(filter);
+}
+
+SkDevice* SkProxyCanvas::createDevice(SkBitmap::Config config, int width,
+ int height, bool isOpaque, bool isForLayer) {
+ return fProxy->createDevice(config, width, height, isOpaque, isForLayer);
+}
+
diff --git a/src/utils/SkUnitMappers.cpp b/src/utils/SkUnitMappers.cpp
new file mode 100644
index 0000000..0363a2b
--- /dev/null
+++ b/src/utils/SkUnitMappers.cpp
@@ -0,0 +1,80 @@
+#include "SkUnitMappers.h"
+
+SkDiscreteMapper::SkDiscreteMapper(int segments)
+{
+ if (segments < 2)
+ {
+ fSegments = 0;
+ fScale = 0;
+ }
+ else
+ {
+ if (segments > 0xFFFF)
+ segments = 0xFFFF;
+ fSegments = segments;
+ fScale = SK_Fract1 / (segments - 1);
+ }
+}
+
+uint16_t SkDiscreteMapper::mapUnit16(uint16_t input)
+{
+ SkFixed x = input * fSegments >> 16;
+ x = x * fScale >> 14;
+ x += x << 15 >> 31; // map 0x10000 to 0xFFFF
+ return SkToU16(x);
+}
+
+SkDiscreteMapper::SkDiscreteMapper(SkFlattenableReadBuffer& rb)
+ : SkUnitMapper(rb)
+{
+ fSegments = rb.readU32();
+ fScale = rb.readU32();
+}
+
+SkFlattenable::Factory SkDiscreteMapper::getFactory()
+{
+ return Create;
+}
+
+SkFlattenable* SkDiscreteMapper::Create(SkFlattenableReadBuffer& rb)
+{
+ return SkNEW_ARGS(SkDiscreteMapper, (rb));
+}
+
+void SkDiscreteMapper::flatten(SkFlattenableWriteBuffer& wb)
+{
+ this->INHERITED::flatten(wb);
+
+ wb.write32(fSegments);
+ wb.write32(fScale);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+uint16_t SkCosineMapper::mapUnit16(uint16_t input)
+{
+ /* we want to call cosine(input * pi/2) treating input as [0...1)
+ however, the straight multitply would overflow 32bits since input is
+ 16bits and pi/2 is 17bits, so we shift down our pi const before we mul
+ */
+ SkFixed rads = (unsigned)(input * (SK_FixedPI >> 2)) >> 15;
+ SkFixed x = SkFixedCos(rads);
+ x += x << 15 >> 31; // map 0x10000 to 0xFFFF
+ return SkToU16(x);
+}
+
+SkCosineMapper::SkCosineMapper(SkFlattenableReadBuffer& rb)
+ : SkUnitMapper(rb)
+{
+}
+
+SkFlattenable::Factory SkCosineMapper::getFactory()
+{
+ return Create;
+}
+
+SkFlattenable* SkCosineMapper::Create(SkFlattenableReadBuffer& rb)
+{
+ return SkNEW_ARGS(SkCosineMapper, (rb));
+}
+