1/***************************************************************************/
2/*                                                                         */
3/*  ftsmooth.c                                                             */
4/*                                                                         */
5/*    Anti-aliasing renderer interface (body).                             */
6/*                                                                         */
7/*  Copyright 2000-2017 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    FT_Library  library = FT_MODULE_LIBRARY( render );
35
36
37    render->clazz->raster_class->raster_reset( render->raster,
38                                               library->raster_pool,
39                                               library->raster_pool_size );
40
41    return 0;
42  }
43
44
45  /* sets render-specific mode */
46  static FT_Error
47  ft_smooth_set_mode( FT_Renderer  render,
48                      FT_ULong     mode_tag,
49                      FT_Pointer   data )
50  {
51    /* we simply pass it to the raster */
52    return render->clazz->raster_class->raster_set_mode( render->raster,
53                                                         mode_tag,
54                                                         data );
55  }
56
57  /* transform a given glyph image */
58  static FT_Error
59  ft_smooth_transform( FT_Renderer       render,
60                       FT_GlyphSlot      slot,
61                       const FT_Matrix*  matrix,
62                       const FT_Vector*  delta )
63  {
64    FT_Error  error = FT_Err_Ok;
65
66
67    if ( slot->format != render->glyph_format )
68    {
69      error = FT_THROW( Invalid_Argument );
70      goto Exit;
71    }
72
73    if ( matrix )
74      FT_Outline_Transform( &slot->outline, matrix );
75
76    if ( delta )
77      FT_Outline_Translate( &slot->outline, delta->x, delta->y );
78
79  Exit:
80    return error;
81  }
82
83
84  /* return the glyph's control box */
85  static void
86  ft_smooth_get_cbox( FT_Renderer   render,
87                      FT_GlyphSlot  slot,
88                      FT_BBox*      cbox )
89  {
90    FT_ZERO( cbox );
91
92    if ( slot->format == render->glyph_format )
93      FT_Outline_Get_CBox( &slot->outline, cbox );
94  }
95
96
97  /* convert a slot's glyph image into a bitmap */
98  static FT_Error
99  ft_smooth_render_generic( FT_Renderer       render,
100                            FT_GlyphSlot      slot,
101                            FT_Render_Mode    mode,
102                            const FT_Vector*  origin,
103                            FT_Render_Mode    required_mode )
104  {
105    FT_Error     error;
106    FT_Outline*  outline = &slot->outline;
107    FT_Bitmap*   bitmap  = &slot->bitmap;
108    FT_Memory    memory  = render->root.memory;
109    FT_BBox      cbox;
110    FT_Pos       x_shift = 0;
111    FT_Pos       y_shift = 0;
112    FT_Pos       x_left, y_top;
113    FT_Pos       width, height, pitch;
114#ifndef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
115    FT_Pos       height_org, width_org;
116#endif
117    FT_Int       hmul    = ( mode == FT_RENDER_MODE_LCD );
118    FT_Int       vmul    = ( mode == FT_RENDER_MODE_LCD_V );
119
120    FT_Raster_Params  params;
121
122    FT_Bool  have_outline_shifted = FALSE;
123    FT_Bool  have_buffer          = FALSE;
124
125
126    /* check glyph image format */
127    if ( slot->format != render->glyph_format )
128    {
129      error = FT_THROW( Invalid_Argument );
130      goto Exit;
131    }
132
133    /* check mode */
134    if ( mode != required_mode )
135    {
136      error = FT_THROW( Cannot_Render_Glyph );
137      goto Exit;
138    }
139
140    if ( origin )
141    {
142      x_shift = origin->x;
143      y_shift = origin->y;
144    }
145
146    /* compute the control box, and grid fit it */
147    /* taking into account the origin shift     */
148    FT_Outline_Get_CBox( outline, &cbox );
149
150    cbox.xMin = FT_PIX_FLOOR( cbox.xMin + x_shift );
151    cbox.yMin = FT_PIX_FLOOR( cbox.yMin + y_shift );
152    cbox.xMax = FT_PIX_CEIL( cbox.xMax + x_shift );
153    cbox.yMax = FT_PIX_CEIL( cbox.yMax + y_shift );
154
155    x_shift -= cbox.xMin;
156    y_shift -= cbox.yMin;
157
158    x_left  = cbox.xMin >> 6;
159    y_top   = cbox.yMax >> 6;
160
161    width  = (FT_ULong)( cbox.xMax - cbox.xMin ) >> 6;
162    height = (FT_ULong)( cbox.yMax - cbox.yMin ) >> 6;
163
164#ifndef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
165    width_org  = width;
166    height_org = height;
167#endif
168
169    pitch = width;
170    if ( hmul )
171    {
172      width *= 3;
173      pitch  = FT_PAD_CEIL( width, 4 );
174    }
175
176    if ( vmul )
177      height *= 3;
178
179#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
180
181    if ( slot->library->lcd_filter_func )
182    {
183      FT_Int  extra = slot->library->lcd_extra;
184
185
186      if ( hmul )
187      {
188        x_shift += 64 * ( extra >> 1 );
189        x_left  -= extra >> 1;
190        width   += 3 * extra;
191        pitch    = FT_PAD_CEIL( width, 4 );
192      }
193
194      if ( vmul )
195      {
196        y_shift += 64 * ( extra >> 1 );
197        y_top   += extra >> 1;
198        height  += 3 * extra;
199      }
200    }
201
202#endif
203
204    /*
205     * XXX: on 16bit system, we return an error for huge bitmap
206     * to prevent an overflow.
207     */
208    if ( x_left > FT_INT_MAX || y_top > FT_INT_MAX ||
209         x_left < FT_INT_MIN || y_top < FT_INT_MIN )
210    {
211      error = FT_THROW( Invalid_Pixel_Size );
212      goto Exit;
213    }
214
215    /* Required check is (pitch * height < FT_ULONG_MAX),        */
216    /* but we care realistic cases only.  Always pitch <= width. */
217    if ( width > 0x7FFF || height > 0x7FFF )
218    {
219      FT_ERROR(( "ft_smooth_render_generic: glyph too large: %u x %u\n",
220                 width, height ));
221      error = FT_THROW( Raster_Overflow );
222      goto Exit;
223    }
224
225    /* release old bitmap buffer */
226    if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP )
227    {
228      FT_FREE( bitmap->buffer );
229      slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP;
230    }
231
232    /* allocate new one */
233    if ( FT_ALLOC( bitmap->buffer, (FT_ULong)( pitch * height ) ) )
234      goto Exit;
235    else
236      have_buffer = TRUE;
237
238    slot->internal->flags |= FT_GLYPH_OWN_BITMAP;
239
240    slot->format      = FT_GLYPH_FORMAT_BITMAP;
241    slot->bitmap_left = (FT_Int)x_left;
242    slot->bitmap_top  = (FT_Int)y_top;
243
244    bitmap->pixel_mode = FT_PIXEL_MODE_GRAY;
245    bitmap->num_grays  = 256;
246    bitmap->width      = (unsigned int)width;
247    bitmap->rows       = (unsigned int)height;
248    bitmap->pitch      = pitch;
249
250    /* translate outline to render it into the bitmap */
251    if ( x_shift || y_shift )
252    {
253      FT_Outline_Translate( outline, x_shift, y_shift );
254      have_outline_shifted = TRUE;
255    }
256
257    /* set up parameters */
258    params.target = bitmap;
259    params.source = outline;
260    params.flags  = FT_RASTER_FLAG_AA;
261
262#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
263
264    /* implode outline if needed */
265    {
266      FT_Vector*  points     = outline->points;
267      FT_Vector*  points_end = points + outline->n_points;
268      FT_Vector*  vec;
269
270
271      if ( hmul )
272        for ( vec = points; vec < points_end; vec++ )
273          vec->x *= 3;
274
275      if ( vmul )
276        for ( vec = points; vec < points_end; vec++ )
277          vec->y *= 3;
278    }
279
280    /* render outline into the bitmap */
281    error = render->raster_render( render->raster, &params );
282
283    /* deflate outline if needed */
284    {
285      FT_Vector*  points     = outline->points;
286      FT_Vector*  points_end = points + outline->n_points;
287      FT_Vector*  vec;
288
289
290      if ( hmul )
291        for ( vec = points; vec < points_end; vec++ )
292          vec->x /= 3;
293
294      if ( vmul )
295        for ( vec = points; vec < points_end; vec++ )
296          vec->y /= 3;
297    }
298
299    if ( error )
300      goto Exit;
301
302    if ( slot->library->lcd_filter_func )
303      slot->library->lcd_filter_func( bitmap, mode, slot->library );
304
305#else /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
306
307    /* render outline into bitmap */
308    error = render->raster_render( render->raster, &params );
309    if ( error )
310      goto Exit;
311
312    /* expand it horizontally */
313    if ( hmul )
314    {
315      FT_Byte*  line = bitmap->buffer;
316      FT_UInt   hh;
317
318
319      for ( hh = height_org; hh > 0; hh--, line += pitch )
320      {
321        FT_UInt   xx;
322        FT_Byte*  end = line + width;
323
324
325        for ( xx = width_org; xx > 0; xx-- )
326        {
327          FT_UInt  pixel = line[xx-1];
328
329
330          end[-3] = (FT_Byte)pixel;
331          end[-2] = (FT_Byte)pixel;
332          end[-1] = (FT_Byte)pixel;
333          end    -= 3;
334        }
335      }
336    }
337
338    /* expand it vertically */
339    if ( vmul )
340    {
341      FT_Byte*  read  = bitmap->buffer + ( height - height_org ) * pitch;
342      FT_Byte*  write = bitmap->buffer;
343      FT_UInt   hh;
344
345
346      for ( hh = height_org; hh > 0; hh-- )
347      {
348        ft_memcpy( write, read, pitch );
349        write += pitch;
350
351        ft_memcpy( write, read, pitch );
352        write += pitch;
353
354        ft_memcpy( write, read, pitch );
355        write += pitch;
356        read  += pitch;
357      }
358    }
359
360#endif /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
361
362    /* everything is fine; don't deallocate buffer */
363    have_buffer = FALSE;
364
365    error = FT_Err_Ok;
366
367  Exit:
368    if ( have_outline_shifted )
369      FT_Outline_Translate( outline, -x_shift, -y_shift );
370    if ( have_buffer )
371    {
372      FT_FREE( bitmap->buffer );
373      slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP;
374    }
375
376    return error;
377  }
378
379
380  /* convert a slot's glyph image into a bitmap */
381  static FT_Error
382  ft_smooth_render( FT_Renderer       render,
383                    FT_GlyphSlot      slot,
384                    FT_Render_Mode    mode,
385                    const FT_Vector*  origin )
386  {
387    if ( mode == FT_RENDER_MODE_LIGHT )
388      mode = FT_RENDER_MODE_NORMAL;
389
390    return ft_smooth_render_generic( render, slot, mode, origin,
391                                     FT_RENDER_MODE_NORMAL );
392  }
393
394
395  /* convert a slot's glyph image into a horizontal LCD bitmap */
396  static FT_Error
397  ft_smooth_render_lcd( FT_Renderer       render,
398                        FT_GlyphSlot      slot,
399                        FT_Render_Mode    mode,
400                        const FT_Vector*  origin )
401  {
402    FT_Error  error;
403
404    error = ft_smooth_render_generic( render, slot, mode, origin,
405                                      FT_RENDER_MODE_LCD );
406    if ( !error )
407      slot->bitmap.pixel_mode = FT_PIXEL_MODE_LCD;
408
409    return error;
410  }
411
412
413  /* convert a slot's glyph image into a vertical LCD bitmap */
414  static FT_Error
415  ft_smooth_render_lcd_v( FT_Renderer       render,
416                          FT_GlyphSlot      slot,
417                          FT_Render_Mode    mode,
418                          const FT_Vector*  origin )
419  {
420    FT_Error  error;
421
422    error = ft_smooth_render_generic( render, slot, mode, origin,
423                                      FT_RENDER_MODE_LCD_V );
424    if ( !error )
425      slot->bitmap.pixel_mode = FT_PIXEL_MODE_LCD_V;
426
427    return error;
428  }
429
430
431  FT_DEFINE_RENDERER(
432    ft_smooth_renderer_class,
433
434      FT_MODULE_RENDERER,
435      sizeof ( FT_RendererRec ),
436
437      "smooth",
438      0x10000L,
439      0x20000L,
440
441      NULL,    /* module specific interface */
442
443      (FT_Module_Constructor)ft_smooth_init,  /* module_init   */
444      (FT_Module_Destructor) NULL,            /* module_done   */
445      (FT_Module_Requester)  NULL,            /* get_interface */
446
447    FT_GLYPH_FORMAT_OUTLINE,
448
449    (FT_Renderer_RenderFunc)   ft_smooth_render,     /* render_glyph    */
450    (FT_Renderer_TransformFunc)ft_smooth_transform,  /* transform_glyph */
451    (FT_Renderer_GetCBoxFunc)  ft_smooth_get_cbox,   /* get_glyph_cbox  */
452    (FT_Renderer_SetModeFunc)  ft_smooth_set_mode,   /* set_mode        */
453
454    (FT_Raster_Funcs*)&FT_GRAYS_RASTER_GET           /* raster_class    */
455  )
456
457
458  FT_DEFINE_RENDERER(
459    ft_smooth_lcd_renderer_class,
460
461      FT_MODULE_RENDERER,
462      sizeof ( FT_RendererRec ),
463
464      "smooth-lcd",
465      0x10000L,
466      0x20000L,
467
468      NULL,    /* module specific interface */
469
470      (FT_Module_Constructor)ft_smooth_init,  /* module_init   */
471      (FT_Module_Destructor) NULL,            /* module_done   */
472      (FT_Module_Requester)  NULL,            /* get_interface */
473
474    FT_GLYPH_FORMAT_OUTLINE,
475
476    (FT_Renderer_RenderFunc)   ft_smooth_render_lcd,  /* render_glyph    */
477    (FT_Renderer_TransformFunc)ft_smooth_transform,   /* transform_glyph */
478    (FT_Renderer_GetCBoxFunc)  ft_smooth_get_cbox,    /* get_glyph_cbox  */
479    (FT_Renderer_SetModeFunc)  ft_smooth_set_mode,    /* set_mode        */
480
481    (FT_Raster_Funcs*)&FT_GRAYS_RASTER_GET            /* raster_class    */
482  )
483
484
485  FT_DEFINE_RENDERER(
486    ft_smooth_lcdv_renderer_class,
487
488      FT_MODULE_RENDERER,
489      sizeof ( FT_RendererRec ),
490
491      "smooth-lcdv",
492      0x10000L,
493      0x20000L,
494
495      NULL,    /* module specific interface */
496
497      (FT_Module_Constructor)ft_smooth_init,  /* module_init   */
498      (FT_Module_Destructor) NULL,            /* module_done   */
499      (FT_Module_Requester)  NULL,            /* get_interface */
500
501    FT_GLYPH_FORMAT_OUTLINE,
502
503    (FT_Renderer_RenderFunc)   ft_smooth_render_lcd_v,  /* render_glyph    */
504    (FT_Renderer_TransformFunc)ft_smooth_transform,     /* transform_glyph */
505    (FT_Renderer_GetCBoxFunc)  ft_smooth_get_cbox,      /* get_glyph_cbox  */
506    (FT_Renderer_SetModeFunc)  ft_smooth_set_mode,      /* set_mode        */
507
508    (FT_Raster_Funcs*)&FT_GRAYS_RASTER_GET              /* raster_class    */
509  )
510
511
512/* END */
513