• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 //----------------------------------------------------------------------------
3 // Anti-Grain Geometry - Version 2.3
4 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
5 //
6 // Permission to copy, use, modify, sell and distribute this software
7 // is granted provided this copyright notice appears in all copies.
8 // This software is provided "as is" without express or implied
9 // warranty, and with no claim as to its suitability for any purpose.
10 //
11 //----------------------------------------------------------------------------
12 //
13 // The author gratefully acknowleges the support of David Turner,
14 // Robert Wilhelm, and Werner Lemberg - the authors of the FreeType
15 // libray - in producing this work. See http://www.freetype.org for details.
16 //
17 //----------------------------------------------------------------------------
18 // Contact: mcseem@antigrain.com
19 //          mcseemagg@yahoo.com
20 //          http://www.antigrain.com
21 //----------------------------------------------------------------------------
22 //
23 // Adaptation for 32-bit screen coordinates has been sponsored by
24 // Liberty Technology Systems, Inc., visit http://lib-sys.com
25 //
26 // Liberty Technology Systems, Inc. is the provider of
27 // PostScript and PDF technology for software developers.
28 //
29 //----------------------------------------------------------------------------
30 #ifndef AGG_RASTERIZER_SCANLINE_AA_INCLUDED
31 #define AGG_RASTERIZER_SCANLINE_AA_INCLUDED
32 
33 #include "agg_array.h"
34 #include "agg_basics.h"
35 #include "agg_clip_liang_barsky.h"
36 #include "agg_math.h"
37 #include "agg_render_scanlines.h"
38 #include "core/fxcrt/fx_coordinates.h"
39 #include "core/fxcrt/fx_memory.h"
40 
41 namespace pdfium
42 {
43 namespace agg
44 {
45 enum poly_base_scale_e {
46     poly_base_shift = 8,
47     poly_base_size  = 1 << poly_base_shift,
48     poly_base_mask  = poly_base_size - 1
49 };
poly_coord(float c)50 inline int poly_coord(float c)
51 {
52     return int(c * float{poly_base_size});
53 }
54 struct cell_aa  {
55     int x;
56     int y;
57     int cover;
58     int area;
59     void set(int x, int y, int c, int a);
60     void set_coord(int x, int y);
61     void set_cover(int c, int a);
62     void add_cover(int c, int a);
63 };
64 class outline_aa
65 {
66     enum cell_block_scale_e {
67         cell_block_shift = 12,
68         cell_block_size  = 1 << cell_block_shift,
69         cell_block_mask  = cell_block_size - 1,
70         cell_block_pool  = 256,
71         cell_block_limit = 1024
72     };
73     struct sorted_y  {
74         unsigned start;
75         unsigned num;
76     };
77 public:
78     ~outline_aa();
79     outline_aa();
80     void reset();
81     void move_to(int x, int y);
82     void line_to(int x, int y);
min_x()83     int min_x() const
84     {
85         return m_min_x;
86     }
min_y()87     int min_y() const
88     {
89         return m_min_y;
90     }
max_x()91     int max_x() const
92     {
93         return m_max_x;
94     }
max_y()95     int max_y() const
96     {
97         return m_max_y;
98     }
99     void sort_cells();
total_cells()100     unsigned total_cells() const
101     {
102         return m_num_cells;
103     }
scanline_num_cells(unsigned y)104     unsigned scanline_num_cells(unsigned y) const
105     {
106         return m_sorted_y[y - m_min_y].num;
107     }
scanline_cells(unsigned y)108     const cell_aa* const* scanline_cells(unsigned y) const
109     {
110         return m_sorted_cells.data() + m_sorted_y[y - m_min_y].start;
111     }
sorted()112     bool sorted() const
113     {
114         return m_sorted;
115     }
116 private:
117     outline_aa(const outline_aa&);
118     const outline_aa& operator = (const outline_aa&);
119     void set_cur_cell(int x, int y);
120     void add_cur_cell();
121     void render_hline(int ey, int x1, int y1, int x2, int y2);
122     void render_line(int x1, int y1, int x2, int y2);
123     void allocate_block();
124 private:
125     unsigned  m_num_blocks;
126     unsigned  m_max_blocks;
127     unsigned  m_cur_block;
128     unsigned  m_num_cells;
129     cell_aa** m_cells;
130     cell_aa*  m_cur_cell_ptr;
131     pod_array<cell_aa*> m_sorted_cells;
132     pod_array<sorted_y> m_sorted_y;
133     cell_aa   m_cur_cell;
134     int       m_cur_x;
135     int       m_cur_y;
136     int       m_min_x;
137     int       m_min_y;
138     int       m_max_x;
139     int       m_max_y;
140     bool      m_sorted;
141 };
142 class scanline_hit_test
143 {
144 public:
scanline_hit_test(int x)145     scanline_hit_test(int x) : m_x(x), m_hit(false) {}
reset_spans()146     void reset_spans() {}
finalize(int)147     void finalize(int) {}
add_cell(int x,int)148     void add_cell(int x, int)
149     {
150         if(m_x == x) {
151             m_hit = true;
152         }
153     }
add_span(int x,int len,int)154     void add_span(int x, int len, int)
155     {
156         if(m_x >= x && m_x < x + len) {
157             m_hit = true;
158         }
159     }
num_spans()160     unsigned num_spans() const
161     {
162         return 1;
163     }
hit()164     bool hit() const
165     {
166         return m_hit;
167     }
168 private:
169     int  m_x;
170     bool m_hit;
171 };
172 enum filling_rule_e {
173     fill_non_zero,
174     fill_even_odd
175 };
176 class rasterizer_scanline_aa
177 {
178     enum status {
179         status_initial,
180         status_line_to,
181         status_closed
182     };
183 public:
184     enum aa_scale_e {
185         aa_num   = 1 << 8,
186         aa_mask  = aa_num - 1,
187         aa_2num  = aa_num * 2,
188         aa_2mask = aa_2num - 1
189     };
rasterizer_scanline_aa()190     rasterizer_scanline_aa() :
191         m_filling_rule(fill_non_zero),
192         m_clipped_start_x(0),
193         m_clipped_start_y(0),
194         m_status(status_initial),
195         m_clipping(false)
196     {
197     }
~rasterizer_scanline_aa()198     ~rasterizer_scanline_aa() {}
filling_rule(filling_rule_e filling_rule)199     void filling_rule(filling_rule_e filling_rule)
200     {
201         m_filling_rule = filling_rule;
202     }
min_x()203     int min_x() const
204     {
205         return m_outline.min_x();
206     }
min_y()207     int min_y() const
208     {
209         return m_outline.min_y();
210     }
max_x()211     int max_x() const
212     {
213         return m_outline.max_x();
214     }
max_y()215     int max_y() const
216     {
217         return m_outline.max_y();
218     }
reset()219     void reset()
220     {
221         m_outline.reset();
222         m_status = status_initial;
223     }
clip_box(float x1,float y1,float x2,float y2)224     void clip_box(float x1, float y1, float x2, float y2)
225     {
226         m_clip_box = rect(poly_coord(x1), poly_coord(y1),
227                           poly_coord(x2), poly_coord(y2));
228         m_clip_box.normalize();
229         m_clipping = true;
230     }
add_vertex(float x,float y,unsigned cmd)231     void add_vertex(float x, float y, unsigned cmd)
232     {
233         if(is_close(cmd)) {
234             close_polygon();
235         } else {
236             if(is_move_to(cmd)) {
237                 move_to(poly_coord(x), poly_coord(y));
238             } else {
239                 if(is_vertex(cmd)) {
240                     line_to(poly_coord(x), poly_coord(y));
241                 }
242             }
243         }
244     }
move_to(int x,int y)245     void move_to(int x, int y)
246     {
247         if(m_clipping) {
248             if(m_outline.sorted()) {
249                 reset();
250             }
251             if(m_status == status_line_to) {
252                 close_polygon();
253             }
254             m_prev_x = m_start_x = x;
255             m_prev_y = m_start_y = y;
256             m_status = status_initial;
257             m_prev_flags = clipping_flags(x, y, m_clip_box);
258             if(m_prev_flags == 0) {
259                 move_to_no_clip(x, y);
260             }
261         } else {
262             move_to_no_clip(x, y);
263         }
264     }
line_to(int x,int y)265     void line_to(int x, int y)
266     {
267         if(m_clipping) {
268             clip_segment(x, y);
269         } else {
270             line_to_no_clip(x, y);
271         }
272     }
close_polygon()273     void close_polygon()
274     {
275         if (m_status != status_line_to) {
276             return;
277         }
278         if(m_clipping) {
279             clip_segment(m_start_x, m_start_y);
280         }
281         close_polygon_no_clip();
282     }
calculate_alpha(int area,bool no_smooth)283     AGG_INLINE unsigned calculate_alpha(int area, bool no_smooth) const
284     {
285         int cover = area >> (poly_base_shift * 2 + 1 - 8);
286         if(cover < 0) {
287             cover = -cover;
288         }
289         if(m_filling_rule == fill_even_odd) {
290             cover &= aa_2mask;
291             if(cover > aa_num) {
292                 cover = aa_2num - cover;
293             }
294         }
295         if (no_smooth) {
296             cover = cover > aa_mask / 2 ? aa_mask : 0;
297         }
298         if(cover > aa_mask) {
299             cover = aa_mask;
300         }
301         return cover;
302     }
sort()303     AGG_INLINE void sort()
304     {
305         m_outline.sort_cells();
306     }
rewind_scanlines()307     AGG_INLINE bool rewind_scanlines()
308     {
309         close_polygon();
310         m_outline.sort_cells();
311         if(m_outline.total_cells() == 0) {
312             return false;
313         }
314         m_cur_y = m_outline.min_y();
315         return true;
316     }
navigate_scanline(int y)317     AGG_INLINE bool navigate_scanline(int y)
318     {
319         close_polygon();
320         m_outline.sort_cells();
321         if(m_outline.total_cells() == 0 ||
322                 y < m_outline.min_y() ||
323                 y > m_outline.max_y()) {
324             return false;
325         }
326         m_cur_y = y;
327         return true;
328     }
sweep_scanline(Scanline & sl,bool no_smooth)329     template<class Scanline> bool sweep_scanline(Scanline& sl, bool no_smooth)
330     {
331         for(;;) {
332             if(m_cur_y > m_outline.max_y()) {
333                 return false;
334             }
335             sl.reset_spans();
336             unsigned num_cells = m_outline.scanline_num_cells(m_cur_y);
337             const cell_aa* const* cells = m_outline.scanline_cells(m_cur_y);
338             int cover = 0;
339             while(num_cells) {
340                 const cell_aa* cur_cell = *cells;
341                 int x    = cur_cell->x;
342                 int area = cur_cell->area;
343                 bool seen_area_overflow = false;
344                 bool seen_cover_overflow = false;
345                 if(!safe_add(&cover, cur_cell->cover)) {
346                     break;
347                 }
348                 while(--num_cells) {
349                     cur_cell = *++cells;
350                     if(cur_cell->x != x) {
351                         break;
352                     }
353                     if(seen_area_overflow) {
354                         continue;
355                     }
356                     if(!safe_add(&area, cur_cell->area)) {
357                         seen_area_overflow = true;
358                         continue;
359                     }
360                     if(!safe_add(&cover, cur_cell->cover)) {
361                         seen_cover_overflow = true;
362                         break;
363                     }
364                 }
365                 if(seen_area_overflow) {
366                     continue;
367                 }
368                 if(seen_cover_overflow) {
369                     break;
370                 }
371                 if(area) {
372                     unsigned alpha = calculate_alpha(calculate_area(cover, poly_base_shift + 1) - area, no_smooth);
373                     if(alpha) {
374                         sl.add_cell(x, alpha);
375                     }
376                     x++;
377                 }
378                 if(num_cells && cur_cell->x > x) {
379                     unsigned alpha = calculate_alpha(calculate_area(cover, poly_base_shift + 1), no_smooth);
380                     if(alpha) {
381                         sl.add_span(x, cur_cell->x - x, alpha);
382                     }
383                 }
384             }
385             if(sl.num_spans()) {
386                 break;
387             }
388             ++m_cur_y;
389         }
390         sl.finalize(m_cur_y);
391         ++m_cur_y;
392         return true;
393     }
394     template<class VertexSource>
395     void add_path(VertexSource& vs, unsigned path_id = 0)
396     {
397         float x;
398         float y;
399         unsigned cmd;
400         vs.rewind(path_id);
401         while(!is_stop(cmd = vs.vertex(&x, &y))) {
402             add_vertex(x, y, cmd);
403         }
404     }
405     template<class VertexSource>
406     void add_path_transformed(VertexSource& vs, const CFX_Matrix* pMatrix, unsigned path_id = 0)
407     {
408         float x;
409         float y;
410         unsigned cmd;
411         vs.rewind(path_id);
412         while(!is_stop(cmd = vs.vertex(&x, &y))) {
413           if (pMatrix) {
414             CFX_PointF ret = pMatrix->Transform(CFX_PointF(x, y));
415             x = ret.x;
416             y = ret.y;
417           }
418           add_vertex(x, y, cmd);
419         }
420     }
421 private:
422     rasterizer_scanline_aa(const rasterizer_scanline_aa&);
423     const rasterizer_scanline_aa&
424     operator = (const rasterizer_scanline_aa&);
move_to_no_clip(int x,int y)425     void move_to_no_clip(int x, int y)
426     {
427         if(m_status == status_line_to) {
428             close_polygon_no_clip();
429         }
430         m_outline.move_to(x * 1, y);
431         m_clipped_start_x = x;
432         m_clipped_start_y = y;
433         m_status = status_line_to;
434     }
line_to_no_clip(int x,int y)435     void line_to_no_clip(int x, int y)
436     {
437         if(m_status != status_initial) {
438             m_outline.line_to(x * 1, y);
439             m_status = status_line_to;
440         }
441     }
close_polygon_no_clip()442     void close_polygon_no_clip()
443     {
444         if(m_status == status_line_to) {
445             m_outline.line_to(m_clipped_start_x * 1, m_clipped_start_y);
446             m_status = status_closed;
447         }
448     }
clip_segment(int x,int y)449     void clip_segment(int x, int y)
450     {
451         unsigned flags = clipping_flags(x, y, m_clip_box);
452         if(m_prev_flags == flags) {
453             if(flags == 0) {
454                 if(m_status == status_initial) {
455                     move_to_no_clip(x, y);
456                 } else {
457                     line_to_no_clip(x, y);
458                 }
459             }
460         } else {
461             int cx[4];
462             int cy[4];
463             unsigned n = clip_liang_barsky(m_prev_x, m_prev_y,
464                                            x, y,
465                                            m_clip_box,
466                                            cx, cy);
467             const int* px = cx;
468             const int* py = cy;
469             while(n--) {
470                 if(m_status == status_initial) {
471                     move_to_no_clip(*px++, *py++);
472                 } else {
473                     line_to_no_clip(*px++, *py++);
474                 }
475             }
476         }
477         m_prev_flags = flags;
478         m_prev_x = x;
479         m_prev_y = y;
480     }
481 private:
482     static int calculate_area(int cover, int shift);
483     static bool safe_add(int* op1, int op2);
484 
485     outline_aa     m_outline;
486     filling_rule_e m_filling_rule;
487     int            m_clipped_start_x;
488     int            m_clipped_start_y;
489     int            m_start_x;
490     int            m_start_y;
491     int            m_prev_x;
492     int            m_prev_y;
493     unsigned       m_prev_flags;
494     unsigned       m_status;
495     rect           m_clip_box;
496     bool           m_clipping;
497     int            m_cur_y;
498 };
499 }
500 }  // namespace pdfium
501 #endif
502