// 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 CORE_FXCRT_INCLUDE_FX_COORDINATES_H_ #define CORE_FXCRT_INCLUDE_FX_COORDINATES_H_ #include "core/fxcrt/include/fx_basic.h" class CFX_Matrix; template class CFX_PSTemplate { public: CFX_PSTemplate() : x(0), y(0) {} CFX_PSTemplate(BaseType new_x, BaseType new_y) : x(new_x), y(new_y) {} CFX_PSTemplate(const CFX_PSTemplate& other) : x(other.x), y(other.y) {} void clear() { x = 0; y = 0; } CFX_PSTemplate operator=(const CFX_PSTemplate& other) { if (this != &other) { x = other.x; y = other.y; } return *this; } bool operator==(const CFX_PSTemplate& other) const { return x == other.x && y == other.y; } bool operator!=(const CFX_PSTemplate& other) const { return !(*this == other); } CFX_PSTemplate& operator+=(const CFX_PSTemplate& obj) { x += obj.x; y += obj.y; return *this; } CFX_PSTemplate& operator-=(const CFX_PSTemplate& obj) { x -= obj.x; y -= obj.y; return *this; } CFX_PSTemplate& operator*=(BaseType factor) { x *= factor; y *= factor; return *this; } CFX_PSTemplate& operator/=(BaseType divisor) { x /= divisor; y /= divisor; return *this; } CFX_PSTemplate operator+(const CFX_PSTemplate& other) { return CFX_PSTemplate(x + other.x, y + other.y); } CFX_PSTemplate operator-(const CFX_PSTemplate& other) { return CFX_PSTemplate(x - other.x, y - other.y); } CFX_PSTemplate operator*(BaseType factor) { return CFX_PSTemplate(x * factor, y * factor); } CFX_PSTemplate operator/(BaseType divisor) { return CFX_PSTemplate(x / divisor, y / divisor); } BaseType x; BaseType y; }; typedef CFX_PSTemplate CFX_Point; typedef CFX_PSTemplate CFX_PointF; typedef CFX_PSTemplate CFX_Size; typedef CFX_PSTemplate CFX_SizeF; typedef CFX_ArrayTemplate CFX_Points; typedef CFX_ArrayTemplate CFX_PointsF; template class CFX_VTemplate : public CFX_PSTemplate { public: using CFX_PSTemplate::x; using CFX_PSTemplate::y; CFX_VTemplate() : CFX_PSTemplate() {} CFX_VTemplate(BaseType new_x, BaseType new_y) : CFX_PSTemplate(new_x, new_y) {} CFX_VTemplate(const CFX_VTemplate& other) : CFX_PSTemplate(other) {} CFX_VTemplate(const CFX_PSTemplate& point1, const CFX_PSTemplate& point2) : CFX_PSTemplate(point2.x - point1.x, point2.y - point1.y) {} FX_FLOAT Length() const { return FXSYS_sqrt(x * x + y * y); } void Normalize() { FX_FLOAT fLen = Length(); if (fLen < 0.0001f) return; x /= fLen; y /= fLen; } void Translate(BaseType dx, BaseType dy) { x += dx; y += dy; } void Scale(BaseType sx, BaseType sy) { x *= sx; y *= sy; } void Rotate(FX_FLOAT fRadian) { FX_FLOAT cosValue = FXSYS_cos(fRadian); FX_FLOAT sinValue = FXSYS_sin(fRadian); x = x * cosValue - y * sinValue; y = x * sinValue + y * cosValue; } }; typedef CFX_VTemplate CFX_Vector; typedef CFX_VTemplate CFX_VectorF; // Rectangles. // TODO(tsepez): Consolidate all these different rectangle classes. // LTRB rectangles (y-axis runs downwards). struct FX_RECT { FX_RECT() : left(0), top(0), right(0), bottom(0) {} FX_RECT(int l, int t, int r, int b) : left(l), top(t), right(r), bottom(b) {} int Width() const { return right - left; } int Height() const { return bottom - top; } bool IsEmpty() const { return right <= left || bottom <= top; } bool Valid() const { pdfium::base::CheckedNumeric w = right; pdfium::base::CheckedNumeric h = bottom; w -= left; h -= top; return w.IsValid() && h.IsValid(); } void Normalize(); void Intersect(const FX_RECT& src); void Intersect(int l, int t, int r, int b) { Intersect(FX_RECT(l, t, r, b)); } void Union(const FX_RECT& other_rect); void Union(int l, int t, int r, int b) { Union(FX_RECT(l, t, r, b)); } void Offset(int dx, int dy) { left += dx; right += dx; top += dy; bottom += dy; } bool operator==(const FX_RECT& src) const { return left == src.left && right == src.right && top == src.top && bottom == src.bottom; } 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; } bool Contains(int x, int y) const { return x >= left && x < right && y >= top && y < bottom; } int32_t left; int32_t top; int32_t right; int32_t bottom; }; // LBRT rectangles (y-axis runs upwards). class CFX_FloatPoint { public: CFX_FloatPoint(FX_FLOAT xx, FX_FLOAT yy) : x(xx), y(yy) {} FX_FLOAT x; FX_FLOAT y; }; class CFX_FloatRect { public: CFX_FloatRect() : CFX_FloatRect(0.0f, 0.0f, 0.0f, 0.0f) {} CFX_FloatRect(FX_FLOAT l, FX_FLOAT b, FX_FLOAT r, FX_FLOAT t) : left(l), bottom(b), right(r), top(t) {} explicit CFX_FloatRect(const FX_FLOAT* pArray) : CFX_FloatRect(pArray[0], pArray[1], pArray[2], pArray[3]) {} explicit CFX_FloatRect(const FX_RECT& rect); void Normalize(); void Reset() { left = 0.0f; right = 0.0f; bottom = 0.0f; top = 0.0f; } bool IsEmpty() const { return left >= right || bottom >= top; } bool Contains(const CFX_FloatRect& other_rect) const; 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 GetOuterRect() const; FX_RECT GetClosestRect() const; int Substract4(CFX_FloatRect& substract_rect, CFX_FloatRect* pRects); void InitRect(FX_FLOAT x, FX_FLOAT y) { left = x; right = x; bottom = y; 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 other_left, FX_FLOAT other_bottom, FX_FLOAT other_right, FX_FLOAT other_top) { Normalize(); left -= other_left; bottom -= other_bottom; right += other_right; top += other_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 other_left, FX_FLOAT other_bottom, FX_FLOAT other_right, FX_FLOAT other_top) { Normalize(); left += other_left; bottom += other_bottom; right -= other_right; top -= other_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_PointF* pPoints, int nPoints); FX_RECT ToFxRect() const { return FX_RECT(static_cast(left), static_cast(top), static_cast(right), static_cast(bottom)); } FX_FLOAT left; FX_FLOAT bottom; FX_FLOAT right; FX_FLOAT top; }; // LTWH rectangles (y-axis runs downwards). template class CFX_RTemplate { public: typedef CFX_PSTemplate FXT_POINT; typedef CFX_PSTemplate FXT_SIZE; typedef CFX_VTemplate FXT_VECTOR; typedef CFX_RTemplate FXT_RECT; void Set(baseType dst_left, baseType dst_top, baseType dst_width, baseType dst_height) { left = dst_left; top = dst_top; width = dst_width; height = dst_height; } void Set(baseType dst_left, baseType dst_top, const FXT_SIZE& dst_size) { left = dst_left; top = dst_top; Size(dst_size); } void Set(const FXT_POINT& p, baseType dst_width, baseType dst_height) { TopLeft(p); width = dst_width; height = dst_height; } void Set(const FXT_POINT& p1, const FXT_POINT& p2) { TopLeft(p1); width = p2.x - p1.x; height = p2.y - p1.y; Normalize(); } void Set(const FXT_POINT& p, const FXT_VECTOR& v) { TopLeft(p); width = v.x; height = v.y; Normalize(); } void Reset() { left = 0; top = 0; width = 0; 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 off_left, baseType off_top, baseType off_right, baseType off_bottom) { left -= off_left; top -= off_top; width += off_left + off_right; height += off_top + off_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 off_left, baseType off_top, baseType off_right, baseType off_bottom) { left += off_left; top += off_top; width -= off_left + off_right; height -= off_top + off_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; } bool Contains(baseType x, baseType y) const { return x >= left && x < left + width && y >= top && y < top + height; } bool Contains(const FXT_POINT& p) const { return Contains(p.x, p.y); } 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 Union(baseType x, baseType y) { baseType r = right(); baseType 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(); baseType 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(); baseType 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 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 bool operator!=(const FXT_RECT& rc1, const FXT_RECT& rc2) { return !(rc1 == rc2); } baseType left, top; baseType width, height; }; typedef CFX_RTemplate CFX_Rect; typedef CFX_RTemplate CFX_RectF; typedef CFX_ArrayTemplate CFX_RectFArray; class CFX_Matrix { public: CFX_Matrix() { SetIdentity(); } 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); 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(int32_t x, int32_t 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; int32_t TransformXDistance(int32_t dx) const; FX_FLOAT TransformYDistance(FX_FLOAT dy) const; int32_t TransformYDistance(int32_t dy) const; FX_FLOAT TransformDistance(FX_FLOAT dx, FX_FLOAT dy) const; int32_t TransformDistance(int32_t dx, int32_t dy) const; FX_FLOAT TransformDistance(FX_FLOAT distance) const; void TransformPoint(FX_FLOAT& x, FX_FLOAT& y) const; void TransformPoint(int32_t& x, int32_t& y) 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; }; #endif // CORE_FXCRT_INCLUDE_FX_COORDINATES_H_