• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /****************************************************************************
2  *
3  * ftsmooth.c
4  *
5  *   Anti-aliasing renderer interface (body).
6  *
7  * Copyright (C) 2000-2020 by
8  * David Turner, Robert Wilhelm, and Werner Lemberg.
9  *
10  * This file is part of the FreeType project, and may only be used,
11  * modified, and distributed under the terms of the FreeType project
12  * license, LICENSE.TXT.  By continuing to use, modify, or distribute
13  * this file you indicate that you have read the license and
14  * understand and accept it fully.
15  *
16  */
17 
18 
19 #include <freetype/internal/ftdebug.h>
20 #include <freetype/internal/ftobjs.h>
21 #include <freetype/ftoutln.h>
22 #include "ftsmooth.h"
23 #include "ftgrays.h"
24 
25 #include "ftsmerrs.h"
26 
27 
28   /* sets render-specific mode */
29   static FT_Error
ft_smooth_set_mode(FT_Renderer render,FT_ULong mode_tag,FT_Pointer data)30   ft_smooth_set_mode( FT_Renderer  render,
31                       FT_ULong     mode_tag,
32                       FT_Pointer   data )
33   {
34     /* we simply pass it to the raster */
35     return render->clazz->raster_class->raster_set_mode( render->raster,
36                                                          mode_tag,
37                                                          data );
38   }
39 
40   /* transform a given glyph image */
41   static FT_Error
ft_smooth_transform(FT_Renderer render,FT_GlyphSlot slot,const FT_Matrix * matrix,const FT_Vector * delta)42   ft_smooth_transform( FT_Renderer       render,
43                        FT_GlyphSlot      slot,
44                        const FT_Matrix*  matrix,
45                        const FT_Vector*  delta )
46   {
47     FT_Error  error = FT_Err_Ok;
48 
49 
50     if ( slot->format != render->glyph_format )
51     {
52       error = FT_THROW( Invalid_Argument );
53       goto Exit;
54     }
55 
56     if ( matrix )
57       FT_Outline_Transform( &slot->outline, matrix );
58 
59     if ( delta )
60       FT_Outline_Translate( &slot->outline, delta->x, delta->y );
61 
62   Exit:
63     return error;
64   }
65 
66 
67   /* return the glyph's control box */
68   static void
ft_smooth_get_cbox(FT_Renderer render,FT_GlyphSlot slot,FT_BBox * cbox)69   ft_smooth_get_cbox( FT_Renderer   render,
70                       FT_GlyphSlot  slot,
71                       FT_BBox*      cbox )
72   {
73     FT_ZERO( cbox );
74 
75     if ( slot->format == render->glyph_format )
76       FT_Outline_Get_CBox( &slot->outline, cbox );
77   }
78 
79   typedef struct TOrigin_
80   {
81     unsigned char*  origin;  /* pixmap origin at the bottom-left */
82     int             pitch;   /* pitch to go down one row */
83 
84   } TOrigin;
85 
86 #ifndef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
87 
88   /* initialize renderer -- init its raster */
89   static FT_Error
ft_smooth_init(FT_Renderer render)90   ft_smooth_init( FT_Renderer  render )
91   {
92     FT_Vector*  sub = render->root.library->lcd_geometry;
93 
94 
95     /* set up default subpixel geometry for striped RGB panels. */
96     sub[0].x = -21;
97     sub[0].y = 0;
98     sub[1].x = 0;
99     sub[1].y = 0;
100     sub[2].x = 21;
101     sub[2].y = 0;
102 
103     render->clazz->raster_class->raster_reset( render->raster, NULL, 0 );
104 
105     return 0;
106   }
107 
108 
109   /* This function writes every third byte in direct rendering mode */
110   static void
ft_smooth_lcd_spans(int y,int count,const FT_Span * spans,TOrigin * target)111   ft_smooth_lcd_spans( int             y,
112                        int             count,
113                        const FT_Span*  spans,
114                        TOrigin*        target )
115   {
116     unsigned char*  dst_line = target->origin - y * target->pitch;
117     unsigned char*  dst;
118     unsigned short  w;
119 
120 
121     for ( ; count--; spans++ )
122       for ( dst = dst_line + spans->x * 3, w = spans->len; w--; dst += 3 )
123         *dst = spans->coverage;
124   }
125 
126 
127   static FT_Error
ft_smooth_raster_lcd(FT_Renderer render,FT_Outline * outline,FT_Bitmap * bitmap)128   ft_smooth_raster_lcd( FT_Renderer  render,
129                         FT_Outline*  outline,
130                         FT_Bitmap*   bitmap )
131   {
132     FT_Error      error = FT_Err_Ok;
133     FT_Vector*    sub   = render->root.library->lcd_geometry;
134     FT_Pos        x, y;
135 
136     FT_Raster_Params   params;
137     TOrigin            target;
138 
139 
140     /* Render 3 separate coverage bitmaps, shifting the outline.  */
141     /* Set up direct rendering to record them on each third byte. */
142     params.source     = outline;
143     params.flags      = FT_RASTER_FLAG_AA | FT_RASTER_FLAG_DIRECT;
144     params.gray_spans = (FT_SpanFunc)ft_smooth_lcd_spans;
145     params.user       = &target;
146 
147     params.clip_box.xMin = 0;
148     params.clip_box.yMin = 0;
149     params.clip_box.xMax = bitmap->width;
150     params.clip_box.yMax = bitmap->rows;
151 
152     if ( bitmap->pitch < 0 )
153       target.origin = bitmap->buffer;
154     else
155       target.origin = bitmap->buffer
156                       + ( bitmap->rows - 1 ) * (unsigned int)bitmap->pitch;
157 
158     target.pitch = bitmap->pitch;
159 
160     FT_Outline_Translate( outline,
161                           -sub[0].x,
162                           -sub[0].y );
163     error = render->raster_render( render->raster, &params );
164     x = sub[0].x;
165     y = sub[0].y;
166     if ( error )
167       goto Exit;
168 
169     target.origin++;
170     FT_Outline_Translate( outline,
171                           sub[0].x - sub[1].x,
172                           sub[0].y - sub[1].y );
173     error = render->raster_render( render->raster, &params );
174     x = sub[1].x;
175     y = sub[1].y;
176     if ( error )
177       goto Exit;
178 
179     target.origin++;
180     FT_Outline_Translate( outline,
181                           sub[1].x - sub[2].x,
182                           sub[1].y - sub[2].y );
183     error = render->raster_render( render->raster, &params );
184     x = sub[2].x;
185     y = sub[2].y;
186 
187   Exit:
188     FT_Outline_Translate( outline, x, y );
189 
190     return error;
191   }
192 
193 
194   static FT_Error
ft_smooth_raster_lcdv(FT_Renderer render,FT_Outline * outline,FT_Bitmap * bitmap)195   ft_smooth_raster_lcdv( FT_Renderer  render,
196                          FT_Outline*  outline,
197                          FT_Bitmap*   bitmap )
198   {
199     FT_Error     error = FT_Err_Ok;
200     int          pitch = bitmap->pitch;
201     FT_Vector*   sub   = render->root.library->lcd_geometry;
202     FT_Pos       x, y;
203 
204     FT_Raster_Params  params;
205 
206 
207     params.target = bitmap;
208     params.source = outline;
209     params.flags  = FT_RASTER_FLAG_AA;
210 
211     /* Render 3 separate coverage bitmaps, shifting the outline. */
212     /* Notice that the subpixel geometry vectors are rotated.    */
213     /* Triple the pitch to render on each third row.            */
214     bitmap->pitch *= 3;
215     bitmap->rows  /= 3;
216 
217     FT_Outline_Translate( outline,
218                           -sub[0].y,
219                           sub[0].x );
220     error = render->raster_render( render->raster, &params );
221     x = sub[0].y;
222     y = -sub[0].x;
223     if ( error )
224       goto Exit;
225 
226     bitmap->buffer += pitch;
227     FT_Outline_Translate( outline,
228                           sub[0].y - sub[1].y,
229                           sub[1].x - sub[0].x );
230     error = render->raster_render( render->raster, &params );
231     x = sub[1].y;
232     y = -sub[1].x;
233     bitmap->buffer -= pitch;
234     if ( error )
235       goto Exit;
236 
237     bitmap->buffer += 2 * pitch;
238     FT_Outline_Translate( outline,
239                           sub[1].y - sub[2].y,
240                           sub[2].x - sub[1].x );
241     error = render->raster_render( render->raster, &params );
242     x = sub[2].y;
243     y = -sub[2].x;
244     bitmap->buffer -= 2 * pitch;
245 
246   Exit:
247     FT_Outline_Translate( outline, x, y );
248 
249     bitmap->pitch /= 3;
250     bitmap->rows  *= 3;
251 
252     return error;
253   }
254 
255 #else   /* FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
256 
257   /* initialize renderer -- init its raster */
258   static FT_Error
ft_smooth_init(FT_Renderer render)259   ft_smooth_init( FT_Renderer  render )
260   {
261     /* set up default LCD filtering */
262     FT_Library_SetLcdFilter( render->root.library, FT_LCD_FILTER_DEFAULT );
263 
264     render->clazz->raster_class->raster_reset( render->raster, NULL, 0 );
265 
266     return 0;
267   }
268 
269 
270   static FT_Error
ft_smooth_raster_lcd(FT_Renderer render,FT_Outline * outline,FT_Bitmap * bitmap)271   ft_smooth_raster_lcd( FT_Renderer  render,
272                         FT_Outline*  outline,
273                         FT_Bitmap*   bitmap )
274   {
275     FT_Error    error      = FT_Err_Ok;
276     FT_Vector*  points     = outline->points;
277     FT_Vector*  points_end = FT_OFFSET( points, outline->n_points );
278     FT_Vector*  vec;
279 
280     FT_Raster_Params  params;
281 
282 
283     params.target = bitmap;
284     params.source = outline;
285     params.flags  = FT_RASTER_FLAG_AA;
286 
287     /* implode outline */
288     for ( vec = points; vec < points_end; vec++ )
289       vec->x *= 3;
290 
291     /* render outline into the bitmap */
292     error = render->raster_render( render->raster, &params );
293 
294     /* deflate outline */
295     for ( vec = points; vec < points_end; vec++ )
296       vec->x /= 3;
297 
298     return error;
299   }
300 
301 
302   static FT_Error
ft_smooth_raster_lcdv(FT_Renderer render,FT_Outline * outline,FT_Bitmap * bitmap)303   ft_smooth_raster_lcdv( FT_Renderer  render,
304                          FT_Outline*  outline,
305                          FT_Bitmap*   bitmap )
306   {
307     FT_Error    error      = FT_Err_Ok;
308     FT_Vector*  points     = outline->points;
309     FT_Vector*  points_end = FT_OFFSET( points, outline->n_points );
310     FT_Vector*  vec;
311 
312     FT_Raster_Params  params;
313 
314 
315     params.target = bitmap;
316     params.source = outline;
317     params.flags  = FT_RASTER_FLAG_AA;
318 
319     /* implode outline */
320     for ( vec = points; vec < points_end; vec++ )
321       vec->y *= 3;
322 
323     /* render outline into the bitmap */
324     error = render->raster_render( render->raster, &params );
325 
326     /* deflate outline */
327     for ( vec = points; vec < points_end; vec++ )
328       vec->y /= 3;
329 
330     return error;
331   }
332 
333 #endif  /* FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
334 
335 /* Oversampling scale to be used in rendering overlaps */
336 #define SCALE  ( 1 << 2 )
337 
338   /* This function averages inflated spans in direct rendering mode */
339   static void
ft_smooth_overlap_spans(int y,int count,const FT_Span * spans,TOrigin * target)340   ft_smooth_overlap_spans( int             y,
341                            int             count,
342                            const FT_Span*  spans,
343                            TOrigin*        target )
344   {
345     unsigned char*  dst = target->origin - ( y / SCALE ) * target->pitch;
346     unsigned short  x;
347     unsigned int    cover, sum;
348 
349 
350     /* When accumulating the oversampled spans we need to assure that  */
351     /* fully covered pixels are equal to 255 and do not overflow.      */
352     /* It is important that the SCALE is a power of 2, each subpixel   */
353     /* cover can also reach a power of 2 after rounding, and the total */
354     /* is clamped to 255 when it adds up to 256.                       */
355     for ( ; count--; spans++ )
356     {
357       cover = ( spans->coverage + SCALE * SCALE / 2 ) / ( SCALE * SCALE );
358       for ( x = 0; x < spans->len; x++ )
359       {
360         sum                           = dst[( spans->x + x ) / SCALE] + cover;
361         dst[( spans->x + x ) / SCALE] = (unsigned char)( sum - ( sum >> 8 ) );
362       }
363     }
364   }
365 
366 
367   static FT_Error
ft_smooth_raster_overlap(FT_Renderer render,FT_Outline * outline,FT_Bitmap * bitmap)368   ft_smooth_raster_overlap( FT_Renderer  render,
369                             FT_Outline*  outline,
370                             FT_Bitmap*   bitmap )
371   {
372     FT_Error    error      = FT_Err_Ok;
373     FT_Vector*  points     = outline->points;
374     FT_Vector*  points_end = FT_OFFSET( points, outline->n_points );
375     FT_Vector*  vec;
376 
377     FT_Raster_Params   params;
378     TOrigin            target;
379 
380 
381     /* Reject outlines that are too wide for 16-bit FT_Span.       */
382     /* Other limits are applied upstream with the same error code. */
383     if ( bitmap->width * SCALE > 0x7FFF )
384       return FT_THROW( Raster_Overflow );
385 
386     /* Set up direct rendering to average oversampled spans. */
387     params.source     = outline;
388     params.flags      = FT_RASTER_FLAG_AA | FT_RASTER_FLAG_DIRECT;
389     params.gray_spans = (FT_SpanFunc)ft_smooth_overlap_spans;
390     params.user       = &target;
391 
392     params.clip_box.xMin = 0;
393     params.clip_box.yMin = 0;
394     params.clip_box.xMax = bitmap->width * SCALE;
395     params.clip_box.yMax = bitmap->rows  * SCALE;
396 
397     if ( bitmap->pitch < 0 )
398       target.origin = bitmap->buffer;
399     else
400       target.origin = bitmap->buffer
401                       + ( bitmap->rows - 1 ) * (unsigned int)bitmap->pitch;
402 
403     target.pitch = bitmap->pitch;
404 
405     /* inflate outline */
406     for ( vec = points; vec < points_end; vec++ )
407     {
408       vec->x *= SCALE;
409       vec->y *= SCALE;
410     }
411 
412     /* render outline into the bitmap */
413     error = render->raster_render( render->raster, &params );
414 
415     /* deflate outline */
416     for ( vec = points; vec < points_end; vec++ )
417     {
418       vec->x /= SCALE;
419       vec->y /= SCALE;
420     }
421 
422     return error;
423   }
424 
425 #undef SCALE
426 
427   static FT_Error
ft_smooth_render(FT_Renderer render,FT_GlyphSlot slot,FT_Render_Mode mode,const FT_Vector * origin)428   ft_smooth_render( FT_Renderer       render,
429                     FT_GlyphSlot      slot,
430                     FT_Render_Mode    mode,
431                     const FT_Vector*  origin )
432   {
433     FT_Error     error   = FT_Err_Ok;
434     FT_Outline*  outline = &slot->outline;
435     FT_Bitmap*   bitmap  = &slot->bitmap;
436     FT_Memory    memory  = render->root.memory;
437     FT_Pos       x_shift = 0;
438     FT_Pos       y_shift = 0;
439 
440 
441     /* check glyph image format */
442     if ( slot->format != render->glyph_format )
443     {
444       error = FT_THROW( Invalid_Argument );
445       goto Exit;
446     }
447 
448     /* check mode */
449     if ( mode != FT_RENDER_MODE_NORMAL &&
450          mode != FT_RENDER_MODE_LIGHT  &&
451          mode != FT_RENDER_MODE_LCD    &&
452          mode != FT_RENDER_MODE_LCD_V  )
453     {
454       error = FT_THROW( Cannot_Render_Glyph );
455       goto Exit;
456     }
457 
458     /* release old bitmap buffer */
459     if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP )
460     {
461       FT_FREE( bitmap->buffer );
462       slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP;
463     }
464 
465     if ( ft_glyphslot_preset_bitmap( slot, mode, origin ) )
466     {
467       error = FT_THROW( Raster_Overflow );
468       goto Exit;
469     }
470 
471     if ( !bitmap->rows || !bitmap->pitch )
472       goto Exit;
473 
474     /* allocate new one */
475     if ( FT_ALLOC_MULT( bitmap->buffer, bitmap->rows, bitmap->pitch ) )
476       goto Exit;
477 
478     slot->internal->flags |= FT_GLYPH_OWN_BITMAP;
479 
480     x_shift = 64 * -slot->bitmap_left;
481     y_shift = 64 * -slot->bitmap_top;
482     if ( bitmap->pixel_mode == FT_PIXEL_MODE_LCD_V )
483       y_shift += 64 * (FT_Int)bitmap->rows / 3;
484     else
485       y_shift += 64 * (FT_Int)bitmap->rows;
486 
487     if ( origin )
488     {
489       x_shift += origin->x;
490       y_shift += origin->y;
491     }
492 
493     /* translate outline to render it into the bitmap */
494     if ( x_shift || y_shift )
495       FT_Outline_Translate( outline, x_shift, y_shift );
496 
497     if ( mode == FT_RENDER_MODE_NORMAL ||
498          mode == FT_RENDER_MODE_LIGHT  )
499     {
500       if ( outline->flags & FT_OUTLINE_OVERLAP )
501         error = ft_smooth_raster_overlap( render, outline, bitmap );
502       else
503       {
504         FT_Raster_Params  params;
505 
506 
507         params.target = bitmap;
508         params.source = outline;
509         params.flags  = FT_RASTER_FLAG_AA;
510 
511         error = render->raster_render( render->raster, &params );
512       }
513     }
514     else
515     {
516       if ( mode == FT_RENDER_MODE_LCD )
517         error = ft_smooth_raster_lcd ( render, outline, bitmap );
518       else if ( mode == FT_RENDER_MODE_LCD_V )
519         error = ft_smooth_raster_lcdv( render, outline, bitmap );
520 
521 #ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
522 
523       /* finally apply filtering */
524       {
525         FT_Byte*                 lcd_weights;
526         FT_Bitmap_LcdFilterFunc  lcd_filter_func;
527 
528 
529         /* Per-face LCD filtering takes priority if set up. */
530         if ( slot->face && slot->face->internal->lcd_filter_func )
531         {
532           lcd_weights     = slot->face->internal->lcd_weights;
533           lcd_filter_func = slot->face->internal->lcd_filter_func;
534         }
535         else
536         {
537           lcd_weights     = slot->library->lcd_weights;
538           lcd_filter_func = slot->library->lcd_filter_func;
539         }
540 
541         if ( lcd_filter_func )
542           lcd_filter_func( bitmap, lcd_weights );
543       }
544 
545 #endif /* FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
546 
547     }
548 
549   Exit:
550     if ( !error )
551     {
552       /* everything is fine; the glyph is now officially a bitmap */
553       slot->format = FT_GLYPH_FORMAT_BITMAP;
554     }
555     else if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP )
556     {
557       FT_FREE( bitmap->buffer );
558       slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP;
559     }
560 
561     if ( x_shift || y_shift )
562       FT_Outline_Translate( outline, -x_shift, -y_shift );
563 
564     return error;
565   }
566 
567 
568   FT_DEFINE_RENDERER(
569     ft_smooth_renderer_class,
570 
571       FT_MODULE_RENDERER,
572       sizeof ( FT_RendererRec ),
573 
574       "smooth",
575       0x10000L,
576       0x20000L,
577 
578       NULL,    /* module specific interface */
579 
580       (FT_Module_Constructor)ft_smooth_init,  /* module_init   */
581       (FT_Module_Destructor) NULL,            /* module_done   */
582       (FT_Module_Requester)  NULL,            /* get_interface */
583 
584     FT_GLYPH_FORMAT_OUTLINE,
585 
586     (FT_Renderer_RenderFunc)   ft_smooth_render,     /* render_glyph    */
587     (FT_Renderer_TransformFunc)ft_smooth_transform,  /* transform_glyph */
588     (FT_Renderer_GetCBoxFunc)  ft_smooth_get_cbox,   /* get_glyph_cbox  */
589     (FT_Renderer_SetModeFunc)  ft_smooth_set_mode,   /* set_mode        */
590 
591     (FT_Raster_Funcs*)&ft_grays_raster               /* raster_class    */
592   )
593 
594 
595 /* END */
596