/* * Copyright (C) 2007 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 #include #include "Transform.h" // --------------------------------------------------------------------------- #define LIKELY( exp ) (__builtin_expect( (exp) != 0, true )) #define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false )) // --------------------------------------------------------------------------- namespace android { // --------------------------------------------------------------------------- Transform::Transform() : mType(0) { mTransform.reset(); } Transform::Transform(const Transform& other) : mTransform(other.mTransform), mType(other.mType) { } Transform::Transform(int32_t flags) { mTransform.reset(); int sx = (flags & FLIP_H) ? -1 : 1; int sy = (flags & FLIP_V) ? -1 : 1; if (flags & ROT_90) { this->set(0, -sy, sx, 0); } else { this->set(sx, 0, 0, sy); } } Transform::~Transform() { } Transform Transform::operator * (const Transform& rhs) const { if (LIKELY(mType == 0)) return rhs; Transform r(*this); r.mTransform.preConcat(rhs.mTransform); r.mType |= rhs.mType; return r; } float Transform::operator [] (int i) const { float r = 0; switch(i) { case 0: r = SkScalarToFloat( mTransform[SkMatrix::kMScaleX] ); break; case 1: r = SkScalarToFloat( mTransform[SkMatrix::kMSkewX] ); break; case 2: r = SkScalarToFloat( mTransform[SkMatrix::kMSkewY] ); break; case 3: r = SkScalarToFloat( mTransform[SkMatrix::kMScaleY] ); break; } return r; } uint8_t Transform::type() const { if (UNLIKELY(mType & 0x80000000)) { mType = mTransform.getType(); } return uint8_t(mType & 0xFF); } bool Transform::transformed() const { return type() > SkMatrix::kTranslate_Mask; } int Transform::tx() const { return SkScalarRound( mTransform[SkMatrix::kMTransX] ); } int Transform::ty() const { return SkScalarRound( mTransform[SkMatrix::kMTransY] ); } void Transform::reset() { mTransform.reset(); mType = 0; } void Transform::set( float xx, float xy, float yx, float yy) { mTransform.set(SkMatrix::kMScaleX, SkFloatToScalar(xx)); mTransform.set(SkMatrix::kMSkewX, SkFloatToScalar(xy)); mTransform.set(SkMatrix::kMSkewY, SkFloatToScalar(yx)); mTransform.set(SkMatrix::kMScaleY, SkFloatToScalar(yy)); mType |= 0x80000000; } void Transform::set(float radian, float x, float y) { float r00 = cosf(radian); float r01 = -sinf(radian); float r10 = sinf(radian); float r11 = cosf(radian); mTransform.set(SkMatrix::kMScaleX, SkFloatToScalar(r00)); mTransform.set(SkMatrix::kMSkewX, SkFloatToScalar(r01)); mTransform.set(SkMatrix::kMSkewY, SkFloatToScalar(r10)); mTransform.set(SkMatrix::kMScaleY, SkFloatToScalar(r11)); mTransform.set(SkMatrix::kMTransX, SkIntToScalar(x - r00*x - r01*y)); mTransform.set(SkMatrix::kMTransY, SkIntToScalar(y - r10*x - r11*y)); mType |= 0x80000000 | SkMatrix::kTranslate_Mask; } void Transform::scale(float s, float x, float y) { mTransform.postScale(s, s, x, y); mType |= 0x80000000; } void Transform::set(int tx, int ty) { if (tx | ty) { mTransform.set(SkMatrix::kMTransX, SkIntToScalar(tx)); mTransform.set(SkMatrix::kMTransY, SkIntToScalar(ty)); mType |= SkMatrix::kTranslate_Mask; } else { mTransform.set(SkMatrix::kMTransX, 0); mTransform.set(SkMatrix::kMTransY, 0); mType &= ~SkMatrix::kTranslate_Mask; } } void Transform::transform(GLfixed* point, int x, int y) const { SkPoint s; mTransform.mapXY(SkIntToScalar(x), SkIntToScalar(y), &s); point[0] = SkScalarToFixed(s.fX); point[1] = SkScalarToFixed(s.fY); } Rect Transform::makeBounds(int w, int h) const { Rect r; SkRect d, s; s.set(0, 0, SkIntToScalar(w), SkIntToScalar(h)); mTransform.mapRect(&d, s); r.left = SkScalarRound( d.fLeft ); r.top = SkScalarRound( d.fTop ); r.right = SkScalarRound( d.fRight ); r.bottom = SkScalarRound( d.fBottom ); return r; } Rect Transform::transform(const Rect& bounds) const { Rect r; SkRect d, s; s.set( SkIntToScalar( bounds.left ), SkIntToScalar( bounds.top ), SkIntToScalar( bounds.right ), SkIntToScalar( bounds.bottom )); mTransform.mapRect(&d, s); r.left = SkScalarRound( d.fLeft ); r.top = SkScalarRound( d.fTop ); r.right = SkScalarRound( d.fRight ); r.bottom = SkScalarRound( d.fBottom ); return r; } Region Transform::transform(const Region& reg) const { Region out; if (UNLIKELY(transformed())) { if (LIKELY(preserveRects())) { Region::const_iterator it = reg.begin(); Region::const_iterator const end = reg.end(); while (it != end) { out.orSelf(transform(*it++)); } } else { out.set(transform(reg.bounds())); } } else { out = reg.translate(tx(), ty()); } return out; } int32_t Transform::getOrientation() const { uint32_t flags = 0; if (UNLIKELY(transformed())) { SkScalar a = mTransform[SkMatrix::kMScaleX]; SkScalar b = mTransform[SkMatrix::kMSkewX]; SkScalar c = mTransform[SkMatrix::kMSkewY]; SkScalar d = mTransform[SkMatrix::kMScaleY]; if (b==0 && c==0 && a && d) { if (a<0) flags |= FLIP_H; if (d<0) flags |= FLIP_V; } else if (b && c && a==0 && d==0) { flags |= ROT_90; if (b>0) flags |= FLIP_H; if (c<0) flags |= FLIP_V; } else { flags = 0x80000000; } } return flags; } bool Transform::preserveRects() const { return mTransform.rectStaysRect(); } // --------------------------------------------------------------------------- }; // namespace android