• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /***************************************************************************/
2 /*                                                                         */
3 /*  ftlcdfil.c                                                             */
4 /*                                                                         */
5 /*    FreeType API for color filtering of subpixel bitmap glyphs (body).   */
6 /*                                                                         */
7 /*  Copyright 2006, 2008-2010, 2013, 2014 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 
22 #include FT_LCD_FILTER_H
23 #include FT_IMAGE_H
24 #include FT_INTERNAL_OBJECTS_H
25 
26 
27 #ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
28 
29 /* define USE_LEGACY to implement the legacy filter */
30 #define  USE_LEGACY
31 
32   /* FIR filter used by the default and light filters */
33   static void
_ft_lcd_filter_fir(FT_Bitmap * bitmap,FT_Render_Mode mode,FT_Library library)34   _ft_lcd_filter_fir( FT_Bitmap*      bitmap,
35                       FT_Render_Mode  mode,
36                       FT_Library      library )
37   {
38     FT_Byte*  weights = library->lcd_weights;
39     FT_UInt   width   = (FT_UInt)bitmap->width;
40     FT_UInt   height  = (FT_UInt)bitmap->rows;
41 
42 
43     /* horizontal in-place FIR filter */
44     if ( mode == FT_RENDER_MODE_LCD && width >= 4 )
45     {
46       FT_Byte*  line = bitmap->buffer;
47 
48 
49       /* `fir' and `pix' must be at least 32 bit wide, since the sum of */
50       /* the values in `weights' can exceed 0xFF                        */
51 
52       for ( ; height > 0; height--, line += bitmap->pitch )
53       {
54         FT_UInt  fir[4];        /* below, `pix' is used as the 5th element */
55         FT_UInt  val1, xx;
56 
57 
58         val1   = line[0];
59         fir[0] = weights[2] * val1;
60         fir[1] = weights[3] * val1;
61         fir[2] = weights[4] * val1;
62         fir[3] = 0;
63 
64         val1    = line[1];
65         fir[0] += weights[1] * val1;
66         fir[1] += weights[2] * val1;
67         fir[2] += weights[3] * val1;
68         fir[3] += weights[4] * val1;
69 
70         for ( xx = 2; xx < width; xx++ )
71         {
72           FT_UInt  val, pix;
73 
74 
75           val    = line[xx];
76           pix    = fir[0] + weights[0] * val;
77           fir[0] = fir[1] + weights[1] * val;
78           fir[1] = fir[2] + weights[2] * val;
79           fir[2] = fir[3] + weights[3] * val;
80           fir[3] =          weights[4] * val;
81 
82           pix        >>= 8;
83           pix         |= (FT_UInt)-(FT_Int)( pix >> 8 );
84           line[xx - 2] = (FT_Byte)pix;
85         }
86 
87         {
88           FT_UInt  pix;
89 
90 
91           pix          = fir[0] >> 8;
92           pix         |= (FT_UInt)-(FT_Int)( pix >> 8 );
93           line[xx - 2] = (FT_Byte)pix;
94 
95           pix          = fir[1] >> 8;
96           pix         |= (FT_UInt)-(FT_Int)( pix >> 8 );
97           line[xx - 1] = (FT_Byte)pix;
98         }
99       }
100     }
101 
102     /* vertical in-place FIR filter */
103     else if ( mode == FT_RENDER_MODE_LCD_V && height >= 4 )
104     {
105       FT_Byte*  column = bitmap->buffer;
106       FT_Int    pitch  = bitmap->pitch;
107 
108 
109       for ( ; width > 0; width--, column++ )
110       {
111         FT_Byte*  col = column;
112         FT_UInt   fir[4];       /* below, `pix' is used as the 5th element */
113         FT_UInt   val1, yy;
114 
115 
116         val1   = col[0];
117         fir[0] = weights[2] * val1;
118         fir[1] = weights[3] * val1;
119         fir[2] = weights[4] * val1;
120         fir[3] = 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
_ft_lcd_filter_legacy(FT_Bitmap * bitmap,FT_Render_Mode mode,FT_Library library)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 )
FT_Library_SetLcdFilterWeights(FT_Library library,unsigned char * weights)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 )
FT_Library_SetLcdFilter(FT_Library library,FT_LcdFilter filter)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 )
FT_Library_SetLcdFilterWeights(FT_Library library,unsigned char * weights)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 )
FT_Library_SetLcdFilter(FT_Library library,FT_LcdFilter filter)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