// 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 #ifndef _FXCRT_COORDINATES_ #define _FXCRT_COORDINATES_ template class CFX_PSVTemplate; template class CFX_VTemplate; template class CFX_PRLTemplate; template class CFX_RTemplate; template class CFX_ETemplate; template class CFX_ATemplate; template class CFX_RRTemplate; class CFX_Matrix; template class CFX_PSVTemplate : public CFX_Object { public: typedef CFX_PSVTemplate FXT_PSV; typedef CFX_PSVTemplate FXT_POINT; typedef CFX_PSVTemplate FXT_SIZE; void Set(baseType x, baseType y) { FXT_PSV::x = x, FXT_PSV::y = y; } void Set(const FXT_PSV &psv) { FXT_PSV::x = psv.x, FXT_PSV::y = psv.y; } void Add(baseType x, baseType y) { FXT_PSV::x += x, FXT_PSV::y += y; } void Subtract(baseType x, baseType y) { FXT_PSV::x -= x, FXT_PSV::y -= y; } void Reset() { FXT_PSV::x = FXT_PSV::y = 0; } FXT_PSV& operator += (const FXT_PSV &obj) { x += obj.x; y += obj.y; return *this; } FXT_PSV& operator -= (const FXT_PSV &obj) { x -= obj.x; y -= obj.y; return *this; } FXT_PSV& operator *= (baseType lamda) { x *= lamda; y *= lamda; return *this; } FXT_PSV& operator /= (baseType lamda) { x /= lamda; y /= lamda; return *this; } friend FX_BOOL operator == (const FXT_PSV &obj1, const FXT_PSV &obj2) { return obj1.x == obj2.x && obj1.y == obj2.y; } friend FX_BOOL operator != (const FXT_PSV &obj1, const FXT_PSV &obj2) { return obj1.x != obj2.x || obj1.y != obj2.y; } friend FXT_PSV operator + (const FXT_PSV &obj1, const FXT_PSV &obj2) { CFX_PSVTemplate obj; obj.x = obj1.x + obj2.x; obj.y = obj1.y + obj2.y; return obj; } friend FXT_PSV operator - (const FXT_PSV &obj1, const FXT_PSV &obj2) { CFX_PSVTemplate obj; obj.x = obj1.x - obj2.x; obj.y = obj1.y - obj2.y; return obj; } friend FXT_PSV operator * (const FXT_PSV &obj, baseType lamda) { CFX_PSVTemplate t; t.x = obj.x * lamda; t.y = obj.y * lamda; return t; } friend FXT_PSV operator * (baseType lamda, const FXT_PSV &obj) { CFX_PSVTemplate t; t.x = lamda * obj.x; t.y = lamda * obj.y; return t; } friend FXT_PSV operator / (const FXT_PSV &obj, baseType lamda) { CFX_PSVTemplate t; t.x = obj.x / lamda; t.y = obj.y / lamda; return t; } baseType x, y; }; typedef CFX_PSVTemplate CFX_Point; typedef CFX_PSVTemplate CFX_PointF; typedef CFX_PSVTemplate CFX_Size; typedef CFX_PSVTemplate CFX_SizeF; typedef CFX_ArrayTemplate CFX_Points; typedef CFX_ArrayTemplate CFX_PointsF; typedef CFX_PSVTemplate * FX_LPPOINT; typedef CFX_PSVTemplate * FX_LPPOINTF; typedef CFX_PSVTemplate const * FX_LPCPOINT; typedef CFX_PSVTemplate const * FX_LPCPOINTF; #define CFX_FloatPoint CFX_PointF template class CFX_VTemplate: public CFX_PSVTemplate { public: typedef CFX_PSVTemplate FXT_PSV; typedef CFX_PSVTemplate FXT_POINT; typedef CFX_PSVTemplate FXT_SIZE; typedef CFX_VTemplate FXT_VECTOR; void Set(baseType x, baseType y) { FXT_PSV::x = x, FXT_PSV::y = y; } void Set(const FXT_PSV &psv) { FXT_PSV::x = psv.x, FXT_PSV::y = psv.y; } void Set(const FXT_POINT &p1, const FXT_POINT &p2) { FXT_PSV::x = p2.x - p1.x, FXT_PSV::y = p2.y - p1.y; } void Reset() { FXT_PSV::x = FXT_PSV::y = 0; } baseType SquareLength() const { return FXT_PSV::x * FXT_PSV::x + FXT_PSV::y * FXT_PSV::y; } baseType Length() const { return FXSYS_sqrt(FXT_PSV::x * FXT_PSV::x + FXT_PSV::y * FXT_PSV::y); } void Normalize() { FX_FLOAT fLen = FXSYS_sqrt(FXT_PSV::x * FXT_PSV::x + FXT_PSV::y * FXT_PSV::y); if (fLen < 0.0001f) { return; } FXT_PSV::x = ((baseType)FXT_PSV::x) / fLen; FXT_PSV::y = ((baseType)FXT_PSV::y) / fLen; } baseType DotProduct(baseType x, baseType y) const { return FXT_PSV::x * x + FXT_PSV::y * y; } baseType DotProduct(const FXT_VECTOR &v) const { return FXT_PSV::x * v.x + FXT_PSV::y * v.y; } FX_BOOL IsParallel(baseType x, baseType y) const { baseType t = FXT_PSV::x * y - FXT_PSV::y * x; return FXSYS_fabs(t) < 0x0001f; } FX_BOOL IsParallel(const FXT_VECTOR &v) const { return IsParallel(v.x, v.y); } FX_BOOL IsPerpendicular(baseType x, baseType y) const { baseType t = DotProduct(x, y); return FXSYS_fabs(t) < 0x0001f; } FX_BOOL IsPerpendicular(const FXT_VECTOR &v) const { return IsPerpendicular(v.x, v.y); } void Translate(baseType dx, baseType dy) { FXT_PSV::x += dx, FXT_PSV::y += dy; } void Scale(baseType sx, baseType sy) { FXT_PSV::x *= sx, FXT_PSV::y *= sy; } void Rotate(FX_FLOAT fRadian) { FX_FLOAT xx = (FX_FLOAT)FXT_PSV::x; FX_FLOAT yy = (FX_FLOAT)FXT_PSV::y; FX_FLOAT cosValue = FXSYS_cos(fRadian); FX_FLOAT sinValue = FXSYS_sin(fRadian); FXT_PSV::x = xx * cosValue - yy * sinValue; FXT_PSV::y = xx * sinValue + yy * cosValue; } friend FX_FLOAT Cosine(const FXT_VECTOR &v1, const FXT_VECTOR &v2) { FXSYS_assert(v1.SquareLength() != 0 && v2.SquareLength() != 0); FX_FLOAT dotProduct = v1.DotProduct(v2); return dotProduct / (FX_FLOAT)FXSYS_sqrt(v1.SquareLength() * v2.SquareLength()); } friend FX_FLOAT ArcCosine(const FXT_VECTOR &v1, const FXT_VECTOR &v2) { return (FX_FLOAT)FXSYS_acos(Cosine(v1, v2)); } friend FX_FLOAT SlopeAngle(const FXT_VECTOR &v) { CFX_VTemplate vx; vx.Set(1, 0); FX_FLOAT fSlope = ArcCosine(v, vx); return v.y < 0 ? -fSlope : fSlope; } }; typedef CFX_VTemplate CFX_Vector; typedef CFX_VTemplate CFX_VectorF; template class CFX_RTemplate: public CFX_Object { public: typedef CFX_PSVTemplate FXT_POINT; typedef CFX_PSVTemplate FXT_SIZE; typedef CFX_VTemplate FXT_VECTOR; typedef CFX_PRLTemplate FXT_PARAL; typedef CFX_RTemplate FXT_RECT; void Set(baseType left, baseType top, baseType width, baseType height) { FXT_RECT::left = left, FXT_RECT::top = top, FXT_RECT::width = width, FXT_RECT::height = height; } void Set(baseType left, baseType top, const FXT_SIZE &size) { FXT_RECT::left = left, FXT_RECT::top = top, FXT_RECT::Size(size); } void Set(const FXT_POINT &p, baseType width, baseType height) { TopLeft(p), FXT_RECT::width = width, FXT_RECT::height = height; } void Set(const FXT_POINT &p1, const FXT_POINT &p2) { TopLeft(p1), FXT_RECT::width = p2.x - p1.x, FXT_RECT::height = p2.y - p1.y, FXT_RECT::Normalize(); } void Set(const FXT_POINT &p, const FXT_VECTOR &v) { TopLeft(p), FXT_RECT::width = v.x, FXT_RECT::height = v.y, FXT_RECT::Normalize(); } void Reset() { FXT_RECT::left = FXT_RECT::top = FXT_RECT::width = FXT_RECT::height = 0; } FXT_RECT& operator += (const FXT_POINT &p) { left += p.x, top += p.y; return *this; } FXT_RECT& operator -= (const FXT_POINT &p) { left -= p.x, top -= p.y; return *this; } baseType right() const { return left + width; } baseType bottom() const { return top + height; } void Normalize() { if (width < 0) { left += width; width = -width; } if (height < 0) { top += height; height = -height; } } void Offset(baseType dx, baseType dy) { left += dx; top += dy; } void Inflate(baseType x, baseType y) { left -= x; width += x * 2; top -= y; height += y * 2; } void Inflate(const FXT_POINT &p) { Inflate(p.x, p.y); } void Inflate(baseType left, baseType top, baseType right, baseType bottom) { FXT_RECT::left -= left; FXT_RECT::top -= top; FXT_RECT::width += left + right; FXT_RECT::height += top + bottom; } void Inflate(const FXT_RECT &rt) { Inflate(rt.left, rt.top, rt.left + rt.width, rt.top + rt.height); } void Deflate(baseType x, baseType y) { left += x; width -= x * 2; top += y; height -= y * 2; } void Deflate(const FXT_POINT &p) { Deflate(p.x, p.y); } void Deflate(baseType left, baseType top, baseType right, baseType bottom) { FXT_RECT::left += left; FXT_RECT::top += top; FXT_RECT::width -= left + right; FXT_RECT::height -= top + bottom; } void Deflate(const FXT_RECT &rt) { Deflate(rt.left, rt.top, rt.top + rt.width, rt.top + rt.height); } FX_BOOL IsEmpty() const { return width <= 0 || height <= 0; } FX_BOOL IsEmpty(FX_FLOAT fEpsilon) const { return width <= fEpsilon || height <= fEpsilon; } void Empty() { width = height = 0; } FX_BOOL Contains(baseType x, baseType y) const { return x >= left && x < left + width && y >= top && y < top + height; } FX_BOOL Contains(const FXT_POINT &p) const { return Contains(p.x, p.y); } FX_BOOL Contains(const FXT_RECT &rt) const { return rt.left >= left && rt.right() <= right() && rt.top >= top && rt.bottom() <= bottom(); } baseType Width() const { return width; } baseType Height() const { return height; } FXT_SIZE Size() const { FXT_SIZE size; size.Set(width, height); return size; } void Size(FXT_SIZE s) { width = s.x, height = s.y; } FXT_POINT TopLeft() const { FXT_POINT p; p.x = left; p.y = top; return p; } FXT_POINT TopRight() const { FXT_POINT p; p.x = left + width; p.y = top; return p; } FXT_POINT BottomLeft() const { FXT_POINT p; p.x = left; p.y = top + height; return p; } FXT_POINT BottomRight() const { FXT_POINT p; p.x = left + width; p.y = top + height; return p; } void TopLeft(FXT_POINT tl) { left = tl.x; top = tl.y; } void TopRight(FXT_POINT tr) { width = tr.x - left; top = tr.y; } void BottomLeft(FXT_POINT bl) { left = bl.x; height = bl.y - top; } void BottomRight(FXT_POINT br) { width = br.x - left; height = br.y - top; } FXT_POINT Center() const { FXT_POINT p; p.x = left + width / 2; p.y = top + height / 2; return p; } void GetParallelogram(FXT_PARAL &pg) const { pg.x = left, pg.y = top; pg.x1 = width, pg.y1 = 0; pg.x2 = 0, pg.y2 = height; } void Union(baseType x, baseType y) { baseType r = right(), b = bottom(); if (left > x) { left = x; } if (r < x) { r = x; } if (top > y) { top = y; } if (b < y) { b = y; } width = r - left; height = b - top; } void Union(const FXT_POINT &p) { Union(p.x, p.y); } void Union(const FXT_RECT &rt) { baseType r = right(), b = bottom(); if (left > rt.left) { left = rt.left; } if (r < rt.right()) { r = rt.right(); } if (top > rt.top) { top = rt.top; } if (b < rt.bottom()) { b = rt.bottom(); } width = r - left; height = b - top; } void Intersect(const FXT_RECT &rt) { baseType r = right(), b = bottom(); if (left < rt.left) { left = rt.left; } if (r > rt.right()) { r = rt.right(); } if (top < rt.top) { top = rt.top; } if (b > rt.bottom()) { b = rt.bottom(); } width = r - left; height = b - top; } FX_BOOL IntersectWith(const FXT_RECT &rt) const { FXT_RECT rect = rt; rect.Intersect(*this); return !rect.IsEmpty(); } FX_BOOL IntersectWith(const FXT_RECT &rt, FX_FLOAT fEpsilon) const { FXT_RECT rect = rt; rect.Intersect(*this); return !rect.IsEmpty(fEpsilon); } friend FX_BOOL operator == (const FXT_RECT &rc1, const FXT_RECT &rc2) { return rc1.left == rc2.left && rc1.top == rc2.top && rc1.width == rc2.width && rc1.height == rc2.height; } friend FX_BOOL operator != (const FXT_RECT &rc1, const FXT_RECT &rc2) { return rc1.left != rc2.left || rc1.top != rc2.top || rc1.width != rc2.width || rc1.height != rc2.height; } baseType left, top; baseType width, height; }; typedef CFX_RTemplate CFX_Rect; typedef CFX_RTemplate CFX_RectF; typedef CFX_RTemplate * FX_LPRECT; typedef CFX_RTemplate * FX_LPRECTF; typedef CFX_RTemplate const * FX_LPCRECT; typedef CFX_RTemplate const * FX_LPCRECTF; typedef CFX_ArrayTemplate CFX_RectFArray; struct FX_RECT { int left; int top; int right; int bottom; FX_RECT() {} FX_RECT(int left1, int top1, int right1, int bottom1) { left = left1; top = top1; right = right1; bottom = bottom1; } int Width() const { return right - left; } int Height() const { return bottom - top; } FX_BOOL IsEmpty() const { return right <= left || bottom <= top; } void Normalize(); void Intersect(const FX_RECT& src); void Intersect(int left1, int top1, int right1, int bottom1) { Intersect(FX_RECT(left1, top1, right1, bottom1)); } void Union(const FX_RECT& other_rect); FX_BOOL operator == (const FX_RECT& src) const { return left == src.left && right == src.right && top == src.top && bottom == src.bottom; } void Offset(int dx, int dy) { left += dx; right += dx; top += dy; bottom += dy; } FX_BOOL Contains(const FX_RECT& other_rect) const { return other_rect.left >= left && other_rect.right <= right && other_rect.top >= top && other_rect.bottom <= bottom; } FX_BOOL Contains(int x, int y) const { return x >= left && x < right && y >= top && y < bottom; } }; struct FX_SMALL_RECT { FX_SHORT Left; FX_SHORT Top; FX_SHORT Right; FX_SHORT Bottom; }; class CFX_FloatRect : public CFX_Object { public: CFX_FloatRect() { left = right = bottom = top = 0; } CFX_FloatRect(FX_FLOAT left1, FX_FLOAT bottom1, FX_FLOAT right1, FX_FLOAT top1) { left = left1; bottom = bottom1; right = right1; top = top1; } CFX_FloatRect(const FX_FLOAT* pArray) { left = pArray[0]; bottom = pArray[1]; right = pArray[2]; top = pArray[3]; } CFX_FloatRect(const FX_RECT& rect); FX_BOOL IsEmpty() const { return left >= right || bottom >= top; } void Normalize(); void Reset() { left = right = bottom = top = 0; } FX_BOOL Contains(const CFX_FloatRect& other_rect) const; FX_BOOL Contains(FX_FLOAT x, FX_FLOAT y) const; void Transform(const CFX_Matrix* pMatrix); void Intersect(const CFX_FloatRect& other_rect); void Union(const CFX_FloatRect& other_rect); FX_RECT GetInnerRect() const; FX_RECT GetOutterRect() const; FX_RECT GetClosestRect() const; int Substract4(CFX_FloatRect& substract_rect, CFX_FloatRect* pRects); void InitRect(FX_FLOAT x, FX_FLOAT y) { left = right = x; bottom = top = y; } void UpdateRect(FX_FLOAT x, FX_FLOAT y); FX_FLOAT Width() const { return right - left; } FX_FLOAT Height() const { return top - bottom; } void Inflate(FX_FLOAT x, FX_FLOAT y) { Normalize(); left -= x; right += x; bottom -= y; top += y; } void Inflate(FX_FLOAT left, FX_FLOAT bottom, FX_FLOAT right, FX_FLOAT top) { Normalize(); this->left -= left; this->bottom -= bottom; this->right += right; this->top += top; } void Inflate(const CFX_FloatRect &rt) { Inflate(rt.left, rt.bottom, rt.right, rt.top); } void Deflate(FX_FLOAT x, FX_FLOAT y) { Normalize(); left += x; right -= x; bottom += y; top -= y; } void Deflate(FX_FLOAT left, FX_FLOAT bottom, FX_FLOAT right, FX_FLOAT top) { Normalize(); this->left += left; this->bottom += bottom; this->right -= right; this->top -= top; } void Deflate(const CFX_FloatRect &rt) { Deflate(rt.left, rt.bottom, rt.right, rt.top); } void Translate(FX_FLOAT e, FX_FLOAT f) { left += e; right += e; top += f; bottom += f; } static CFX_FloatRect GetBBox(const CFX_FloatPoint* pPoints, int nPoints); FX_FLOAT left; FX_FLOAT right; FX_FLOAT bottom; FX_FLOAT top; }; class CFX_Matrix : public CFX_Object { public: CFX_Matrix() { a = d = 1; b = c = e = f = 0; } CFX_Matrix(FX_FLOAT a1, FX_FLOAT b1, FX_FLOAT c1, FX_FLOAT d1, FX_FLOAT e1, FX_FLOAT f1) { a = a1; b = b1; c = c1; d = d1; e = e1; f = f1; } void Set(FX_FLOAT a, FX_FLOAT b, FX_FLOAT c, FX_FLOAT d, FX_FLOAT e, FX_FLOAT f); void Set(const FX_FLOAT n[6]); void SetIdentity() { a = d = 1; b = c = e = f = 0; } void SetReverse(const CFX_Matrix &m); void Concat(FX_FLOAT a, FX_FLOAT b, FX_FLOAT c, FX_FLOAT d, FX_FLOAT e, FX_FLOAT f, FX_BOOL bPrepended = FALSE); void Concat(const CFX_Matrix &m, FX_BOOL bPrepended = FALSE); void ConcatInverse(const CFX_Matrix& m, FX_BOOL bPrepended = FALSE); void Reset() { SetIdentity(); } void Copy(const CFX_Matrix& m) { *this = m; } FX_BOOL IsIdentity() const { return a == 1 && b == 0 && c == 0 && d == 1 && e == 0 && f == 0; } FX_BOOL IsInvertible() const; FX_BOOL Is90Rotated() const; FX_BOOL IsScaled() const; void Translate(FX_FLOAT x, FX_FLOAT y, FX_BOOL bPrepended = FALSE); void TranslateI(FX_INT32 x, FX_INT32 y, FX_BOOL bPrepended = FALSE) { Translate((FX_FLOAT)x, (FX_FLOAT)y, bPrepended); } void Scale(FX_FLOAT sx, FX_FLOAT sy, FX_BOOL bPrepended = FALSE); void Rotate(FX_FLOAT fRadian, FX_BOOL bPrepended = FALSE); void RotateAt(FX_FLOAT fRadian, FX_FLOAT x, FX_FLOAT y, FX_BOOL bPrepended = FALSE); void Shear(FX_FLOAT fAlphaRadian, FX_FLOAT fBetaRadian, FX_BOOL bPrepended = FALSE); void MatchRect(const CFX_FloatRect &dest, const CFX_FloatRect &src); FX_FLOAT GetXUnit() const; FX_FLOAT GetYUnit() const; void GetUnitRect(CFX_RectF &rect) const; CFX_FloatRect GetUnitRect() const; FX_FLOAT GetUnitArea() const; FX_FLOAT TransformXDistance(FX_FLOAT dx) const; FX_INT32 TransformXDistance(FX_INT32 dx) const; FX_FLOAT TransformYDistance(FX_FLOAT dy) const; FX_INT32 TransformYDistance(FX_INT32 dy) const; FX_FLOAT TransformDistance(FX_FLOAT dx, FX_FLOAT dy) const; FX_INT32 TransformDistance(FX_INT32 dx, FX_INT32 dy) const; FX_FLOAT TransformDistance(FX_FLOAT distance) const; void TransformPoint(FX_FLOAT &x, FX_FLOAT &y) const; void TransformPoint(FX_INT32 &x, FX_INT32 &y) const; void TransformPoints(CFX_PointF *points, FX_INT32 iCount) const; void TransformPoints(CFX_Point *points, FX_INT32 iCount) const; void Transform(FX_FLOAT& x, FX_FLOAT& y) const { TransformPoint(x, y); } void Transform(FX_FLOAT x, FX_FLOAT y, FX_FLOAT& x1, FX_FLOAT& y1) const { x1 = x, y1 = y; TransformPoint(x1, y1); } void TransformVector(CFX_VectorF &v) const; void TransformVector(CFX_Vector &v) const; void TransformRect(CFX_RectF &rect) const; void TransformRect(CFX_Rect &rect) const; void TransformRect(FX_FLOAT& left, FX_FLOAT& right, FX_FLOAT& top, FX_FLOAT& bottom) const; void TransformRect(CFX_FloatRect& rect) const { TransformRect(rect.left, rect.right, rect.top, rect.bottom); } FX_FLOAT GetA() const { return a; } FX_FLOAT GetB() const { return b; } FX_FLOAT GetC() const { return c; } FX_FLOAT GetD() const { return d; } FX_FLOAT GetE() const { return e; } FX_FLOAT GetF() const { return f; } public: FX_FLOAT a; FX_FLOAT b; FX_FLOAT c; FX_FLOAT d; FX_FLOAT e; FX_FLOAT f; }; #define CFX_AffineMatrix CFX_Matrix #endif