• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /****************************************************************************
2  *
3  * ftsmooth.c
4  *
5  *   Anti-aliasing renderer interface (body).
6  *
7  * Copyright 2000-2018 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 #endif
48 
49     render->clazz->raster_class->raster_reset( render->raster, NULL, 0 );
50 
51     return 0;
52   }
53 
54 
55   /* sets render-specific mode */
56   static FT_Error
ft_smooth_set_mode(FT_Renderer render,FT_ULong mode_tag,FT_Pointer data)57   ft_smooth_set_mode( FT_Renderer  render,
58                       FT_ULong     mode_tag,
59                       FT_Pointer   data )
60   {
61     /* we simply pass it to the raster */
62     return render->clazz->raster_class->raster_set_mode( render->raster,
63                                                          mode_tag,
64                                                          data );
65   }
66 
67   /* transform a given glyph image */
68   static FT_Error
ft_smooth_transform(FT_Renderer render,FT_GlyphSlot slot,const FT_Matrix * matrix,const FT_Vector * delta)69   ft_smooth_transform( FT_Renderer       render,
70                        FT_GlyphSlot      slot,
71                        const FT_Matrix*  matrix,
72                        const FT_Vector*  delta )
73   {
74     FT_Error  error = FT_Err_Ok;
75 
76 
77     if ( slot->format != render->glyph_format )
78     {
79       error = FT_THROW( Invalid_Argument );
80       goto Exit;
81     }
82 
83     if ( matrix )
84       FT_Outline_Transform( &slot->outline, matrix );
85 
86     if ( delta )
87       FT_Outline_Translate( &slot->outline, delta->x, delta->y );
88 
89   Exit:
90     return error;
91   }
92 
93 
94   /* return the glyph's control box */
95   static void
ft_smooth_get_cbox(FT_Renderer render,FT_GlyphSlot slot,FT_BBox * cbox)96   ft_smooth_get_cbox( FT_Renderer   render,
97                       FT_GlyphSlot  slot,
98                       FT_BBox*      cbox )
99   {
100     FT_ZERO( cbox );
101 
102     if ( slot->format == render->glyph_format )
103       FT_Outline_Get_CBox( &slot->outline, cbox );
104   }
105 
106 
107   /* convert a slot's glyph image into a bitmap */
108   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)109   ft_smooth_render_generic( FT_Renderer       render,
110                             FT_GlyphSlot      slot,
111                             FT_Render_Mode    mode,
112                             const FT_Vector*  origin,
113                             FT_Render_Mode    required_mode )
114   {
115     FT_Error     error   = FT_Err_Ok;
116     FT_Outline*  outline = &slot->outline;
117     FT_Bitmap*   bitmap  = &slot->bitmap;
118     FT_Memory    memory  = render->root.memory;
119     FT_Pos       x_shift = 0;
120     FT_Pos       y_shift = 0;
121     FT_Int       hmul    = ( mode == FT_RENDER_MODE_LCD );
122     FT_Int       vmul    = ( mode == FT_RENDER_MODE_LCD_V );
123 
124     FT_Raster_Params  params;
125 
126 
127     /* check glyph image format */
128     if ( slot->format != render->glyph_format )
129     {
130       error = FT_THROW( Invalid_Argument );
131       goto Exit;
132     }
133 
134     /* check mode */
135     if ( mode != required_mode )
136     {
137       error = FT_THROW( Cannot_Render_Glyph );
138       goto Exit;
139     }
140 
141     /* release old bitmap buffer */
142     if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP )
143     {
144       FT_FREE( bitmap->buffer );
145       slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP;
146     }
147 
148     ft_glyphslot_preset_bitmap( slot, mode, origin );
149 
150     if ( bitmap->width > 0x7FFF || bitmap->rows > 0x7FFF )
151     {
152       FT_ERROR(( "ft_smooth_render_generic: glyph is too large: %u x %u\n",
153                  bitmap->width, bitmap->rows ));
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, mode, 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,           -sub[0].x,           -sub[0].y );
268       error = render->raster_render( render->raster, &params );
269       if ( error )
270         goto Exit;
271 
272       bitmap->buffer += width;
273       FT_Outline_Translate( outline, sub[0].x - sub[1].x, sub[0].y - sub[1].y );
274       error = render->raster_render( render->raster, &params );
275       bitmap->buffer -= width;
276       if ( error )
277         goto Exit;
278 
279       bitmap->buffer += 2 * width;
280       FT_Outline_Translate( outline, sub[1].x - sub[2].x, sub[1].y - sub[2].y );
281       error = render->raster_render( render->raster, &params );
282       bitmap->buffer -= 2 * width;
283       if ( error )
284         goto Exit;
285 
286       x_shift        -= sub[2].x;
287       y_shift        -= sub[2].y;
288 
289       /* XXX: Rearrange the bytes according to FT_PIXEL_MODE_LCD.    */
290       /* XXX: It is more efficient to render every third byte above. */
291 
292       if ( FT_ALLOC( temp, (FT_ULong)pitch ) )
293         goto Exit;
294 
295       for ( i = 0; i < height; i++ )
296       {
297         line = bitmap->buffer + i * (FT_ULong)pitch;
298         for ( j = 0; j < width; j++ )
299         {
300           temp[3 * j    ] = line[j];
301           temp[3 * j + 1] = line[j + width];
302           temp[3 * j + 2] = line[j + width + width];
303         }
304         FT_MEM_COPY( line, temp, pitch );
305       }
306 
307       FT_FREE( temp );
308     }
309     else if ( vmul )  /* lcd_v */
310     {
311       int  pitch  = bitmap->pitch;
312 
313       FT_Vector*  sub = slot->library->lcd_geometry;
314 
315 
316       /* Render 3 separate monochrome bitmaps, shifting the outline. */
317       /* Notice that the subpixel geometry vectors are rotated.      */
318       /* Triple the pitch to render on each third row.               */
319       bitmap->pitch *= 3;
320       bitmap->rows  /= 3;
321 
322       FT_Outline_Translate( outline,           -sub[0].y, sub[0].x            );
323       error = render->raster_render( render->raster, &params );
324       if ( error )
325         goto Exit;
326 
327       bitmap->buffer += pitch;
328       FT_Outline_Translate( outline, sub[0].y - sub[1].y, sub[1].x - sub[0].x );
329       error = render->raster_render( render->raster, &params );
330       bitmap->buffer -= pitch;
331       if ( error )
332         goto Exit;
333 
334       bitmap->buffer += 2 * pitch;
335       FT_Outline_Translate( outline, sub[1].y - sub[2].y, sub[2].x - sub[1].x );
336       error = render->raster_render( render->raster, &params );
337       bitmap->buffer -= 2 * pitch;
338       if ( error )
339         goto Exit;
340 
341       x_shift        -= sub[2].y;
342       y_shift        += sub[2].x;
343 
344       bitmap->pitch /= 3;
345       bitmap->rows  *= 3;
346     }
347     else  /* grayscale */
348       error = render->raster_render( render->raster, &params );
349 
350 #endif /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
351 
352   Exit:
353     if ( !error )
354     {
355       /* everything is fine; the glyph is now officially a bitmap */
356       slot->format = FT_GLYPH_FORMAT_BITMAP;
357     }
358     else if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP )
359     {
360       FT_FREE( bitmap->buffer );
361       slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP;
362     }
363 
364     if ( x_shift || y_shift )
365       FT_Outline_Translate( outline, -x_shift, -y_shift );
366 
367     return error;
368   }
369 
370 
371   /* convert a slot's glyph image into a bitmap */
372   static FT_Error
ft_smooth_render(FT_Renderer render,FT_GlyphSlot slot,FT_Render_Mode mode,const FT_Vector * origin)373   ft_smooth_render( FT_Renderer       render,
374                     FT_GlyphSlot      slot,
375                     FT_Render_Mode    mode,
376                     const FT_Vector*  origin )
377   {
378     if ( mode == FT_RENDER_MODE_LIGHT )
379       mode = FT_RENDER_MODE_NORMAL;
380 
381     return ft_smooth_render_generic( render, slot, mode, origin,
382                                      FT_RENDER_MODE_NORMAL );
383   }
384 
385 
386   /* convert a slot's glyph image into a horizontal LCD bitmap */
387   static FT_Error
ft_smooth_render_lcd(FT_Renderer render,FT_GlyphSlot slot,FT_Render_Mode mode,const FT_Vector * origin)388   ft_smooth_render_lcd( FT_Renderer       render,
389                         FT_GlyphSlot      slot,
390                         FT_Render_Mode    mode,
391                         const FT_Vector*  origin )
392   {
393     return ft_smooth_render_generic( render, slot, mode, origin,
394                                      FT_RENDER_MODE_LCD );
395   }
396 
397 
398   /* convert a slot's glyph image into a vertical LCD bitmap */
399   static FT_Error
ft_smooth_render_lcd_v(FT_Renderer render,FT_GlyphSlot slot,FT_Render_Mode mode,const FT_Vector * origin)400   ft_smooth_render_lcd_v( 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_V );
407   }
408 
409 
410   FT_DEFINE_RENDERER(
411     ft_smooth_renderer_class,
412 
413       FT_MODULE_RENDERER,
414       sizeof ( FT_RendererRec ),
415 
416       "smooth",
417       0x10000L,
418       0x20000L,
419 
420       NULL,    /* module specific interface */
421 
422       (FT_Module_Constructor)ft_smooth_init,  /* module_init   */
423       (FT_Module_Destructor) NULL,            /* module_done   */
424       (FT_Module_Requester)  NULL,            /* get_interface */
425 
426     FT_GLYPH_FORMAT_OUTLINE,
427 
428     (FT_Renderer_RenderFunc)   ft_smooth_render,     /* render_glyph    */
429     (FT_Renderer_TransformFunc)ft_smooth_transform,  /* transform_glyph */
430     (FT_Renderer_GetCBoxFunc)  ft_smooth_get_cbox,   /* get_glyph_cbox  */
431     (FT_Renderer_SetModeFunc)  ft_smooth_set_mode,   /* set_mode        */
432 
433     (FT_Raster_Funcs*)&ft_grays_raster               /* raster_class    */
434   )
435 
436 
437   FT_DEFINE_RENDERER(
438     ft_smooth_lcd_renderer_class,
439 
440       FT_MODULE_RENDERER,
441       sizeof ( FT_RendererRec ),
442 
443       "smooth-lcd",
444       0x10000L,
445       0x20000L,
446 
447       NULL,    /* module specific interface */
448 
449       (FT_Module_Constructor)ft_smooth_init,  /* module_init   */
450       (FT_Module_Destructor) NULL,            /* module_done   */
451       (FT_Module_Requester)  NULL,            /* get_interface */
452 
453     FT_GLYPH_FORMAT_OUTLINE,
454 
455     (FT_Renderer_RenderFunc)   ft_smooth_render_lcd,  /* render_glyph    */
456     (FT_Renderer_TransformFunc)ft_smooth_transform,   /* transform_glyph */
457     (FT_Renderer_GetCBoxFunc)  ft_smooth_get_cbox,    /* get_glyph_cbox  */
458     (FT_Renderer_SetModeFunc)  ft_smooth_set_mode,    /* set_mode        */
459 
460     (FT_Raster_Funcs*)&ft_grays_raster                /* raster_class    */
461   )
462 
463 
464   FT_DEFINE_RENDERER(
465     ft_smooth_lcdv_renderer_class,
466 
467       FT_MODULE_RENDERER,
468       sizeof ( FT_RendererRec ),
469 
470       "smooth-lcdv",
471       0x10000L,
472       0x20000L,
473 
474       NULL,    /* module specific interface */
475 
476       (FT_Module_Constructor)ft_smooth_init,  /* module_init   */
477       (FT_Module_Destructor) NULL,            /* module_done   */
478       (FT_Module_Requester)  NULL,            /* get_interface */
479 
480     FT_GLYPH_FORMAT_OUTLINE,
481 
482     (FT_Renderer_RenderFunc)   ft_smooth_render_lcd_v,  /* render_glyph    */
483     (FT_Renderer_TransformFunc)ft_smooth_transform,     /* transform_glyph */
484     (FT_Renderer_GetCBoxFunc)  ft_smooth_get_cbox,      /* get_glyph_cbox  */
485     (FT_Renderer_SetModeFunc)  ft_smooth_set_mode,      /* set_mode        */
486 
487     (FT_Raster_Funcs*)&ft_grays_raster                  /* raster_class    */
488   )
489 
490 
491 /* END */
492