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 "pre.h" 8#include "fx_path_generator.h" 9CFX_PathGenerator::CFX_PathGenerator() { 10 m_pPathData = NULL; 11} 12void CFX_PathGenerator::Create() { 13 m_pPathData = new CFX_PathData; 14} 15CFX_PathGenerator::~CFX_PathGenerator() { 16 if (m_pPathData) { 17 delete m_pPathData; 18 m_pPathData = NULL; 19 } 20} 21void CFX_PathGenerator::AddPathData(CFX_PathData* pPathData) { 22 if (pPathData && pPathData->GetPointCount() > 0) { 23 int nCount = pPathData->GetPointCount(); 24 FX_PATHPOINT* pPoints = pPathData->GetPoints(); 25 AddPathData(pPoints, nCount); 26 } 27} 28void CFX_PathGenerator::AddPathData(FX_PATHPOINT* pPoints, int nCount) { 29 if (pPoints && nCount > 0) { 30 int nOldCount = m_pPathData->GetPointCount(); 31 m_pPathData->AddPointCount(nCount); 32 FX_PATHPOINT* pDstPoints = m_pPathData->GetPoints(); 33 FXSYS_memcpy(pDstPoints + nOldCount, pPoints, 34 sizeof(FX_PATHPOINT) * nCount); 35 } 36} 37void CFX_PathGenerator::MoveTo(FX_FLOAT x, FX_FLOAT y) { 38 m_pPathData->AddPointCount(1); 39 m_pPathData->SetPoint(m_pPathData->GetPointCount() - 1, x, y, FXPT_MOVETO); 40} 41void CFX_PathGenerator::LineTo(FX_FLOAT x, FX_FLOAT y) { 42 m_pPathData->AddPointCount(1); 43 m_pPathData->SetPoint(m_pPathData->GetPointCount() - 1, x, y, FXPT_LINETO); 44} 45void CFX_PathGenerator::BezierTo(FX_FLOAT ctrl_x1, 46 FX_FLOAT ctrl_y1, 47 FX_FLOAT ctrl_x2, 48 FX_FLOAT ctrl_y2, 49 FX_FLOAT to_x, 50 FX_FLOAT to_y) { 51 int old_count = m_pPathData->GetPointCount(); 52 m_pPathData->AddPointCount(3); 53 m_pPathData->SetPoint(old_count, ctrl_x1, ctrl_y1, FXPT_BEZIERTO); 54 m_pPathData->SetPoint(old_count + 1, ctrl_x2, ctrl_y2, FXPT_BEZIERTO); 55 m_pPathData->SetPoint(old_count + 2, to_x, to_y, FXPT_BEZIERTO); 56} 57void CFX_PathGenerator::Close() { 58 if (m_pPathData->GetPointCount() > 0) { 59 int index = m_pPathData->GetPointCount() - 1; 60 FX_PATHPOINT* pPoints = m_pPathData->GetPoints(); 61 pPoints[index].m_Flag |= FXPT_CLOSEFIGURE; 62 } 63} 64void CFX_PathGenerator::AddLine(FX_FLOAT x1, 65 FX_FLOAT y1, 66 FX_FLOAT x2, 67 FX_FLOAT y2) { 68 int old_count = m_pPathData->GetPointCount(); 69 m_pPathData->AddPointCount(2); 70 m_pPathData->SetPoint(old_count, x1, y1, FXPT_MOVETO); 71 m_pPathData->SetPoint(old_count + 1, x2, y2, FXPT_LINETO); 72} 73void CFX_PathGenerator::AddBezier(FX_FLOAT start_x, 74 FX_FLOAT start_y, 75 FX_FLOAT ctrl_x1, 76 FX_FLOAT ctrl_y1, 77 FX_FLOAT ctrl_x2, 78 FX_FLOAT ctrl_y2, 79 FX_FLOAT end_x, 80 FX_FLOAT end_y) { 81 int old_count = m_pPathData->GetPointCount(); 82 m_pPathData->AddPointCount(4); 83 m_pPathData->SetPoint(old_count, start_x, start_y, FXPT_MOVETO); 84 m_pPathData->SetPoint(old_count + 1, ctrl_x1, ctrl_y1, FXPT_BEZIERTO); 85 m_pPathData->SetPoint(old_count + 2, ctrl_x2, ctrl_y2, FXPT_BEZIERTO); 86 m_pPathData->SetPoint(old_count + 3, end_x, end_y, FXPT_BEZIERTO); 87} 88void CFX_PathGenerator::AddRectangle(FX_FLOAT x1, 89 FX_FLOAT y1, 90 FX_FLOAT x2, 91 FX_FLOAT y2) { 92 m_pPathData->AppendRect(x1, y1, x2, y2); 93} 94void CFX_PathGenerator::AddEllipse(FX_FLOAT x, 95 FX_FLOAT y, 96 FX_FLOAT width, 97 FX_FLOAT height) { 98#if 0 99 FX_FIXFLOAT16 k; 100 k = fix16_to_8(fixsqrt_32_to_16(fixmul_8_8_to_32(width, width) + fixmul_8_8_to_32(height, height)) / 2); 101 int old_count = m_pPathData->GetPointCount(); 102 m_pPathData->AddPointCount(7); 103 m_pPathData->SetPoint(old_count, x, y - height / 2, FXPT_MOVETO); 104 m_pPathData->SetPoint(old_count + 1, x + k, y - height / 2, FXPT_BEZIERTO); 105 m_pPathData->SetPoint(old_count + 2, x + k, y + height / 2, FXPT_BEZIERTO); 106 m_pPathData->SetPoint(old_count + 3, x, y + height / 2, FXPT_BEZIERTO); 107 m_pPathData->SetPoint(old_count + 4, x - k, y + height / 2, FXPT_BEZIERTO); 108 m_pPathData->SetPoint(old_count + 5, x - k, y - height / 2, FXPT_BEZIERTO); 109 m_pPathData->SetPoint(old_count + 6, x, y - height / 2, FXPT_BEZIERTO); 110#else 111 AddArc(x, y, width, height, 0, FX_PI * 2); 112#endif 113} 114void CFX_PathGenerator::ArcTo(FX_FLOAT x, 115 FX_FLOAT y, 116 FX_FLOAT width, 117 FX_FLOAT height, 118 FX_FLOAT start_angle, 119 FX_FLOAT sweep_angle) { 120 FX_FLOAT x0 = FXSYS_cos(sweep_angle / 2); 121 FX_FLOAT y0 = FXSYS_sin(sweep_angle / 2); 122 FX_FLOAT tx = FXSYS_Div((1.0f - x0) * 4, 3 * 1.0f); 123 FX_FLOAT ty = y0 - FXSYS_Div(FXSYS_Mul(tx, x0), y0); 124 FX_FLOAT px[3], py[3]; 125 px[0] = x0 + tx; 126 py[0] = -ty; 127 px[1] = x0 + tx; 128 py[1] = ty; 129 FX_FLOAT sn = FXSYS_sin(start_angle + sweep_angle / 2); 130 FX_FLOAT cs = FXSYS_cos(start_angle + sweep_angle / 2); 131 int old_count = m_pPathData->GetPointCount(); 132 m_pPathData->AddPointCount(3); 133 FX_FLOAT bezier_x, bezier_y; 134 bezier_x = x + FXSYS_Mul(width, FXSYS_Mul(px[0], cs) - FXSYS_Mul(py[0], sn)); 135 bezier_y = y + FXSYS_Mul(height, FXSYS_Mul(px[0], sn) + FXSYS_Mul(py[0], cs)); 136 m_pPathData->SetPoint(old_count, bezier_x, bezier_y, FXPT_BEZIERTO); 137 bezier_x = x + FXSYS_Mul(width, FXSYS_Mul(px[1], cs) - FXSYS_Mul(py[1], sn)); 138 bezier_y = y + FXSYS_Mul(height, FXSYS_Mul(px[1], sn) + FXSYS_Mul(py[1], cs)); 139 m_pPathData->SetPoint(old_count + 1, bezier_x, bezier_y, FXPT_BEZIERTO); 140 bezier_x = x + FXSYS_Mul(width, FXSYS_cos(start_angle + sweep_angle)), 141 bezier_y = y + FXSYS_Mul(height, FXSYS_sin(start_angle + sweep_angle)); 142 m_pPathData->SetPoint(old_count + 2, bezier_x, bezier_y, FXPT_BEZIERTO); 143} 144void CFX_PathGenerator::AddArc(FX_FLOAT x, 145 FX_FLOAT y, 146 FX_FLOAT width, 147 FX_FLOAT height, 148 FX_FLOAT start_angle, 149 FX_FLOAT sweep_angle) { 150#if 0 151 FX_FIXFLOAT32 sweep = sweep_angle; 152 while (sweep > FIXFLOAT32_PI * 2) { 153 sweep -= FIXFLOAT32_PI * 2; 154 } 155 if (sweep == 0) { 156 return; 157 } 158 m_pPathData->AddPointCount(1); 159 m_pPathData->SetPoint(m_pPathData->GetPointCount() - 1, 160 x + fixmul_8_32_to_8(width, fixcos(start_angle)), 161 y + fixmul_8_32_to_8(height, fixsin(start_angle)), FXPT_MOVETO); 162 FX_FIXFLOAT32 angle1 = 0, angle2; 163 FX_BOOL bDone = FALSE; 164 do { 165 angle2 = angle1 + FIXFLOAT32_PI / 2; 166 if (angle2 >= sweep) { 167 angle2 = sweep; 168 bDone = TRUE; 169 } 170 ArcTo(x, y, width, height, start_angle + angle1, angle2 - angle1); 171 angle1 = angle2; 172 } while (!bDone); 173#else 174 if (sweep_angle == 0) { 175 return; 176 } 177 static const FX_FLOAT bezier_arc_angle_epsilon = (FX_FLOAT)(0.01f); 178 while (start_angle > FX_PI * 2) { 179 start_angle -= FX_PI * 2; 180 } 181 while (start_angle < 0) { 182 start_angle += FX_PI * 2; 183 } 184 if (sweep_angle >= FX_PI * 2) { 185 sweep_angle = FX_PI * 2; 186 } 187 if (sweep_angle <= -FX_PI * 2) { 188 sweep_angle = -FX_PI * 2; 189 } 190 m_pPathData->AddPointCount(1); 191 m_pPathData->SetPoint(m_pPathData->GetPointCount() - 1, 192 x + FXSYS_Mul(width, FXSYS_cos(start_angle)), 193 y + FXSYS_Mul(height, FXSYS_sin(start_angle)), 194 FXPT_MOVETO); 195 FX_FLOAT total_sweep = 0, local_sweep = 0, prev_sweep = 0; 196 FX_BOOL done = FALSE; 197 do { 198 if (sweep_angle < 0) { 199 prev_sweep = total_sweep; 200 local_sweep = -FX_PI / 2; 201 total_sweep -= FX_PI / 2; 202 if (total_sweep <= sweep_angle + bezier_arc_angle_epsilon) { 203 local_sweep = sweep_angle - prev_sweep; 204 done = TRUE; 205 } 206 } else { 207 prev_sweep = total_sweep; 208 local_sweep = FX_PI / 2; 209 total_sweep += FX_PI / 2; 210 if (total_sweep >= sweep_angle - bezier_arc_angle_epsilon) { 211 local_sweep = sweep_angle - prev_sweep; 212 done = TRUE; 213 } 214 } 215 ArcTo(x, y, width, height, start_angle, local_sweep); 216 start_angle += local_sweep; 217 } while (!done); 218#endif 219} 220void CFX_PathGenerator::AddPie(FX_FLOAT x, 221 FX_FLOAT y, 222 FX_FLOAT width, 223 FX_FLOAT height, 224 FX_FLOAT start_angle, 225 FX_FLOAT sweep_angle) { 226 if (sweep_angle == 0) { 227 int old_count = m_pPathData->GetPointCount(); 228 m_pPathData->AddPointCount(2); 229 m_pPathData->SetPoint(old_count, x, y, FXPT_MOVETO); 230 m_pPathData->SetPoint( 231 old_count + 1, x + FXSYS_Mul(width, FXSYS_cos(start_angle)), 232 y + FXSYS_Mul(height, FXSYS_sin(start_angle)), FXPT_LINETO); 233 return; 234 } 235 AddArc(x, y, width, height, start_angle, sweep_angle); 236 m_pPathData->AddPointCount(1); 237 m_pPathData->SetPoint(m_pPathData->GetPointCount() - 1, x, y, 238 FXPT_LINETO | FXPT_CLOSEFIGURE); 239} 240