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