|
1 /***************************************************************************/ |
|
2 /* */ |
|
3 /* ftsmooth.c */ |
|
4 /* */ |
|
5 /* Anti-aliasing renderer interface (body). */ |
|
6 /* */ |
|
7 /* Copyright 2000-2001, 2002, 2003, 2004, 2005, 2006, 2009, 2010 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 #include FT_INTERNAL_OBJECTS_H |
|
22 #include FT_OUTLINE_H |
|
23 #include "ftsmooth.h" |
|
24 #include "ftgrays.h" |
|
25 #include "ftspic.h" |
|
26 |
|
27 #include "ftsmerrs.h" |
|
28 |
|
29 |
|
30 /* initialize renderer -- init its raster */ |
|
31 static FT_Error |
|
32 ft_smooth_init( FT_Renderer render ) |
|
33 { |
|
34 FT_Library library = FT_MODULE_LIBRARY( render ); |
|
35 |
|
36 |
|
37 render->clazz->raster_class->raster_reset( render->raster, |
|
38 library->raster_pool, |
|
39 library->raster_pool_size ); |
|
40 |
|
41 return 0; |
|
42 } |
|
43 |
|
44 |
|
45 /* sets render-specific mode */ |
|
46 static FT_Error |
|
47 ft_smooth_set_mode( FT_Renderer render, |
|
48 FT_ULong mode_tag, |
|
49 FT_Pointer data ) |
|
50 { |
|
51 /* we simply pass it to the raster */ |
|
52 return render->clazz->raster_class->raster_set_mode( render->raster, |
|
53 mode_tag, |
|
54 data ); |
|
55 } |
|
56 |
|
57 /* transform a given glyph image */ |
|
58 static FT_Error |
|
59 ft_smooth_transform( FT_Renderer render, |
|
60 FT_GlyphSlot slot, |
|
61 const FT_Matrix* matrix, |
|
62 const FT_Vector* delta ) |
|
63 { |
|
64 FT_Error error = Smooth_Err_Ok; |
|
65 |
|
66 |
|
67 if ( slot->format != render->glyph_format ) |
|
68 { |
|
69 error = Smooth_Err_Invalid_Argument; |
|
70 goto Exit; |
|
71 } |
|
72 |
|
73 if ( matrix ) |
|
74 FT_Outline_Transform( &slot->outline, matrix ); |
|
75 |
|
76 if ( delta ) |
|
77 FT_Outline_Translate( &slot->outline, delta->x, delta->y ); |
|
78 |
|
79 Exit: |
|
80 return error; |
|
81 } |
|
82 |
|
83 |
|
84 /* return the glyph's control box */ |
|
85 static void |
|
86 ft_smooth_get_cbox( FT_Renderer render, |
|
87 FT_GlyphSlot slot, |
|
88 FT_BBox* cbox ) |
|
89 { |
|
90 FT_MEM_ZERO( cbox, sizeof ( *cbox ) ); |
|
91 |
|
92 if ( slot->format == render->glyph_format ) |
|
93 FT_Outline_Get_CBox( &slot->outline, cbox ); |
|
94 } |
|
95 |
|
96 |
|
97 /* convert a slot's glyph image into a bitmap */ |
|
98 static FT_Error |
|
99 ft_smooth_render_generic( FT_Renderer render, |
|
100 FT_GlyphSlot slot, |
|
101 FT_Render_Mode mode, |
|
102 const FT_Vector* origin, |
|
103 FT_Render_Mode required_mode ) |
|
104 { |
|
105 FT_Error error; |
|
106 FT_Outline* outline = NULL; |
|
107 FT_BBox cbox; |
|
108 FT_UInt width, height, height_org, width_org, pitch; |
|
109 FT_Bitmap* bitmap; |
|
110 FT_Memory memory; |
|
111 FT_Int hmul = mode == FT_RENDER_MODE_LCD; |
|
112 FT_Int vmul = mode == FT_RENDER_MODE_LCD_V; |
|
113 FT_Pos x_shift, y_shift, x_left, y_top; |
|
114 |
|
115 FT_Raster_Params params; |
|
116 |
|
117 |
|
118 /* check glyph image format */ |
|
119 if ( slot->format != render->glyph_format ) |
|
120 { |
|
121 error = Smooth_Err_Invalid_Argument; |
|
122 goto Exit; |
|
123 } |
|
124 |
|
125 /* check mode */ |
|
126 if ( mode != required_mode ) |
|
127 return Smooth_Err_Cannot_Render_Glyph; |
|
128 |
|
129 outline = &slot->outline; |
|
130 |
|
131 /* translate the outline to the new origin if needed */ |
|
132 if ( origin ) |
|
133 FT_Outline_Translate( outline, origin->x, origin->y ); |
|
134 |
|
135 /* compute the control box, and grid fit it */ |
|
136 FT_Outline_Get_CBox( outline, &cbox ); |
|
137 |
|
138 cbox.xMin = FT_PIX_FLOOR( cbox.xMin ); |
|
139 cbox.yMin = FT_PIX_FLOOR( cbox.yMin ); |
|
140 cbox.xMax = FT_PIX_CEIL( cbox.xMax ); |
|
141 cbox.yMax = FT_PIX_CEIL( cbox.yMax ); |
|
142 |
|
143 if ( cbox.xMin < 0 && cbox.xMax > FT_INT_MAX + cbox.xMin ) |
|
144 { |
|
145 FT_ERROR(( "ft_smooth_render_generic: glyph too large:" |
|
146 " xMin = %d, xMax = %d\n", |
|
147 cbox.xMin >> 6, cbox.xMax >> 6 )); |
|
148 return Smooth_Err_Raster_Overflow; |
|
149 } |
|
150 else |
|
151 width = (FT_UInt)( ( cbox.xMax - cbox.xMin ) >> 6 ); |
|
152 |
|
153 if ( cbox.yMin < 0 && cbox.yMax > FT_INT_MAX + cbox.yMin ) |
|
154 { |
|
155 FT_ERROR(( "ft_smooth_render_generic: glyph too large:" |
|
156 " yMin = %d, yMax = %d\n", |
|
157 cbox.yMin >> 6, cbox.yMax >> 6 )); |
|
158 return Smooth_Err_Raster_Overflow; |
|
159 } |
|
160 else |
|
161 height = (FT_UInt)( ( cbox.yMax - cbox.yMin ) >> 6 ); |
|
162 |
|
163 bitmap = &slot->bitmap; |
|
164 memory = render->root.memory; |
|
165 |
|
166 width_org = width; |
|
167 height_org = height; |
|
168 |
|
169 /* release old bitmap buffer */ |
|
170 if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) |
|
171 { |
|
172 FT_FREE( bitmap->buffer ); |
|
173 slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP; |
|
174 } |
|
175 |
|
176 /* allocate new one */ |
|
177 pitch = width; |
|
178 if ( hmul ) |
|
179 { |
|
180 width = width * 3; |
|
181 pitch = FT_PAD_CEIL( width, 4 ); |
|
182 } |
|
183 |
|
184 if ( vmul ) |
|
185 height *= 3; |
|
186 |
|
187 x_shift = (FT_Int) cbox.xMin; |
|
188 y_shift = (FT_Int) cbox.yMin; |
|
189 x_left = (FT_Int)( cbox.xMin >> 6 ); |
|
190 y_top = (FT_Int)( cbox.yMax >> 6 ); |
|
191 |
|
192 #ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING |
|
193 |
|
194 if ( slot->library->lcd_filter_func ) |
|
195 { |
|
196 FT_Int extra = slot->library->lcd_extra; |
|
197 |
|
198 |
|
199 if ( hmul ) |
|
200 { |
|
201 x_shift -= 64 * ( extra >> 1 ); |
|
202 width += 3 * extra; |
|
203 pitch = FT_PAD_CEIL( width, 4 ); |
|
204 x_left -= extra >> 1; |
|
205 } |
|
206 |
|
207 if ( vmul ) |
|
208 { |
|
209 y_shift -= 64 * ( extra >> 1 ); |
|
210 height += 3 * extra; |
|
211 y_top += extra >> 1; |
|
212 } |
|
213 } |
|
214 |
|
215 #endif |
|
216 |
|
217 #if FT_UINT_MAX > 0xFFFFU |
|
218 |
|
219 /* Required check is ( pitch * height < FT_ULONG_MAX ), */ |
|
220 /* but we care realistic cases only. Always pitch <= width. */ |
|
221 if ( width > 0x7FFFU || height > 0x7FFFU ) |
|
222 { |
|
223 FT_ERROR(( "ft_smooth_render_generic: glyph too large: %u x %u\n", |
|
224 width, height )); |
|
225 return Smooth_Err_Raster_Overflow; |
|
226 } |
|
227 |
|
228 #endif |
|
229 |
|
230 bitmap->pixel_mode = FT_PIXEL_MODE_GRAY; |
|
231 bitmap->num_grays = 256; |
|
232 bitmap->width = width; |
|
233 bitmap->rows = height; |
|
234 bitmap->pitch = pitch; |
|
235 |
|
236 /* translate outline to render it into the bitmap */ |
|
237 FT_Outline_Translate( outline, -x_shift, -y_shift ); |
|
238 |
|
239 if ( FT_ALLOC( bitmap->buffer, (FT_ULong)pitch * height ) ) |
|
240 goto Exit; |
|
241 |
|
242 slot->internal->flags |= FT_GLYPH_OWN_BITMAP; |
|
243 |
|
244 /* set up parameters */ |
|
245 params.target = bitmap; |
|
246 params.source = outline; |
|
247 params.flags = FT_RASTER_FLAG_AA; |
|
248 |
|
249 #ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING |
|
250 |
|
251 /* implode outline if needed */ |
|
252 { |
|
253 FT_Vector* points = outline->points; |
|
254 FT_Vector* points_end = points + outline->n_points; |
|
255 FT_Vector* vec; |
|
256 |
|
257 |
|
258 if ( hmul ) |
|
259 for ( vec = points; vec < points_end; vec++ ) |
|
260 vec->x *= 3; |
|
261 |
|
262 if ( vmul ) |
|
263 for ( vec = points; vec < points_end; vec++ ) |
|
264 vec->y *= 3; |
|
265 } |
|
266 |
|
267 /* render outline into the bitmap */ |
|
268 error = render->raster_render( render->raster, ¶ms ); |
|
269 |
|
270 /* deflate outline if needed */ |
|
271 { |
|
272 FT_Vector* points = outline->points; |
|
273 FT_Vector* points_end = points + outline->n_points; |
|
274 FT_Vector* vec; |
|
275 |
|
276 |
|
277 if ( hmul ) |
|
278 for ( vec = points; vec < points_end; vec++ ) |
|
279 vec->x /= 3; |
|
280 |
|
281 if ( vmul ) |
|
282 for ( vec = points; vec < points_end; vec++ ) |
|
283 vec->y /= 3; |
|
284 } |
|
285 |
|
286 if ( slot->library->lcd_filter_func ) |
|
287 slot->library->lcd_filter_func( bitmap, mode, slot->library ); |
|
288 |
|
289 #else /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ |
|
290 |
|
291 /* render outline into bitmap */ |
|
292 error = render->raster_render( render->raster, ¶ms ); |
|
293 |
|
294 /* expand it horizontally */ |
|
295 if ( hmul ) |
|
296 { |
|
297 FT_Byte* line = bitmap->buffer; |
|
298 FT_UInt hh; |
|
299 |
|
300 |
|
301 for ( hh = height_org; hh > 0; hh--, line += pitch ) |
|
302 { |
|
303 FT_UInt xx; |
|
304 FT_Byte* end = line + width; |
|
305 |
|
306 |
|
307 for ( xx = width_org; xx > 0; xx-- ) |
|
308 { |
|
309 FT_UInt pixel = line[xx-1]; |
|
310 |
|
311 |
|
312 end[-3] = (FT_Byte)pixel; |
|
313 end[-2] = (FT_Byte)pixel; |
|
314 end[-1] = (FT_Byte)pixel; |
|
315 end -= 3; |
|
316 } |
|
317 } |
|
318 } |
|
319 |
|
320 /* expand it vertically */ |
|
321 if ( vmul ) |
|
322 { |
|
323 FT_Byte* read = bitmap->buffer + ( height - height_org ) * pitch; |
|
324 FT_Byte* write = bitmap->buffer; |
|
325 FT_UInt hh; |
|
326 |
|
327 |
|
328 for ( hh = height_org; hh > 0; hh-- ) |
|
329 { |
|
330 ft_memcpy( write, read, pitch ); |
|
331 write += pitch; |
|
332 |
|
333 ft_memcpy( write, read, pitch ); |
|
334 write += pitch; |
|
335 |
|
336 ft_memcpy( write, read, pitch ); |
|
337 write += pitch; |
|
338 read += pitch; |
|
339 } |
|
340 } |
|
341 |
|
342 #endif /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ |
|
343 |
|
344 FT_Outline_Translate( outline, x_shift, y_shift ); |
|
345 |
|
346 /* |
|
347 * XXX: on 16bit system, we return an error for huge bitmap |
|
348 * to prevent an overflow. |
|
349 */ |
|
350 if ( x_left > FT_INT_MAX || y_top > FT_INT_MAX ) |
|
351 return Smooth_Err_Invalid_Pixel_Size; |
|
352 |
|
353 if ( error ) |
|
354 goto Exit; |
|
355 |
|
356 slot->format = FT_GLYPH_FORMAT_BITMAP; |
|
357 slot->bitmap_left = (FT_Int)x_left; |
|
358 slot->bitmap_top = (FT_Int)y_top; |
|
359 |
|
360 Exit: |
|
361 if ( outline && origin ) |
|
362 FT_Outline_Translate( outline, -origin->x, -origin->y ); |
|
363 |
|
364 return error; |
|
365 } |
|
366 |
|
367 |
|
368 /* convert a slot's glyph image into a bitmap */ |
|
369 static FT_Error |
|
370 ft_smooth_render( FT_Renderer render, |
|
371 FT_GlyphSlot slot, |
|
372 FT_Render_Mode mode, |
|
373 const FT_Vector* origin ) |
|
374 { |
|
375 if ( mode == FT_RENDER_MODE_LIGHT ) |
|
376 mode = FT_RENDER_MODE_NORMAL; |
|
377 |
|
378 return ft_smooth_render_generic( render, slot, mode, origin, |
|
379 FT_RENDER_MODE_NORMAL ); |
|
380 } |
|
381 |
|
382 |
|
383 /* convert a slot's glyph image into a horizontal LCD bitmap */ |
|
384 static FT_Error |
|
385 ft_smooth_render_lcd( FT_Renderer render, |
|
386 FT_GlyphSlot slot, |
|
387 FT_Render_Mode mode, |
|
388 const FT_Vector* origin ) |
|
389 { |
|
390 FT_Error error; |
|
391 |
|
392 error = ft_smooth_render_generic( render, slot, mode, origin, |
|
393 FT_RENDER_MODE_LCD ); |
|
394 if ( !error ) |
|
395 slot->bitmap.pixel_mode = FT_PIXEL_MODE_LCD; |
|
396 |
|
397 return error; |
|
398 } |
|
399 |
|
400 |
|
401 /* convert a slot's glyph image into a vertical LCD bitmap */ |
|
402 static FT_Error |
|
403 ft_smooth_render_lcd_v( FT_Renderer render, |
|
404 FT_GlyphSlot slot, |
|
405 FT_Render_Mode mode, |
|
406 const FT_Vector* origin ) |
|
407 { |
|
408 FT_Error error; |
|
409 |
|
410 error = ft_smooth_render_generic( render, slot, mode, origin, |
|
411 FT_RENDER_MODE_LCD_V ); |
|
412 if ( !error ) |
|
413 slot->bitmap.pixel_mode = FT_PIXEL_MODE_LCD_V; |
|
414 |
|
415 return error; |
|
416 } |
|
417 |
|
418 |
|
419 FT_DEFINE_RENDERER(ft_smooth_renderer_class, |
|
420 |
|
421 FT_MODULE_RENDERER, |
|
422 sizeof( FT_RendererRec ), |
|
423 |
|
424 "smooth", |
|
425 0x10000L, |
|
426 0x20000L, |
|
427 |
|
428 0, /* module specific interface */ |
|
429 |
|
430 (FT_Module_Constructor)ft_smooth_init, |
|
431 (FT_Module_Destructor) 0, |
|
432 (FT_Module_Requester) 0 |
|
433 , |
|
434 |
|
435 FT_GLYPH_FORMAT_OUTLINE, |
|
436 |
|
437 (FT_Renderer_RenderFunc) ft_smooth_render, |
|
438 (FT_Renderer_TransformFunc)ft_smooth_transform, |
|
439 (FT_Renderer_GetCBoxFunc) ft_smooth_get_cbox, |
|
440 (FT_Renderer_SetModeFunc) ft_smooth_set_mode, |
|
441 |
|
442 (FT_Raster_Funcs*) &FT_GRAYS_RASTER_GET |
|
443 ) |
|
444 |
|
445 |
|
446 FT_DEFINE_RENDERER(ft_smooth_lcd_renderer_class, |
|
447 |
|
448 FT_MODULE_RENDERER, |
|
449 sizeof( FT_RendererRec ), |
|
450 |
|
451 "smooth-lcd", |
|
452 0x10000L, |
|
453 0x20000L, |
|
454 |
|
455 0, /* module specific interface */ |
|
456 |
|
457 (FT_Module_Constructor)ft_smooth_init, |
|
458 (FT_Module_Destructor) 0, |
|
459 (FT_Module_Requester) 0 |
|
460 , |
|
461 |
|
462 FT_GLYPH_FORMAT_OUTLINE, |
|
463 |
|
464 (FT_Renderer_RenderFunc) ft_smooth_render_lcd, |
|
465 (FT_Renderer_TransformFunc)ft_smooth_transform, |
|
466 (FT_Renderer_GetCBoxFunc) ft_smooth_get_cbox, |
|
467 (FT_Renderer_SetModeFunc) ft_smooth_set_mode, |
|
468 |
|
469 (FT_Raster_Funcs*) &FT_GRAYS_RASTER_GET |
|
470 ) |
|
471 |
|
472 FT_DEFINE_RENDERER(ft_smooth_lcdv_renderer_class, |
|
473 |
|
474 FT_MODULE_RENDERER, |
|
475 sizeof( FT_RendererRec ), |
|
476 |
|
477 "smooth-lcdv", |
|
478 0x10000L, |
|
479 0x20000L, |
|
480 |
|
481 0, /* module specific interface */ |
|
482 |
|
483 (FT_Module_Constructor)ft_smooth_init, |
|
484 (FT_Module_Destructor) 0, |
|
485 (FT_Module_Requester) 0 |
|
486 , |
|
487 |
|
488 FT_GLYPH_FORMAT_OUTLINE, |
|
489 |
|
490 (FT_Renderer_RenderFunc) ft_smooth_render_lcd_v, |
|
491 (FT_Renderer_TransformFunc)ft_smooth_transform, |
|
492 (FT_Renderer_GetCBoxFunc) ft_smooth_get_cbox, |
|
493 (FT_Renderer_SetModeFunc) ft_smooth_set_mode, |
|
494 |
|
495 (FT_Raster_Funcs*) &FT_GRAYS_RASTER_GET |
|
496 ) |
|
497 |
|
498 |
|
499 /* END */ |