Coverage Report

Created: 2026-06-07 08:13

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