Merge to XF: Add constructor for CPDF_ColorSpace.
[pdfium.git] / core / src / fxge / agg / agg23 / fx_agg_vcgen_stroke.cpp
1
2 //----------------------------------------------------------------------------
3 // XYQ: 2006-01-22 Copied from AGG project.
4 // TODO: This file uses intensive floating point operations, so it's NOT suitable
5 // for platforms like Symbian OS. We need to change to FIX format.
6 //----------------------------------------------------------------------------
7 //----------------------------------------------------------------------------
8 // Anti-Grain Geometry - Version 2.3
9 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
10 //
11 // Permission to copy, use, modify, sell and distribute this software
12 // is granted provided this copyright notice appears in all copies.
13 // This software is provided "as is" without express or implied
14 // warranty, and with no claim as to its suitability for any purpose.
15 //
16 //----------------------------------------------------------------------------
17 // Contact: mcseem@antigrain.com
18 //          mcseemagg@yahoo.com
19 //          http://www.antigrain.com
20 //----------------------------------------------------------------------------
21 //
22 // Stroke generator
23 //
24 //----------------------------------------------------------------------------
25 #include "../../../../include/fxcrt/fx_basic.h"
26 #include "agg_vcgen_stroke.h"
27 namespace agg
28 {
29
30 vcgen_stroke::vcgen_stroke() :
31     m_src_vertices(),
32     m_out_vertices(),
33     m_width(0.5f),
34     m_miter_limit(4 * 1.0f),
35     m_inner_miter_limit(1.0f + 1.0f / 100),
36     m_approx_scale(1.0f),
37     m_line_cap(butt_cap),
38     m_line_join(miter_join),
39     m_inner_join(inner_miter),
40     m_closed(0),
41     m_status(initial),
42     m_src_vertex(0),
43     m_out_vertex(0)
44 {
45 }
46 void vcgen_stroke::remove_all()
47 {
48     m_src_vertices.remove_all();
49     m_closed = 0;
50     m_status = initial;
51 }
52 void vcgen_stroke::add_vertex(FX_FLOAT x, FX_FLOAT y, unsigned cmd)
53 {
54     m_status = initial;
55     if(is_move_to(cmd)) {
56         m_src_vertices.modify_last(vertex_dist_cmd(x, y, cmd));
57     } else {
58         if(is_vertex(cmd)) {
59             m_src_vertices.add(vertex_dist_cmd(x, y, cmd));
60         } else {
61             m_closed = get_close_flag(cmd);
62         }
63     }
64 }
65 static inline void calc_butt_cap(FX_FLOAT* cap,
66                                  const vertex_dist& v0,
67                                  const vertex_dist& v1,
68                                  FX_FLOAT len,
69                                  FX_FLOAT width)
70 {
71     FX_FLOAT dx = FXSYS_MulDiv(v1.y - v0.y, width, len);
72     FX_FLOAT dy = FXSYS_MulDiv(v1.x - v0.x, width, len);
73     cap[0] = v0.x - dx;
74     cap[1] = v0.y + dy;
75     cap[2] = v0.x + dx;
76     cap[3] = v0.y - dy;
77 }
78 void vcgen_stroke::rewind(unsigned)
79 {
80     if(m_status == initial) {
81         m_src_vertices.close(m_closed != 0);
82         if(m_src_vertices.size() < 3) {
83             m_closed = 0;
84         }
85     }
86     m_status = ready;
87     m_src_vertex = 0;
88     m_out_vertex = 0;
89 }
90 unsigned vcgen_stroke::vertex(FX_FLOAT* x, FX_FLOAT* y)
91 {
92     unsigned cmd = path_cmd_line_to;
93     line_join_e curj;
94     while(!is_stop(cmd)) {
95         switch(m_status) {
96             case initial:
97                 rewind(0);
98             case ready:
99                 if(m_src_vertices.size() < 2 + unsigned(m_closed != 0)) {
100                     cmd = path_cmd_stop;
101                     break;
102                 }
103                 m_status = m_closed ? outline1 : cap1;
104                 cmd = path_cmd_move_to;
105                 m_src_vertex = 0;
106                 m_out_vertex = 0;
107                 break;
108             case cap1:
109                 stroke_calc_cap(m_out_vertices,
110                                 m_src_vertices[0],
111                                 m_src_vertices[1],
112                                 m_src_vertices[0].dist,
113                                 m_line_cap,
114                                 m_width,
115                                 m_approx_scale);
116                 m_src_vertex = 1;
117                 m_prev_status = outline1;
118                 m_status = out_vertices;
119                 m_out_vertex = 0;
120                 break;
121             case cap2:
122                 stroke_calc_cap(m_out_vertices,
123                                 m_src_vertices[m_src_vertices.size() - 1],
124                                 m_src_vertices[m_src_vertices.size() - 2],
125                                 m_src_vertices[m_src_vertices.size() - 2].dist,
126                                 m_line_cap,
127                                 m_width,
128                                 m_approx_scale);
129                 m_prev_status = outline2;
130                 m_status = out_vertices;
131                 m_out_vertex = 0;
132                 break;
133             case outline1:
134                 if(m_closed) {
135                     if(m_src_vertex >= m_src_vertices.size()) {
136                         m_prev_status = close_first;
137                         m_status = end_poly1;
138                         break;
139                     }
140                 } else {
141                     if(m_src_vertex >= m_src_vertices.size() - 1) {
142                         m_status = cap2;
143                         break;
144                     }
145                 }
146                 curj = m_src_vertices[m_src_vertex].cmd & path_flags_jr ? miter_join_round : m_line_join;
147                 stroke_calc_join(m_out_vertices,
148                                  m_src_vertices.prev(m_src_vertex),
149                                  m_src_vertices.curr(m_src_vertex),
150                                  m_src_vertices.next(m_src_vertex),
151                                  m_src_vertices.prev(m_src_vertex).dist,
152                                  m_src_vertices.curr(m_src_vertex).dist,
153                                  m_width,
154                                  curj,
155                                  m_inner_join,
156                                  m_miter_limit,
157                                  m_inner_miter_limit,
158                                  m_approx_scale);
159                 ++m_src_vertex;
160                 m_prev_status = m_status;
161                 m_status = out_vertices;
162                 m_out_vertex = 0;
163                 break;
164             case close_first:
165                 m_status = outline2;
166                 cmd = path_cmd_move_to;
167             case outline2:
168                 if(m_src_vertex <= unsigned(m_closed == 0)) {
169                     m_status = end_poly2;
170                     m_prev_status = stop;
171                     break;
172                 }
173                 --m_src_vertex;
174                 curj = m_src_vertices[m_src_vertex].cmd & path_flags_jr ? miter_join_round : m_line_join;
175                 stroke_calc_join(m_out_vertices,
176                                  m_src_vertices.next(m_src_vertex),
177                                  m_src_vertices.curr(m_src_vertex),
178                                  m_src_vertices.prev(m_src_vertex),
179                                  m_src_vertices.curr(m_src_vertex).dist,
180                                  m_src_vertices.prev(m_src_vertex).dist,
181                                  m_width,
182                                  curj,
183                                  m_inner_join,
184                                  m_miter_limit,
185                                  m_inner_miter_limit,
186                                  m_approx_scale);
187                 m_prev_status = m_status;
188                 m_status = out_vertices;
189                 m_out_vertex = 0;
190                 break;
191             case out_vertices:
192                 if(m_out_vertex >= m_out_vertices.size()) {
193                     m_status = m_prev_status;
194                 } else {
195                     const point_type& c = m_out_vertices[m_out_vertex++];
196                     *x = c.x;
197                     *y = c.y;
198                     return cmd;
199                 }
200                 break;
201             case end_poly1:
202                 m_status = m_prev_status;
203                 return path_cmd_end_poly | path_flags_close | path_flags_ccw;
204             case end_poly2:
205                 m_status = m_prev_status;
206                 return path_cmd_end_poly | path_flags_close | path_flags_cw;
207             case stop:
208                 cmd = path_cmd_stop;
209                 break;
210         }
211     }
212     return cmd;
213 }
214 }