// Copyright 2014 PDFium Authors. All rights reserved. | |
// Use of this source code is governed by a BSD-style license that can be | |
// found in the LICENSE file. | |
// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com | |
#include "../../include/fxcrt/fx_ext.h" | |
void FX_RECT::Normalize() | |
{ | |
if (left > right) { | |
int temp = left; | |
left = right; | |
right = temp; | |
} | |
if (top > bottom) { | |
int temp = top; | |
top = bottom; | |
bottom = temp; | |
} | |
} | |
void FX_RECT::Intersect(const FX_RECT& src) | |
{ | |
FX_RECT src_n = src; | |
src_n.Normalize(); | |
Normalize(); | |
left = left > src_n.left ? left : src_n.left; | |
top = top > src_n.top ? top : src_n.top; | |
right = right < src_n.right ? right : src_n.right; | |
bottom = bottom < src_n.bottom ? bottom : src_n.bottom; | |
if (left > right || top > bottom) { | |
left = top = right = bottom = 0; | |
} | |
} | |
void FX_RECT::Union(const FX_RECT& other_rect) | |
{ | |
Normalize(); | |
FX_RECT other = other_rect; | |
other.Normalize(); | |
left = left < other.left ? left : other.left; | |
right = right > other.right ? right : other.right; | |
bottom = bottom > other.bottom ? bottom : other.bottom; | |
top = top < other.top ? top : other.top; | |
} | |
FX_BOOL GetIntersection(FX_FLOAT low1, FX_FLOAT high1, FX_FLOAT low2, FX_FLOAT high2, | |
FX_FLOAT& interlow, FX_FLOAT& interhigh) | |
{ | |
if (low1 >= high2 || low2 >= high1) { | |
return FALSE; | |
} | |
interlow = low1 > low2 ? low1 : low2; | |
interhigh = high1 > high2 ? high2 : high1; | |
return TRUE; | |
} | |
extern "C" int FXSYS_round(FX_FLOAT d) | |
{ | |
int iRet = 0; | |
if (d >= 0.0f) { | |
iRet = (int)(d + 0.5f); | |
if (iRet >= 0) { | |
return iRet; | |
} | |
return -iRet; | |
} | |
return (int)(d - 0.5f); | |
} | |
CFX_FloatRect::CFX_FloatRect(const FX_RECT& rect) | |
{ | |
left = (FX_FLOAT)(rect.left); | |
right = (FX_FLOAT)(rect.right); | |
bottom = (FX_FLOAT)(rect.top); | |
top = (FX_FLOAT)(rect.bottom); | |
} | |
void CFX_FloatRect::Normalize() | |
{ | |
FX_FLOAT temp; | |
if (left > right) { | |
temp = left; | |
left = right; | |
right = temp; | |
} | |
if (bottom > top) { | |
temp = top; | |
top = bottom; | |
bottom = temp; | |
} | |
} | |
void CFX_FloatRect::Intersect(const CFX_FloatRect& other_rect) | |
{ | |
Normalize(); | |
CFX_FloatRect other = other_rect; | |
other.Normalize(); | |
left = left > other.left ? left : other.left; | |
right = right < other.right ? right : other.right; | |
bottom = bottom > other.bottom ? bottom : other.bottom; | |
top = top < other.top ? top : other.top; | |
if (left > right || bottom > top) { | |
left = right = bottom = top = 0; | |
} | |
} | |
void CFX_FloatRect::Union(const CFX_FloatRect& other_rect) | |
{ | |
Normalize(); | |
CFX_FloatRect other = other_rect; | |
other.Normalize(); | |
left = left < other.left ? left : other.left; | |
right = right > other.right ? right : other.right; | |
bottom = bottom < other.bottom ? bottom : other.bottom; | |
top = top > other.top ? top : other.top; | |
} | |
void CFX_FloatRect::Transform(const CFX_Matrix* pMatrix) | |
{ | |
pMatrix->TransformRect(left, right, top, bottom); | |
} | |
int CFX_FloatRect::Substract4(CFX_FloatRect& s, CFX_FloatRect* pRects) | |
{ | |
Normalize(); | |
s.Normalize(); | |
int nRects = 0; | |
CFX_FloatRect rects[4]; | |
if (left < s.left) { | |
rects[nRects].left = left; | |
rects[nRects].right = s.left; | |
rects[nRects].bottom = bottom; | |
rects[nRects].top = top; | |
nRects ++; | |
} | |
if (s.left < right && s.top < top) { | |
rects[nRects].left = s.left; | |
rects[nRects].right = right; | |
rects[nRects].bottom = s.top; | |
rects[nRects].top = top; | |
nRects ++; | |
} | |
if (s.top > bottom && s.right < right) { | |
rects[nRects].left = s.right; | |
rects[nRects].right = right; | |
rects[nRects].bottom = bottom; | |
rects[nRects].top = s.top; | |
nRects ++; | |
} | |
if (s.bottom > bottom) { | |
rects[nRects].left = s.left; | |
rects[nRects].right = s.right; | |
rects[nRects].bottom = bottom; | |
rects[nRects].top = s.bottom; | |
nRects ++; | |
} | |
if (nRects == 0) { | |
return 0; | |
} | |
for (int i = 0; i < nRects; i ++) { | |
pRects[i] = rects[i]; | |
pRects[i].Intersect(*this); | |
} | |
return nRects; | |
} | |
FX_RECT CFX_FloatRect::GetOutterRect() const | |
{ | |
CFX_FloatRect rect1 = *this; | |
FX_RECT rect; | |
rect.left = (int)FXSYS_floor(rect1.left); | |
rect.right = (int)FXSYS_ceil(rect1.right); | |
rect.top = (int)FXSYS_floor(rect1.bottom); | |
rect.bottom = (int)FXSYS_ceil(rect1.top); | |
rect.Normalize(); | |
return rect; | |
} | |
FX_RECT CFX_FloatRect::GetInnerRect() const | |
{ | |
CFX_FloatRect rect1 = *this; | |
FX_RECT rect; | |
rect.left = (int)FXSYS_ceil(rect1.left); | |
rect.right = (int)FXSYS_floor(rect1.right); | |
rect.top = (int)FXSYS_ceil(rect1.bottom); | |
rect.bottom = (int)FXSYS_floor(rect1.top); | |
rect.Normalize(); | |
return rect; | |
} | |
static void _MatchFloatRange(FX_FLOAT f1, FX_FLOAT f2, int& i1, int& i2) | |
{ | |
int length = (int)FXSYS_ceil(f2 - f1); | |
int i1_1 = (int)FXSYS_floor(f1); | |
int i1_2 = (int)FXSYS_ceil(f1); | |
FX_FLOAT error1 = f1 - i1_1 + (FX_FLOAT)FXSYS_fabs(f2 - i1_1 - length); | |
FX_FLOAT error2 = i1_2 - f1 + (FX_FLOAT)FXSYS_fabs(f2 - i1_2 - length); | |
i1 = (error1 > error2) ? i1_2 : i1_1; | |
i2 = i1 + length; | |
} | |
FX_RECT CFX_FloatRect::GetClosestRect() const | |
{ | |
CFX_FloatRect rect1 = *this; | |
FX_RECT rect; | |
_MatchFloatRange(rect1.left, rect1.right, rect.left, rect.right); | |
_MatchFloatRange(rect1.bottom, rect1.top, rect.top, rect.bottom); | |
rect.Normalize(); | |
return rect; | |
} | |
FX_BOOL CFX_FloatRect::Contains(const CFX_FloatRect& other_rect) const | |
{ | |
CFX_FloatRect n1 = *this; | |
n1.Normalize(); | |
CFX_FloatRect n2 = other_rect; | |
n2.Normalize(); | |
if (n2.left >= n1.left && n2.right <= n1.right && n2.bottom >= n1.bottom && n2.top <= n1.top) { | |
return TRUE; | |
} | |
return FALSE; | |
} | |
FX_BOOL CFX_FloatRect::Contains(FX_FLOAT x, FX_FLOAT y) const | |
{ | |
CFX_FloatRect n1 = *this; | |
n1.Normalize(); | |
return x <= n1.right && x >= n1.left && y <= n1.top && y >= n1.bottom; | |
} | |
void CFX_FloatRect::UpdateRect(FX_FLOAT x, FX_FLOAT y) | |
{ | |
if (left > x) { | |
left = x; | |
} | |
if (right < x) { | |
right = x; | |
} | |
if (bottom > y) { | |
bottom = y; | |
} | |
if (top < y) { | |
top = y; | |
} | |
} | |
CFX_FloatRect CFX_FloatRect::GetBBox(const CFX_FloatPoint* pPoints, int nPoints) | |
{ | |
if (nPoints == 0) { | |
return CFX_FloatRect(); | |
} | |
FX_FLOAT min_x = pPoints->x, max_x = pPoints->x, min_y = pPoints->y, max_y = pPoints->y; | |
for (int i = 1; i < nPoints; i ++) { | |
if (min_x > pPoints[i].x) { | |
min_x = pPoints[i].x; | |
} | |
if (max_x < pPoints[i].x) { | |
max_x = pPoints[i].x; | |
} | |
if (min_y > pPoints[i].y) { | |
min_y = pPoints[i].y; | |
} | |
if (max_y < pPoints[i].y) { | |
max_y = pPoints[i].y; | |
} | |
} | |
return CFX_FloatRect(min_x, min_y, max_x, max_y); | |
} | |
void CFX_Matrix::Set(FX_FLOAT a, FX_FLOAT b, FX_FLOAT c, FX_FLOAT d, FX_FLOAT e, FX_FLOAT f) | |
{ | |
this->a = a; | |
this->b = b; | |
this->c = c; | |
this->d = d; | |
this->e = e; | |
this->f = f; | |
} | |
void CFX_Matrix::Set(const FX_FLOAT n[6]) | |
{ | |
FXSYS_memcpy32((void*)this, &n, sizeof(CFX_Matrix)); | |
} | |
void CFX_Matrix::SetReverse(const CFX_Matrix &m) | |
{ | |
FX_FLOAT i = m.a * m.d - m.b * m.c; | |
if (FXSYS_fabs(i) == 0) { | |
return; | |
} | |
FX_FLOAT j = -i; | |
a = m.d / i; | |
b = m.b / j; | |
c = m.c / j; | |
d = m.a / i; | |
e = (m.c * m.f - m.d * m.e) / i; | |
f = (m.a * m.f - m.b * m.e) / j; | |
} | |
static void FXCRT_Matrix_Concat(CFX_Matrix &m, const CFX_Matrix &m1, const CFX_Matrix &m2) | |
{ | |
FX_FLOAT aa = m1.a * m2.a + m1.b * m2.c; | |
FX_FLOAT bb = m1.a * m2.b + m1.b * m2.d; | |
FX_FLOAT cc = m1.c * m2.a + m1.d * m2.c; | |
FX_FLOAT dd = m1.c * m2.b + m1.d * m2.d; | |
FX_FLOAT ee = m1.e * m2.a + m1.f * m2.c + m2.e; | |
FX_FLOAT ff = m1.e * m2.b + m1.f * m2.d + m2.f; | |
m.a = aa, m.b = bb, m.c = cc, m.d = dd, m.e = ee, m.f = ff; | |
} | |
void CFX_Matrix::Concat(FX_FLOAT a, FX_FLOAT b, FX_FLOAT c, FX_FLOAT d, FX_FLOAT e, FX_FLOAT f, FX_BOOL bPrepended) | |
{ | |
CFX_Matrix m; | |
m.Set(a, b, c, d, e, f); | |
Concat(m, bPrepended); | |
} | |
void CFX_Matrix::Concat(const CFX_Matrix &m, FX_BOOL bPrepended) | |
{ | |
if (bPrepended) { | |
FXCRT_Matrix_Concat(*this, m, *this); | |
} else { | |
FXCRT_Matrix_Concat(*this, *this, m); | |
} | |
} | |
void CFX_Matrix::ConcatInverse(const CFX_Matrix& src, FX_BOOL bPrepended) | |
{ | |
CFX_Matrix m; | |
m.SetReverse(src); | |
Concat(m, bPrepended); | |
} | |
FX_BOOL CFX_Matrix::IsInvertible() const | |
{ | |
return FXSYS_fabs(a * d - b * c) >= 0.0001f; | |
} | |
FX_BOOL CFX_Matrix::Is90Rotated() const | |
{ | |
return FXSYS_fabs(a * 1000) < FXSYS_fabs(b) && FXSYS_fabs(d * 1000) < FXSYS_fabs(c); | |
} | |
FX_BOOL CFX_Matrix::IsScaled() const | |
{ | |
return FXSYS_fabs(b * 1000) < FXSYS_fabs(a) && FXSYS_fabs(c * 1000) < FXSYS_fabs(d); | |
} | |
void CFX_Matrix::Translate(FX_FLOAT x, FX_FLOAT y, FX_BOOL bPrepended) | |
{ | |
if (bPrepended) { | |
e += x * a + y * c; | |
f += y * d + x * b; | |
} else { | |
e += x, f += y; | |
} | |
} | |
void CFX_Matrix::Scale(FX_FLOAT sx, FX_FLOAT sy, FX_BOOL bPrepended) | |
{ | |
a *= sx, d *= sy; | |
if (bPrepended) { | |
b *= sx; | |
c *= sy; | |
} else { | |
b *= sy; | |
c *= sx; | |
e *= sx; | |
f *= sy; | |
} | |
} | |
void CFX_Matrix::Rotate(FX_FLOAT fRadian, FX_BOOL bPrepended) | |
{ | |
FX_FLOAT cosValue = FXSYS_cos(fRadian); | |
FX_FLOAT sinValue = FXSYS_sin(fRadian); | |
CFX_Matrix m; | |
m.Set(cosValue, sinValue, -sinValue, cosValue, 0, 0); | |
if (bPrepended) { | |
FXCRT_Matrix_Concat(*this, m, *this); | |
} else { | |
FXCRT_Matrix_Concat(*this, *this, m); | |
} | |
} | |
void CFX_Matrix::RotateAt(FX_FLOAT fRadian, FX_FLOAT dx, FX_FLOAT dy, FX_BOOL bPrepended) | |
{ | |
Translate(dx, dy, bPrepended); | |
Rotate(fRadian, bPrepended); | |
Translate(-dx, -dy, bPrepended); | |
} | |
void CFX_Matrix::Shear(FX_FLOAT fAlphaRadian, FX_FLOAT fBetaRadian, FX_BOOL bPrepended) | |
{ | |
CFX_Matrix m; | |
m.Set(1, FXSYS_tan(fAlphaRadian), FXSYS_tan(fBetaRadian), 1, 0, 0); | |
if (bPrepended) { | |
FXCRT_Matrix_Concat(*this, m, *this); | |
} else { | |
FXCRT_Matrix_Concat(*this, *this, m); | |
} | |
} | |
void CFX_Matrix::MatchRect(const CFX_FloatRect& dest, const CFX_FloatRect& src) | |
{ | |
FX_FLOAT fDiff = src.left - src.right; | |
a = FXSYS_fabs(fDiff) < 0.001f ? 1 : (dest.left - dest.right) / fDiff; | |
fDiff = src.bottom - src.top; | |
d = FXSYS_fabs(fDiff) < 0.001f ? 1 : (dest.bottom - dest.top) / fDiff; | |
e = dest.left - src.left * a; | |
f = dest.bottom - src.bottom * d; | |
b = 0; | |
c = 0; | |
} | |
FX_FLOAT CFX_Matrix::GetXUnit() const | |
{ | |
if (b == 0) { | |
return (a > 0 ? a : -a); | |
} | |
if (a == 0) { | |
return (b > 0 ? b : -b); | |
} | |
return FXSYS_sqrt(a * a + b * b); | |
} | |
FX_FLOAT CFX_Matrix::GetYUnit() const | |
{ | |
if (c == 0) { | |
return (d > 0 ? d : -d); | |
} | |
if (d == 0) { | |
return (c > 0 ? c : -c); | |
} | |
return FXSYS_sqrt(c * c + d * d); | |
} | |
void CFX_Matrix::GetUnitRect(CFX_RectF &rect) const | |
{ | |
rect.left = rect.top = 0; | |
rect.width = rect.height = 1; | |
TransformRect(rect); | |
} | |
CFX_FloatRect CFX_Matrix::GetUnitRect() const | |
{ | |
CFX_FloatRect rect(0, 0, 1, 1); | |
rect.Transform((const CFX_Matrix*)this); | |
return rect; | |
} | |
FX_FLOAT CFX_Matrix::GetUnitArea() const | |
{ | |
FX_FLOAT A = FXSYS_sqrt(a * a + b * b); | |
FX_FLOAT B = FXSYS_sqrt(c * c + d * d); | |
FX_FLOAT ac = a + c, bd = b + d; | |
FX_FLOAT C = FXSYS_sqrt(ac * ac + bd * bd); | |
FX_FLOAT P = (A + B + C ) / 2; | |
return FXSYS_sqrt(P * (P - A) * (P - B) * (P - C)) * 2; | |
} | |
FX_FLOAT CFX_Matrix::TransformXDistance(FX_FLOAT dx) const | |
{ | |
FX_FLOAT fx = a * dx, fy = b * dx; | |
return FXSYS_sqrt(fx * fx + fy * fy); | |
} | |
FX_INT32 CFX_Matrix::TransformXDistance(FX_INT32 dx) const | |
{ | |
FX_FLOAT fx = a * dx, fy = b * dx; | |
return FXSYS_round(FXSYS_sqrt(fx * fx + fy * fy)); | |
} | |
FX_FLOAT CFX_Matrix::TransformYDistance(FX_FLOAT dy) const | |
{ | |
FX_FLOAT fx = c * dy, fy = d * dy; | |
return FXSYS_sqrt(fx * fx + fy * fy); | |
} | |
FX_INT32 CFX_Matrix::TransformYDistance(FX_INT32 dy) const | |
{ | |
FX_FLOAT fx = c * dy, fy = d * dy; | |
return FXSYS_round(FXSYS_sqrt(fx * fx + fy * fy)); | |
} | |
FX_FLOAT CFX_Matrix::TransformDistance(FX_FLOAT dx, FX_FLOAT dy) const | |
{ | |
FX_FLOAT fx = a * dx + c * dy, fy = b * dx + d * dy; | |
return FXSYS_sqrt(fx * fx + fy * fy); | |
} | |
FX_INT32 CFX_Matrix::TransformDistance(FX_INT32 dx, FX_INT32 dy) const | |
{ | |
FX_FLOAT fx = a * dx + c * dy, fy = b * dx + d * dy; | |
return FXSYS_round(FXSYS_sqrt(fx * fx + fy * fy)); | |
} | |
FX_FLOAT CFX_Matrix::TransformDistance(FX_FLOAT distance) const | |
{ | |
return distance * (GetXUnit() + GetYUnit()) / 2; | |
} | |
void CFX_Matrix::TransformVector(CFX_VectorF &v) const | |
{ | |
FX_FLOAT fx = a * v.x + c * v.y; | |
FX_FLOAT fy = b * v.x + d * v.y; | |
v.x = fx, v.y = fy; | |
} | |
void CFX_Matrix::TransformVector(CFX_Vector &v) const | |
{ | |
FX_FLOAT fx = a * v.x + c * v.y; | |
FX_FLOAT fy = b * v.x + d * v.y; | |
v.x = FXSYS_round(fx); | |
v.y = FXSYS_round(fy); | |
} | |
void CFX_Matrix::TransformPoints(CFX_Point *points, FX_INT32 iCount) const | |
{ | |
FXSYS_assert(iCount > 0); | |
FX_FLOAT fx, fy; | |
for (FX_INT32 i = 0; i < iCount; i ++) { | |
fx = a * points->x + c * points->y + e; | |
fy = b * points->x + d * points->y + f; | |
points->x = FXSYS_round(fx); | |
points->y = FXSYS_round(fy); | |
points ++; | |
} | |
} | |
void CFX_Matrix::TransformPoints(CFX_PointF *points, FX_INT32 iCount) const | |
{ | |
FXSYS_assert(iCount > 0); | |
FX_FLOAT fx, fy; | |
for (FX_INT32 i = 0; i < iCount; i ++) { | |
fx = a * points->x + c * points->y + e; | |
fy = b * points->x + d * points->y + f; | |
points->x = fx, points->y = fy; | |
points ++; | |
} | |
} | |
void CFX_Matrix::TransformPoint(FX_FLOAT &x, FX_FLOAT &y) const | |
{ | |
FX_FLOAT fx = a * x + c * y + e; | |
FX_FLOAT fy = b * x + d * y + f; | |
x = fx, y = fy; | |
} | |
void CFX_Matrix::TransformPoint(FX_INT32 &x, FX_INT32 &y) const | |
{ | |
FX_FLOAT fx = a * x + c * y + e; | |
FX_FLOAT fy = b * x + d * y + f; | |
x = FXSYS_round(fx); | |
y = FXSYS_round(fy); | |
} | |
void CFX_Matrix::TransformRect(CFX_RectF &rect) const | |
{ | |
FX_FLOAT right = rect.right(), bottom = rect.bottom(); | |
TransformRect(rect.left, right, bottom, rect.top); | |
rect.width = right - rect.left; | |
rect.height = bottom - rect.top; | |
} | |
void CFX_Matrix::TransformRect(CFX_Rect &rect) const | |
{ | |
FX_FLOAT left = (FX_FLOAT)rect.left; | |
FX_FLOAT top = (FX_FLOAT)rect.bottom(); | |
FX_FLOAT right = (FX_FLOAT)rect.right(); | |
FX_FLOAT bottom = (FX_FLOAT)rect.top; | |
TransformRect(left, right, top, bottom); | |
rect.left = FXSYS_round(left); | |
rect.top = FXSYS_round(bottom); | |
rect.width = FXSYS_round(right - left); | |
rect.height = FXSYS_round(top - bottom); | |
} | |
void CFX_Matrix::TransformRect(FX_FLOAT& left, FX_FLOAT& right, FX_FLOAT& top, FX_FLOAT& bottom) const | |
{ | |
FX_FLOAT x[4], y[4]; | |
x[0] = left; | |
y[0] = top; | |
x[1] = left; | |
y[1] = bottom; | |
x[2] = right; | |
y[2] = top; | |
x[3] = right; | |
y[3] = bottom; | |
int i; | |
for (i = 0; i < 4; i ++) { | |
Transform(x[i], y[i], x[i], y[i]); | |
} | |
right = left = x[0]; | |
top = bottom = y[0]; | |
for (i = 1; i < 4; i ++) { | |
if (right < x[i]) { | |
right = x[i]; | |
} | |
if (left > x[i]) { | |
left = x[i]; | |
} | |
if (top < y[i]) { | |
top = y[i]; | |
} | |
if (bottom > y[i]) { | |
bottom = y[i]; | |
} | |
} | |
} |