235 lines
6.4 KiB
C++
235 lines
6.4 KiB
C++
/*
|
|
* 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 <ui/Region.h>
|
|
|
|
#include <private/pixelflinger/ggl_fixed.h>
|
|
|
|
#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
|