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