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