• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /****************************************************************************
2  *
3  * ftsmooth.c
4  *
5  *   Anti-aliasing renderer interface (body).
6  *
7  * Copyright (C) 2000-2019 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 <ft2build.h>
20 #include FT_INTERNAL_DEBUG_H
21 #include FT_INTERNAL_OBJECTS_H
22 #include FT_OUTLINE_H
23 #include "ftsmooth.h"
24 #include "ftgrays.h"
25 
26 #include "ftsmerrs.h"
27 
28 
29   /* initialize renderer -- init its raster */
30   static FT_Error
ft_smooth_init(FT_Renderer render)31   ft_smooth_init( FT_Renderer  render )
32   {
33 
34 #ifndef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
35 
36     FT_Vector*  sub = render->root.library->lcd_geometry;
37 
38 
39     /* set up default subpixel geometry for striped RGB panels. */
40     sub[0].x = -21;
41     sub[0].y = 0;
42     sub[1].x = 0;
43     sub[1].y = 0;
44     sub[2].x = 21;
45     sub[2].y = 0;
46 
47 #elif 0   /* or else, once ClearType patents expire */
48 
49     FT_Library_SetLcdFilter( render->root.library, FT_LCD_FILTER_DEFAULT );
50 
51 #endif
52 
53     render->clazz->raster_class->raster_reset( render->raster, NULL, 0 );
54 
55     return 0;
56   }
57 
58 
59   /* sets render-specific mode */
60   static FT_Error
ft_smooth_set_mode(FT_Renderer render,FT_ULong mode_tag,FT_Pointer data)61   ft_smooth_set_mode( FT_Renderer  render,
62                       FT_ULong     mode_tag,
63                       FT_Pointer   data )
64   {
65     /* we simply pass it to the raster */
66     return render->clazz->raster_class->raster_set_mode( render->raster,
67                                                          mode_tag,
68                                                          data );
69   }
70 
71   /* transform a given glyph image */
72   static FT_Error
ft_smooth_transform(FT_Renderer render,FT_GlyphSlot slot,const FT_Matrix * matrix,const FT_Vector * delta)73   ft_smooth_transform( FT_Renderer       render,
74                        FT_GlyphSlot      slot,
75                        const FT_Matrix*  matrix,
76                        const FT_Vector*  delta )
77   {
78     FT_Error  error = FT_Err_Ok;
79 
80 
81     if ( slot->format != render->glyph_format )
82     {
83       error = FT_THROW( Invalid_Argument );
84       goto Exit;
85     }
86 
87     if ( matrix )
88       FT_Outline_Transform( &slot->outline, matrix );
89 
90     if ( delta )
91       FT_Outline_Translate( &slot->outline, delta->x, delta->y );
92 
93   Exit:
94     return error;
95   }
96 
97 
98   /* return the glyph's control box */
99   static void
ft_smooth_get_cbox(FT_Renderer render,FT_GlyphSlot slot,FT_BBox * cbox)100   ft_smooth_get_cbox( FT_Renderer   render,
101                       FT_GlyphSlot  slot,
102                       FT_BBox*      cbox )
103   {
104     FT_ZERO( cbox );
105 
106     if ( slot->format == render->glyph_format )
107       FT_Outline_Get_CBox( &slot->outline, cbox );
108   }
109 
110 
111   /* convert a slot's glyph image into a bitmap */
112   static FT_Error
ft_smooth_render_generic(FT_Renderer render,FT_GlyphSlot slot,FT_Render_Mode mode,const FT_Vector * origin,FT_Render_Mode required_mode)113   ft_smooth_render_generic( FT_Renderer       render,
114                             FT_GlyphSlot      slot,
115                             FT_Render_Mode    mode,
116                             const FT_Vector*  origin,
117                             FT_Render_Mode    required_mode )
118   {
119     FT_Error     error   = FT_Err_Ok;
120     FT_Outline*  outline = &slot->outline;
121     FT_Bitmap*   bitmap  = &slot->bitmap;
122     FT_Memory    memory  = render->root.memory;
123     FT_Pos       x_shift = 0;
124     FT_Pos       y_shift = 0;
125     FT_Int       hmul    = ( mode == FT_RENDER_MODE_LCD );
126     FT_Int       vmul    = ( mode == FT_RENDER_MODE_LCD_V );
127 
128     FT_Raster_Params  params;
129 
130 
131     /* check glyph image format */
132     if ( slot->format != render->glyph_format )
133     {
134       error = FT_THROW( Invalid_Argument );
135       goto Exit;
136     }
137 
138     /* check mode */
139     if ( mode != required_mode )
140     {
141       error = FT_THROW( Cannot_Render_Glyph );
142       goto Exit;
143     }
144 
145     /* release old bitmap buffer */
146     if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP )
147     {
148       FT_FREE( bitmap->buffer );
149       slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP;
150     }
151 
152     if ( ft_glyphslot_preset_bitmap( slot, mode, origin ) )
153     {
154       error = FT_THROW( Raster_Overflow );
155       goto Exit;
156     }
157 
158     /* allocate new one */
159     if ( FT_ALLOC_MULT( bitmap->buffer, bitmap->rows, bitmap->pitch ) )
160       goto Exit;
161 
162     slot->internal->flags |= FT_GLYPH_OWN_BITMAP;
163 
164     x_shift = 64 * -slot->bitmap_left;
165     y_shift = 64 * -slot->bitmap_top;
166     if ( bitmap->pixel_mode == FT_PIXEL_MODE_LCD_V )
167       y_shift += 64 * (FT_Int)bitmap->rows / 3;
168     else
169       y_shift += 64 * (FT_Int)bitmap->rows;
170 
171     if ( origin )
172     {
173       x_shift += origin->x;
174       y_shift += origin->y;
175     }
176 
177     /* translate outline to render it into the bitmap */
178     if ( x_shift || y_shift )
179       FT_Outline_Translate( outline, x_shift, y_shift );
180 
181     /* set up parameters */
182     params.target = bitmap;
183     params.source = outline;
184     params.flags  = FT_RASTER_FLAG_AA;
185 
186 #ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
187 
188     /* implode outline if needed */
189     {
190       FT_Vector*  points     = outline->points;
191       FT_Vector*  points_end = points + outline->n_points;
192       FT_Vector*  vec;
193 
194 
195       if ( hmul )
196         for ( vec = points; vec < points_end; vec++ )
197           vec->x *= 3;
198 
199       if ( vmul )
200         for ( vec = points; vec < points_end; vec++ )
201           vec->y *= 3;
202     }
203 
204     /* render outline into the bitmap */
205     error = render->raster_render( render->raster, &params );
206 
207     /* deflate outline if needed */
208     {
209       FT_Vector*  points     = outline->points;
210       FT_Vector*  points_end = points + outline->n_points;
211       FT_Vector*  vec;
212 
213 
214       if ( hmul )
215         for ( vec = points; vec < points_end; vec++ )
216           vec->x /= 3;
217 
218       if ( vmul )
219         for ( vec = points; vec < points_end; vec++ )
220           vec->y /= 3;
221     }
222 
223     if ( error )
224       goto Exit;
225 
226     /* finally apply filtering */
227     if ( hmul || vmul )
228     {
229       FT_Byte*                 lcd_weights;
230       FT_Bitmap_LcdFilterFunc  lcd_filter_func;
231 
232 
233       /* Per-face LCD filtering takes priority if set up. */
234       if ( slot->face && slot->face->internal->lcd_filter_func )
235       {
236         lcd_weights     = slot->face->internal->lcd_weights;
237         lcd_filter_func = slot->face->internal->lcd_filter_func;
238       }
239       else
240       {
241         lcd_weights     = slot->library->lcd_weights;
242         lcd_filter_func = slot->library->lcd_filter_func;
243       }
244 
245       if ( lcd_filter_func )
246         lcd_filter_func( bitmap, lcd_weights );
247     }
248 
249 #else /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
250 
251     if ( hmul )  /* lcd */
252     {
253       FT_Byte*  line;
254       FT_Byte*  temp = NULL;
255       FT_UInt   i, j;
256 
257       unsigned int  height = bitmap->rows;
258       unsigned int  width  = bitmap->width;
259       int           pitch  = bitmap->pitch;
260 
261       FT_Vector*  sub = slot->library->lcd_geometry;
262 
263 
264       /* Render 3 separate monochrome bitmaps, shifting the outline.  */
265       width /= 3;
266 
267       FT_Outline_Translate( outline,
268                             -sub[0].x,
269                             -sub[0].y );
270       error = render->raster_render( render->raster, &params );
271       if ( error )
272         goto Exit;
273 
274       bitmap->buffer += width;
275       FT_Outline_Translate( outline,
276                             sub[0].x - sub[1].x,
277                             sub[0].y - sub[1].y );
278       error = render->raster_render( render->raster, &params );
279       bitmap->buffer -= width;
280       if ( error )
281         goto Exit;
282 
283       bitmap->buffer += 2 * width;
284       FT_Outline_Translate( outline,
285                             sub[1].x - sub[2].x,
286                             sub[1].y - sub[2].y );
287       error = render->raster_render( render->raster, &params );
288       bitmap->buffer -= 2 * width;
289       if ( error )
290         goto Exit;
291 
292       x_shift -= sub[2].x;
293       y_shift -= sub[2].y;
294 
295       /* XXX: Rearrange the bytes according to FT_PIXEL_MODE_LCD.    */
296       /* XXX: It is more efficient to render every third byte above. */
297 
298       if ( FT_ALLOC( temp, (FT_ULong)pitch ) )
299         goto Exit;
300 
301       for ( i = 0; i < height; i++ )
302       {
303         line = bitmap->buffer + i * (FT_ULong)pitch;
304         for ( j = 0; j < width; j++ )
305         {
306           temp[3 * j    ] = line[j];
307           temp[3 * j + 1] = line[j + width];
308           temp[3 * j + 2] = line[j + width + width];
309         }
310         FT_MEM_COPY( line, temp, pitch );
311       }
312 
313       FT_FREE( temp );
314     }
315     else if ( vmul )  /* lcd_v */
316     {
317       int  pitch  = bitmap->pitch;
318 
319       FT_Vector*  sub = slot->library->lcd_geometry;
320 
321 
322       /* Render 3 separate monochrome bitmaps, shifting the outline. */
323       /* Notice that the subpixel geometry vectors are rotated.      */
324       /* Triple the pitch to render on each third row.               */
325       bitmap->pitch *= 3;
326       bitmap->rows  /= 3;
327 
328       FT_Outline_Translate( outline,
329                             -sub[0].y,
330                             sub[0].x );
331       error = render->raster_render( render->raster, &params );
332       if ( error )
333         goto Exit;
334 
335       bitmap->buffer += pitch;
336       FT_Outline_Translate( outline,
337                             sub[0].y - sub[1].y,
338                             sub[1].x - sub[0].x );
339       error = render->raster_render( render->raster, &params );
340       bitmap->buffer -= pitch;
341       if ( error )
342         goto Exit;
343 
344       bitmap->buffer += 2 * pitch;
345       FT_Outline_Translate( outline,
346                             sub[1].y - sub[2].y,
347                             sub[2].x - sub[1].x );
348       error = render->raster_render( render->raster, &params );
349       bitmap->buffer -= 2 * pitch;
350       if ( error )
351         goto Exit;
352 
353       x_shift -= sub[2].y;
354       y_shift += sub[2].x;
355 
356       bitmap->pitch /= 3;
357       bitmap->rows  *= 3;
358     }
359     else  /* grayscale */
360       error = render->raster_render( render->raster, &params );
361 
362 #endif /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
363 
364   Exit:
365     if ( !error )
366     {
367       /* everything is fine; the glyph is now officially a bitmap */
368       slot->format = FT_GLYPH_FORMAT_BITMAP;
369     }
370     else if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP )
371     {
372       FT_FREE( bitmap->buffer );
373       slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP;
374     }
375 
376     if ( x_shift || y_shift )
377       FT_Outline_Translate( outline, -x_shift, -y_shift );
378 
379     return error;
380   }
381 
382 
383   /* convert a slot's glyph image into a bitmap */
384   static FT_Error
ft_smooth_render(FT_Renderer render,FT_GlyphSlot slot,FT_Render_Mode mode,const FT_Vector * origin)385   ft_smooth_render( FT_Renderer       render,
386                     FT_GlyphSlot      slot,
387                     FT_Render_Mode    mode,
388                     const FT_Vector*  origin )
389   {
390     if ( mode == FT_RENDER_MODE_LIGHT )
391       mode = FT_RENDER_MODE_NORMAL;
392 
393     return ft_smooth_render_generic( render, slot, mode, origin,
394                                      FT_RENDER_MODE_NORMAL );
395   }
396 
397 
398   /* convert a slot's glyph image into a horizontal LCD bitmap */
399   static FT_Error
ft_smooth_render_lcd(FT_Renderer render,FT_GlyphSlot slot,FT_Render_Mode mode,const FT_Vector * origin)400   ft_smooth_render_lcd( FT_Renderer       render,
401                         FT_GlyphSlot      slot,
402                         FT_Render_Mode    mode,
403                         const FT_Vector*  origin )
404   {
405     return ft_smooth_render_generic( render, slot, mode, origin,
406                                      FT_RENDER_MODE_LCD );
407   }
408 
409 
410   /* convert a slot's glyph image into a vertical LCD bitmap */
411   static FT_Error
ft_smooth_render_lcd_v(FT_Renderer render,FT_GlyphSlot slot,FT_Render_Mode mode,const FT_Vector * origin)412   ft_smooth_render_lcd_v( FT_Renderer       render,
413                           FT_GlyphSlot      slot,
414                           FT_Render_Mode    mode,
415                           const FT_Vector*  origin )
416   {
417     return ft_smooth_render_generic( render, slot, mode, origin,
418                                      FT_RENDER_MODE_LCD_V );
419   }
420 
421 
422   FT_DEFINE_RENDERER(
423     ft_smooth_renderer_class,
424 
425       FT_MODULE_RENDERER,
426       sizeof ( FT_RendererRec ),
427 
428       "smooth",
429       0x10000L,
430       0x20000L,
431 
432       NULL,    /* module specific interface */
433 
434       (FT_Module_Constructor)ft_smooth_init,  /* module_init   */
435       (FT_Module_Destructor) NULL,            /* module_done   */
436       (FT_Module_Requester)  NULL,            /* get_interface */
437 
438     FT_GLYPH_FORMAT_OUTLINE,
439 
440     (FT_Renderer_RenderFunc)   ft_smooth_render,     /* render_glyph    */
441     (FT_Renderer_TransformFunc)ft_smooth_transform,  /* transform_glyph */
442     (FT_Renderer_GetCBoxFunc)  ft_smooth_get_cbox,   /* get_glyph_cbox  */
443     (FT_Renderer_SetModeFunc)  ft_smooth_set_mode,   /* set_mode        */
444 
445     (FT_Raster_Funcs*)&ft_grays_raster               /* raster_class    */
446   )
447 
448 
449   FT_DEFINE_RENDERER(
450     ft_smooth_lcd_renderer_class,
451 
452       FT_MODULE_RENDERER,
453       sizeof ( FT_RendererRec ),
454 
455       "smooth-lcd",
456       0x10000L,
457       0x20000L,
458 
459       NULL,    /* module specific interface */
460 
461       (FT_Module_Constructor)ft_smooth_init,  /* module_init   */
462       (FT_Module_Destructor) NULL,            /* module_done   */
463       (FT_Module_Requester)  NULL,            /* get_interface */
464 
465     FT_GLYPH_FORMAT_OUTLINE,
466 
467     (FT_Renderer_RenderFunc)   ft_smooth_render_lcd,  /* render_glyph    */
468     (FT_Renderer_TransformFunc)ft_smooth_transform,   /* transform_glyph */
469     (FT_Renderer_GetCBoxFunc)  ft_smooth_get_cbox,    /* get_glyph_cbox  */
470     (FT_Renderer_SetModeFunc)  ft_smooth_set_mode,    /* set_mode        */
471 
472     (FT_Raster_Funcs*)&ft_grays_raster                /* raster_class    */
473   )
474 
475 
476   FT_DEFINE_RENDERER(
477     ft_smooth_lcdv_renderer_class,
478 
479       FT_MODULE_RENDERER,
480       sizeof ( FT_RendererRec ),
481 
482       "smooth-lcdv",
483       0x10000L,
484       0x20000L,
485 
486       NULL,    /* module specific interface */
487 
488       (FT_Module_Constructor)ft_smooth_init,  /* module_init   */
489       (FT_Module_Destructor) NULL,            /* module_done   */
490       (FT_Module_Requester)  NULL,            /* get_interface */
491 
492     FT_GLYPH_FORMAT_OUTLINE,
493 
494     (FT_Renderer_RenderFunc)   ft_smooth_render_lcd_v,  /* render_glyph    */
495     (FT_Renderer_TransformFunc)ft_smooth_transform,     /* transform_glyph */
496     (FT_Renderer_GetCBoxFunc)  ft_smooth_get_cbox,      /* get_glyph_cbox  */
497     (FT_Renderer_SetModeFunc)  ft_smooth_set_mode,      /* set_mode        */
498 
499     (FT_Raster_Funcs*)&ft_grays_raster                  /* raster_class    */
500   )
501 
502 
503 /* END */
504