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
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
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
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
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
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
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
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
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