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