Home | History | Annotate | Download | only in fde
      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 "xfa/src/foxitlib.h"
      8 #include "fde_object.h"
      9 #include "fde_geobject.h"
     10 #ifndef _FDEPLUS
     11 IFDE_Path* IFDE_Path::Create() {
     12   return new CFDE_Path;
     13 }
     14 FX_BOOL CFDE_Path::StartFigure() {
     15   return CloseFigure();
     16 }
     17 FX_BOOL CFDE_Path::CloseFigure() {
     18   FX_PATHPOINT* pPoint = GetLastPoint();
     19   if (pPoint) {
     20     pPoint->m_Flag |= FXPT_CLOSEFIGURE;
     21   }
     22   return TRUE;
     23 }
     24 FX_PATHPOINT* CFDE_Path::GetLastPoint(int32_t iCount) const {
     25   if (iCount < 1) {
     26     return NULL;
     27   }
     28   int32_t iPoints = m_Path.GetPointCount();
     29   if (iCount > iPoints) {
     30     return NULL;
     31   }
     32   return m_Path.GetPoints() + iPoints - iCount;
     33 }
     34 FX_BOOL CFDE_Path::FigureClosed() const {
     35   FX_PATHPOINT* pPoint = GetLastPoint();
     36   return pPoint ? (pPoint->m_Flag & FXPT_CLOSEFIGURE) : TRUE;
     37 }
     38 FX_PATHPOINT* CFDE_Path::AddPoints(int32_t iCount) {
     39   if (iCount < 1) {
     40     return NULL;
     41   }
     42   int32_t iPoints = m_Path.GetPointCount();
     43   m_Path.AddPointCount(iCount);
     44   return m_Path.GetPoints() + iPoints;
     45 }
     46 void CFDE_Path::MoveTo(FX_FLOAT fx, FX_FLOAT fy) {
     47   FX_PATHPOINT* pPoint = AddPoints(1);
     48   pPoint->m_PointX = fx;
     49   pPoint->m_PointY = fy;
     50   pPoint->m_Flag = FXPT_MOVETO;
     51 }
     52 void CFDE_Path::LineTo(FX_FLOAT fx, FX_FLOAT fy) {
     53   FX_PATHPOINT* pPoint = AddPoints(1);
     54   pPoint->m_PointX = fx;
     55   pPoint->m_PointY = fy;
     56   pPoint->m_Flag = FXPT_LINETO;
     57 }
     58 void CFDE_Path::BezierTo(const CFX_PointF& p1,
     59                          const CFX_PointF& p2,
     60                          const CFX_PointF& p3) {
     61   FX_PATHPOINT* p = AddPoints(3);
     62   p[0].m_PointX = p1.x;
     63   p[0].m_PointY = p1.y;
     64   p[0].m_Flag = FXPT_BEZIERTO;
     65   p[1].m_PointX = p2.x;
     66   p[1].m_PointY = p2.y;
     67   p[1].m_Flag = FXPT_BEZIERTO;
     68   p[2].m_PointX = p3.x;
     69   p[2].m_PointY = p3.y;
     70   p[2].m_Flag = FXPT_BEZIERTO;
     71 }
     72 void CFDE_Path::ArcTo(FX_BOOL bStart,
     73                       const CFX_RectF& rect,
     74                       FX_FLOAT startAngle,
     75                       FX_FLOAT endAngle) {
     76   FX_FLOAT rx = rect.width / 2;
     77   FX_FLOAT ry = rect.height / 2;
     78   FX_FLOAT cx = rect.left + rx;
     79   FX_FLOAT cy = rect.top + ry;
     80   FX_FLOAT alpha =
     81       FXSYS_atan2(rx * FXSYS_sin(startAngle), ry * FXSYS_cos(startAngle));
     82   FX_FLOAT beta =
     83       FXSYS_atan2(rx * FXSYS_sin(endAngle), ry * FXSYS_cos(endAngle));
     84   if (FXSYS_fabs(beta - alpha) > FX_PI) {
     85     if (beta > alpha) {
     86       beta -= 2 * FX_PI;
     87     } else {
     88       alpha -= 2 * FX_PI;
     89     }
     90   }
     91   FX_FLOAT half_delta = (beta - alpha) / 2;
     92   FX_FLOAT bcp = 4.0f / 3 * (1 - FXSYS_cos(half_delta)) / FXSYS_sin(half_delta);
     93   FX_FLOAT sin_alpha = FXSYS_sin(alpha);
     94   FX_FLOAT sin_beta = FXSYS_sin(beta);
     95   FX_FLOAT cos_alpha = FXSYS_cos(alpha);
     96   FX_FLOAT cos_beta = FXSYS_cos(beta);
     97   if (bStart) {
     98     CFX_PointF p0;
     99     p0.Set(cx + rx * cos_alpha, cy + ry * sin_alpha);
    100     MoveTo(p0);
    101   }
    102   CFX_PointF p1;
    103   p1.Set(cx + rx * (cos_alpha - bcp * sin_alpha),
    104          cy + ry * (sin_alpha + bcp * cos_alpha));
    105   CFX_PointF p2;
    106   p2.Set(cx + rx * (cos_beta + bcp * sin_beta),
    107          cy + ry * (sin_beta - bcp * cos_beta));
    108   CFX_PointF p3;
    109   p3.Set(cx + rx * cos_beta, cy + ry * sin_beta);
    110   BezierTo(p1, p2, p3);
    111 }
    112 void CFDE_Path::AddBezier(const CFX_PointsF& points) {
    113   if (points.GetSize() != 4) {
    114     return;
    115   }
    116   FX_LPCPOINTF p = points.GetData();
    117   MoveTo(p[0]);
    118   BezierTo(p[1], p[2], p[3]);
    119 }
    120 void CFDE_Path::AddBeziers(const CFX_PointsF& points) {
    121   int32_t iCount = points.GetSize();
    122   if (iCount < 4) {
    123     return;
    124   }
    125   FX_LPCPOINTF p = points.GetData();
    126   FX_LPCPOINTF pEnd = p + iCount;
    127   MoveTo(p[0]);
    128   for (++p; p <= pEnd - 3; p += 3) {
    129     BezierTo(p[0], p[1], p[2]);
    130   }
    131 }
    132 void CFDE_Path::GetCurveTangents(const CFX_PointsF& points,
    133                                  CFX_PointsF& tangents,
    134                                  FX_BOOL bClosed,
    135                                  FX_FLOAT fTension) const {
    136   int32_t iCount = points.GetSize();
    137   tangents.SetSize(iCount);
    138   if (iCount < 3) {
    139     return;
    140   }
    141   FX_FLOAT fCoefficient = fTension / 3.0f;
    142   FX_LPCPOINTF pPoints = points.GetData();
    143   FX_LPPOINTF pTangents = tangents.GetData();
    144   for (int32_t i = 0; i < iCount; ++i) {
    145     int32_t r = i + 1;
    146     int32_t s = i - 1;
    147     if (r >= iCount) {
    148       r = bClosed ? (r - iCount) : (iCount - 1);
    149     }
    150     if (s < 0) {
    151       s = bClosed ? (s + iCount) : 0;
    152     }
    153     pTangents[i].x += (fCoefficient * (pPoints[r].x - pPoints[s].x));
    154     pTangents[i].y += (fCoefficient * (pPoints[r].y - pPoints[s].y));
    155   }
    156 }
    157 void CFDE_Path::AddCurve(const CFX_PointsF& points,
    158                          FX_BOOL bClosed,
    159                          FX_FLOAT fTension) {
    160   int32_t iLast = points.GetUpperBound();
    161   if (iLast < 1) {
    162     return;
    163   }
    164   CFX_PointsF tangents;
    165   GetCurveTangents(points, tangents, bClosed, fTension);
    166   FX_LPCPOINTF pPoints = points.GetData();
    167   FX_LPPOINTF pTangents = tangents.GetData();
    168   MoveTo(pPoints[0]);
    169   for (int32_t i = 0; i < iLast; ++i) {
    170     int32_t j = i + 1;
    171     CFX_PointF p1;
    172     p1.Set(pPoints[i].x + pTangents[i].x, pPoints[i].y + pTangents[i].y);
    173     CFX_PointF p2;
    174     p2.Set(pPoints[j].x - pTangents[j].x, pPoints[j].y - pTangents[j].y);
    175     CFX_PointF p3;
    176     p3.Set(pPoints[j].x, pPoints[j].y);
    177     BezierTo(p1, p2, p3);
    178   }
    179   if (bClosed) {
    180     CFX_PointF p1;
    181     p1.Set(pPoints[iLast].x + pTangents[iLast].x,
    182            pPoints[iLast].y + pTangents[iLast].y);
    183     CFX_PointF p2;
    184     p2.Set(pPoints[0].x - pTangents[0].x, pPoints[0].y - pTangents[0].y);
    185     CFX_PointF p3;
    186     p3.Set(pPoints[0].x, pPoints[0].y);
    187     BezierTo(p1, p2, p3);
    188     CloseFigure();
    189   }
    190 }
    191 void CFDE_Path::AddEllipse(const CFX_RectF& rect) {
    192   FX_FLOAT fStartAngle = 0;
    193   FX_FLOAT fEndAngle = FX_PI / 2;
    194   for (int32_t i = 0; i < 4; ++i) {
    195     ArcTo(i == 0, rect, fStartAngle, fEndAngle);
    196     fStartAngle += FX_PI / 2;
    197     fEndAngle += FX_PI / 2;
    198   }
    199   CloseFigure();
    200 }
    201 void CFDE_Path::AddLine(const CFX_PointF& pt1, const CFX_PointF& pt2) {
    202   FX_PATHPOINT* pLast = GetLastPoint();
    203   if (pLast == NULL || FXSYS_fabs(pLast->m_PointX - pt1.x) > 0.001 ||
    204       FXSYS_fabs(pLast->m_PointY - pt1.y) > 0.001) {
    205     MoveTo(pt1);
    206   }
    207   LineTo(pt2);
    208 }
    209 void CFDE_Path::AddPath(const IFDE_Path* pSrc, FX_BOOL bConnect) {
    210   CFDE_Path* pPath = (CFDE_Path*)pSrc;
    211   if (pPath == NULL) {
    212     return;
    213   }
    214   int32_t iCount = pPath->m_Path.GetPointCount();
    215   if (iCount < 1) {
    216     return;
    217   }
    218   if (bConnect) {
    219     LineTo(pPath->m_Path.GetPointX(0), pPath->m_Path.GetPointY(0));
    220   }
    221   m_Path.Append(&pPath->m_Path, NULL);
    222 }
    223 void CFDE_Path::AddPolygon(const CFX_PointsF& points) {
    224   int32_t iCount = points.GetSize();
    225   if (iCount < 2) {
    226     return;
    227   }
    228   AddLines(points);
    229   FX_LPCPOINTF p = points.GetData();
    230   if (FXSYS_fabs(p[0].x - p[iCount - 1].x) < 0.01f ||
    231       FXSYS_fabs(p[0].y - p[iCount - 1].y) < 0.01f) {
    232     LineTo(p[0]);
    233   }
    234   CloseFigure();
    235 }
    236 void CFDE_Path::AddLines(const CFX_PointsF& points) {
    237   int32_t iCount = points.GetSize();
    238   if (iCount < 2) {
    239     return;
    240   }
    241   FX_LPCPOINTF p = points.GetData();
    242   FX_LPCPOINTF pEnd = p + iCount;
    243   MoveTo(p[0]);
    244   for (++p; p < pEnd; ++p) {
    245     LineTo(*p);
    246   }
    247 }
    248 void CFDE_Path::AddRectangle(const CFX_RectF& rect) {
    249   MoveTo(rect.TopLeft());
    250   LineTo(rect.TopRight());
    251   LineTo(rect.BottomRight());
    252   LineTo(rect.BottomLeft());
    253   CloseFigure();
    254 }
    255 void CFDE_Path::GetBBox(CFX_RectF& bbox) const {
    256   CFX_FloatRect rect = m_Path.GetBoundingBox();
    257   bbox.Set(rect.left, rect.top, rect.Width(), rect.Height());
    258   bbox.Normalize();
    259 }
    260 void CFDE_Path::GetBBox(CFX_RectF& bbox,
    261                         FX_FLOAT fLineWidth,
    262                         FX_FLOAT fMiterLimit) const {
    263   CFX_FloatRect rect = m_Path.GetBoundingBox(fLineWidth, fMiterLimit);
    264   bbox.Set(rect.left, rect.top, rect.Width(), rect.Height());
    265   bbox.Normalize();
    266 }
    267 #endif
    268