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