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 <limits.h>
      8 
      9 #include <algorithm>
     10 
     11 #include "core/fxcrt/fx_coordinates.h"
     12 #include "core/fxcrt/fx_ext.h"
     13 
     14 namespace {
     15 
     16 void MatchFloatRange(FX_FLOAT f1, FX_FLOAT f2, int* i1, int* i2) {
     17   int length = static_cast<int>(FXSYS_ceil(f2 - f1));
     18   int i1_1 = static_cast<int>(FXSYS_floor(f1));
     19   int i1_2 = static_cast<int>(FXSYS_ceil(f1));
     20   FX_FLOAT error1 = f1 - i1_1 + (FX_FLOAT)FXSYS_fabs(f2 - i1_1 - length);
     21   FX_FLOAT error2 = i1_2 - f1 + (FX_FLOAT)FXSYS_fabs(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     int temp = left;
     32     left = right;
     33     right = temp;
     34   }
     35   if (top > bottom) {
     36     int temp = top;
     37     top = bottom;
     38     bottom = temp;
     39   }
     40 }
     41 void FX_RECT::Intersect(const FX_RECT& src) {
     42   FX_RECT src_n = src;
     43   src_n.Normalize();
     44   Normalize();
     45   left = left > src_n.left ? left : src_n.left;
     46   top = top > src_n.top ? top : src_n.top;
     47   right = right < src_n.right ? right : src_n.right;
     48   bottom = bottom < src_n.bottom ? bottom : src_n.bottom;
     49   if (left > right || top > bottom) {
     50     left = top = right = bottom = 0;
     51   }
     52 }
     53 
     54 bool GetIntersection(FX_FLOAT low1,
     55                      FX_FLOAT high1,
     56                      FX_FLOAT low2,
     57                      FX_FLOAT high2,
     58                      FX_FLOAT& interlow,
     59                      FX_FLOAT& interhigh) {
     60   if (low1 >= high2 || low2 >= high1) {
     61     return false;
     62   }
     63   interlow = low1 > low2 ? low1 : low2;
     64   interhigh = high1 > high2 ? high2 : high1;
     65   return true;
     66 }
     67 extern "C" int FXSYS_round(FX_FLOAT d) {
     68   if (d < (FX_FLOAT)INT_MIN) {
     69     return INT_MIN;
     70   }
     71   if (d > (FX_FLOAT)INT_MAX) {
     72     return INT_MAX;
     73   }
     74 
     75   return (int)round(d);
     76 }
     77 CFX_FloatRect::CFX_FloatRect(const FX_RECT& rect) {
     78   left = (FX_FLOAT)(rect.left);
     79   right = (FX_FLOAT)(rect.right);
     80   bottom = (FX_FLOAT)(rect.top);
     81   top = (FX_FLOAT)(rect.bottom);
     82 }
     83 void CFX_FloatRect::Normalize() {
     84   FX_FLOAT temp;
     85   if (left > right) {
     86     temp = left;
     87     left = right;
     88     right = temp;
     89   }
     90   if (bottom > top) {
     91     temp = top;
     92     top = bottom;
     93     bottom = temp;
     94   }
     95 }
     96 void CFX_FloatRect::Intersect(const CFX_FloatRect& other_rect) {
     97   Normalize();
     98   CFX_FloatRect other = other_rect;
     99   other.Normalize();
    100   left = left > other.left ? left : other.left;
    101   right = right < other.right ? right : other.right;
    102   bottom = bottom > other.bottom ? bottom : other.bottom;
    103   top = top < other.top ? top : other.top;
    104   if (left > right || bottom > top) {
    105     left = right = bottom = top = 0;
    106   }
    107 }
    108 void CFX_FloatRect::Union(const CFX_FloatRect& other_rect) {
    109   Normalize();
    110   CFX_FloatRect other = other_rect;
    111   other.Normalize();
    112   left = left < other.left ? left : other.left;
    113   right = right > other.right ? right : other.right;
    114   bottom = bottom < other.bottom ? bottom : other.bottom;
    115   top = top > other.top ? top : other.top;
    116 }
    117 
    118 int CFX_FloatRect::Substract4(CFX_FloatRect& s, CFX_FloatRect* pRects) {
    119   Normalize();
    120   s.Normalize();
    121   int nRects = 0;
    122   CFX_FloatRect rects[4];
    123   if (left < s.left) {
    124     rects[nRects].left = left;
    125     rects[nRects].right = s.left;
    126     rects[nRects].bottom = bottom;
    127     rects[nRects].top = top;
    128     nRects++;
    129   }
    130   if (s.left < right && s.top < top) {
    131     rects[nRects].left = s.left;
    132     rects[nRects].right = right;
    133     rects[nRects].bottom = s.top;
    134     rects[nRects].top = top;
    135     nRects++;
    136   }
    137   if (s.top > bottom && s.right < right) {
    138     rects[nRects].left = s.right;
    139     rects[nRects].right = right;
    140     rects[nRects].bottom = bottom;
    141     rects[nRects].top = s.top;
    142     nRects++;
    143   }
    144   if (s.bottom > bottom) {
    145     rects[nRects].left = s.left;
    146     rects[nRects].right = s.right;
    147     rects[nRects].bottom = bottom;
    148     rects[nRects].top = s.bottom;
    149     nRects++;
    150   }
    151   if (nRects == 0) {
    152     return 0;
    153   }
    154   for (int i = 0; i < nRects; i++) {
    155     pRects[i] = rects[i];
    156     pRects[i].Intersect(*this);
    157   }
    158   return nRects;
    159 }
    160 
    161 FX_RECT CFX_FloatRect::GetOuterRect() const {
    162   CFX_FloatRect rect1 = *this;
    163   FX_RECT rect;
    164   rect.left = (int)FXSYS_floor(rect1.left);
    165   rect.right = (int)FXSYS_ceil(rect1.right);
    166   rect.top = (int)FXSYS_floor(rect1.bottom);
    167   rect.bottom = (int)FXSYS_ceil(rect1.top);
    168   rect.Normalize();
    169   return rect;
    170 }
    171 
    172 FX_RECT CFX_FloatRect::GetInnerRect() const {
    173   CFX_FloatRect rect1 = *this;
    174   FX_RECT rect;
    175   rect.left = (int)FXSYS_ceil(rect1.left);
    176   rect.right = (int)FXSYS_floor(rect1.right);
    177   rect.top = (int)FXSYS_ceil(rect1.bottom);
    178   rect.bottom = (int)FXSYS_floor(rect1.top);
    179   rect.Normalize();
    180   return rect;
    181 }
    182 
    183 FX_RECT CFX_FloatRect::GetClosestRect() const {
    184   CFX_FloatRect rect1 = *this;
    185   FX_RECT rect;
    186   MatchFloatRange(rect1.left, rect1.right, &rect.left, &rect.right);
    187   MatchFloatRange(rect1.bottom, rect1.top, &rect.top, &rect.bottom);
    188   rect.Normalize();
    189   return rect;
    190 }
    191 
    192 bool CFX_FloatRect::Contains(const CFX_PointF& point) const {
    193   CFX_FloatRect n1(*this);
    194   n1.Normalize();
    195   return point.x <= n1.right && point.x >= n1.left && point.y <= n1.top &&
    196          point.y >= n1.bottom;
    197 }
    198 
    199 bool CFX_FloatRect::Contains(const CFX_FloatRect& other_rect) const {
    200   CFX_FloatRect n1(*this);
    201   CFX_FloatRect n2(other_rect);
    202   n1.Normalize();
    203   n2.Normalize();
    204   return n2.left >= n1.left && n2.right <= n1.right && n2.bottom >= n1.bottom &&
    205          n2.top <= n1.top;
    206 }
    207 
    208 void CFX_FloatRect::UpdateRect(FX_FLOAT x, FX_FLOAT y) {
    209   left = std::min(left, x);
    210   right = std::max(right, x);
    211   bottom = std::min(bottom, y);
    212   top = std::max(top, y);
    213 }
    214 
    215 CFX_FloatRect CFX_FloatRect::GetBBox(const CFX_PointF* pPoints, int nPoints) {
    216   if (nPoints == 0)
    217     return CFX_FloatRect();
    218 
    219   FX_FLOAT min_x = pPoints->x;
    220   FX_FLOAT max_x = pPoints->x;
    221   FX_FLOAT min_y = pPoints->y;
    222   FX_FLOAT max_y = pPoints->y;
    223   for (int i = 1; i < nPoints; i++) {
    224     min_x = std::min(min_x, pPoints[i].x);
    225     max_x = std::max(max_x, pPoints[i].x);
    226     min_y = std::min(min_y, pPoints[i].y);
    227     max_y = std::max(max_y, pPoints[i].y);
    228   }
    229   return CFX_FloatRect(min_x, min_y, max_x, max_y);
    230 }
    231 
    232 void CFX_Matrix::SetReverse(const CFX_Matrix& m) {
    233   FX_FLOAT i = m.a * m.d - m.b * m.c;
    234   if (FXSYS_fabs(i) == 0)
    235     return;
    236 
    237   FX_FLOAT j = -i;
    238   a = m.d / i;
    239   b = m.b / j;
    240   c = m.c / j;
    241   d = m.a / i;
    242   e = (m.c * m.f - m.d * m.e) / i;
    243   f = (m.a * m.f - m.b * m.e) / j;
    244 }
    245 
    246 void CFX_Matrix::Concat(const CFX_Matrix& m, bool bPrepended) {
    247   ConcatInternal(m, bPrepended);
    248 }
    249 
    250 void CFX_Matrix::ConcatInverse(const CFX_Matrix& src, bool bPrepended) {
    251   CFX_Matrix m;
    252   m.SetReverse(src);
    253   Concat(m, bPrepended);
    254 }
    255 
    256 bool CFX_Matrix::Is90Rotated() const {
    257   return FXSYS_fabs(a * 1000) < FXSYS_fabs(b) &&
    258          FXSYS_fabs(d * 1000) < FXSYS_fabs(c);
    259 }
    260 
    261 bool CFX_Matrix::IsScaled() const {
    262   return FXSYS_fabs(b * 1000) < FXSYS_fabs(a) &&
    263          FXSYS_fabs(c * 1000) < FXSYS_fabs(d);
    264 }
    265 
    266 void CFX_Matrix::Translate(FX_FLOAT x, FX_FLOAT y, bool bPrepended) {
    267   if (bPrepended) {
    268     e += x * a + y * c;
    269     f += y * d + x * b;
    270     return;
    271   }
    272   e += x;
    273   f += y;
    274 }
    275 
    276 void CFX_Matrix::Scale(FX_FLOAT sx, FX_FLOAT sy, bool bPrepended) {
    277   a *= sx;
    278   d *= sy;
    279   if (bPrepended) {
    280     b *= sx;
    281     c *= sy;
    282     return;
    283   }
    284 
    285   b *= sy;
    286   c *= sx;
    287   e *= sx;
    288   f *= sy;
    289 }
    290 
    291 void CFX_Matrix::Rotate(FX_FLOAT fRadian, bool bPrepended) {
    292   FX_FLOAT cosValue = FXSYS_cos(fRadian);
    293   FX_FLOAT sinValue = FXSYS_sin(fRadian);
    294   ConcatInternal(CFX_Matrix(cosValue, sinValue, -sinValue, cosValue, 0, 0),
    295                  bPrepended);
    296 }
    297 
    298 void CFX_Matrix::RotateAt(FX_FLOAT fRadian,
    299                           FX_FLOAT dx,
    300                           FX_FLOAT dy,
    301                           bool bPrepended) {
    302   Translate(dx, dy, bPrepended);
    303   Rotate(fRadian, bPrepended);
    304   Translate(-dx, -dy, bPrepended);
    305 }
    306 
    307 void CFX_Matrix::Shear(FX_FLOAT fAlphaRadian,
    308                        FX_FLOAT fBetaRadian,
    309                        bool bPrepended) {
    310   ConcatInternal(
    311       CFX_Matrix(1, FXSYS_tan(fAlphaRadian), FXSYS_tan(fBetaRadian), 1, 0, 0),
    312       bPrepended);
    313 }
    314 
    315 void CFX_Matrix::MatchRect(const CFX_FloatRect& dest,
    316                            const CFX_FloatRect& src) {
    317   FX_FLOAT fDiff = src.left - src.right;
    318   a = FXSYS_fabs(fDiff) < 0.001f ? 1 : (dest.left - dest.right) / fDiff;
    319 
    320   fDiff = src.bottom - src.top;
    321   d = FXSYS_fabs(fDiff) < 0.001f ? 1 : (dest.bottom - dest.top) / fDiff;
    322   e = dest.left - src.left * a;
    323   f = dest.bottom - src.bottom * d;
    324   b = 0;
    325   c = 0;
    326 }
    327 
    328 FX_FLOAT CFX_Matrix::GetXUnit() const {
    329   if (b == 0)
    330     return (a > 0 ? a : -a);
    331   if (a == 0)
    332     return (b > 0 ? b : -b);
    333   return FXSYS_sqrt(a * a + b * b);
    334 }
    335 
    336 FX_FLOAT CFX_Matrix::GetYUnit() const {
    337   if (c == 0)
    338     return (d > 0 ? d : -d);
    339   if (d == 0)
    340     return (c > 0 ? c : -c);
    341   return FXSYS_sqrt(c * c + d * d);
    342 }
    343 
    344 CFX_FloatRect CFX_Matrix::GetUnitRect() const {
    345   CFX_FloatRect rect(0, 0, 1, 1);
    346   TransformRect(rect);
    347   return rect;
    348 }
    349 
    350 FX_FLOAT CFX_Matrix::TransformXDistance(FX_FLOAT dx) const {
    351   FX_FLOAT fx = a * dx;
    352   FX_FLOAT fy = b * dx;
    353   return FXSYS_sqrt(fx * fx + fy * fy);
    354 }
    355 
    356 FX_FLOAT CFX_Matrix::TransformDistance(FX_FLOAT dx, FX_FLOAT dy) const {
    357   FX_FLOAT fx = a * dx + c * dy;
    358   FX_FLOAT fy = b * dx + d * dy;
    359   return FXSYS_sqrt(fx * fx + fy * fy);
    360 }
    361 
    362 FX_FLOAT CFX_Matrix::TransformDistance(FX_FLOAT distance) const {
    363   return distance * (GetXUnit() + GetYUnit()) / 2;
    364 }
    365 
    366 CFX_PointF CFX_Matrix::Transform(const CFX_PointF& point) const {
    367   return CFX_PointF(a * point.x + c * point.y + e,
    368                     b * point.x + d * point.y + f);
    369 }
    370 
    371 void CFX_Matrix::TransformRect(CFX_RectF& rect) const {
    372   FX_FLOAT right = rect.right(), bottom = rect.bottom();
    373   TransformRect(rect.left, right, bottom, rect.top);
    374   rect.width = right - rect.left;
    375   rect.height = bottom - rect.top;
    376 }
    377 
    378 void CFX_Matrix::TransformRect(FX_FLOAT& left,
    379                                FX_FLOAT& right,
    380                                FX_FLOAT& top,
    381                                FX_FLOAT& bottom) const {
    382   CFX_PointF points[] = {
    383       {left, top}, {left, bottom}, {right, top}, {right, bottom}};
    384   for (int i = 0; i < 4; i++)
    385     points[i] = Transform(points[i]);
    386 
    387   right = points[0].x;
    388   left = points[0].x;
    389   top = points[0].y;
    390   bottom = points[0].y;
    391   for (int i = 1; i < 4; i++) {
    392     right = std::max(right, points[i].x);
    393     left = std::min(left, points[i].x);
    394     top = std::max(top, points[i].y);
    395     bottom = std::min(bottom, points[i].y);
    396   }
    397 }
    398 
    399 void CFX_Matrix::ConcatInternal(const CFX_Matrix& other, bool prepend) {
    400   CFX_Matrix left;
    401   CFX_Matrix right;
    402   if (prepend) {
    403     left = other;
    404     right = *this;
    405   } else {
    406     left = *this;
    407     right = other;
    408   }
    409 
    410   a = left.a * right.a + left.b * right.c;
    411   b = left.a * right.b + left.b * right.d;
    412   c = left.c * right.a + left.d * right.c;
    413   d = left.c * right.b + left.d * right.d;
    414   e = left.e * right.a + left.f * right.c + right.e;
    415   f = left.e * right.b + left.f * right.d + right.f;
    416 }
    417