From d8b4514d43c4090d863b320482ccc2385fbdeb69 Mon Sep 17 00:00:00 2001 From: David Turner Date: Tue, 22 Aug 2000 22:53:03 +0000 Subject: [PATCH] added preliminary emboldening code.. still _very_ experimental --- include/freetype/ftsynth.h | 18 ++ src/base/ftsynth.c | 371 +++++++++++++++++++++++++++++++++++++ 2 files changed, 389 insertions(+) create mode 100644 include/freetype/ftsynth.h create mode 100644 src/base/ftsynth.c diff --git a/include/freetype/ftsynth.h b/include/freetype/ftsynth.h new file mode 100644 index 000000000..32cc840e4 --- /dev/null +++ b/include/freetype/ftsynth.h @@ -0,0 +1,18 @@ +#ifndef FTSYNTH_H +#define FTSYNTH_H + +#include + + /* this code is completely experimental - use with care */ + /* it will probably be completely rewritten in the future */ + /* or even integrated within the library... */ + FT_EXPORT_DEF(FT_Error) FT_Embolden_Outline( FT_Face original, + FT_Outline* outline, + FT_Pos* advance ); + + FT_EXPORT_DEF(FT_Error) FT_Oblique_Outline( FT_Face original, + FT_Outline* outline, + FT_Pos* advance ); + + +#endif /* FTEMBOLD_H */ diff --git a/src/base/ftsynth.c b/src/base/ftsynth.c new file mode 100644 index 000000000..81d8a9ddd --- /dev/null +++ b/src/base/ftsynth.c @@ -0,0 +1,371 @@ +#include + +#define FT_BOLD_THRESHOLD 0x0100 + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** EXPERIMENTAL OBLIQUING SUPPORT ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_EXPORT_DEF(FT_Error) FT_Oblique_Outline( FT_GlyphSlot original, + FT_Outline* outline, + FT_Pos* advance ) + { + FT_Matrix transform; + + FT_UNUSED(original); + + /* For italic, simply apply a shear transform, with an angle */ + /* of about 12 degrees.. */ + + transform.xx = 0x10000; + transform.yx = 0x00000; + + transform.xy = 0x06000; + transform.yy = 0x10000; + + FT_Transform_Outline( outline, &transform ); + + /* we don't touch the advance width */ + FT_UNUSED(advance); + + return 0; + } + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** EXPERIMENTAL EMBOLDENING/OUTLINING SUPPORT ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + /* Compute the norm of a vector */ + +#ifdef FT_CONFIG_OPTION_OLD_CALCS + +#include + + static + FT_Pos ft_norm( FT_Vector* vec ) + { + FT_Int64 t1, t2; + + + MUL_64( vec->x, vec->x, t1 ); + MUL_64( vec->y, vec->y, t2 ); + ADD_64( t1, t2, t1 ); + + return (FT_Pos)SQRT_64( t1 ); + } + +#else /* FT_CONFIG_OPTION_OLD_CALCS */ + + static + FT_Pos ft_norm( FT_Vector* vec ) + { + FT_F26Dot6 u, v, d; + FT_Int shift; + FT_ULong H, L, L2, hi, lo, med; + + + u = vec->x; if ( u < 0 ) u = -u; + v = vec->y; if ( v < 0 ) v = -v; + + if ( u < v ) + { + d = u; + u = v; + v = d; + } + + /* check that we are not trying to normalize zero! */ + if ( u == 0 ) + return 0; + + /* compute (u*u + v*v) on 64 bits with two 32-bit registers [H:L] */ + hi = (FT_ULong)u >> 16; + lo = (FT_ULong)u & 0xFFFF; + med = hi * lo; + + H = hi * hi + ( med >> 15 ); + med <<= 17; + L = lo * lo + med; + if ( L < med ) + H++; + + hi = (FT_ULong)v >> 16; + lo = (FT_ULong)v & 0xFFFF; + med = hi * lo; + + H += hi * hi + ( med >> 15 ); + med <<= 17; + L2 = lo * lo + med; + if ( L2 < med ) + H++; + + L += L2; + if ( L < L2 ) + H++; + + /* if the value is smaller than 32 bits */ + shift = 0; + if ( H == 0 ) + { + while ( ( L & 0xC0000000UL ) == 0 ) + { + L <<= 2; + shift++; + } + return ( FT_Sqrt32( L ) >> shift ); + } + else + { + while ( H ) + { + L = ( L >> 2 ) | ( H << 30 ); + H >>= 2; + shift++; + } + return ( FT_Sqrt32( L ) << shift ); + } + } + +#endif /* FT_CONFIG_OPTION_OLD_CALCS */ + + + static + int ft_test_extrema( FT_Outline* outline, + int n ) + { + FT_Vector *prev, *cur, *next; + FT_Pos product; + FT_Int c, first, last; + + + /* we need to compute the `previous' and `next' point */ + /* for these extrema. */ + cur = outline->points + n; + prev = cur - 1; + next = cur + 1; + + first = 0; + for ( c = 0; c < outline->n_contours; c++ ) + { + last = outline->contours[c]; + + if ( n == first ) + prev = outline->points + last; + + if ( n == last ) + next = outline->points + first; + + first = last + 1; + } + + product = FT_MulDiv( cur->x - prev->x, /* in.x */ + next->y - cur->y, /* out.y */ + 0x40 ) + - + FT_MulDiv( cur->y - prev->y, /* in.y */ + next->x - cur->x, /* out.x */ + 0x40 ); + + if ( product ) + product = product > 0 ? 1 : -1; + + return product; + } + + + /* Compute the orientation of path filling. It differs between TrueType */ + /* and Type1 formats. We could use the `ft_outline_reverse_fill' flag, */ + /* but it is better to re-compute it directly (it seems that this flag */ + /* isn't correctly set for some weird composite glyphs currently). */ + /* */ + /* We do this by computing bounding box points, and computing their */ + /* curvature. */ + /* */ + /* The function returns either 1 or -1. */ + /* */ + static + int ft_get_orientation( FT_Outline* outline ) + { + FT_BBox box; + FT_BBox indices; + int n, last; + + + indices.xMin = -1; + indices.yMin = -1; + indices.xMax = -1; + indices.yMax = -1; + + box.xMin = box.yMin = 32767; + box.xMax = box.yMax = -32768; + + /* is it empty ? */ + if ( outline->n_contours < 1 ) + return 1; + + last = outline->contours[outline->n_contours - 1]; + + for ( n = 0; n <= last; n++ ) + { + FT_Pos x, y; + + + x = outline->points[n].x; + if ( x < box.xMin ) + { + box.xMin = x; + indices.xMin = n; + } + if ( x > box.xMax ) + { + box.xMax = x; + indices.xMax = n; + } + + y = outline->points[n].y; + if ( y < box.yMin ) + { + box.yMin = y; + indices.yMin = n; + } + if ( y > box.yMax ) + { + box.yMax = y; + indices.yMax = n; + } + } + + /* test orientation of the xmin */ + n = ft_test_extrema( outline, indices.xMin ); + if (n) + goto Exit; + + n = ft_test_extrema( outline, indices.yMin ); + if (n) + goto Exit; + + n = ft_test_extrema( outline, indices.xMax ); + if (n) + goto Exit; + + n = ft_test_extrema( outline, indices.yMax ); + if (!n) + n = 1; + + Exit: + return n; + } + + + FT_EXPORT_FUNC(FT_Error) FT_Embolden_Outline( FT_GlyphSlot original, + FT_Outline* outline, + FT_Pos* advance ) + { + FT_Vector u, v; + FT_Vector* points; + FT_Vector cur, prev, next; + FT_Pos distance; + FT_Face face = FT_SLOT_FACE(original); + int c, n, first, orientation; + + FT_UNUSED( advance ); + + + /* compute control distance */ + distance = FT_MulFix( face->units_per_EM / 60, + face->size->metrics.y_scale ); + + orientation = ft_get_orientation( &original->outline ); + + points = original->outline.points; + + first = 0; + for ( c = 0; c < outline->n_contours; c++ ) + { + int last = outline->contours[c]; + + + prev = points[last]; + + for ( n = first; n <= last; n++ ) + { + FT_Pos norm, delta, d; + FT_Vector in, out; + + + cur = points[n]; + if ( n < last ) next = points[n + 1]; + else next = points[first]; + + /* compute the in and out vectors */ + in.x = cur.x - prev.x; + in.y = cur.y - prev.y; + + out.x = next.x - cur.x; + out.y = next.y - cur.y; + + /* compute U and V */ + norm = ft_norm( &in ); + u.x = orientation * FT_DivFix( in.y, norm ); + u.y = orientation * -FT_DivFix( in.x, norm ); + + norm = ft_norm( &out ); + v.x = orientation * FT_DivFix( out.y, norm ); + v.y = orientation * -FT_DivFix( out.x, norm ); + + d = distance; + + if ( ( outline->tags[n] & FT_Curve_Tag_On ) == 0 ) + d *= 2; + + /* Check discriminant for parallel vectors */ + delta = FT_MulFix( u.x, v.y ) - FT_MulFix( u.y, v.x ); + if ( delta > FT_BOLD_THRESHOLD || delta < -FT_BOLD_THRESHOLD ) + { + /* Move point -- compute A and B */ + FT_Pos x, y, A, B; + + + A = d + FT_MulFix( cur.x, u.x ) + FT_MulFix( cur.y, u.y ); + B = d + FT_MulFix( cur.x, v.x ) + FT_MulFix( cur.y, v.y ); + + x = FT_MulFix( A, v.y ) - FT_MulFix( B, u.y ); + y = FT_MulFix( B, u.x ) - FT_MulFix( A, v.x ); + + outline->points[n].x = distance + FT_DivFix( x, delta ); + outline->points[n].y = distance + FT_DivFix( y, delta ); + } + else + { + /* Vectors are nearly parallel */ + FT_Pos x, y; + + + x = distance + cur.x + FT_MulFix( d, u.x + v.x ) / 2; + y = distance + cur.y + FT_MulFix( d, u.y + v.y ) / 2; + + outline->points[n].x = x; + outline->points[n].y = y; + } + + prev = cur; + } + + first = last + 1; + } + + if ( advance ) + *advance = ( *advance + distance * 4 ) & -64; + + return 0; + } + +