1/***************************************************************************/
2/*                                                                         */
3/*  ftlcdfil.c                                                             */
4/*                                                                         */
5/*    FreeType API for color filtering of subpixel bitmap glyphs (body).   */
6/*                                                                         */
7/*  Copyright 2006, 2008, 2009, 2010 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_LCD_FILTER_H
21#include FT_IMAGE_H
22#include FT_INTERNAL_OBJECTS_H
23
24
25#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
26
27/* define USE_LEGACY to implement the legacy filter */
28#define  USE_LEGACY
29
30  /* FIR filter used by the default and light filters */
31  static void
32  _ft_lcd_filter_fir( FT_Bitmap*      bitmap,
33                      FT_Render_Mode  mode,
34                      FT_Library      library )
35  {
36    FT_Byte*  weights = library->lcd_weights;
37    FT_UInt   width   = (FT_UInt)bitmap->width;
38    FT_UInt   height  = (FT_UInt)bitmap->rows;
39
40
41    /* horizontal in-place FIR filter */
42    if ( mode == FT_RENDER_MODE_LCD && width >= 4 )
43    {
44      FT_Byte*  line = bitmap->buffer;
45
46
47      for ( ; height > 0; height--, line += bitmap->pitch )
48      {
49        FT_UInt  fir[5];
50        FT_UInt  val1, xx;
51
52
53        val1   = line[0];
54        fir[0] = weights[2] * val1;
55        fir[1] = weights[3] * val1;
56        fir[2] = weights[4] * val1;
57        fir[3] = 0;
58        fir[4] = 0;
59
60        val1    = line[1];
61        fir[0] += weights[1] * val1;
62        fir[1] += weights[2] * val1;
63        fir[2] += weights[3] * val1;
64        fir[3] += weights[4] * val1;
65
66        for ( xx = 2; xx < width; xx++ )
67        {
68          FT_UInt  val, pix;
69
70
71          val    = line[xx];
72          pix    = fir[0] + weights[0] * val;
73          fir[0] = fir[1] + weights[1] * val;
74          fir[1] = fir[2] + weights[2] * val;
75          fir[2] = fir[3] + weights[3] * val;
76          fir[3] =          weights[4] * val;
77
78          pix        >>= 8;
79          pix         |= -( pix >> 8 );
80          line[xx - 2] = (FT_Byte)pix;
81        }
82
83        {
84          FT_UInt  pix;
85
86
87          pix          = fir[0] >> 8;
88          pix         |= -( pix >> 8 );
89          line[xx - 2] = (FT_Byte)pix;
90
91          pix          = fir[1] >> 8;
92          pix         |= -( pix >> 8 );
93          line[xx - 1] = (FT_Byte)pix;
94        }
95      }
96    }
97
98    /* vertical in-place FIR filter */
99    else if ( mode == FT_RENDER_MODE_LCD_V && height >= 4 )
100    {
101      FT_Byte*  column = bitmap->buffer;
102      FT_Int    pitch  = bitmap->pitch;
103
104
105      for ( ; width > 0; width--, column++ )
106      {
107        FT_Byte*  col = column;
108        FT_UInt   fir[5];
109        FT_UInt   val1, yy;
110
111
112        val1   = col[0];
113        fir[0] = weights[2] * val1;
114        fir[1] = weights[3] * val1;
115        fir[2] = weights[4] * val1;
116        fir[3] = 0;
117        fir[4] = 0;
118        col   += pitch;
119
120        val1    = col[0];
121        fir[0] += weights[1] * val1;
122        fir[1] += weights[2] * val1;
123        fir[2] += weights[3] * val1;
124        fir[3] += weights[4] * val1;
125        col    += pitch;
126
127        for ( yy = 2; yy < height; yy++ )
128        {
129          FT_UInt  val, pix;
130
131
132          val    = col[0];
133          pix    = fir[0] + weights[0] * val;
134          fir[0] = fir[1] + weights[1] * val;
135          fir[1] = fir[2] + weights[2] * val;
136          fir[2] = fir[3] + weights[3] * val;
137          fir[3] =          weights[4] * val;
138
139          pix           >>= 8;
140          pix            |= -( pix >> 8 );
141          col[-2 * pitch] = (FT_Byte)pix;
142          col            += pitch;
143        }
144
145        {
146          FT_UInt  pix;
147
148
149          pix             = fir[0] >> 8;
150          pix            |= -( pix >> 8 );
151          col[-2 * pitch] = (FT_Byte)pix;
152
153          pix         = fir[1] >> 8;
154          pix        |= -( pix >> 8 );
155          col[-pitch] = (FT_Byte)pix;
156        }
157      }
158    }
159  }
160
161
162#ifdef USE_LEGACY
163
164  /* intra-pixel filter used by the legacy filter */
165  static void
166  _ft_lcd_filter_legacy( FT_Bitmap*      bitmap,
167                         FT_Render_Mode  mode,
168                         FT_Library      library )
169  {
170    FT_UInt  width  = (FT_UInt)bitmap->width;
171    FT_UInt  height = (FT_UInt)bitmap->rows;
172    FT_Int   pitch  = bitmap->pitch;
173
174    static const int  filters[3][3] =
175    {
176      { 65538 * 9/13, 65538 * 1/6, 65538 * 1/13 },
177      { 65538 * 3/13, 65538 * 4/6, 65538 * 3/13 },
178      { 65538 * 1/13, 65538 * 1/6, 65538 * 9/13 }
179    };
180
181    FT_UNUSED( library );
182
183
184    /* horizontal in-place intra-pixel filter */
185    if ( mode == FT_RENDER_MODE_LCD && width >= 3 )
186    {
187      FT_Byte*  line = bitmap->buffer;
188
189
190      for ( ; height > 0; height--, line += pitch )
191      {
192        FT_UInt  xx;
193
194
195        for ( xx = 0; xx < width; xx += 3 )
196        {
197          FT_UInt  r = 0;
198          FT_UInt  g = 0;
199          FT_UInt  b = 0;
200          FT_UInt  p;
201
202
203          p  = line[xx];
204          r += filters[0][0] * p;
205          g += filters[0][1] * p;
206          b += filters[0][2] * p;
207
208          p  = line[xx + 1];
209          r += filters[1][0] * p;
210          g += filters[1][1] * p;
211          b += filters[1][2] * p;
212
213          p  = line[xx + 2];
214          r += filters[2][0] * p;
215          g += filters[2][1] * p;
216          b += filters[2][2] * p;
217
218          line[xx]     = (FT_Byte)( r / 65536 );
219          line[xx + 1] = (FT_Byte)( g / 65536 );
220          line[xx + 2] = (FT_Byte)( b / 65536 );
221        }
222      }
223    }
224    else if ( mode == FT_RENDER_MODE_LCD_V && height >= 3 )
225    {
226      FT_Byte*  column = bitmap->buffer;
227
228
229      for ( ; width > 0; width--, column++ )
230      {
231        FT_Byte*  col     = column;
232        FT_Byte*  col_end = col + height * pitch;
233
234
235        for ( ; col < col_end; col += 3 * pitch )
236        {
237          FT_UInt  r = 0;
238          FT_UInt  g = 0;
239          FT_UInt  b = 0;
240          FT_UInt  p;
241
242
243          p  = col[0];
244          r += filters[0][0] * p;
245          g += filters[0][1] * p;
246          b += filters[0][2] * p;
247
248          p  = col[pitch];
249          r += filters[1][0] * p;
250          g += filters[1][1] * p;
251          b += filters[1][2] * p;
252
253          p  = col[pitch * 2];
254          r += filters[2][0] * p;
255          g += filters[2][1] * p;
256          b += filters[2][2] * p;
257
258          col[0]         = (FT_Byte)( r / 65536 );
259          col[pitch]     = (FT_Byte)( g / 65536 );
260          col[2 * pitch] = (FT_Byte)( b / 65536 );
261        }
262      }
263    }
264  }
265
266#endif /* USE_LEGACY */
267
268
269  FT_EXPORT_DEF( FT_Error )
270  FT_Library_SetLcdFilterWeights( FT_Library      library,
271                                  unsigned char  *weights )
272  {
273    if ( !library || !weights )
274      return FT_Err_Invalid_Argument;
275
276    ft_memcpy( library->lcd_weights, weights, 5 );
277
278    return FT_Err_Ok;
279  }
280
281
282  FT_EXPORT_DEF( FT_Error )
283  FT_Library_SetLcdFilter( FT_Library    library,
284                           FT_LcdFilter  filter )
285  {
286    static const FT_Byte  light_filter[5] =
287                            { 0x00, 0x55, 0x56, 0x55, 0x00 };
288    /* the values here sum up to a value larger than 256, */
289    /* providing a cheap gamma correction                 */
290    static const FT_Byte  default_filter[5] =
291                            { 0x10, 0x40, 0x70, 0x40, 0x10 };
292
293
294    if ( !library )
295      return FT_Err_Invalid_Argument;
296
297    switch ( filter )
298    {
299    case FT_LCD_FILTER_NONE:
300      library->lcd_filter_func = NULL;
301      library->lcd_extra       = 0;
302      break;
303
304    case FT_LCD_FILTER_DEFAULT:
305#if defined( FT_FORCE_LEGACY_LCD_FILTER )
306
307      library->lcd_filter_func = _ft_lcd_filter_legacy;
308      library->lcd_extra       = 0;
309
310#elif defined( FT_FORCE_LIGHT_LCD_FILTER )
311
312      ft_memcpy( library->lcd_weights, light_filter, 5 );
313      library->lcd_filter_func = _ft_lcd_filter_fir;
314      library->lcd_extra       = 2;
315
316#else
317
318      ft_memcpy( library->lcd_weights, default_filter, 5 );
319      library->lcd_filter_func = _ft_lcd_filter_fir;
320      library->lcd_extra       = 2;
321
322#endif
323
324      break;
325
326    case FT_LCD_FILTER_LIGHT:
327      ft_memcpy( library->lcd_weights, light_filter, 5 );
328      library->lcd_filter_func = _ft_lcd_filter_fir;
329      library->lcd_extra       = 2;
330      break;
331
332#ifdef USE_LEGACY
333
334    case FT_LCD_FILTER_LEGACY:
335      library->lcd_filter_func = _ft_lcd_filter_legacy;
336      library->lcd_extra       = 0;
337      break;
338
339#endif
340
341    default:
342      return FT_Err_Invalid_Argument;
343    }
344
345    library->lcd_filter = filter;
346
347    return FT_Err_Ok;
348  }
349
350#else /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
351
352  FT_EXPORT_DEF( FT_Error )
353  FT_Library_SetLcdFilterWeights( FT_Library      library,
354                                  unsigned char  *weights )
355  {
356    FT_UNUSED( library );
357    FT_UNUSED( weights );
358
359    return FT_Err_Unimplemented_Feature;
360  }
361
362
363  FT_EXPORT_DEF( FT_Error )
364  FT_Library_SetLcdFilter( FT_Library    library,
365                           FT_LcdFilter  filter )
366  {
367    FT_UNUSED( library );
368    FT_UNUSED( filter );
369
370    return FT_Err_Unimplemented_Feature;
371  }
372
373#endif /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
374
375
376/* END */
377