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