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