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