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