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