Home | History | Annotate | Download | only in fxcrt
      1 // Copyright 2014 PDFium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
      6 
      7 #include "core/fxcrt/fx_coordinates.h"
      8 
      9 #include <algorithm>
     10 #include <utility>
     11 
     12 #include "core/fxcrt/fx_extension.h"
     13 
     14 namespace {
     15 
     16 void MatchFloatRange(float f1, float f2, int* i1, int* i2) {
     17   int length = static_cast<int>(ceil(f2 - f1));
     18   int i1_1 = static_cast<int>(floor(f1));
     19   int i1_2 = static_cast<int>(ceil(f1));
     20   float error1 = f1 - i1_1 + fabsf(f2 - i1_1 - length);
     21   float error2 = i1_2 - f1 + fabsf(f2 - i1_2 - length);
     22 
     23   *i1 = error1 > error2 ? i1_2 : i1_1;
     24   *i2 = *i1 + length;
     25 }
     26 
     27 }  // namespace
     28 
     29 void FX_RECT::Normalize() {
     30   if (left > right)
     31     std::swap(left, right);
     32   if (top > bottom)
     33     std::swap(top, bottom);
     34 }
     35 
     36 void FX_RECT::Intersect(const FX_RECT& src) {
     37   FX_RECT src_n = src;
     38   src_n.Normalize();
     39   Normalize();
     40   left = std::max(left, src_n.left);
     41   top = std::max(top, src_n.top);
     42   right = std::min(right, src_n.right);
     43   bottom = std::min(bottom, src_n.bottom);
     44   if (left > right || top > bottom) {
     45     left = top = right = bottom = 0;
     46   }
     47 }
     48 
     49 CFX_FloatRect::CFX_FloatRect(const FX_RECT& rect) {
     50   left = rect.left;
     51   top = rect.bottom;
     52   right = rect.right;
     53   bottom = rect.top;
     54 }
     55 
     56 // static
     57 CFX_FloatRect CFX_FloatRect::GetBBox(const CFX_PointF* pPoints, int nPoints) {
     58   if (nPoints == 0)
     59     return CFX_FloatRect();
     60 
     61   float min_x = pPoints->x;
     62   float max_x = pPoints->x;
     63   float min_y = pPoints->y;
     64   float max_y = pPoints->y;
     65   for (int i = 1; i < nPoints; i++) {
     66     min_x = std::min(min_x, pPoints[i].x);
     67     max_x = std::max(max_x, pPoints[i].x);
     68     min_y = std::min(min_y, pPoints[i].y);
     69     max_y = std::max(max_y, pPoints[i].y);
     70   }
     71   return CFX_FloatRect(min_x, min_y, max_x, max_y);
     72 }
     73 
     74 void CFX_FloatRect::Normalize() {
     75   if (left > right)
     76     std::swap(left, right);
     77   if (bottom > top)
     78     std::swap(top, bottom);
     79 }
     80 
     81 void CFX_FloatRect::Reset() {
     82   left = 0.0f;
     83   right = 0.0f;
     84   bottom = 0.0f;
     85   top = 0.0f;
     86 }
     87 
     88 void CFX_FloatRect::Intersect(const CFX_FloatRect& other_rect) {
     89   Normalize();
     90   CFX_FloatRect other = other_rect;
     91   other.Normalize();
     92   left = std::max(left, other.left);
     93   bottom = std::max(bottom, other.bottom);
     94   right = std::min(right, other.right);
     95   top = std::min(top, other.top);
     96   if (left > right || bottom > top)
     97     Reset();
     98 }
     99 
    100 void CFX_FloatRect::Union(const CFX_FloatRect& other_rect) {
    101   Normalize();
    102   CFX_FloatRect other = other_rect;
    103   other.Normalize();
    104   left = std::min(left, other.left);
    105   bottom = std::min(bottom, other.bottom);
    106   right = std::max(right, other.right);
    107   top = std::max(top, other.top);
    108 }
    109 
    110 FX_RECT CFX_FloatRect::GetOuterRect() const {
    111   FX_RECT rect;
    112   rect.left = static_cast<int>(floor(left));
    113   rect.bottom = static_cast<int>(ceil(top));
    114   rect.right = static_cast<int>(ceil(right));
    115   rect.top = static_cast<int>(floor(bottom));
    116   rect.Normalize();
    117   return rect;
    118 }
    119 
    120 FX_RECT CFX_FloatRect::GetInnerRect() const {
    121   FX_RECT rect;
    122   rect.left = static_cast<int>(ceil(left));
    123   rect.bottom = static_cast<int>(floor(top));
    124   rect.right = static_cast<int>(floor(right));
    125   rect.top = static_cast<int>(ceil(bottom));
    126   rect.Normalize();
    127   return rect;
    128 }
    129 
    130 FX_RECT CFX_FloatRect::GetClosestRect() const {
    131   FX_RECT rect;
    132   MatchFloatRange(left, right, &rect.left, &rect.right);
    133   MatchFloatRange(bottom, top, &rect.top, &rect.bottom);
    134   rect.Normalize();
    135   return rect;
    136 }
    137 
    138 CFX_FloatRect CFX_FloatRect::GetCenterSquare() const {
    139   float fWidth = right - left;
    140   float fHeight = top - bottom;
    141   float fHalfWidth = (fWidth > fHeight) ? fHeight / 2 : fWidth / 2;
    142 
    143   float fCenterX = (left + right) / 2.0f;
    144   float fCenterY = (top + bottom) / 2.0f;
    145   return CFX_FloatRect(fCenterX - fHalfWidth, fCenterY - fHalfWidth,
    146                        fCenterX + fHalfWidth, fCenterY + fHalfWidth);
    147 }
    148 
    149 bool CFX_FloatRect::Contains(const CFX_PointF& point) const {
    150   CFX_FloatRect n1(*this);
    151   n1.Normalize();
    152   return point.x <= n1.right && point.x >= n1.left && point.y <= n1.top &&
    153          point.y >= n1.bottom;
    154 }
    155 
    156 bool CFX_FloatRect::Contains(const CFX_FloatRect& other_rect) const {
    157   CFX_FloatRect n1(*this);
    158   CFX_FloatRect n2(other_rect);
    159   n1.Normalize();
    160   n2.Normalize();
    161   return n2.left >= n1.left && n2.right <= n1.right && n2.bottom >= n1.bottom &&
    162          n2.top <= n1.top;
    163 }
    164 
    165 void CFX_FloatRect::UpdateRect(const CFX_PointF& point) {
    166   left = std::min(left, point.x);
    167   bottom = std::min(bottom, point.y);
    168   right = std::max(right, point.x);
    169   top = std::max(top, point.y);
    170 }
    171 
    172 void CFX_FloatRect::Scale(float fScale) {
    173   left *= fScale;
    174   bottom *= fScale;
    175   right *= fScale;
    176   top *= fScale;
    177 }
    178 
    179 void CFX_FloatRect::ScaleFromCenterPoint(float fScale) {
    180   float fHalfWidth = (right - left) / 2.0f;
    181   float fHalfHeight = (top - bottom) / 2.0f;
    182 
    183   float center_x = (left + right) / 2;
    184   float center_y = (top + bottom) / 2;
    185 
    186   left = center_x - fHalfWidth * fScale;
    187   bottom = center_y - fHalfHeight * fScale;
    188   right = center_x + fHalfWidth * fScale;
    189   top = center_y + fHalfHeight * fScale;
    190 }
    191 
    192 FX_RECT CFX_FloatRect::ToFxRect() const {
    193   return FX_RECT(static_cast<int>(left), static_cast<int>(top),
    194                  static_cast<int>(right), static_cast<int>(bottom));
    195 }
    196 
    197 FX_RECT CFX_FloatRect::ToRoundedFxRect() const {
    198   return FX_RECT(FXSYS_round(left), FXSYS_round(top), FXSYS_round(right),
    199                  FXSYS_round(bottom));
    200 }
    201 
    202 #ifndef NDEBUG
    203 std::ostream& operator<<(std::ostream& os, const CFX_FloatRect& rect) {
    204   os << "rect[" << rect.Width() << "x" << rect.Height() << " (" << rect.left
    205      << ", " << rect.bottom << ")]";
    206   return os;
    207 }
    208 #endif
    209 
    210 CFX_Matrix CFX_Matrix::GetInverse() const {
    211   CFX_Matrix inverse;
    212   float i = a * d - b * c;
    213   if (fabs(i) == 0)
    214     return inverse;
    215 
    216   float j = -i;
    217   inverse.a = d / i;
    218   inverse.b = b / j;
    219   inverse.c = c / j;
    220   inverse.d = a / i;
    221   inverse.e = (c * f - d * e) / i;
    222   inverse.f = (a * f - b * e) / j;
    223   return inverse;
    224 }
    225 
    226 void CFX_Matrix::Concat(const CFX_Matrix& m, bool bPrepended) {
    227   ConcatInternal(m, bPrepended);
    228 }
    229 
    230 void CFX_Matrix::ConcatInverse(const CFX_Matrix& src, bool bPrepended) {
    231   Concat(src.GetInverse(), bPrepended);
    232 }
    233 
    234 bool CFX_Matrix::Is90Rotated() const {
    235   return fabs(a * 1000) < fabs(b) && fabs(d * 1000) < fabs(c);
    236 }
    237 
    238 bool CFX_Matrix::IsScaled() const {
    239   return fabs(b * 1000) < fabs(a) && fabs(c * 1000) < fabs(d);
    240 }
    241 
    242 void CFX_Matrix::Translate(float x, float y, bool bPrepended) {
    243   if (bPrepended) {
    244     e += x * a + y * c;
    245     f += y * d + x * b;
    246     return;
    247   }
    248   e += x;
    249   f += y;
    250 }
    251 
    252 void CFX_Matrix::Scale(float sx, float sy, bool bPrepended) {
    253   a *= sx;
    254   d *= sy;
    255   if (bPrepended) {
    256     b *= sx;
    257     c *= sy;
    258     return;
    259   }
    260 
    261   b *= sy;
    262   c *= sx;
    263   e *= sx;
    264   f *= sy;
    265 }
    266 
    267 void CFX_Matrix::Rotate(float fRadian, bool bPrepended) {
    268   float cosValue = cos(fRadian);
    269   float sinValue = sin(fRadian);
    270   ConcatInternal(CFX_Matrix(cosValue, sinValue, -sinValue, cosValue, 0, 0),
    271                  bPrepended);
    272 }
    273 
    274 void CFX_Matrix::RotateAt(float fRadian, float dx, float dy, bool bPrepended) {
    275   Translate(dx, dy, bPrepended);
    276   Rotate(fRadian, bPrepended);
    277   Translate(-dx, -dy, bPrepended);
    278 }
    279 
    280 void CFX_Matrix::Shear(float fAlphaRadian, float fBetaRadian, bool bPrepended) {
    281   ConcatInternal(CFX_Matrix(1, tan(fAlphaRadian), tan(fBetaRadian), 1, 0, 0),
    282                  bPrepended);
    283 }
    284 
    285 void CFX_Matrix::MatchRect(const CFX_FloatRect& dest,
    286                            const CFX_FloatRect& src) {
    287   float fDiff = src.left - src.right;
    288   a = fabs(fDiff) < 0.001f ? 1 : (dest.left - dest.right) / fDiff;
    289 
    290   fDiff = src.bottom - src.top;
    291   d = fabs(fDiff) < 0.001f ? 1 : (dest.bottom - dest.top) / fDiff;
    292   e = dest.left - src.left * a;
    293   f = dest.bottom - src.bottom * d;
    294   b = 0;
    295   c = 0;
    296 }
    297 
    298 float CFX_Matrix::GetXUnit() const {
    299   if (b == 0)
    300     return (a > 0 ? a : -a);
    301   if (a == 0)
    302     return (b > 0 ? b : -b);
    303   return sqrt(a * a + b * b);
    304 }
    305 
    306 float CFX_Matrix::GetYUnit() const {
    307   if (c == 0)
    308     return (d > 0 ? d : -d);
    309   if (d == 0)
    310     return (c > 0 ? c : -c);
    311   return sqrt(c * c + d * d);
    312 }
    313 
    314 CFX_FloatRect CFX_Matrix::GetUnitRect() const {
    315   return TransformRect(CFX_FloatRect(0.f, 0.f, 1.f, 1.f));
    316 }
    317 
    318 float CFX_Matrix::TransformXDistance(float dx) const {
    319   float fx = a * dx;
    320   float fy = b * dx;
    321   return sqrt(fx * fx + fy * fy);
    322 }
    323 
    324 float CFX_Matrix::TransformDistance(float distance) const {
    325   return distance * (GetXUnit() + GetYUnit()) / 2;
    326 }
    327 
    328 CFX_PointF CFX_Matrix::Transform(const CFX_PointF& point) const {
    329   return CFX_PointF(a * point.x + c * point.y + e,
    330                     b * point.x + d * point.y + f);
    331 }
    332 std::tuple<float, float, float, float> CFX_Matrix::TransformRect(
    333     const float& left,
    334     const float& right,
    335     const float& top,
    336     const float& bottom) const {
    337   CFX_PointF points[] = {
    338       {left, top}, {left, bottom}, {right, top}, {right, bottom}};
    339   for (int i = 0; i < 4; i++)
    340     points[i] = Transform(points[i]);
    341 
    342   float new_right = points[0].x;
    343   float new_left = points[0].x;
    344   float new_top = points[0].y;
    345   float new_bottom = points[0].y;
    346   for (int i = 1; i < 4; i++) {
    347     new_right = std::max(new_right, points[i].x);
    348     new_left = std::min(new_left, points[i].x);
    349     new_top = std::max(new_top, points[i].y);
    350     new_bottom = std::min(new_bottom, points[i].y);
    351   }
    352   return std::make_tuple(new_left, new_right, new_top, new_bottom);
    353 }
    354 
    355 CFX_RectF CFX_Matrix::TransformRect(const CFX_RectF& rect) const {
    356   float left;
    357   float right;
    358   float bottom;
    359   float top;
    360   std::tie(left, right, bottom, top) =
    361       TransformRect(rect.left, rect.right(), rect.bottom(), rect.top);
    362   return CFX_RectF(left, top, right - left, bottom - top);
    363 }
    364 
    365 CFX_FloatRect CFX_Matrix::TransformRect(const CFX_FloatRect& rect) const {
    366   float left;
    367   float right;
    368   float top;
    369   float bottom;
    370   std::tie(left, right, top, bottom) =
    371       TransformRect(rect.left, rect.right, rect.top, rect.bottom);
    372   return CFX_FloatRect(left, bottom, right, top);
    373 }
    374 
    375 void CFX_Matrix::ConcatInternal(const CFX_Matrix& other, bool prepend) {
    376   CFX_Matrix left;
    377   CFX_Matrix right;
    378   if (prepend) {
    379     left = other;
    380     right = *this;
    381   } else {
    382     left = *this;
    383     right = other;
    384   }
    385 
    386   a = left.a * right.a + left.b * right.c;
    387   b = left.a * right.b + left.b * right.d;
    388   c = left.c * right.a + left.d * right.c;
    389   d = left.c * right.b + left.d * right.d;
    390   e = left.e * right.a + left.f * right.c + right.e;
    391   f = left.e * right.b + left.f * right.d + right.f;
    392 }
    393