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