26#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
31#define FT_SHIFTCLAMP( x ) ( x >>= 8, (FT_Byte)( x > 255 ? 255 : x ) )
36 ft_lcd_padding( FT_BBox* cbox,
41 FT_Bitmap_LcdFilterFunc lcd_filter_func;
45 if ( slot->face && slot->face->internal->lcd_filter_func )
47 lcd_weights = slot->face->internal->lcd_weights;
48 lcd_filter_func = slot->face->internal->lcd_filter_func;
52 lcd_weights = slot->library->lcd_weights;
53 lcd_filter_func = slot->library->lcd_filter_func;
56 if ( lcd_filter_func == ft_lcd_filter_fir )
58 if ( mode == FT_RENDER_MODE_LCD )
60 cbox->xMin -= lcd_weights[0] ? 43 :
61 lcd_weights[1] ? 22 : 0;
62 cbox->xMax += lcd_weights[4] ? 43 :
63 lcd_weights[3] ? 22 : 0;
65 else if ( mode == FT_RENDER_MODE_LCD_V )
67 cbox->yMin -= lcd_weights[0] ? 43 :
68 lcd_weights[1] ? 22 : 0;
69 cbox->yMax += lcd_weights[4] ? 43 :
70 lcd_weights[3] ? 22 : 0;
78 ft_lcd_filter_fir( FT_Bitmap* bitmap,
79 FT_LcdFiveTapFilter weights )
81 FT_UInt width = (FT_UInt)bitmap->width;
82 FT_UInt height = (FT_UInt)bitmap->rows;
83 FT_Int pitch = bitmap->pitch;
84 FT_Byte* origin = bitmap->buffer;
85 FT_Byte mode = bitmap->pixel_mode;
89 if ( pitch > 0 && height > 0 )
90 origin += pitch * (FT_Int)( height - 1 );
93 if ( mode == FT_PIXEL_MODE_LCD && width >= 2 )
95 FT_Byte* line = origin;
101 for ( ; height > 0; height--, line -= pitch )
108 fir[2] = weights[2] * val;
109 fir[3] = weights[3] * val;
110 fir[4] = weights[4] * 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;
118 for ( xx = 2; xx < width; xx++ )
121 fir[0] = fir[1] + weights[0] * val;
122 fir[1] = fir[2] + weights[1] * val;
123 fir[2] = fir[3] + weights[2] * val;
124 fir[3] = fir[4] + weights[3] * val;
125 fir[4] = weights[4] * val;
127 line[xx - 2] = FT_SHIFTCLAMP( fir[0] );
130 line[xx - 2] = FT_SHIFTCLAMP( fir[1] );
131 line[xx - 1] = FT_SHIFTCLAMP( fir[2] );
136 else if ( mode == FT_PIXEL_MODE_LCD_V && height >= 2 )
138 FT_Byte* column = origin;
141 for ( ; width > 0; width--, column++ )
143 FT_Byte* col = column;
149 fir[2] = weights[2] * val;
150 fir[3] = weights[3] * val;
151 fir[4] = weights[4] * val;
155 fir[1] = fir[2] + weights[1] * val;
156 fir[2] = fir[3] + weights[2] * val;
157 fir[3] = fir[4] + weights[3] * val;
158 fir[4] = weights[4] * val;
161 for ( yy = 2; yy < height; yy++, col -= pitch )
164 fir[0] = fir[1] + weights[0] * val;
165 fir[1] = fir[2] + weights[1] * val;
166 fir[2] = fir[3] + weights[2] * val;
167 fir[3] = fir[4] + weights[3] * val;
168 fir[4] = weights[4] * val;
170 col[pitch * 2] = FT_SHIFTCLAMP( fir[0] );
173 col[pitch * 2] = FT_SHIFTCLAMP( fir[1] );
174 col[pitch] = FT_SHIFTCLAMP( fir[2] );
184 _ft_lcd_filter_legacy( FT_Bitmap* bitmap,
187 FT_UInt width = (FT_UInt)bitmap->width;
188 FT_UInt height = (FT_UInt)bitmap->rows;
189 FT_Int pitch = bitmap->pitch;
190 FT_Byte* origin = bitmap->buffer;
191 FT_Byte mode = bitmap->pixel_mode;
193 static const unsigned int filters[3][3] =
195 { 65538 * 9/13, 65538 * 1/6, 65538 * 1/13 },
196 { 65538 * 3/13, 65538 * 4/6, 65538 * 3/13 },
197 { 65538 * 1/13, 65538 * 1/6, 65538 * 9/13 }
200 FT_UNUSED( weights );
204 if ( pitch > 0 && height > 0 )
205 origin += pitch * (FT_Int)( height - 1 );
208 if ( mode == FT_PIXEL_MODE_LCD && width >= 3 )
210 FT_Byte* line = origin;
213 for ( ; height > 0; height--, line -= pitch )
218 for ( xx = 0; xx < width; xx += 3 )
225 r = filters[0][0] * p;
226 g = filters[0][1] * p;
227 b = filters[0][2] * p;
230 r += filters[1][0] * p;
231 g += filters[1][1] * p;
232 b += filters[1][2] * p;
235 r += filters[2][0] * p;
236 g += filters[2][1] * p;
237 b += filters[2][2] * p;
239 line[xx] = (FT_Byte)( r / 65536 );
240 line[xx + 1] = (FT_Byte)( g / 65536 );
241 line[xx + 2] = (FT_Byte)( b / 65536 );
245 else if ( mode == FT_PIXEL_MODE_LCD_V && height >= 3 )
247 FT_Byte* column = origin;
250 for ( ; width > 0; width--, column++ )
252 FT_Byte* col = column - 2 * pitch;
255 for ( ; height > 0; height -= 3, col -= 3 * pitch )
262 r = filters[0][0] * p;
263 g = filters[0][1] * p;
264 b = filters[0][2] * p;
267 r += filters[1][0] * p;
268 g += filters[1][1] * p;
269 b += filters[1][2] * p;
272 r += filters[2][0] * p;
273 g += filters[2][1] * p;
274 b += filters[2][2] * p;
276 col[0] = (FT_Byte)( r / 65536 );
277 col[pitch] = (FT_Byte)( g / 65536 );
278 col[pitch * 2] = (FT_Byte)( b / 65536 );
289 FT_EXPORT_DEF( FT_Error )
290 FT_Library_SetLcdFilterWeights( FT_Library library,
291 unsigned char *weights )
294 return FT_THROW( Invalid_Library_Handle );
297 return FT_THROW( Invalid_Argument );
299 ft_memcpy( library->lcd_weights, weights, FT_LCD_FILTER_FIVE_TAPS );
300 library->lcd_filter_func = ft_lcd_filter_fir;
308 FT_EXPORT_DEF( FT_Error )
309 FT_Library_SetLcdFilter( FT_Library library,
310 FT_LcdFilter filter )
312 static const FT_LcdFiveTapFilter default_weights =
313 { 0x08, 0x4d, 0x56, 0x4d, 0x08 };
314 static const FT_LcdFiveTapFilter light_weights =
315 { 0x00, 0x55, 0x56, 0x55, 0x00 };
319 return FT_THROW( Invalid_Library_Handle );
323 case FT_LCD_FILTER_NONE:
324 library->lcd_filter_func = NULL;
327 case FT_LCD_FILTER_DEFAULT:
328 ft_memcpy( library->lcd_weights,
330 FT_LCD_FILTER_FIVE_TAPS );
331 library->lcd_filter_func = ft_lcd_filter_fir;
334 case FT_LCD_FILTER_LIGHT:
335 ft_memcpy( library->lcd_weights,
337 FT_LCD_FILTER_FIVE_TAPS );
338 library->lcd_filter_func = ft_lcd_filter_fir;
343 case FT_LCD_FILTER_LEGACY:
344 case FT_LCD_FILTER_LEGACY1:
345 library->lcd_filter_func = _ft_lcd_filter_legacy;
351 return FT_THROW( Invalid_Argument );
358 FT_EXPORT_DEF( FT_Error )
359 FT_Library_SetLcdGeometry( FT_Library library,
362 FT_UNUSED( library );
365 return FT_THROW( Unimplemented_Feature );
372 ft_lcd_padding( FT_BBox* cbox,
374 FT_Render_Mode mode )
376 FT_Vector* sub = slot->library->lcd_geometry;
378 if ( mode == FT_RENDER_MODE_LCD )
380 cbox->xMin -= FT_MAX( FT_MAX( sub[0].x, sub[1].x ), sub[2].x );
381 cbox->xMax -= FT_MIN( FT_MIN( sub[0].x, sub[1].x ), sub[2].x );
382 cbox->yMin -= FT_MAX( FT_MAX( sub[0].y, sub[1].y ), sub[2].y );
383 cbox->yMax -= FT_MIN( FT_MIN( sub[0].y, sub[1].y ), sub[2].y );
385 else if ( mode == FT_RENDER_MODE_LCD_V )
387 cbox->xMin -= FT_MAX( FT_MAX( sub[0].y, sub[1].y ), sub[2].y );
388 cbox->xMax -= FT_MIN( FT_MIN( sub[0].y, sub[1].y ), sub[2].y );
389 cbox->yMin += FT_MIN( FT_MIN( sub[0].x, sub[1].x ), sub[2].x );
390 cbox->yMax += FT_MAX( FT_MAX( sub[0].x, sub[1].x ), sub[2].x );
395 FT_EXPORT_DEF( FT_Error )
396 FT_Library_SetLcdFilterWeights( FT_Library library,
397 unsigned char *weights )
399 FT_UNUSED( library );
400 FT_UNUSED( weights );
402 return FT_THROW( Unimplemented_Feature );
406 FT_EXPORT_DEF( FT_Error )
407 FT_Library_SetLcdFilter( FT_Library library,
408 FT_LcdFilter filter )
410 FT_UNUSED( library );
413 return FT_THROW( Unimplemented_Feature );
419 FT_EXPORT_DEF( FT_Error )
420 FT_Library_SetLcdGeometry( FT_Library library,
424 return FT_THROW( Invalid_Library_Handle );
427 return FT_THROW( Invalid_Argument );
429 ft_memcpy( library->lcd_geometry, sub, 3 *
sizeof( FT_Vector ) );