diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2009-01-09 17:51:21 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-01-09 17:51:21 -0800 |
commit | 03202c9c3dfbf8c4feb0a1ee9b3680817e633f58 (patch) | |
tree | 1d0ba7cbf3e77c239527697ac455312b216c434e /src/utils | |
parent | 37df15a82319228ae28fe5d99c010b288aad7091 (diff) | |
download | external_skia-03202c9c3dfbf8c4feb0a1ee9b3680817e633f58.zip external_skia-03202c9c3dfbf8c4feb0a1ee9b3680817e633f58.tar.gz external_skia-03202c9c3dfbf8c4feb0a1ee9b3680817e633f58.tar.bz2 |
auto import from //branches/cupcake/...@125939
Diffstat (limited to 'src/utils')
-rw-r--r-- | src/utils/SkCamera.cpp | 449 | ||||
-rw-r--r-- | src/utils/SkColorMatrix.cpp | 165 | ||||
-rw-r--r-- | src/utils/SkCullPoints.cpp | 168 | ||||
-rw-r--r-- | src/utils/SkDumpCanvas.cpp | 398 | ||||
-rw-r--r-- | src/utils/SkInterpolator.cpp | 339 | ||||
-rw-r--r-- | src/utils/SkNinePatch.cpp | 287 | ||||
-rw-r--r-- | src/utils/SkProxyCanvas.cpp | 162 | ||||
-rw-r--r-- | src/utils/SkUnitMappers.cpp | 80 | ||||
-rw-r--r-- | src/utils/mac/SkBitmap_Mac.cpp | 142 | ||||
-rw-r--r-- | src/utils/mac/SkCreateCGImageRef.cpp | 67 | ||||
-rw-r--r-- | src/utils/mac/SkOSWindow_Mac.cpp | 450 |
11 files changed, 2707 insertions, 0 deletions
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)); +} + diff --git a/src/utils/mac/SkBitmap_Mac.cpp b/src/utils/mac/SkBitmap_Mac.cpp new file mode 100644 index 0000000..06c2b27 --- /dev/null +++ b/src/utils/mac/SkBitmap_Mac.cpp @@ -0,0 +1,142 @@ +#include "SkBitmap.h" +#include "SkColorPriv.h" +#include "SkMath.h" + +#if defined(SK_BUILD_FOR_MAC) && !defined(SK_USE_WXWIDGETS) + +#include <ApplicationServices/ApplicationServices.h> + +#ifndef __ppc__ + #define SWAP_16BIT +#endif + +static void convertGL32_to_Mac32(uint32_t dst[], const SkBitmap& bm) { + memcpy(dst, bm.getPixels(), bm.getSize()); + return; + + uint32_t* stop = dst + (bm.getSize() >> 2); + const uint8_t* src = (const uint8_t*)bm.getPixels(); + while (dst < stop) { + *dst++ = src[2] << 24 | src[1] << 16 | src[0] << 8 | src[3] << 0; + src += sizeof(uint32_t); + } +} + +static void convert565_to_32(uint32_t dst[], const SkBitmap& bm) { + for (int y = 0; y < bm.height(); y++) { + const uint16_t* src = bm.getAddr16(0, y); + const uint16_t* stop = src + bm.width(); + while (src < stop) { + unsigned c = *src++; + unsigned r = SkPacked16ToR32(c); + unsigned g = SkPacked16ToG32(c); + unsigned b = SkPacked16ToB32(c); + + *dst++ = (b << 24) | (g << 16) | (r << 8) | 0xFF; + } + } +} + +static void convert4444_to_555(uint16_t dst[], const uint16_t src[], int count) +{ + const uint16_t* stop = src + count; + + while (src < stop) + { + unsigned c = *src++; + + unsigned r = SkGetPackedR4444(c); + unsigned g = SkGetPackedG4444(c); + unsigned b = SkGetPackedB4444(c); + // convert to 5 bits + r = (r << 1) | (r >> 3); + g = (g << 1) | (g >> 3); + b = (b << 1) | (b >> 3); + // build the 555 + c = (r << 10) | (g << 5) | b; + +#ifdef SWAP_16BIT + c = (c >> 8) | (c << 8); +#endif + *dst++ = c; + } +} + +#include "SkTemplates.h" + +static CGImageRef bitmap2imageref(const SkBitmap& bm) { + size_t bitsPerComp; + size_t bitsPerPixel; + CGBitmapInfo info; + CGColorSpaceRef cs = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); + CGDataProviderRef data = CGDataProviderCreateWithData(NULL, + bm.getPixels(), + bm.getSize(), + NULL); + SkAutoTCallVProc<CGDataProvider, CGDataProviderRelease> acp(data); + SkAutoTCallVProc<CGColorSpace, CGColorSpaceRelease> acp2(cs); + + switch (bm.config()) { + case SkBitmap::kARGB_8888_Config: + bitsPerComp = 8; + bitsPerPixel = 32; + info = kCGImageAlphaPremultipliedLast; + break; + case SkBitmap::kARGB_4444_Config: + bitsPerComp = 4; + bitsPerPixel = 16; + info = kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder16Little; + break; +#if 0 // not supported by quartz !!! + case SkBitmap::kRGB_565_Config: + bitsPerComp = 5; + bitsPerPixel = 16; + info = kCGImageAlphaNone | kCGBitmapByteOrder16Little; + break; +#endif + default: + return NULL; + } + + return CGImageCreate(bm.width(), bm.height(), bitsPerComp, bitsPerPixel, + bm.rowBytes(), cs, info, data, + NULL, false, kCGRenderingIntentDefault); +} + +void SkBitmap::drawToPort(WindowRef wind, CGContextRef cg) const { + if (fPixels == NULL || fWidth == 0 || fHeight == 0) { + return; + } + + bool useQD = false; + if (NULL == cg) { + SetPortWindowPort(wind); + QDBeginCGContext(GetWindowPort(wind), &cg); + useQD = true; + } + + SkBitmap bm; + if (this->config() == kRGB_565_Config) { + this->copyTo(&bm, kARGB_8888_Config); + } else { + bm = *this; + } + bm.lockPixels(); + + CGImageRef image = bitmap2imageref(bm); + if (image) { + CGRect rect; + rect.origin.x = rect.origin.y = 0; + rect.size.width = bm.width(); + rect.size.height = bm.height(); + + CGContextDrawImage(cg, rect, image); + CGImageRelease(image); + } + + if (useQD) { + QDEndCGContext(GetWindowPort(wind), &cg); + } +} + +#endif diff --git a/src/utils/mac/SkCreateCGImageRef.cpp b/src/utils/mac/SkCreateCGImageRef.cpp new file mode 100644 index 0000000..6c9415e --- /dev/null +++ b/src/utils/mac/SkCreateCGImageRef.cpp @@ -0,0 +1,67 @@ +#include "SkCGUtils.h" +#include "SkBitmap.h" + +extern CGImageRef SkCreateCGImageRef(const SkBitmap&); + +static void SkBitmap_ReleaseInfo(void* info, const void* pixelData, size_t size) { + SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(info); + delete bitmap; +} + +static SkBitmap* prepareForImageRef(const SkBitmap& bm, + size_t* bitsPerComponent, + CGBitmapInfo* info) { + switch (bm.config()) { + case SkBitmap::kARGB_8888_Config: + *bitsPerComponent = 8; + // try to match our argb ordering in SkColorPriv + *info = kCGBitmapByteOrder32Big | + kCGImageAlphaPremultipliedLast; + break; + case SkBitmap::kRGB_565_Config: + // doesn't see quite right. Are they thinking 1555? + *bitsPerComponent = 5; + *info = kCGBitmapByteOrder16Little; + break; + case SkBitmap::kARGB_4444_Config: + *bitsPerComponent = 4; + *info = kCGBitmapByteOrder16Little | kCGImageAlphaPremultipliedLast; + break; + default: + return NULL; + } + + return new SkBitmap(bm); +} + +CGImageRef SkCreateCGImageRef(const SkBitmap& bm) { + size_t bitsPerComponent; + CGBitmapInfo info; + + SkBitmap* bitmap = prepareForImageRef(bm, &bitsPerComponent, &info); + if (NULL == bitmap) { + return NULL; + } + + const int w = bitmap->width(); + const int h = bitmap->height(); + const size_t s = bitmap->getSize(); + + // our provider "owns" the bitmap*, and will take care of deleting it + // we initially lock it, so we can access the pixels. The bitmap will be deleted in the release + // proc, which will in turn unlock the pixels + bitmap->lockPixels(); + CGDataProviderRef dataRef = CGDataProviderCreateWithData(bitmap, bitmap->getPixels(), s, + SkBitmap_ReleaseInfo); + + CGColorSpaceRef space = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); + CGImageRef ref = CGImageCreate(w, h, bitsPerComponent, + bitmap->bytesPerPixel() * 8, + bitmap->rowBytes(), space, info, dataRef, + NULL, false, kCGRenderingIntentDefault); + CGColorSpaceRelease(space); + CGDataProviderRelease(dataRef); + return ref; +} + + diff --git a/src/utils/mac/SkOSWindow_Mac.cpp b/src/utils/mac/SkOSWindow_Mac.cpp new file mode 100644 index 0000000..40ed57c --- /dev/null +++ b/src/utils/mac/SkOSWindow_Mac.cpp @@ -0,0 +1,450 @@ +#include "SkTypes.h" + +#if defined(SK_BUILD_FOR_MAC) && !defined(SK_USE_WXWIDGETS) + +#include <Carbon/Carbon.h> +#include "SkCGUtils.h" + +#include "SkWindow.h" +#include "SkCanvas.h" +#include "SkOSMenu.h" +#include "SkTime.h" + +#include "SkGraphics.h" +#include <new.h> + +static void (*gPrevNewHandler)(); + +extern "C" { + static void sk_new_handler() + { + if (SkGraphics::SetFontCacheUsed(0)) + return; + if (gPrevNewHandler) + gPrevNewHandler(); + else + sk_throw(); + } +} + +static SkOSWindow* gCurrOSWin; +static EventTargetRef gEventTarget; +static EventQueueRef gCurrEventQ; + +static OSStatus MyDrawEventHandler(EventHandlerCallRef myHandler, + EventRef event, void *userData) { + // NOTE: GState is save/restored by the HIView system doing the callback, + // so the draw handler doesn't need to do it + + OSStatus status = noErr; + CGContextRef context; + HIRect bounds; + + // Get the CGContextRef + status = GetEventParameter (event, kEventParamCGContextRef, + typeCGContextRef, NULL, + sizeof (CGContextRef), + NULL, + &context); + + if (status != noErr) { + SkDebugf("Got error %d getting the context!\n", status); + return status; + } + + // Get the bounding rectangle + HIViewGetBounds ((HIViewRef) userData, &bounds); + + gCurrOSWin->doPaint(context); + return status; +} + +#define SK_MacEventClass FOUR_CHAR_CODE('SKec') +#define SK_MacEventKind FOUR_CHAR_CODE('SKek') +#define SK_MacEventParamName FOUR_CHAR_CODE('SKev') +#define SK_MacEventSinkIDParamName FOUR_CHAR_CODE('SKes') + +static void set_bindingside(HISideBinding* side, HIViewRef parent, HIBindingKind kind) { + side->toView = parent; + side->kind = kind; + side->offset = 0; +} + +static void set_axisscale(HIAxisScale* axis, HIViewRef parent) { + axis->toView = parent; + axis->kind = kHILayoutScaleAbsolute; + axis->ratio = 1; +} + +static void set_axisposition(HIAxisPosition* pos, HIViewRef parent, HIPositionKind kind) { + pos->toView = parent; + pos->kind = kind; + pos->offset = 0; +} + +SkOSWindow::SkOSWindow(void* hWnd) : fHWND(hWnd) +{ + OSStatus result; + WindowRef wr = (WindowRef)hWnd; + + HIViewRef imageView, parent; + HIViewRef rootView = HIViewGetRoot(wr); + HIViewFindByID(rootView, kHIViewWindowContentID, &parent); + result = HIImageViewCreate(NULL, &imageView); + SkASSERT(result == noErr); + + result = HIViewAddSubview(parent, imageView); + SkASSERT(result == noErr); + + fHVIEW = imageView; + + HIViewSetVisible(imageView, true); + HIViewPlaceInSuperviewAt(imageView, 0, 0); + + if (true) { + HILayoutInfo layout; + layout.version = kHILayoutInfoVersionZero; + set_bindingside(&layout.binding.left, parent, kHILayoutBindLeft); + set_bindingside(&layout.binding.top, parent, kHILayoutBindTop); + set_bindingside(&layout.binding.right, parent, kHILayoutBindRight); + set_bindingside(&layout.binding.bottom, parent, kHILayoutBindBottom); + set_axisscale(&layout.scale.x, parent); + set_axisscale(&layout.scale.y, parent); + set_axisposition(&layout.position.x, parent, kHILayoutPositionLeft); + set_axisposition(&layout.position.y, rootView, kHILayoutPositionTop); + HIViewSetLayoutInfo(imageView, &layout); + } + + HIImageViewSetOpaque(imageView, true); + HIImageViewSetScaleToFit(imageView, false); + + static const EventTypeSpec gTypes[] = { + { kEventClassKeyboard, kEventRawKeyDown }, + { kEventClassKeyboard, kEventRawKeyUp }, + { kEventClassMouse, kEventMouseDown }, + { kEventClassMouse, kEventMouseDragged }, + { kEventClassMouse, kEventMouseUp }, + { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent }, + { kEventClassWindow, kEventWindowBoundsChanged }, +// { kEventClassWindow, kEventWindowDrawContent }, + { SK_MacEventClass, SK_MacEventKind } + }; + + EventHandlerUPP handlerUPP = NewEventHandlerUPP(SkOSWindow::EventHandler); + int count = SK_ARRAY_COUNT(gTypes); + + result = InstallEventHandler(GetWindowEventTarget(wr), handlerUPP, + count, gTypes, this, nil); + SkASSERT(result == noErr); + + gCurrOSWin = this; + gCurrEventQ = GetCurrentEventQueue(); + gEventTarget = GetWindowEventTarget(wr); + + static bool gOnce = true; + if (gOnce) { + gOnce = false; + gPrevNewHandler = set_new_handler(sk_new_handler); + } +} + +void SkOSWindow::doPaint(void* ctx) +{ +#if 0 + this->update(NULL); + + const SkBitmap& bm = this->getBitmap(); + CGImageRef img = SkCreateCGImageRef(bm); + + if (img) { + CGRect r = CGRectMake(0, 0, bm.width(), bm.height()); + + CGContextRef cg = reinterpret_cast<CGContextRef>(ctx); + + CGContextSaveGState(cg); + CGContextTranslateCTM(cg, 0, r.size.height); + CGContextScaleCTM(cg, 1, -1); + + CGContextDrawImage(cg, r, img); + + CGContextRestoreGState(cg); + + CGImageRelease(img); + } +#endif +} + +void SkOSWindow::updateSize() +{ + Rect r; + + GetWindowBounds((WindowRef)fHWND, kWindowContentRgn, &r); + this->resize(r.right - r.left, r.bottom - r.top); + +#if 0 + HIRect frame; + HIViewRef imageView = (HIViewRef)getHVIEW(); + HIViewRef parent = HIViewGetSuperview(imageView); + + HIViewGetBounds(imageView, &frame); + SkDebugf("------ %d bounds %g %g %g %g\n", r.right - r.left, + frame.origin.x, frame.origin.y, frame.size.width, frame.size.height); +#endif +} + +void SkOSWindow::onHandleInval(const SkIRect& r) +{ + SkEvent* evt = new SkEvent("inval-imageview"); + evt->post(this->getSinkID()); +} + +bool SkOSWindow::onEvent(const SkEvent& evt) { + if (evt.isType("inval-imageview")) { + this->update(NULL); + + const SkBitmap& bm = this->getBitmap(); + + CGImageRef img = SkCreateCGImageRef(bm); + HIImageViewSetImage((HIViewRef)getHVIEW(), img); + CGImageRelease(img); + return true; + } + return INHERITED::onEvent(evt); +} + +void SkOSWindow::onSetTitle(const char title[]) +{ + CFStringRef str = CFStringCreateWithCString(NULL, title, kCFStringEncodingUTF8); + SetWindowTitleWithCFString((WindowRef)fHWND, str); + CFRelease(str); +} + +void SkOSWindow::onAddMenu(const SkOSMenu* sk_menu) +{ +} + +static void getparam(EventRef inEvent, OSType name, OSType type, UInt32 size, void* data) +{ + EventParamType actualType; + UInt32 actualSize; + OSStatus status; + + status = GetEventParameter(inEvent, name, type, &actualType, size, &actualSize, data); + SkASSERT(status == noErr); + SkASSERT(actualType == type); + SkASSERT(actualSize == size); +} + +enum { + SK_MacReturnKey = 36, + SK_MacDeleteKey = 51, + SK_MacEndKey = 119, + SK_MacLeftKey = 123, + SK_MacRightKey = 124, + SK_MacDownKey = 125, + SK_MacUpKey = 126, + + SK_Mac0Key = 0x52, + SK_Mac1Key = 0x53, + SK_Mac2Key = 0x54, + SK_Mac3Key = 0x55, + SK_Mac4Key = 0x56, + SK_Mac5Key = 0x57, + SK_Mac6Key = 0x58, + SK_Mac7Key = 0x59, + SK_Mac8Key = 0x5b, + SK_Mac9Key = 0x5c +}; + +static SkKey raw2key(UInt32 raw) +{ + static const struct { + UInt32 fRaw; + SkKey fKey; + } gKeys[] = { + { SK_MacUpKey, kUp_SkKey }, + { SK_MacDownKey, kDown_SkKey }, + { SK_MacLeftKey, kLeft_SkKey }, + { SK_MacRightKey, kRight_SkKey }, + { SK_MacReturnKey, kOK_SkKey }, + { SK_MacDeleteKey, kBack_SkKey }, + { SK_MacEndKey, kEnd_SkKey }, + { SK_Mac0Key, k0_SkKey }, + { SK_Mac1Key, k1_SkKey }, + { SK_Mac2Key, k2_SkKey }, + { SK_Mac3Key, k3_SkKey }, + { SK_Mac4Key, k4_SkKey }, + { SK_Mac5Key, k5_SkKey }, + { SK_Mac6Key, k6_SkKey }, + { SK_Mac7Key, k7_SkKey }, + { SK_Mac8Key, k8_SkKey }, + { SK_Mac9Key, k9_SkKey } + }; + + for (unsigned i = 0; i < SK_ARRAY_COUNT(gKeys); i++) + if (gKeys[i].fRaw == raw) + return gKeys[i].fKey; + return kNONE_SkKey; +} + +static void post_skmacevent() +{ + EventRef ref; + OSStatus status = CreateEvent(nil, SK_MacEventClass, SK_MacEventKind, 0, 0, &ref); + SkASSERT(status == noErr); + +#if 0 + status = SetEventParameter(ref, SK_MacEventParamName, SK_MacEventParamName, sizeof(evt), &evt); + SkASSERT(status == noErr); + status = SetEventParameter(ref, SK_MacEventSinkIDParamName, SK_MacEventSinkIDParamName, sizeof(sinkID), &sinkID); + SkASSERT(status == noErr); +#endif + + EventTargetRef target = gEventTarget; + SetEventParameter(ref, kEventParamPostTarget, typeEventTargetRef, sizeof(target), &target); + SkASSERT(status == noErr); + + status = PostEventToQueue(gCurrEventQ, ref, kEventPriorityStandard); + SkASSERT(status == noErr); + + ReleaseEvent(ref); +} + +pascal OSStatus SkOSWindow::EventHandler( EventHandlerCallRef inHandler, EventRef inEvent, void* userData ) +{ + SkOSWindow* win = (SkOSWindow*)userData; + OSStatus result = eventNotHandledErr; + UInt32 wClass = GetEventClass(inEvent); + UInt32 wKind = GetEventKind(inEvent); + + gCurrOSWin = win; // will need to be in TLS. Set this so PostEvent will work + + switch (wClass) { + case kEventClassMouse: { + Point pt; + getparam(inEvent, kEventParamMouseLocation, typeQDPoint, sizeof(pt), &pt); + SetPortWindowPort((WindowRef)win->getHWND()); + GlobalToLocal(&pt); + + switch (wKind) { + case kEventMouseDown: + (void)win->handleClick(pt.h, pt.v, Click::kDown_State); + break; + case kEventMouseDragged: + (void)win->handleClick(pt.h, pt.v, Click::kMoved_State); + break; + case kEventMouseUp: + (void)win->handleClick(pt.h, pt.v, Click::kUp_State); + break; + default: + break; + } + break; + } + case kEventClassKeyboard: + if (wKind == kEventRawKeyDown) { + UInt32 raw; + getparam(inEvent, kEventParamKeyCode, typeUInt32, sizeof(raw), &raw); + SkKey key = raw2key(raw); + if (key != kNONE_SkKey) + (void)win->handleKey(key); + } else if (wKind == kEventRawKeyUp) { + UInt32 raw; + getparam(inEvent, kEventParamKeyCode, typeUInt32, sizeof(raw), &raw); + SkKey key = raw2key(raw); + if (key != kNONE_SkKey) + (void)win->handleKeyUp(key); + } + break; + case kEventClassTextInput: + if (wKind == kEventTextInputUnicodeForKeyEvent) { + UInt16 uni; + getparam(inEvent, kEventParamTextInputSendText, typeUnicodeText, sizeof(uni), &uni); + win->handleChar(uni); + } + break; + case kEventClassWindow: + switch (wKind) { + case kEventWindowBoundsChanged: + win->updateSize(); + break; + case kEventWindowDrawContent: { + CGContextRef cg; + result = GetEventParameter(inEvent, + kEventParamCGContextRef, + typeCGContextRef, + NULL, + sizeof (CGContextRef), + NULL, + &cg); + if (result != 0) { + cg = NULL; + } + win->doPaint(cg); + break; + } + default: + break; + } + break; + case SK_MacEventClass: { + SkASSERT(wKind == SK_MacEventKind); + if (SkEvent::ProcessEvent()) { + post_skmacevent(); + } + #if 0 + SkEvent* evt; + SkEventSinkID sinkID; + getparam(inEvent, SK_MacEventParamName, SK_MacEventParamName, sizeof(evt), &evt); + getparam(inEvent, SK_MacEventSinkIDParamName, SK_MacEventSinkIDParamName, sizeof(sinkID), &sinkID); + #endif + result = noErr; + break; + } + default: + break; + } + if (result == eventNotHandledErr) { + result = CallNextEventHandler(inHandler, inEvent); + } + return result; +} + +/////////////////////////////////////////////////////////////////////////////////////// + +void SkEvent::SignalNonEmptyQueue() +{ + post_skmacevent(); +// SkDebugf("signal nonempty\n"); +} + +static TMTask gTMTaskRec; +static TMTask* gTMTaskPtr; + +static void sk_timer_proc(TMTask* rec) +{ + SkEvent::ServiceQueueTimer(); +// SkDebugf("timer task fired\n"); +} + +void SkEvent::SignalQueueTimer(SkMSec delay) +{ + if (gTMTaskPtr) + { + RemoveTimeTask((QElem*)gTMTaskPtr); + DisposeTimerUPP(gTMTaskPtr->tmAddr); + gTMTaskPtr = nil; + } + if (delay) + { + gTMTaskPtr = &gTMTaskRec; + memset(gTMTaskPtr, 0, sizeof(gTMTaskRec)); + gTMTaskPtr->tmAddr = NewTimerUPP(sk_timer_proc); + OSErr err = InstallTimeTask((QElem*)gTMTaskPtr); +// SkDebugf("installtimetask of %d returned %d\n", delay, err); + PrimeTimeTask((QElem*)gTMTaskPtr, delay); + } +} + +#endif + |