xref: /aosp_15_r20/external/pdfium/third_party/agg23/agg_vcgen_stroke.cpp (revision 3ac0a46f773bac49fa9476ec2b1cf3f8da5ec3a4)
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: [email protected]
18 //          [email protected]
19 //          http://www.antigrain.com
20 //----------------------------------------------------------------------------
21 //
22 // Stroke generator
23 //
24 //----------------------------------------------------------------------------
25 
26 #include "agg_vcgen_stroke.h"
27 
28 namespace pdfium
29 {
30 namespace agg
31 {
32 
vcgen_stroke()33 vcgen_stroke::vcgen_stroke() :
34     m_src_vertices(),
35     m_out_vertices(),
36     m_width(0.5f),
37     m_miter_limit(4 * 1.0f),
38     m_inner_miter_limit(1.0f + 1.0f / 100),
39     m_approx_scale(1.0f),
40     m_line_cap(butt_cap),
41     m_line_join(miter_join),
42     m_inner_join(inner_miter),
43     m_closed(0),
44     m_status(initial),
45     m_src_vertex(0),
46     m_out_vertex(0)
47 {
48 }
remove_all()49 void vcgen_stroke::remove_all()
50 {
51     m_src_vertices.remove_all();
52     m_closed = 0;
53     m_status = initial;
54 }
add_vertex(float x,float y,unsigned cmd)55 void vcgen_stroke::add_vertex(float x, float y, unsigned cmd)
56 {
57     m_status = initial;
58     if(is_move_to(cmd)) {
59         m_src_vertices.modify_last(vertex_dist_cmd(x, y, cmd));
60     } else {
61         if(is_vertex(cmd)) {
62             m_src_vertices.add(vertex_dist_cmd(x, y, cmd));
63         } else {
64             m_closed = get_close_flag(cmd);
65         }
66     }
67 }
calc_butt_cap(float * cap,const vertex_dist & v0,const vertex_dist & v1,float len,float width)68 static inline void calc_butt_cap(float* cap,
69                                  const vertex_dist& v0,
70                                  const vertex_dist& v1,
71                                  float len,
72                                  float width) {
73   float dx = (v1.y - v0.y) * width / len;
74   float dy = (v1.x - v0.x) * width / len;
75   cap[0] = v0.x - dx;
76   cap[1] = v0.y + dy;
77   cap[2] = v0.x + dx;
78   cap[3] = v0.y - dy;
79 }
rewind(unsigned)80 void vcgen_stroke::rewind(unsigned)
81 {
82     if(m_status == initial) {
83         m_src_vertices.close(m_closed != 0);
84         if(m_src_vertices.size() < 3) {
85             m_closed = 0;
86         }
87     }
88     m_status = ready;
89     m_src_vertex = 0;
90     m_out_vertex = 0;
91 }
vertex(float * x,float * y)92 unsigned vcgen_stroke::vertex(float* x, float* y)
93 {
94     unsigned cmd = path_cmd_line_to;
95     line_join_e curj;
96     while(!is_stop(cmd)) {
97         switch(m_status) {
98             case initial:
99                 rewind(0);
100             case ready:
101                 if(m_src_vertices.size() < 2 + unsigned(m_closed != 0)) {
102                     cmd = path_cmd_stop;
103                     break;
104                 }
105                 m_status = m_closed ? outline1 : cap1;
106                 cmd = path_cmd_move_to;
107                 m_src_vertex = 0;
108                 m_out_vertex = 0;
109                 break;
110             case cap1:
111                 stroke_calc_cap(m_out_vertices,
112                                 m_src_vertices[0],
113                                 m_src_vertices[1],
114                                 m_src_vertices[0].dist,
115                                 m_line_cap,
116                                 m_width,
117                                 m_approx_scale);
118                 m_src_vertex = 1;
119                 m_prev_status = outline1;
120                 m_status = out_vertices;
121                 m_out_vertex = 0;
122                 break;
123             case cap2:
124                 stroke_calc_cap(m_out_vertices,
125                                 m_src_vertices[m_src_vertices.size() - 1],
126                                 m_src_vertices[m_src_vertices.size() - 2],
127                                 m_src_vertices[m_src_vertices.size() - 2].dist,
128                                 m_line_cap,
129                                 m_width,
130                                 m_approx_scale);
131                 m_prev_status = outline2;
132                 m_status = out_vertices;
133                 m_out_vertex = 0;
134                 break;
135             case outline1:
136                 if(m_closed) {
137                     if(m_src_vertex >= m_src_vertices.size()) {
138                         m_prev_status = close_first;
139                         m_status = end_poly1;
140                         break;
141                     }
142                 } else {
143                     if(m_src_vertex >= m_src_vertices.size() - 1) {
144                         m_status = cap2;
145                         break;
146                     }
147                 }
148                 curj = m_src_vertices[m_src_vertex].cmd & path_flags_jr ? miter_join_round : m_line_join;
149                 stroke_calc_join(m_out_vertices,
150                                  m_src_vertices.prev(m_src_vertex),
151                                  m_src_vertices.curr(m_src_vertex),
152                                  m_src_vertices.next(m_src_vertex),
153                                  m_src_vertices.prev(m_src_vertex).dist,
154                                  m_src_vertices.curr(m_src_vertex).dist,
155                                  m_width,
156                                  curj,
157                                  m_inner_join,
158                                  m_miter_limit,
159                                  m_inner_miter_limit,
160                                  m_approx_scale);
161                 ++m_src_vertex;
162                 m_prev_status = m_status;
163                 m_status = out_vertices;
164                 m_out_vertex = 0;
165                 break;
166             case close_first:
167                 m_status = outline2;
168                 cmd = path_cmd_move_to;
169             case outline2:
170                 if(m_src_vertex <= unsigned(m_closed == 0)) {
171                     m_status = end_poly2;
172                     m_prev_status = stop;
173                     break;
174                 }
175                 --m_src_vertex;
176                 curj = m_src_vertices[m_src_vertex].cmd & path_flags_jr ? miter_join_round : m_line_join;
177                 stroke_calc_join(m_out_vertices,
178                                  m_src_vertices.next(m_src_vertex),
179                                  m_src_vertices.curr(m_src_vertex),
180                                  m_src_vertices.prev(m_src_vertex),
181                                  m_src_vertices.curr(m_src_vertex).dist,
182                                  m_src_vertices.prev(m_src_vertex).dist,
183                                  m_width,
184                                  curj,
185                                  m_inner_join,
186                                  m_miter_limit,
187                                  m_inner_miter_limit,
188                                  m_approx_scale);
189                 m_prev_status = m_status;
190                 m_status = out_vertices;
191                 m_out_vertex = 0;
192                 break;
193             case out_vertices:
194                 if(m_out_vertex >= m_out_vertices.size()) {
195                     m_status = m_prev_status;
196                 } else {
197                     const point_type& c = m_out_vertices[m_out_vertex++];
198                     *x = c.x;
199                     *y = c.y;
200                     return cmd;
201                 }
202                 break;
203             case end_poly1:
204                 m_status = m_prev_status;
205                 return unsigned{path_cmd_end_poly} | path_flags_close | path_flags_ccw;
206             case end_poly2:
207                 m_status = m_prev_status;
208                 return unsigned{path_cmd_end_poly} | path_flags_close | path_flags_cw;
209             case stop:
210                 cmd = path_cmd_stop;
211                 break;
212         }
213     }
214     return cmd;
215 }
216 }
217 }  // namespace pdfium
218