1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file.  Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 /***************************************************************************/
43 /*                                                                         */
44 /*  qgrayraster.c, derived from ftgrays.c                                  */
45 /*                                                                         */
46 /*    A new `perfect' anti-aliasing renderer (body).                       */
47 /*                                                                         */
48 /*  Copyright 2000-2001, 2002, 2003 by                                     */
49 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
50 /*                                                                         */
51 /*  This file is part of the FreeType project, and may only be used,       */
52 /*  modified, and distributed under the terms of the FreeType project      */
53 /*  license, ../../3rdparty/freetype/docs/FTL.TXT.  By continuing to use,  */
54 /*  modify, or distribute this file you indicate that you have read        */
55 /*  the license and understand and accept it fully.                        */
56 /*                                                                         */
57 /***************************************************************************/
58 
59   /*************************************************************************/
60   /*                                                                       */
61   /* This file can be compiled without the rest of the FreeType engine, by */
62   /* defining the _STANDALONE_ macro when compiling it.  You also need to  */
63   /* put the files `ftgrays.h' and `ftimage.h' into the current            */
64   /* compilation directory.  Typically, you could do something like        */
65   /*                                                                       */
66   /* - copy `src/smooth/ftgrays.c' (this file) to your current directory   */
67   /*                                                                       */
68   /* - copy `include/freetype/ftimage.h' and `src/smooth/ftgrays.h' to the */
69   /*   same directory                                                      */
70   /*                                                                       */
71   /* - compile `ftgrays' with the _STANDALONE_ macro defined, as in        */
72   /*                                                                       */
73   /*     cc -c -D_STANDALONE_ ftgrays.c                                    */
74   /*                                                                       */
75   /* The renderer can be initialized with a call to                        */
76   /* `qt_ft_gray_raster.raster_new'; an anti-aliased bitmap can be generated  */
77   /* with a call to `qt_ft_gray_raster.raster_render'.                        */
78   /*                                                                       */
79   /* See the comments and documentation in the file `ftimage.h' for more   */
80   /* details on how the raster works.                                      */
81   /*                                                                       */
82   /*************************************************************************/
83 
84   /*************************************************************************/
85   /*                                                                       */
86   /* This is a new anti-aliasing scan-converter for FreeType 2.  The       */
87   /* algorithm used here is _very_ different from the one in the standard  */
88   /* `ftraster' module.  Actually, `ftgrays' computes the _exact_          */
89   /* coverage of the outline on each pixel cell.                           */
90   /*                                                                       */
91   /* It is based on ideas that I initially found in Raph Levien's          */
92   /* excellent LibArt graphics library (see http://www.levien.com/libart   */
93   /* for more information, though the web pages do not tell anything       */
94   /* about the renderer; you'll have to dive into the source code to       */
95   /* understand how it works).                                             */
96   /*                                                                       */
97   /* Note, however, that this is a _very_ different implementation         */
98   /* compared to Raph's.  Coverage information is stored in a very         */
99   /* different way, and I don't use sorted vector paths.  Also, it doesn't */
100   /* use floating point values.                                            */
101   /*                                                                       */
102   /* This renderer has the following advantages:                           */
103   /*                                                                       */
104   /* - It doesn't need an intermediate bitmap.  Instead, one can supply a  */
105   /*   callback function that will be called by the renderer to draw gray  */
106   /*   spans on any target surface.  You can thus do direct composition on */
107   /*   any kind of bitmap, provided that you give the renderer the right   */
108   /*   callback.                                                           */
109   /*                                                                       */
110   /* - A perfect anti-aliaser, i.e., it computes the _exact_ coverage on   */
111   /*   each pixel cell.                                                    */
112   /*                                                                       */
113   /* - It performs a single pass on the outline (the `standard' FT2        */
114   /*   renderer makes two passes).                                         */
115   /*                                                                       */
116   /* - It can easily be modified to render to _any_ number of gray levels  */
117   /*   cheaply.                                                            */
118   /*                                                                       */
119   /* - For small (< 20) pixel sizes, it is faster than the standard        */
120   /*   renderer.                                                           */
121   /*                                                                       */
122   /*************************************************************************/
123 
124 /* experimental support for gamma correction within the rasterizer */
125 #define xxxGRAYS_USE_GAMMA
126 
127 
128   /*************************************************************************/
129   /*                                                                       */
130   /* The macro QT_FT_COMPONENT is used in trace mode.  It is an implicit      */
131   /* parameter of the QT_FT_TRACE() and QT_FT_ERROR() macros, used to print/log  */
132   /* messages during execution.                                            */
133   /*                                                                       */
134 #undef  QT_FT_COMPONENT
135 #define QT_FT_COMPONENT  trace_smooth
136 
137 
138 #define ErrRaster_MemoryOverflow   -4
139 
140 #if defined(VXWORKS)
141 #  include <vxWorksCommon.h>    /* needed for setjmp.h */
142 #endif
143 #include <string.h>             /* for qt_ft_memcpy() */
144 #include <setjmp.h>
145 #include <limits.h>
146 
147 #define QT_FT_UINT_MAX  UINT_MAX
148 
149 #define qt_ft_memset   memset
150 
151 #define qt_ft_setjmp   setjmp
152 #define qt_ft_longjmp  longjmp
153 #define qt_ft_jmp_buf  jmp_buf
154 
155 #define ErrRaster_Invalid_Mode      -2
156 #define ErrRaster_Invalid_Outline   -1
157 #define ErrRaster_Invalid_Argument  -3
158 #define ErrRaster_Memory_Overflow   -4
159 #define ErrRaster_OutOfMemory       -6
160 
161 #define QT_FT_BEGIN_HEADER
162 #define QT_FT_END_HEADER
163 
164 #include <private/qrasterdefs_p.h>
165 #include <private/qgrayraster_p.h>
166 
167 #include <stdlib.h>
168 #include <stdio.h>
169 
170   /* This macro is used to indicate that a function parameter is unused. */
171   /* Its purpose is simply to reduce compiler warnings.  Note also that  */
172   /* simply defining it as `(void)x' doesn't avoid warnings with certain */
173   /* ANSI compilers (e.g. LCC).                                          */
174 #define QT_FT_UNUSED( x )  (x) = (x)
175 
176   /* Disable the tracing mechanism for simplicity -- developers can      */
177   /* activate it easily by redefining these two macros.                  */
178 #ifndef QT_FT_ERROR
179 #define QT_FT_ERROR( x )  do ; while ( 0 )     /* nothing */
180 #endif
181 
182 #ifndef QT_FT_TRACE
183 #define QT_FT_TRACE( x )  do ; while ( 0 )     /* nothing */
184 #endif
185 
186 #ifndef QT_FT_MEM_SET
187 #define QT_FT_MEM_SET( d, s, c )  qt_ft_memset( d, s, c )
188 #endif
189 
190 #ifndef QT_FT_MEM_ZERO
191 #define QT_FT_MEM_ZERO( dest, count )  QT_FT_MEM_SET( dest, 0, count )
192 #endif
193 
194   /* define this to dump debugging information */
195 #define xxxDEBUG_GRAYS
196 
197 
198 #define RAS_ARG   PWorker  worker
199 #define RAS_ARG_  PWorker  worker,
200 
201 #define RAS_VAR   worker
202 #define RAS_VAR_  worker,
203 
204 #define ras       (*worker)
205 
206 
207   /* must be at least 6 bits! */
208 #define PIXEL_BITS  8
209 
210 #define ONE_PIXEL       ( 1L << PIXEL_BITS )
211 #define PIXEL_MASK      ( -1L << PIXEL_BITS )
212 #define TRUNC( x )      ( (TCoord)( (x) >> PIXEL_BITS ) )
213 #define SUBPIXELS( x )  ( (TPos)(x) << PIXEL_BITS )
214 #define FLOOR( x )      ( (x) & -ONE_PIXEL )
215 #define CEILING( x )    ( ( (x) + ONE_PIXEL - 1 ) & -ONE_PIXEL )
216 #define ROUND( x )      ( ( (x) + ONE_PIXEL / 2 ) & -ONE_PIXEL )
217 
218 #if PIXEL_BITS >= 6
219 #define UPSCALE( x )    ( (x) << ( PIXEL_BITS - 6 ) )
220 #define DOWNSCALE( x )  ( (x) >> ( PIXEL_BITS - 6 ) )
221 #else
222 #define UPSCALE( x )    ( (x) >> ( 6 - PIXEL_BITS ) )
223 #define DOWNSCALE( x )  ( (x) << ( 6 - PIXEL_BITS ) )
224 #endif
225 
226   /*************************************************************************/
227   /*                                                                       */
228   /*   TYPE DEFINITIONS                                                    */
229   /*                                                                       */
230 
231   /* don't change the following types to QT_FT_Int or QT_FT_Pos, since we might */
232   /* need to define them to "float" or "double" when experimenting with   */
233   /* new algorithms                                                       */
234 
235   typedef int   TCoord;   /* integer scanline/pixel coordinate */
236   typedef int   TPos;     /* sub-pixel coordinate              */
237 
238   /* determine the type used to store cell areas.  This normally takes at */
239   /* least PIXEL_BITS*2 + 1 bits.  On 16-bit systems, we need to use      */
240   /* `long' instead of `int', otherwise bad things happen                 */
241 
242 #if PIXEL_BITS <= 7
243 
244   typedef int  TArea;
245 
246 #else /* PIXEL_BITS >= 8 */
247 
248   /* approximately determine the size of integers using an ANSI-C header */
249 #if QT_FT_UINT_MAX == 0xFFFFU
250   typedef long  TArea;
251 #else
252   typedef int   TArea;
253 #endif
254 
255 #endif /* PIXEL_BITS >= 8 */
256 
257 
258   /* maximal number of gray spans in a call to the span callback */
259 #define QT_FT_MAX_GRAY_SPANS  256
260 
261 
262   typedef struct TCell_*  PCell;
263 
264   typedef struct  TCell_
265   {
266     int    x;
267     int    cover;
268     TArea  area;
269     PCell  next;
270 
271   } TCell;
272 
273 
274   typedef struct  TWorker_
275   {
276     TCoord  ex, ey;
277     TPos    min_ex, max_ex;
278     TPos    min_ey, max_ey;
279     TPos    count_ex, count_ey;
280 
281     TArea   area;
282     int     cover;
283     int     invalid;
284 
285     PCell   cells;
286     int     max_cells;
287     int     num_cells;
288 
289     TCoord  cx, cy;
290     TPos    x,  y;
291 
292     TPos    last_ey;
293 
294     QT_FT_Vector   bez_stack[32 * 3 + 1];
295     int         lev_stack[32];
296 
297     QT_FT_Outline  outline;
298     QT_FT_Bitmap   target;
299     QT_FT_BBox     clip_box;
300 
301     QT_FT_Span     gray_spans[QT_FT_MAX_GRAY_SPANS];
302     int         num_gray_spans;
303 
304     QT_FT_Raster_Span_Func  render_span;
305     void*                render_span_data;
306 
307     int  band_size;
308     int  band_shoot;
309     int  conic_level;
310     int  cubic_level;
311 
312     qt_ft_jmp_buf  jump_buffer;
313 
314     void*       buffer;
315     long        buffer_size;
316 
317     PCell*     ycells;
318     int        ycount;
319 
320     int        skip_spans;
321   } TWorker, *PWorker;
322 
323 
324   typedef struct TRaster_
325   {
326     void*    buffer;
327     long     buffer_size;
328     long     buffer_allocated_size;
329     int      band_size;
330     void*    memory;
331     PWorker  worker;
332 
333   } TRaster, *PRaster;
334 
q_gray_rendered_spans(TRaster * raster)335   int q_gray_rendered_spans(TRaster *raster)
336   {
337     if ( raster && raster->worker )
338       return raster->worker->skip_spans > 0 ? 0 : -raster->worker->skip_spans;
339     return 0;
340   }
341 
342   /*************************************************************************/
343   /*                                                                       */
344   /* Initialize the cells table.                                           */
345   /*                                                                       */
346   static void
gray_init_cells(RAS_ARG_ void * buffer,long byte_size)347   gray_init_cells( RAS_ARG_ void*  buffer,
348                    long            byte_size )
349   {
350     ras.buffer      = buffer;
351     ras.buffer_size = byte_size;
352 
353     ras.ycells      = (PCell*) buffer;
354     ras.cells       = NULL;
355     ras.max_cells   = 0;
356     ras.num_cells   = 0;
357     ras.area        = 0;
358     ras.cover       = 0;
359     ras.invalid     = 1;
360   }
361 
362 
363   /*************************************************************************/
364   /*                                                                       */
365   /* Compute the outline bounding box.                                     */
366   /*                                                                       */
367   static void
gray_compute_cbox(RAS_ARG)368   gray_compute_cbox( RAS_ARG )
369   {
370     QT_FT_Outline*  outline = &ras.outline;
371     QT_FT_Vector*   vec     = outline->points;
372     QT_FT_Vector*   limit   = vec + outline->n_points;
373 
374 
375     if ( outline->n_points <= 0 )
376     {
377       ras.min_ex = ras.max_ex = 0;
378       ras.min_ey = ras.max_ey = 0;
379       return;
380     }
381 
382     ras.min_ex = ras.max_ex = vec->x;
383     ras.min_ey = ras.max_ey = vec->y;
384 
385     vec++;
386 
387     for ( ; vec < limit; vec++ )
388     {
389       TPos  x = vec->x;
390       TPos  y = vec->y;
391 
392 
393       if ( x < ras.min_ex ) ras.min_ex = x;
394       if ( x > ras.max_ex ) ras.max_ex = x;
395       if ( y < ras.min_ey ) ras.min_ey = y;
396       if ( y > ras.max_ey ) ras.max_ey = y;
397     }
398 
399     /* truncate the bounding box to integer pixels */
400     ras.min_ex = ras.min_ex >> 6;
401     ras.min_ey = ras.min_ey >> 6;
402     ras.max_ex = ( ras.max_ex + 63 ) >> 6;
403     ras.max_ey = ( ras.max_ey + 63 ) >> 6;
404   }
405 
406 
407   /*************************************************************************/
408   /*                                                                       */
409   /* Record the current cell in the table.                                 */
410   /*                                                                       */
411   static void
gray_record_cell(RAS_ARG)412   gray_record_cell( RAS_ARG )
413   {
414     PCell  *pcell, cell;
415     int     x = ras.ex;
416 
417     if ( ras.invalid || !( ras.area | ras.cover ) )
418         return;
419 
420     if ( x > ras.max_ex )
421       x = ras.max_ex;
422 
423     pcell = &ras.ycells[ras.ey];
424 
425     for (;;)
426     {
427       cell = *pcell;
428       if ( cell == NULL || cell->x > x )
429         break;
430 
431       if ( cell->x == x ) {
432           cell->area  += ras.area;
433           cell->cover += ras.cover;
434           return;
435       }
436 
437       pcell = &cell->next;
438     }
439 
440     if ( ras.num_cells >= ras.max_cells )
441       qt_ft_longjmp( ras.jump_buffer, 1 );
442 
443     cell        = ras.cells + ras.num_cells++;
444     cell->x     = x;
445     cell->area  = ras.area;
446     cell->cover = ras.cover;
447 
448     cell->next  = *pcell;
449     *pcell      = cell;
450   }
451 
452 
453   /*************************************************************************/
454   /*                                                                       */
455   /* Set the current cell to a new position.                               */
456   /*                                                                       */
457   static void
gray_set_cell(RAS_ARG_ TCoord ex,TCoord ey)458   gray_set_cell( RAS_ARG_ TCoord  ex,
459                           TCoord  ey )
460   {
461     /* Move the cell pointer to a new position.  We set the `invalid'      */
462     /* flag to indicate that the cell isn't part of those we're interested */
463     /* in during the render phase.  This means that:                       */
464     /*                                                                     */
465     /* . the new vertical position must be within min_ey..max_ey-1.        */
466     /* . the new horizontal position must be strictly less than max_ex     */
467     /*                                                                     */
468     /* Note that if a cell is to the left of the clipping region, it is    */
469     /* actually set to the (min_ex-1) horizontal position.                 */
470 
471     /* All cells that are on the left of the clipping region go to the */
472     /* min_ex - 1 horizontal position.                                 */
473     ey -= ras.min_ey;
474 
475     if ( ex > ras.max_ex )
476       ex = ras.max_ex;
477 
478     ex -= ras.min_ex;
479     if ( ex < 0 )
480       ex = -1;
481 
482     /* are we moving to a different cell ? */
483     if ( ex != ras.ex || ey != ras.ey )
484     {
485       /* record the current one if it is valid */
486       if ( !ras.invalid )
487         gray_record_cell( RAS_VAR );
488 
489       ras.area  = 0;
490       ras.cover = 0;
491     }
492 
493     ras.ex      = ex;
494     ras.ey      = ey;
495     ras.invalid = ( (unsigned)ey >= (unsigned)ras.count_ey ||
496                               ex >= ras.count_ex           );
497   }
498 
499 
500   /*************************************************************************/
501   /*                                                                       */
502   /* Start a new contour at a given cell.                                  */
503   /*                                                                       */
504   static void
gray_start_cell(RAS_ARG_ TCoord ex,TCoord ey)505   gray_start_cell( RAS_ARG_ TCoord  ex,
506                             TCoord  ey )
507   {
508     if ( ex > ras.max_ex )
509       ex = (TCoord)( ras.max_ex );
510 
511     if ( ex < ras.min_ex )
512       ex = (TCoord)( ras.min_ex - 1 );
513 
514     ras.area    = 0;
515     ras.cover   = 0;
516     ras.ex      = ex - ras.min_ex;
517     ras.ey      = ey - ras.min_ey;
518     ras.last_ey = SUBPIXELS( ey );
519     ras.invalid = 0;
520 
521     gray_set_cell( RAS_VAR_ ex, ey );
522   }
523 
524 
525   /*************************************************************************/
526   /*                                                                       */
527   /* Render a scanline as one or more cells.                               */
528   /*                                                                       */
529   static void
gray_render_scanline(RAS_ARG_ TCoord ey,TPos x1,TCoord y1,TPos x2,TCoord y2)530   gray_render_scanline( RAS_ARG_ TCoord  ey,
531                                  TPos    x1,
532                                  TCoord  y1,
533                                  TPos    x2,
534                                  TCoord  y2 )
535   {
536     TCoord  ex1, ex2, fx1, fx2, delta;
537     int     p, first, dx;
538     int     incr, lift, mod, rem;
539 
540 
541     dx = x2 - x1;
542 
543     ex1 = TRUNC( x1 );
544     ex2 = TRUNC( x2 );
545     fx1 = (TCoord)( x1 - SUBPIXELS( ex1 ) );
546     fx2 = (TCoord)( x2 - SUBPIXELS( ex2 ) );
547 
548     /* trivial case.  Happens often */
549     if ( y1 == y2 )
550     {
551       gray_set_cell( RAS_VAR_ ex2, ey );
552       return;
553     }
554 
555     /* everything is located in a single cell.  That is easy! */
556     /*                                                        */
557     if ( ex1 == ex2 )
558     {
559       delta      = y2 - y1;
560       ras.area  += (TArea)( fx1 + fx2 ) * delta;
561       ras.cover += delta;
562       return;
563     }
564 
565     /* ok, we'll have to render a run of adjacent cells on the same */
566     /* scanline...                                                  */
567     /*                                                              */
568     p     = ( ONE_PIXEL - fx1 ) * ( y2 - y1 );
569     first = ONE_PIXEL;
570     incr  = 1;
571 
572     if ( dx < 0 )
573     {
574       p     = fx1 * ( y2 - y1 );
575       first = 0;
576       incr  = -1;
577       dx    = -dx;
578     }
579 
580     delta = (TCoord)( p / dx );
581     mod   = (TCoord)( p % dx );
582     if ( mod < 0 )
583     {
584       delta--;
585       mod += (TCoord)dx;
586     }
587 
588     ras.area  += (TArea)( fx1 + first ) * delta;
589     ras.cover += delta;
590 
591     ex1 += incr;
592     gray_set_cell( RAS_VAR_ ex1, ey );
593     y1  += delta;
594 
595     if ( ex1 != ex2 )
596     {
597       p    = ONE_PIXEL * ( y2 - y1 + delta );
598       lift = (TCoord)( p / dx );
599       rem  = (TCoord)( p % dx );
600       if ( rem < 0 )
601       {
602         lift--;
603         rem += (TCoord)dx;
604       }
605 
606       mod -= (int)dx;
607 
608       while ( ex1 != ex2 )
609       {
610         delta = lift;
611         mod  += rem;
612         if ( mod >= 0 )
613         {
614           mod -= (TCoord)dx;
615           delta++;
616         }
617 
618         ras.area  += (TArea)ONE_PIXEL * delta;
619         ras.cover += delta;
620         y1        += delta;
621         ex1       += incr;
622         gray_set_cell( RAS_VAR_ ex1, ey );
623       }
624     }
625 
626     delta      = y2 - y1;
627     ras.area  += (TArea)( fx2 + ONE_PIXEL - first ) * delta;
628     ras.cover += delta;
629   }
630 
631 
632   /*************************************************************************/
633   /*                                                                       */
634   /* Render a given line as a series of scanlines.                         */
635   /*                                                                       */
636   static void
gray_render_line(RAS_ARG_ TPos to_x,TPos to_y)637   gray_render_line( RAS_ARG_ TPos  to_x,
638                              TPos  to_y )
639   {
640     TCoord  ey1, ey2, fy1, fy2;
641     TPos    dx, dy, x, x2;
642     int     p, first;
643     int     delta, rem, mod, lift, incr;
644 
645 
646     ey1 = TRUNC( ras.last_ey );
647     ey2 = TRUNC( to_y );     /* if (ey2 >= ras.max_ey) ey2 = ras.max_ey-1; */
648     fy1 = (TCoord)( ras.y - ras.last_ey );
649     fy2 = (TCoord)( to_y - SUBPIXELS( ey2 ) );
650 
651     dx = to_x - ras.x;
652     dy = to_y - ras.y;
653 
654     /* XXX: we should do something about the trivial case where dx == 0, */
655     /*      as it happens very often!                                    */
656 
657     /* perform vertical clipping */
658     {
659       TCoord  min, max;
660 
661 
662       min = ey1;
663       max = ey2;
664       if ( ey1 > ey2 )
665       {
666         min = ey2;
667         max = ey1;
668       }
669       if ( min >= ras.max_ey || max < ras.min_ey )
670         goto End;
671     }
672 
673     /* everything is on a single scanline */
674     if ( ey1 == ey2 )
675     {
676       gray_render_scanline( RAS_VAR_ ey1, ras.x, fy1, to_x, fy2 );
677       goto End;
678     }
679 
680     /* vertical line - avoid calling gray_render_scanline */
681     incr = 1;
682 
683     if ( dx == 0 )
684     {
685       TCoord  ex     = TRUNC( ras.x );
686       TCoord  two_fx = (TCoord)( ( ras.x - SUBPIXELS( ex ) ) << 1 );
687       TPos    area;
688 
689 
690       first = ONE_PIXEL;
691       if ( dy < 0 )
692       {
693         first = 0;
694         incr  = -1;
695       }
696 
697       delta      = (int)( first - fy1 );
698       ras.area  += (TArea)two_fx * delta;
699       ras.cover += delta;
700       ey1       += incr;
701 
702       gray_set_cell( &ras, ex, ey1 );
703 
704       delta = (int)( first + first - ONE_PIXEL );
705       area  = (TArea)two_fx * delta;
706       while ( ey1 != ey2 )
707       {
708         ras.area  += area;
709         ras.cover += delta;
710         ey1       += incr;
711 
712         gray_set_cell( &ras, ex, ey1 );
713       }
714 
715       delta      = (int)( fy2 - ONE_PIXEL + first );
716       ras.area  += (TArea)two_fx * delta;
717       ras.cover += delta;
718 
719       goto End;
720     }
721 
722     /* ok, we have to render several scanlines */
723     p     = ( ONE_PIXEL - fy1 ) * dx;
724     first = ONE_PIXEL;
725     incr  = 1;
726 
727     if ( dy < 0 )
728     {
729       p     = fy1 * dx;
730       first = 0;
731       incr  = -1;
732       dy    = -dy;
733     }
734 
735     delta = (int)( p / dy );
736     mod   = (int)( p % dy );
737     if ( mod < 0 )
738     {
739       delta--;
740       mod += (TCoord)dy;
741     }
742 
743     x = ras.x + delta;
744     gray_render_scanline( RAS_VAR_ ey1, ras.x, fy1, x, (TCoord)first );
745 
746     ey1 += incr;
747     gray_set_cell( RAS_VAR_ TRUNC( x ), ey1 );
748 
749     if ( ey1 != ey2 )
750     {
751       p     = ONE_PIXEL * dx;
752       lift  = (int)( p / dy );
753       rem   = (int)( p % dy );
754       if ( rem < 0 )
755       {
756         lift--;
757         rem += (int)dy;
758       }
759       mod -= (int)dy;
760 
761       while ( ey1 != ey2 )
762       {
763         delta = lift;
764         mod  += rem;
765         if ( mod >= 0 )
766         {
767           mod -= (int)dy;
768           delta++;
769         }
770 
771         x2 = x + delta;
772         gray_render_scanline( RAS_VAR_ ey1, x,
773                                        (TCoord)( ONE_PIXEL - first ), x2,
774                                        (TCoord)first );
775         x = x2;
776 
777         ey1 += incr;
778         gray_set_cell( RAS_VAR_ TRUNC( x ), ey1 );
779       }
780     }
781 
782     gray_render_scanline( RAS_VAR_ ey1, x,
783                                    (TCoord)( ONE_PIXEL - first ), to_x,
784                                    fy2 );
785 
786   End:
787     ras.x       = to_x;
788     ras.y       = to_y;
789     ras.last_ey = SUBPIXELS( ey2 );
790   }
791 
792 
793   static void
gray_split_conic(QT_FT_Vector * base)794   gray_split_conic( QT_FT_Vector*  base )
795   {
796     TPos  a, b;
797 
798 
799     base[4].x = base[2].x;
800     b = base[1].x;
801     a = base[3].x = ( base[2].x + b ) / 2;
802     b = base[1].x = ( base[0].x + b ) / 2;
803     base[2].x = ( a + b ) / 2;
804 
805     base[4].y = base[2].y;
806     b = base[1].y;
807     a = base[3].y = ( base[2].y + b ) / 2;
808     b = base[1].y = ( base[0].y + b ) / 2;
809     base[2].y = ( a + b ) / 2;
810   }
811 
812 
813   static void
gray_render_conic(RAS_ARG_ const QT_FT_Vector * control,const QT_FT_Vector * to)814   gray_render_conic( RAS_ARG_ const QT_FT_Vector*  control,
815                               const QT_FT_Vector*  to )
816   {
817     TPos        dx, dy;
818     int         top, level;
819     int*        levels;
820     QT_FT_Vector*  arc;
821 
822 
823     dx = DOWNSCALE( ras.x ) + to->x - ( control->x << 1 );
824     if ( dx < 0 )
825       dx = -dx;
826     dy = DOWNSCALE( ras.y ) + to->y - ( control->y << 1 );
827     if ( dy < 0 )
828       dy = -dy;
829     if ( dx < dy )
830       dx = dy;
831 
832     level = 1;
833     dx = dx / ras.conic_level;
834     while ( dx > 0 )
835     {
836       dx >>= 2;
837       level++;
838     }
839 
840     /* a shortcut to speed things up */
841     if ( level <= 1 )
842     {
843       /* we compute the mid-point directly in order to avoid */
844       /* calling gray_split_conic()                          */
845       TPos  to_x, to_y, mid_x, mid_y;
846 
847 
848       to_x  = UPSCALE( to->x );
849       to_y  = UPSCALE( to->y );
850       mid_x = ( ras.x + to_x + 2 * UPSCALE( control->x ) ) / 4;
851       mid_y = ( ras.y + to_y + 2 * UPSCALE( control->y ) ) / 4;
852 
853       gray_render_line( RAS_VAR_ mid_x, mid_y );
854       gray_render_line( RAS_VAR_ to_x, to_y );
855 
856       return;
857     }
858 
859     arc       = ras.bez_stack;
860     levels    = ras.lev_stack;
861     top       = 0;
862     levels[0] = level;
863 
864     arc[0].x = UPSCALE( to->x );
865     arc[0].y = UPSCALE( to->y );
866     arc[1].x = UPSCALE( control->x );
867     arc[1].y = UPSCALE( control->y );
868     arc[2].x = ras.x;
869     arc[2].y = ras.y;
870 
871     while ( top >= 0 )
872     {
873       level = levels[top];
874       if ( level > 1 )
875       {
876         /* check that the arc crosses the current band */
877         TPos  min, max, y;
878 
879 
880         min = max = arc[0].y;
881 
882         y = arc[1].y;
883         if ( y < min ) min = y;
884         if ( y > max ) max = y;
885 
886         y = arc[2].y;
887         if ( y < min ) min = y;
888         if ( y > max ) max = y;
889 
890         if ( TRUNC( min ) >= ras.max_ey || TRUNC( max ) < ras.min_ey )
891           goto Draw;
892 
893         gray_split_conic( arc );
894         arc += 2;
895         top++;
896         levels[top] = levels[top - 1] = level - 1;
897         continue;
898       }
899 
900     Draw:
901       {
902         TPos  to_x, to_y, mid_x, mid_y;
903 
904 
905         to_x  = arc[0].x;
906         to_y  = arc[0].y;
907         mid_x = ( ras.x + to_x + 2 * arc[1].x ) / 4;
908         mid_y = ( ras.y + to_y + 2 * arc[1].y ) / 4;
909 
910         gray_render_line( RAS_VAR_ mid_x, mid_y );
911         gray_render_line( RAS_VAR_ to_x, to_y );
912 
913         top--;
914         arc -= 2;
915       }
916     }
917 
918     return;
919   }
920 
921 
922   static void
gray_split_cubic(QT_FT_Vector * base)923   gray_split_cubic( QT_FT_Vector*  base )
924   {
925     TPos  a, b, c, d;
926 
927 
928     base[6].x = base[3].x;
929     c = base[1].x;
930     d = base[2].x;
931     base[1].x = a = ( base[0].x + c ) / 2;
932     base[5].x = b = ( base[3].x + d ) / 2;
933     c = ( c + d ) / 2;
934     base[2].x = a = ( a + c ) / 2;
935     base[4].x = b = ( b + c ) / 2;
936     base[3].x = ( a + b ) / 2;
937 
938     base[6].y = base[3].y;
939     c = base[1].y;
940     d = base[2].y;
941     base[1].y = a = ( base[0].y + c ) / 2;
942     base[5].y = b = ( base[3].y + d ) / 2;
943     c = ( c + d ) / 2;
944     base[2].y = a = ( a + c ) / 2;
945     base[4].y = b = ( b + c ) / 2;
946     base[3].y = ( a + b ) / 2;
947   }
948 
949 
950   static void
gray_render_cubic(RAS_ARG_ const QT_FT_Vector * control1,const QT_FT_Vector * control2,const QT_FT_Vector * to)951   gray_render_cubic( RAS_ARG_ const QT_FT_Vector*  control1,
952                               const QT_FT_Vector*  control2,
953                               const QT_FT_Vector*  to )
954   {
955     TPos        dx, dy, da, db;
956     int         top, level;
957     int*        levels;
958     QT_FT_Vector*  arc;
959 
960 
961     dx = DOWNSCALE( ras.x ) + to->x - ( control1->x << 1 );
962     if ( dx < 0 )
963       dx = -dx;
964     dy = DOWNSCALE( ras.y ) + to->y - ( control1->y << 1 );
965     if ( dy < 0 )
966       dy = -dy;
967     if ( dx < dy )
968       dx = dy;
969     da = dx;
970 
971     dx = DOWNSCALE( ras.x ) + to->x - 3 * ( control1->x + control2->x );
972     if ( dx < 0 )
973       dx = -dx;
974     dy = DOWNSCALE( ras.y ) + to->y - 3 * ( control1->y + control2->y );
975     if ( dy < 0 )
976       dy = -dy;
977     if ( dx < dy )
978       dx = dy;
979     db = dx;
980 
981     level = 1;
982     da    = da / ras.cubic_level;
983     db    = db / ras.conic_level;
984     while ( da > 0 || db > 0 )
985     {
986       da >>= 2;
987       db >>= 3;
988       level++;
989     }
990 
991     if ( level <= 1 )
992     {
993       TPos   to_x, to_y, mid_x, mid_y;
994 
995 
996       to_x  = UPSCALE( to->x );
997       to_y  = UPSCALE( to->y );
998       mid_x = ( ras.x + to_x +
999                 3 * UPSCALE( control1->x + control2->x ) ) / 8;
1000       mid_y = ( ras.y + to_y +
1001                 3 * UPSCALE( control1->y + control2->y ) ) / 8;
1002 
1003       gray_render_line( RAS_VAR_ mid_x, mid_y );
1004       gray_render_line( RAS_VAR_ to_x, to_y );
1005       return;
1006     }
1007 
1008     arc      = ras.bez_stack;
1009     arc[0].x = UPSCALE( to->x );
1010     arc[0].y = UPSCALE( to->y );
1011     arc[1].x = UPSCALE( control2->x );
1012     arc[1].y = UPSCALE( control2->y );
1013     arc[2].x = UPSCALE( control1->x );
1014     arc[2].y = UPSCALE( control1->y );
1015     arc[3].x = ras.x;
1016     arc[3].y = ras.y;
1017 
1018     levels    = ras.lev_stack;
1019     top       = 0;
1020     levels[0] = level;
1021 
1022     while ( top >= 0 )
1023     {
1024       level = levels[top];
1025       if ( level > 1 )
1026       {
1027         /* check that the arc crosses the current band */
1028         TPos  min, max, y;
1029 
1030 
1031         min = max = arc[0].y;
1032         y = arc[1].y;
1033         if ( y < min ) min = y;
1034         if ( y > max ) max = y;
1035         y = arc[2].y;
1036         if ( y < min ) min = y;
1037         if ( y > max ) max = y;
1038         y = arc[3].y;
1039         if ( y < min ) min = y;
1040         if ( y > max ) max = y;
1041         if ( TRUNC( min ) >= ras.max_ey || TRUNC( max ) < 0 )
1042           goto Draw;
1043         gray_split_cubic( arc );
1044         arc += 3;
1045         top ++;
1046         levels[top] = levels[top - 1] = level - 1;
1047         continue;
1048       }
1049 
1050     Draw:
1051       {
1052         TPos  to_x, to_y, mid_x, mid_y;
1053 
1054 
1055         to_x  = arc[0].x;
1056         to_y  = arc[0].y;
1057         mid_x = ( ras.x + to_x + 3 * ( arc[1].x + arc[2].x ) ) / 8;
1058         mid_y = ( ras.y + to_y + 3 * ( arc[1].y + arc[2].y ) ) / 8;
1059 
1060         gray_render_line( RAS_VAR_ mid_x, mid_y );
1061         gray_render_line( RAS_VAR_ to_x, to_y );
1062         top --;
1063         arc -= 3;
1064       }
1065     }
1066 
1067     return;
1068   }
1069 
1070 
1071 
1072   static int
gray_move_to(const QT_FT_Vector * to,PWorker worker)1073   gray_move_to( const QT_FT_Vector*  to,
1074                 PWorker           worker )
1075   {
1076     TPos  x, y;
1077 
1078 
1079     /* record current cell, if any */
1080     gray_record_cell( worker );
1081 
1082     /* start to a new position */
1083     x = UPSCALE( to->x );
1084     y = UPSCALE( to->y );
1085 
1086     gray_start_cell( worker, TRUNC( x ), TRUNC( y ) );
1087 
1088     worker->x = x;
1089     worker->y = y;
1090     return 0;
1091   }
1092 
1093 
1094   static int
gray_line_to(const QT_FT_Vector * to,PWorker worker)1095   gray_line_to( const QT_FT_Vector*  to,
1096                 PWorker           worker )
1097   {
1098     gray_render_line( worker, UPSCALE( to->x ), UPSCALE( to->y ) );
1099     return 0;
1100   }
1101 
1102 
1103   static int
gray_conic_to(const QT_FT_Vector * control,const QT_FT_Vector * to,PWorker worker)1104   gray_conic_to( const QT_FT_Vector*  control,
1105                  const QT_FT_Vector*  to,
1106                  PWorker           worker )
1107   {
1108     gray_render_conic( worker, control, to );
1109     return 0;
1110   }
1111 
1112 
1113   static int
gray_cubic_to(const QT_FT_Vector * control1,const QT_FT_Vector * control2,const QT_FT_Vector * to,PWorker worker)1114   gray_cubic_to( const QT_FT_Vector*  control1,
1115                  const QT_FT_Vector*  control2,
1116                  const QT_FT_Vector*  to,
1117                  PWorker           worker )
1118   {
1119     gray_render_cubic( worker, control1, control2, to );
1120     return 0;
1121   }
1122 
1123 
1124   static void
gray_render_span(int count,const QT_FT_Span * spans,PWorker worker)1125   gray_render_span( int             count,
1126                     const QT_FT_Span*  spans,
1127                     PWorker         worker )
1128   {
1129     unsigned char*  p;
1130     QT_FT_Bitmap*      map = &worker->target;
1131 
1132     for ( ; count > 0; count--, spans++ )
1133     {
1134       unsigned char  coverage = spans->coverage;
1135 
1136       /* first of all, compute the scanline offset */
1137       p = (unsigned char*)map->buffer - spans->y * map->pitch;
1138       if ( map->pitch >= 0 )
1139         p += ( map->rows - 1 ) * map->pitch;
1140 
1141 
1142       if ( coverage )
1143       {
1144         /* For small-spans it is faster to do it by ourselves than
1145          * calling `memset'.  This is mainly due to the cost of the
1146          * function call.
1147          */
1148         if ( spans->len >= 8 )
1149           QT_FT_MEM_SET( p + spans->x, (unsigned char)coverage, spans->len );
1150         else
1151         {
1152           unsigned char*  q = p + spans->x;
1153 
1154 
1155           switch ( spans->len )
1156           {
1157           case 7: *q++ = (unsigned char)coverage;
1158           case 6: *q++ = (unsigned char)coverage;
1159           case 5: *q++ = (unsigned char)coverage;
1160           case 4: *q++ = (unsigned char)coverage;
1161           case 3: *q++ = (unsigned char)coverage;
1162           case 2: *q++ = (unsigned char)coverage;
1163           case 1: *q   = (unsigned char)coverage;
1164           default:
1165             ;
1166           }
1167         }
1168       }
1169     }
1170   }
1171 
1172 
1173   static void
gray_hline(RAS_ARG_ TCoord x,TCoord y,TPos area,int acount)1174   gray_hline( RAS_ARG_ TCoord  x,
1175                        TCoord  y,
1176                        TPos    area,
1177                        int     acount )
1178   {
1179     QT_FT_Span*  span;
1180     int       coverage;
1181     int       skip;
1182 
1183 
1184     /* compute the coverage line's coverage, depending on the    */
1185     /* outline fill rule                                         */
1186     /*                                                           */
1187     /* the coverage percentage is area/(PIXEL_BITS*PIXEL_BITS*2) */
1188     /*                                                           */
1189     coverage = (int)( area >> ( PIXEL_BITS * 2 + 1 - 8 ) );
1190                                                     /* use range 0..256 */
1191     if ( coverage < 0 )
1192       coverage = -coverage;
1193 
1194     if ( ras.outline.flags & QT_FT_OUTLINE_EVEN_ODD_FILL )
1195     {
1196       coverage &= 511;
1197 
1198       if ( coverage > 256 )
1199         coverage = 512 - coverage;
1200       else if ( coverage == 256 )
1201         coverage = 255;
1202     }
1203     else
1204     {
1205       /* normal non-zero winding rule */
1206       if ( coverage >= 256 )
1207         coverage = 255;
1208     }
1209 
1210     y += (TCoord)ras.min_ey;
1211     x += (TCoord)ras.min_ex;
1212 
1213     /* QT_FT_Span.x is a 16-bit short, so limit our coordinates appropriately */
1214     if ( x >= 32768 )
1215       x = 32767;
1216 
1217     if ( coverage )
1218     {
1219       /* see whether we can add this span to the current list */
1220       span  = ras.gray_spans + ras.num_gray_spans - 1;
1221       if ( ras.num_gray_spans > 0             &&
1222            span->y == y                       &&
1223            (int)span->x + span->len == (int)x &&
1224            span->coverage == coverage         )
1225       {
1226         span->len = (unsigned short)( span->len + acount );
1227         return;
1228       }
1229 
1230       if ( ras.num_gray_spans >= QT_FT_MAX_GRAY_SPANS )
1231       {
1232         if ( ras.render_span && ras.num_gray_spans > ras.skip_spans )
1233         {
1234           skip = ras.skip_spans > 0 ? ras.skip_spans : 0;
1235           ras.render_span( ras.num_gray_spans - skip,
1236                            ras.gray_spans + skip,
1237                            ras.render_span_data );
1238         }
1239 
1240         ras.skip_spans -= ras.num_gray_spans;
1241 
1242         /* ras.render_span( span->y, ras.gray_spans, count ); */
1243 
1244 #ifdef DEBUG_GRAYS
1245 
1246         if ( 1 )
1247         {
1248           int  n;
1249 
1250 
1251           fprintf( stderr, "y=%3d ", y );
1252           span = ras.gray_spans;
1253           for ( n = 0; n < count; n++, span++ )
1254             fprintf( stderr, "[%d..%d]:%02x ",
1255                      span->x, span->x + span->len - 1, span->coverage );
1256           fprintf( stderr, "\n" );
1257         }
1258 
1259 #endif /* DEBUG_GRAYS */
1260 
1261         ras.num_gray_spans = 0;
1262 
1263         span  = ras.gray_spans;
1264       }
1265       else
1266         span++;
1267 
1268       /* add a gray span to the current list */
1269       span->x        = (short)x;
1270       span->len      = (unsigned short)acount;
1271       span->y        = (short)y;
1272       span->coverage = (unsigned char)coverage;
1273 
1274       ras.num_gray_spans++;
1275     }
1276   }
1277 
1278 
1279 #ifdef DEBUG_GRAYS
1280 
1281   /* to be called while in the debugger */
gray_dump_cells(RAS_ARG)1282   gray_dump_cells( RAS_ARG )
1283   {
1284     int  yindex;
1285 
1286 
1287     for ( yindex = 0; yindex < ras.ycount; yindex++ )
1288     {
1289       PCell  cell;
1290 
1291 
1292       printf( "%3d:", yindex );
1293 
1294       for ( cell = ras.ycells[yindex]; cell != NULL; cell = cell->next )
1295         printf( " (%3d, c:%4d, a:%6d)", cell->x, cell->cover, cell->area );
1296       printf( "\n" );
1297     }
1298   }
1299 
1300 #endif /* DEBUG_GRAYS */
1301 
1302 
1303   static void
gray_sweep(RAS_ARG_ const QT_FT_Bitmap * target)1304   gray_sweep( RAS_ARG_ const QT_FT_Bitmap*  target )
1305   {
1306     int  yindex;
1307 
1308     QT_FT_UNUSED( target );
1309 
1310 
1311     if ( ras.num_cells == 0 )
1312       return;
1313 
1314     for ( yindex = 0; yindex < ras.ycount; yindex++ )
1315     {
1316       PCell   cell  = ras.ycells[yindex];
1317       TCoord  cover = 0;
1318       TCoord  x     = 0;
1319 
1320 
1321       for ( ; cell != NULL; cell = cell->next )
1322       {
1323         TArea  area;
1324 
1325 
1326         if ( cell->x > x && cover != 0 )
1327           gray_hline( RAS_VAR_ x, yindex, cover * ( ONE_PIXEL * 2 ),
1328                       cell->x - x );
1329 
1330         cover += cell->cover;
1331         area   = cover * ( ONE_PIXEL * 2 ) - cell->area;
1332 
1333         if ( area != 0 && cell->x >= 0 )
1334           gray_hline( RAS_VAR_ cell->x, yindex, area, 1 );
1335 
1336         x = cell->x + 1;
1337       }
1338 
1339       if ( ras.count_ex > x && cover != 0 )
1340         gray_hline( RAS_VAR_ x, yindex, cover * ( ONE_PIXEL * 2 ),
1341                     ras.count_ex - x );
1342     }
1343   }
1344 
1345   /*************************************************************************/
1346   /*                                                                       */
1347   /*  The following function should only compile in stand_alone mode,      */
1348   /*  i.e., when building this component without the rest of FreeType.     */
1349   /*                                                                       */
1350   /*************************************************************************/
1351 
1352   /*************************************************************************/
1353   /*                                                                       */
1354   /* <Function>                                                            */
1355   /*    QT_FT_Outline_Decompose                                               */
1356   /*                                                                       */
1357   /* <Description>                                                         */
1358   /*    Walks over an outline's structure to decompose it into individual  */
1359   /*    segments and Bezier arcs.  This function is also able to emit      */
1360   /*    `move to' and `close to' operations to indicate the start and end  */
1361   /*    of new contours in the outline.                                    */
1362   /*                                                                       */
1363   /* <Input>                                                               */
1364   /*    outline        :: A pointer to the source target.                  */
1365   /*                                                                       */
1366   /*    user           :: A typeless pointer which is passed to each       */
1367   /*                      emitter during the decomposition.  It can be     */
1368   /*                      used to store the state during the               */
1369   /*                      decomposition.                                   */
1370   /*                                                                       */
1371   /* <Return>                                                              */
1372   /*    Error code.  0 means success.                                      */
1373   /*                                                                       */
1374   static
QT_FT_Outline_Decompose(const QT_FT_Outline * outline,void * user)1375   int  QT_FT_Outline_Decompose( const QT_FT_Outline*        outline,
1376                              void*                    user )
1377   {
1378 #undef SCALED
1379 #define SCALED( x )  (x)
1380 
1381     QT_FT_Vector   v_last;
1382     QT_FT_Vector   v_control;
1383     QT_FT_Vector   v_start;
1384 
1385     QT_FT_Vector*  point;
1386     QT_FT_Vector*  limit;
1387     char*       tags;
1388 
1389     int   n;         /* index of contour in outline     */
1390     int   first;     /* index of first point in contour */
1391     int   error;
1392     char  tag;       /* current point's state           */
1393 
1394     first = 0;
1395 
1396     for ( n = 0; n < outline->n_contours; n++ )
1397     {
1398       int  last;  /* index of last point in contour */
1399 
1400 
1401       last  = outline->contours[n];
1402       limit = outline->points + last;
1403 
1404       v_start = outline->points[first];
1405       v_last  = outline->points[last];
1406 
1407       v_start.x = SCALED( v_start.x );
1408       v_start.y = SCALED( v_start.y );
1409 
1410       v_last.x  = SCALED( v_last.x );
1411       v_last.y  = SCALED( v_last.y );
1412 
1413       v_control = v_start;
1414 
1415       point = outline->points + first;
1416       tags  = outline->tags  + first;
1417       tag   = QT_FT_CURVE_TAG( tags[0] );
1418 
1419       /* A contour cannot start with a cubic control point! */
1420       if ( tag == QT_FT_CURVE_TAG_CUBIC )
1421         goto Invalid_Outline;
1422 
1423       /* check first point to determine origin */
1424       if ( tag == QT_FT_CURVE_TAG_CONIC )
1425       {
1426         /* first point is conic control.  Yes, this happens. */
1427         if ( QT_FT_CURVE_TAG( outline->tags[last] ) == QT_FT_CURVE_TAG_ON )
1428         {
1429           /* start at last point if it is on the curve */
1430           v_start = v_last;
1431           limit--;
1432         }
1433         else
1434         {
1435           /* if both first and last points are conic,         */
1436           /* start at their middle and record its position    */
1437           /* for closure                                      */
1438           v_start.x = ( v_start.x + v_last.x ) / 2;
1439           v_start.y = ( v_start.y + v_last.y ) / 2;
1440 
1441           v_last = v_start;
1442         }
1443         point--;
1444         tags--;
1445       }
1446 
1447       error = gray_move_to( &v_start, user );
1448       if ( error )
1449         goto Exit;
1450 
1451       while ( point < limit )
1452       {
1453         point++;
1454         tags++;
1455 
1456         tag = QT_FT_CURVE_TAG( tags[0] );
1457         switch ( tag )
1458         {
1459         case QT_FT_CURVE_TAG_ON:  /* emit a single line_to */
1460           {
1461             QT_FT_Vector  vec;
1462 
1463 
1464             vec.x = SCALED( point->x );
1465             vec.y = SCALED( point->y );
1466 
1467             error = gray_line_to( &vec, user );
1468             if ( error )
1469               goto Exit;
1470             continue;
1471           }
1472 
1473         case QT_FT_CURVE_TAG_CONIC:  /* consume conic arcs */
1474           {
1475             v_control.x = SCALED( point->x );
1476             v_control.y = SCALED( point->y );
1477 
1478           Do_Conic:
1479             if ( point < limit )
1480             {
1481               QT_FT_Vector  vec;
1482               QT_FT_Vector  v_middle;
1483 
1484 
1485               point++;
1486               tags++;
1487               tag = QT_FT_CURVE_TAG( tags[0] );
1488 
1489               vec.x = SCALED( point->x );
1490               vec.y = SCALED( point->y );
1491 
1492               if ( tag == QT_FT_CURVE_TAG_ON )
1493               {
1494                 error = gray_conic_to( &v_control, &vec,
1495                                                   user );
1496                 if ( error )
1497                   goto Exit;
1498                 continue;
1499               }
1500 
1501               if ( tag != QT_FT_CURVE_TAG_CONIC )
1502                 goto Invalid_Outline;
1503 
1504               v_middle.x = ( v_control.x + vec.x ) / 2;
1505               v_middle.y = ( v_control.y + vec.y ) / 2;
1506 
1507               error = gray_conic_to( &v_control, &v_middle,
1508                                                 user );
1509               if ( error )
1510                 goto Exit;
1511 
1512               v_control = vec;
1513               goto Do_Conic;
1514             }
1515 
1516             error = gray_conic_to( &v_control, &v_start,
1517                                               user );
1518             goto Close;
1519           }
1520 
1521         default:  /* QT_FT_CURVE_TAG_CUBIC */
1522           {
1523             QT_FT_Vector  vec1, vec2;
1524 
1525 
1526             if ( point + 1 > limit                             ||
1527                  QT_FT_CURVE_TAG( tags[1] ) != QT_FT_CURVE_TAG_CUBIC )
1528               goto Invalid_Outline;
1529 
1530             point += 2;
1531             tags  += 2;
1532 
1533             vec1.x = SCALED( point[-2].x );
1534             vec1.y = SCALED( point[-2].y );
1535 
1536             vec2.x = SCALED( point[-1].x );
1537             vec2.y = SCALED( point[-1].y );
1538 
1539             if ( point <= limit )
1540             {
1541               QT_FT_Vector  vec;
1542 
1543 
1544               vec.x = SCALED( point->x );
1545               vec.y = SCALED( point->y );
1546 
1547               error = gray_cubic_to( &vec1, &vec2, &vec, user );
1548               if ( error )
1549                 goto Exit;
1550               continue;
1551             }
1552 
1553             error = gray_cubic_to( &vec1, &vec2, &v_start, user );
1554             goto Close;
1555           }
1556         }
1557       }
1558 
1559       /* close the contour with a line segment */
1560       error = gray_line_to( &v_start, user );
1561 
1562    Close:
1563       if ( error )
1564         goto Exit;
1565 
1566       first = last + 1;
1567     }
1568 
1569     return 0;
1570 
1571   Exit:
1572     return error;
1573 
1574   Invalid_Outline:
1575     return ErrRaster_Invalid_Outline;
1576   }
1577 
1578   typedef struct  TBand_
1579   {
1580     TPos  min, max;
1581 
1582   } TBand;
1583 
1584 
1585   static int
gray_convert_glyph_inner(RAS_ARG)1586   gray_convert_glyph_inner( RAS_ARG )
1587   {
1588     volatile int  error = 0;
1589 
1590     if ( qt_ft_setjmp( ras.jump_buffer ) == 0 )
1591     {
1592       error = QT_FT_Outline_Decompose( &ras.outline, &ras );
1593       gray_record_cell( RAS_VAR );
1594     }
1595     else
1596     {
1597       error = ErrRaster_Memory_Overflow;
1598     }
1599 
1600     return error;
1601   }
1602 
1603 
1604   static int
gray_convert_glyph(RAS_ARG)1605   gray_convert_glyph( RAS_ARG )
1606   {
1607     TBand            bands[40];
1608     TBand* volatile  band;
1609     int volatile     n, num_bands;
1610     TPos volatile    min, max, max_y;
1611     QT_FT_BBox*      clip;
1612     int              skip;
1613 
1614     ras.num_gray_spans = 0;
1615 
1616     /* Set up state in the raster object */
1617     gray_compute_cbox( RAS_VAR );
1618 
1619     /* clip to target bitmap, exit if nothing to do */
1620     clip = &ras.clip_box;
1621 
1622     if ( ras.max_ex <= clip->xMin || ras.min_ex >= clip->xMax ||
1623          ras.max_ey <= clip->yMin || ras.min_ey >= clip->yMax )
1624       return 0;
1625 
1626     if ( ras.min_ex < clip->xMin ) ras.min_ex = clip->xMin;
1627     if ( ras.min_ey < clip->yMin ) ras.min_ey = clip->yMin;
1628 
1629     if ( ras.max_ex > clip->xMax ) ras.max_ex = clip->xMax;
1630     if ( ras.max_ey > clip->yMax ) ras.max_ey = clip->yMax;
1631 
1632     ras.count_ex = ras.max_ex - ras.min_ex;
1633     ras.count_ey = ras.max_ey - ras.min_ey;
1634 
1635     /* simple heuristic used to speed-up the bezier decomposition -- see */
1636     /* the code in gray_render_conic() and gray_render_cubic() for more  */
1637     /* details                                                           */
1638     ras.conic_level = 32;
1639     ras.cubic_level = 16;
1640 
1641     {
1642       int level = 0;
1643 
1644 
1645       if ( ras.count_ex > 24 || ras.count_ey > 24 )
1646         level++;
1647       if ( ras.count_ex > 120 || ras.count_ey > 120 )
1648         level++;
1649 
1650       ras.conic_level <<= level;
1651       ras.cubic_level <<= level;
1652     }
1653 
1654     /* setup vertical bands */
1655     num_bands = (int)( ( ras.max_ey - ras.min_ey ) / ras.band_size );
1656     if ( num_bands == 0 )  num_bands = 1;
1657     if ( num_bands >= 39 ) num_bands = 39;
1658 
1659     ras.band_shoot = 0;
1660 
1661     min   = ras.min_ey;
1662     max_y = ras.max_ey;
1663 
1664     for ( n = 0; n < num_bands; n++, min = max )
1665     {
1666       max = min + ras.band_size;
1667       if ( n == num_bands - 1 || max > max_y )
1668         max = max_y;
1669 
1670       bands[0].min = min;
1671       bands[0].max = max;
1672       band         = bands;
1673 
1674       while ( band >= bands )
1675       {
1676         TPos  bottom, top, middle;
1677         int   error;
1678 
1679         {
1680           PCell  cells_max;
1681           int    yindex;
1682           int    cell_start, cell_end, cell_mod;
1683 
1684 
1685           ras.ycells = (PCell*)ras.buffer;
1686           ras.ycount = band->max - band->min;
1687 
1688           cell_start = sizeof ( PCell ) * ras.ycount;
1689           cell_mod   = cell_start % sizeof ( TCell );
1690           if ( cell_mod > 0 )
1691             cell_start += sizeof ( TCell ) - cell_mod;
1692 
1693           cell_end  = ras.buffer_size;
1694           cell_end -= cell_end % sizeof( TCell );
1695 
1696           cells_max = (PCell)( (char*)ras.buffer + cell_end );
1697           ras.cells = (PCell)( (char*)ras.buffer + cell_start );
1698           if ( ras.cells >= cells_max )
1699             goto ReduceBands;
1700 
1701           ras.max_cells = (int)(cells_max - ras.cells);
1702           if ( ras.max_cells < 2 )
1703             goto ReduceBands;
1704 
1705           for ( yindex = 0; yindex < ras.ycount; yindex++ )
1706             ras.ycells[yindex] = NULL;
1707         }
1708 
1709         ras.num_cells = 0;
1710         ras.invalid   = 1;
1711         ras.min_ey    = band->min;
1712         ras.max_ey    = band->max;
1713         ras.count_ey  = band->max - band->min;
1714 
1715         error = gray_convert_glyph_inner( RAS_VAR );
1716 
1717         if ( !error )
1718         {
1719           gray_sweep( RAS_VAR_ &ras.target );
1720           band--;
1721           continue;
1722         }
1723         else if ( error != ErrRaster_Memory_Overflow )
1724           return 1;
1725 
1726       ReduceBands:
1727         /* render pool overflow; we will reduce the render band by half */
1728         bottom = band->min;
1729         top    = band->max;
1730         middle = bottom + ( ( top - bottom ) >> 1 );
1731 
1732         /* This is too complex for a single scanline; there must */
1733         /* be some problems.                                     */
1734         if ( middle == bottom )
1735         {
1736 #ifdef DEBUG_GRAYS
1737           fprintf( stderr, "Rotten glyph!\n" );
1738 #endif
1739           return ErrRaster_OutOfMemory;
1740         }
1741 
1742         if ( bottom-top >= ras.band_size )
1743           ras.band_shoot++;
1744 
1745         band[1].min = bottom;
1746         band[1].max = middle;
1747         band[0].min = middle;
1748         band[0].max = top;
1749         band++;
1750       }
1751     }
1752 
1753     if ( ras.render_span && ras.num_gray_spans > ras.skip_spans )
1754     {
1755         skip = ras.skip_spans > 0 ? ras.skip_spans : 0;
1756         ras.render_span( ras.num_gray_spans - skip,
1757                          ras.gray_spans + skip,
1758                          ras.render_span_data );
1759     }
1760 
1761     ras.skip_spans -= ras.num_gray_spans;
1762 
1763     if ( ras.band_shoot > 8 && ras.band_size > 16 )
1764       ras.band_size = ras.band_size / 2;
1765 
1766     return 0;
1767   }
1768 
1769 
1770   static int
gray_raster_render(QT_FT_Raster raster,const QT_FT_Raster_Params * params)1771   gray_raster_render( QT_FT_Raster                  raster,
1772                       const QT_FT_Raster_Params*  params )
1773   {
1774     const QT_FT_Outline*  outline    = (const QT_FT_Outline*)params->source;
1775     const QT_FT_Bitmap*   target_map = params->target;
1776     PWorker            worker;
1777 
1778 
1779     if ( !raster || !raster->buffer || !raster->buffer_size )
1780       return ErrRaster_Invalid_Argument;
1781 
1782     if ( raster->worker )
1783       raster->worker->skip_spans = params->skip_spans;
1784 
1785     /* If raster object and raster buffer are allocated, but  */
1786     /* raster size isn't of the minimum size, indicate out of */
1787     /* memory.                                                */
1788     if (raster->buffer_allocated_size < MINIMUM_POOL_SIZE )
1789       return ErrRaster_OutOfMemory;
1790 
1791     /* return immediately if the outline is empty */
1792     if ( outline->n_points == 0 || outline->n_contours <= 0 )
1793       return 0;
1794 
1795     if ( !outline || !outline->contours || !outline->points )
1796       return ErrRaster_Invalid_Outline;
1797 
1798     if ( outline->n_points !=
1799            outline->contours[outline->n_contours - 1] + 1 )
1800       return ErrRaster_Invalid_Outline;
1801 
1802     worker = raster->worker;
1803 
1804     /* if direct mode is not set, we must have a target bitmap */
1805     if ( ( params->flags & QT_FT_RASTER_FLAG_DIRECT ) == 0 )
1806     {
1807       if ( !target_map )
1808         return ErrRaster_Invalid_Argument;
1809 
1810       /* nothing to do */
1811       if ( !target_map->width || !target_map->rows )
1812         return 0;
1813 
1814       if ( !target_map->buffer )
1815         return ErrRaster_Invalid_Argument;
1816     }
1817 
1818     /* this version does not support monochrome rendering */
1819     if ( !( params->flags & QT_FT_RASTER_FLAG_AA ) )
1820       return ErrRaster_Invalid_Mode;
1821 
1822     /* compute clipping box */
1823     if ( ( params->flags & QT_FT_RASTER_FLAG_DIRECT ) == 0 )
1824     {
1825       /* compute clip box from target pixmap */
1826       ras.clip_box.xMin = 0;
1827       ras.clip_box.yMin = 0;
1828       ras.clip_box.xMax = target_map->width;
1829       ras.clip_box.yMax = target_map->rows;
1830     }
1831     else if ( params->flags & QT_FT_RASTER_FLAG_CLIP )
1832     {
1833       ras.clip_box = params->clip_box;
1834     }
1835     else
1836     {
1837       ras.clip_box.xMin = -32768L;
1838       ras.clip_box.yMin = -32768L;
1839       ras.clip_box.xMax =  32767L;
1840       ras.clip_box.yMax =  32767L;
1841     }
1842 
1843     gray_init_cells( worker, raster->buffer, raster->buffer_size );
1844 
1845     ras.outline   = *outline;
1846     ras.num_cells = 0;
1847     ras.invalid   = 1;
1848     ras.band_size = raster->band_size;
1849 
1850     if ( target_map )
1851       ras.target = *target_map;
1852 
1853     ras.render_span      = (QT_FT_Raster_Span_Func)gray_render_span;
1854     ras.render_span_data = &ras;
1855 
1856     if ( params->flags & QT_FT_RASTER_FLAG_DIRECT )
1857     {
1858       ras.render_span      = (QT_FT_Raster_Span_Func)params->gray_spans;
1859       ras.render_span_data = params->user;
1860     }
1861 
1862     return gray_convert_glyph( worker );
1863   }
1864 
1865 
1866   /**** RASTER OBJECT CREATION: In standalone mode, we simply use *****/
1867   /****                         a static object.                  *****/
1868 
1869   static int
gray_raster_new(QT_FT_Raster * araster)1870   gray_raster_new( QT_FT_Raster*  araster )
1871   {
1872     *araster = malloc(sizeof(TRaster));
1873     if (!*araster) {
1874         *araster = 0;
1875         return ErrRaster_Memory_Overflow;
1876     }
1877     QT_FT_MEM_ZERO(*araster, sizeof(TRaster));
1878 
1879     return 0;
1880   }
1881 
1882 
1883   static void
gray_raster_done(QT_FT_Raster raster)1884   gray_raster_done( QT_FT_Raster  raster )
1885   {
1886     free(raster);
1887   }
1888 
1889 
1890   static void
gray_raster_reset(QT_FT_Raster raster,char * pool_base,long pool_size)1891   gray_raster_reset( QT_FT_Raster  raster,
1892                      char*      pool_base,
1893                      long       pool_size )
1894   {
1895     PRaster  rast = (PRaster)raster;
1896 
1897     if ( raster )
1898     {
1899       if ( pool_base && ( pool_size >= MINIMUM_POOL_SIZE ) )
1900       {
1901         PWorker  worker = (PWorker)pool_base;
1902 
1903 
1904         rast->worker      = worker;
1905         rast->buffer      = pool_base +
1906                               ( ( sizeof ( TWorker ) + sizeof ( TCell ) - 1 ) &
1907                                 ~( sizeof ( TCell ) - 1 ) );
1908         rast->buffer_size = (long)( ( pool_base + pool_size ) -
1909                                     (char*)rast->buffer ) &
1910                                       ~( sizeof ( TCell ) - 1 );
1911         rast->band_size   = (int)( rast->buffer_size /
1912                                      ( sizeof ( TCell ) * 8 ) );
1913       }
1914       else if ( pool_base)
1915       { /* Case when there is a raster pool allocated, but it                */
1916         /* doesn't have the minimum size (and so memory will be reallocated) */
1917           rast->buffer = pool_base;
1918           rast->worker = NULL;
1919           rast->buffer_size = pool_size;
1920       }
1921       else
1922       {
1923         rast->buffer      = NULL;
1924         rast->buffer_size = 0;
1925         rast->worker      = NULL;
1926       }
1927       rast->buffer_allocated_size = pool_size;
1928     }
1929   }
1930 
1931   const QT_FT_Raster_Funcs  qt_ft_grays_raster =
1932   {
1933     QT_FT_GLYPH_FORMAT_OUTLINE,
1934 
1935     (QT_FT_Raster_New_Func)     gray_raster_new,
1936     (QT_FT_Raster_Reset_Func)   gray_raster_reset,
1937     (QT_FT_Raster_Set_Mode_Func)0,
1938     (QT_FT_Raster_Render_Func)  gray_raster_render,
1939     (QT_FT_Raster_Done_Func)    gray_raster_done
1940   };
1941 
1942 /* END */
1943