From 281679de8591f6884ea904c9c812e520ba3cc5dc Mon Sep 17 00:00:00 2001 From: David Turner Date: Wed, 17 May 2006 13:34:21 +0000 Subject: * include/freetype/internal/tttypes.h, src/autofit/afangles.c, src/autofit/afcjk.c, src/autofit/afhints.c, src/autofit/aflatin.c, src/autofit/aftypes.h, src/base/ftcalc.c, src/base/ftoutln.c, src/gzip/ftgzip.c, src/psaux/psconv.c, src/truetype/ttgload.c, src/type1/t1gload.c: this is a major patch used to drastically improve the performance of loading glyphs. This both speeds up loading the glypn vector themselves and the auto-fitter. note that we've started using inline assembler with GCC to implement FT_MulFix, given that this function is so damn important for the engine's performance. the resulting speed-up is about 25%. --- ChangeLog | 23 ++- include/freetype/internal/tttypes.h | 4 + src/autofit/afangles.c | 346 +++++++++--------------------------- src/autofit/afcjk.c | 4 +- src/autofit/afhints.c | 184 +++++++++++++++---- src/autofit/aflatin.c | 21 +-- src/autofit/aftypes.h | 23 ++- src/base/ftcalc.c | 24 ++- src/base/ftoutln.c | 16 +- src/gzip/ftgzip.c | 62 +++++++ src/psaux/psconv.c | 66 ++++++- src/truetype/ttgload.c | 143 +++++++-------- src/type1/t1gload.c | 13 +- 13 files changed, 536 insertions(+), 393 deletions(-) diff --git a/ChangeLog b/ChangeLog index 5ce535870..393ded2a3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,22 @@ 2006-05-17 David Turner + * include/freetype/internal/tttypes.h, src/autofit/afangles.c, + src/autofit/afcjk.c, src/autofit/afhints.c, src/autofit/aflatin.c, + src/autofit/aftypes.h, src/base/ftcalc.c, src/base/ftoutln.c, + src/gzip/ftgzip.c, src/psaux/psconv.c, src/truetype/ttgload.c, + src/type1/t1gload.c: + + this is a major patch used to drastically improve the performance + of loading glyphs. This both speeds up loading the glypn vector + themselves and the auto-fitter. + + note that we've started using inline assembler with GCC to + implement FT_MulFix, given that this function is so damn + important for the engine's performance. + + the resulting speed-up is about 25%. + + * src/ftccmap.c (FTC_CMapCache_Lookup): changed the threshold used to detect rogue clients from 4 to 16. This is to prevent some segmentation faults with fonts like KozMinProVI-Regular.otf @@ -8,7 +25,7 @@ 2007-05-17 Werner Lemberg * src/cff/cffload.c (cff_font_done): Deallocate subfont array. This - fixes the first part of Savannah bug #16590. + fixes the first part of Savannah bug #16590. 2006-05-16 Werner Lemberg @@ -52,8 +69,8 @@ Update handling of re_italic and re_bold. 2006-05-11 Masatake YAMATO - - * builds/unix/ftsystem.c (FT_Stream_Open): Check errno only if + + * builds/unix/ftsystem.c (FT_Stream_Open): Check errno only if read system call returns -1. Remove a redundant parenthesis. diff --git a/include/freetype/internal/tttypes.h b/include/freetype/internal/tttypes.h index 5235cc0d2..6a62a36c5 100644 --- a/include/freetype/internal/tttypes.h +++ b/include/freetype/internal/tttypes.h @@ -1521,6 +1521,10 @@ FT_BEGIN_HEADER FT_Vector pp3; FT_Vector pp4; + /* since version 2.2.1 */ + FT_Byte* cursor; + FT_Byte* limit; + } TT_LoaderRec; diff --git a/src/autofit/afangles.c b/src/autofit/afangles.c index 94a84862b..dac8ba8a1 100644 --- a/src/autofit/afangles.c +++ b/src/autofit/afangles.c @@ -20,7 +20,94 @@ #include "aftypes.h" -#if 1 + FT_LOCAL_DEF( FT_Int ) + af_corner_is_flat( FT_Pos x_in, + FT_Pos y_in, + FT_Pos x_out, + FT_Pos y_out ) + { + FT_Pos ax = x_in; + FT_Pos ay = y_in; + + FT_Pos d_in, d_out, d_corner; + + if ( ax < 0 ) ax = -ax; + if ( ay < 0 ) ay = -ay; + d_in = ax + ay; + + ax = x_out; if ( ax < 0 ) ax = -ax; + ay = y_out; if ( ay < 0 ) ay = -ay; + d_out = ax+ay; + + ax = x_out + x_in; if ( ax < 0 ) ax = -ax; + ay = y_out + y_in; if ( ay < 0 ) ay = -ay; + d_corner = ax+ay; + + return ( d_in + d_out - d_corner ) < (d_corner >> 4); + } + + + FT_LOCAL_DEF( FT_Int ) + af_corner_orientation( FT_Pos x_in, + FT_Pos y_in, + FT_Pos x_out, + FT_Pos y_out ) + { + FT_Pos delta; + + delta = x_in*y_out - y_in*x_out; + + if ( delta == 0 ) + return 0; + else + return 1 - 2*(delta < 0); + } + + + /* we're not using af_angle_atan anymore, but we keep the source + * code below just in case :-) + */ +#if 0 + + /* the trick here is to realize that we don't need an very accurate + * angle approximation. We're going to use the result of af_angle_atan + * to only compare the sign of angle differences, or see if its magnitude + * is very small. + * + * the approximation (dy*PI/(|dx|+|dy|))) should be enough, and much + * faster to compute. + */ + FT_LOCAL_DEF( AF_Angle ) + af_angle_atan( FT_Fixed dx, + FT_Fixed dy ) + { + AF_Angle angle; + FT_Fixed ax = dx; + FT_Fixed ay = dy; + + if ( ax < 0 ) ax = -ax; + if ( ay < 0 ) ay = -ay; + + ax += ay; + + if ( ax == 0 ) + angle = 0; + else + { + angle = (AF_ANGLE_PI2*dy)/(ax+ay); + if ( dx < 0 ) + { + if ( angle >= 0 ) + angle = AF_ANGLE_PI - angle; + else + angle = -AF_ANGLE_PI - angle; + } + } + + return angle; + } + +#elif 0 /* the following table has been automatically generated with */ /* the `mather.py' Python script */ @@ -124,224 +211,8 @@ } -#else /* 0 */ - -/* - * a python script used to generate the following table - * - -import sys, math - -units = 256 -scale = units/math.pi -comma = "" - -print "" -print "table of arctan( 1/2^n ) for PI = " + repr( units / 65536.0 ) + " units" - -r = [-1] + range( 32 ) - -for n in r: - if n >= 0: - x = 1.0 / ( 2.0 ** n ) # tangent value - else: - x = 2.0 ** ( -n ) - - angle = math.atan( x ) # arctangent - angle2 = angle * scale # arctangent in FT_Angle units - - # determine which integer value for angle gives the best tangent - lo = int( angle2 ) - hi = lo + 1 - tlo = math.tan( lo / scale ) - thi = math.tan( hi / scale ) - - errlo = abs( tlo - x ) - errhi = abs( thi - x ) - - angle2 = hi - if errlo < errhi: - angle2 = lo - - if angle2 <= 0: - break - - sys.stdout.write( comma + repr( int( angle2 ) ) ) - comma = ", " - -* -* end of python script -*/ - - - /* this table was generated for AF_ANGLE_PI = 256 */ -#define AF_ANGLE_MAX_ITERS 8 -#define AF_TRIG_MAX_ITERS 8 - - static const FT_Fixed - af_angle_arctan_table[9] = - { - 90, 64, 38, 20, 10, 5, 3, 1, 1 - }; - - - static FT_Int - af_angle_prenorm( FT_Vector* vec ) - { - FT_Fixed x, y, z; - FT_Int shift; - - - x = vec->x; - y = vec->y; - - z = ( ( x >= 0 ) ? x : - x ) | ( (y >= 0) ? y : -y ); - shift = 0; - - if ( z < ( 1L << 27 ) ) - { - do - { - shift++; - z <<= 1; - } while ( z < ( 1L << 27 ) ); - - vec->x = x << shift; - vec->y = y << shift; - } - else if ( z > ( 1L << 28 ) ) - { - do - { - shift++; - z >>= 1; - } while ( z > ( 1L << 28 ) ); - - vec->x = x >> shift; - vec->y = y >> shift; - shift = -shift; - } - return shift; - } - - - static void - af_angle_pseudo_polarize( FT_Vector* vec ) - { - FT_Fixed theta; - FT_Fixed yi, i; - FT_Fixed x, y; - const FT_Fixed *arctanptr; - - - x = vec->x; - y = vec->y; - - /* Get the vector into the right half plane */ - theta = 0; - if ( x < 0 ) - { - x = -x; - y = -y; - theta = AF_ANGLE_PI; - } - - if ( y > 0 ) - theta = -theta; - - arctanptr = af_angle_arctan_table; - - if ( y < 0 ) - { - /* Rotate positive */ - yi = y + ( x << 1 ); - x = x - ( y << 1 ); - y = yi; - theta -= *arctanptr++; /* Subtract angle */ - } - else - { - /* Rotate negative */ - yi = y - ( x << 1 ); - x = x + ( y << 1 ); - y = yi; - theta += *arctanptr++; /* Add angle */ - } - - i = 0; - do - { - if ( y < 0 ) - { - /* Rotate positive */ - yi = y + ( x >> i ); - x = x - ( y >> i ); - y = yi; - theta -= *arctanptr++; - } - else - { - /* Rotate negative */ - yi = y - ( x >> i ); - x = x + ( y >> i ); - y = yi; - theta += *arctanptr++; - } - } while ( ++i < AF_TRIG_MAX_ITERS ); - -#if 0 - /* round theta */ - if ( theta >= 0 ) - theta = FT_PAD_ROUND( theta, 2 ); - else - theta = -FT_PAD_ROUND( -theta, 2 ); #endif - vec->x = x; - vec->y = theta; - } - - - /* cf. documentation in fttrigon.h */ - - FT_LOCAL_DEF( AF_Angle ) - af_angle_atan( FT_Fixed dx, - FT_Fixed dy ) - { - FT_Vector v; - - - if ( dx == 0 && dy == 0 ) - return 0; - - v.x = dx; - v.y = dy; - af_angle_prenorm( &v ); - af_angle_pseudo_polarize( &v ); - - return v.y; - } - - - FT_LOCAL_DEF( AF_Angle ) - af_angle_diff( AF_Angle angle1, - AF_Angle angle2 ) - { - AF_Angle delta = angle2 - angle1; - - - delta %= AF_ANGLE_2PI; - if ( delta < 0 ) - delta += AF_ANGLE_2PI; - - if ( delta > AF_ANGLE_PI ) - delta -= AF_ANGLE_2PI; - - return delta; - } - -#endif /* 0 */ - FT_LOCAL_DEF( void ) af_sort_pos( FT_UInt count, @@ -389,45 +260,4 @@ for n in r: } -#ifdef TEST - -#include -#include - -int main( void ) -{ - int angle; - int dist; - - - for ( dist = 100; dist < 1000; dist++ ) - { - for ( angle = AF_ANGLE_PI; angle < AF_ANGLE_2PI * 4; angle++ ) - { - double a = ( angle * 3.1415926535 ) / ( 1.0 * AF_ANGLE_PI ); - int dx, dy, angle1, angle2, delta; - - - dx = dist * cos( a ); - dy = dist * sin( a ); - - angle1 = ( ( atan2( dy, dx ) * AF_ANGLE_PI ) / 3.1415926535 ); - angle2 = af_angle_atan( dx, dy ); - delta = ( angle2 - angle1 ) % AF_ANGLE_2PI; - if ( delta < 0 ) - delta = -delta; - - if ( delta >= 2 ) - { - printf( "dist:%4d angle:%4d => (%4d,%4d) angle1:%4d angle2:%4d\n", - dist, angle, dx, dy, angle1, angle2 ); - } - } - } - return 0; -} - -#endif /* TEST */ - - /* END */ diff --git a/src/autofit/afcjk.c b/src/autofit/afcjk.c index 6a020e3f4..78d4fd81b 100644 --- a/src/autofit/afcjk.c +++ b/src/autofit/afcjk.c @@ -1437,7 +1437,9 @@ static const AF_Script_UniRangeRec af_cjk_uniranges[] = { - { 0x0100, 0xFFFF }, +#if 0 + { 0x0100, 0xFFFF }, /* why ?? */ +#endif { 0x2E80, 0x2EFF }, /* CJK Radicals Supplement */ { 0x2F00, 0x2FDF }, /* Kangxi Radicals */ { 0x3000, 0x303F }, /* CJK Symbols and Punctuation */ diff --git a/src/autofit/afhints.c b/src/autofit/afhints.c index b011c15b0..818c6b717 100644 --- a/src/autofit/afhints.c +++ b/src/autofit/afhints.c @@ -53,7 +53,9 @@ } segment = axis->segments + axis->num_segments++; +#if 0 FT_ZERO( segment ); +#endif Exit: *asegment = segment; @@ -272,54 +274,46 @@ FT_Pos dy ) { #if 1 - AF_Direction dir = AF_DIR_NONE; + FT_Pos ll, ss; /* long and short arm lengths */ + AF_Direction dir; /* candidate direction */ - - /* atan(1/12) == 4.7 degrees */ - - if ( dx < 0 ) + if ( dy >= dx ) { - if ( dy < 0 ) + if ( dy >= -dx ) { - if ( -dx * 12 < -dy ) - dir = AF_DIR_DOWN; - - else if ( -dy * 12 < -dx ) - dir = AF_DIR_LEFT; + dir = AF_DIR_UP; + ll = dy; + ss = dx; } - else /* dy >= 0 */ + else { - if ( -dx * 12 < dy ) - dir = AF_DIR_UP; - - else if ( dy * 12 < -dx ) - dir = AF_DIR_LEFT; + dir = AF_DIR_LEFT; + ll = -dx; + ss = dy; } } - else /* dx >= 0 */ + else /* dy < dx */ { - if ( dy < 0 ) + if ( dy >= -dx ) { - if ( dx * 12 < -dy ) - dir = AF_DIR_DOWN; - - else if ( -dy * 12 < dx ) - dir = AF_DIR_RIGHT; + dir = AF_DIR_RIGHT; + ll = dx; + ss = dy; } - else /* dy >= 0 */ + else { - if ( dx * 12 < dy ) - dir = AF_DIR_UP; - - else if ( dy * 12 < dx ) - dir = AF_DIR_RIGHT; + dir = AF_DIR_DOWN; + ll = dy; + ss = dx; } } - return dir; + ss *= 12; + if ( ll <= FT_ABS(ss) ) + dir = AF_DIR_NONE; + return dir; #else /* 0 */ - AF_Direction dir; FT_Pos ax = FT_ABS( dx ); FT_Pos ay = FT_ABS( dy ); @@ -341,13 +335,125 @@ } return dir; - #endif /* 0 */ } /* compute all inflex points in a given glyph */ +#if 1 + static void + af_glyph_hints_compute_inflections( AF_GlyphHints hints ) + { + AF_Point* contour = hints->contours; + AF_Point* contour_limit = contour + hints->num_contours; + + + /* do each contour separately */ + for ( ; contour < contour_limit; contour++ ) + { + AF_Point point = contour[0]; + AF_Point first = point; + AF_Point start = point; + AF_Point end = point; + AF_Point before; + AF_Point after; + FT_Pos in_x, in_y, out_x, out_y; + AF_Angle orient_prev, orient_cur; + FT_Int finished = 0; + + + /* compute first segment in contour */ + first = point; + + start = end = first; + do + { + end = end->next; + if ( end == first ) + goto Skip; + + in_x = end->fx - start->fx; + in_y = end->fy - start->fy; + + } while ( in_x == 0 && in_y == 0 ); + + /* extend the segment start whenever possible */ + before = start; + do + { + do + { + start = before; + before = before->prev; + if ( before == first ) + goto Skip; + + out_x = start->fx - before->fx; + out_y = start->fy - before->fy; + + } while ( out_x == 0 && out_y == 0 ); + + orient_prev = af_corner_orientation( in_x, in_y, out_x, out_y ); + + } while ( orient_prev == 0 ); + + first = start; + + in_x = out_x; + in_y = out_y; + + /* now, process all segments in the contour */ + do + { + /* first, extend current segment's end whenever possible */ + after = end; + do + { + do + { + end = after; + after = after->next; + if ( after == first ) + finished = 1; + + out_x = after->fx - end->fx; + out_y = after->fy - end->fy; + + } while ( out_x == 0 && out_y == 0 ); + + orient_cur = af_corner_orientation( in_x, in_y, out_x, out_y ); + + } while ( orient_cur == 0 ); + + if ( ( orient_prev + orient_cur ) == 0 ) + { + /* we have an inflection point here */ + do + { + start->flags |= AF_FLAG_INFLECTION; + start = start->next; + + } while ( start != end ); + + start->flags |= AF_FLAG_INFLECTION; + } + + start = end; + end = after; + + orient_prev = orient_cur; + in_x = out_x; + in_y = out_y; + + } while ( !finished ); + + Skip: + ; + } + } + +#else /* old code */ static void af_glyph_hints_compute_inflections( AF_GlyphHints hints ) { @@ -454,6 +560,7 @@ ; } } +#endif /* old code */ FT_LOCAL_DEF( void ) @@ -702,6 +809,14 @@ } else if ( point->out_dir == point->in_dir ) { +#if 1 + if ( point->out_dir != AF_DIR_NONE ) + goto Is_Weak_Point; + + if ( af_corner_is_flat( in_x, in_y, out_x, out_y ) ) + goto Is_Weak_Point; + +#else /* old code */ AF_Angle angle_in, angle_out, delta; @@ -715,6 +830,7 @@ if ( delta < 2 && delta > -2 ) goto Is_Weak_Point; +#endif /* old code */ } else if ( point->in_dir == -point->out_dir ) goto Is_Weak_Point; @@ -1152,7 +1268,7 @@ AF_Point points = hints->points; AF_Point points_limit = points + hints->num_points; AF_Point point; - + if ( dim == AF_DIMENSION_HORZ ) { diff --git a/src/autofit/aflatin.c b/src/autofit/aflatin.c index 2351f23f1..5329a0bca 100644 --- a/src/autofit/aflatin.c +++ b/src/autofit/aflatin.c @@ -590,6 +590,7 @@ FT_Memory memory = hints->memory; FT_Error error = AF_Err_Ok; AF_Segment segment = NULL; + AF_SegmentRec seg0; AF_Point* contour = hints->contours; AF_Point* contour_limit = contour + hints->num_contours; AF_Direction major_dir, segment_dir; @@ -601,6 +602,10 @@ FT_Pos max_coord = -32000; #endif + FT_ZERO( &seg0 ); + seg0.score = 32000; + seg0.flags = AF_EDGE_NORMAL; + major_dir = (AF_Direction)FT_ABS( axis->major_dir ); segment_dir = major_dir; @@ -742,15 +747,12 @@ if ( error ) goto Exit; + segment[0] = seg0; segment->dir = (FT_Char)segment_dir; - segment->flags = AF_EDGE_NORMAL; min_pos = max_pos = point->u; segment->first = point; segment->last = point; segment->contour = contour; - segment->score = 32000; - segment->len = 0; - segment->link = NULL; on_edge = 1; #ifdef AF_HINT_METRICS @@ -810,14 +812,11 @@ if ( error ) goto Exit; + segment[0] = seg0; segment->dir = segment_dir; - segment->flags = AF_EDGE_NORMAL; segment->first = min_point; segment->last = min_point; segment->pos = min_pos; - segment->score = 32000; - segment->len = 0; - segment->link = NULL; segment = NULL; } @@ -830,14 +829,11 @@ if ( error ) goto Exit; + segment[0] = seg0; segment->dir = segment_dir; - segment->flags = AF_EDGE_NORMAL; segment->first = max_point; segment->last = max_point; segment->pos = max_pos; - segment->score = 32000; - segment->len = 0; - segment->link = NULL; segment = NULL; } @@ -926,7 +922,6 @@ if ( seg2 ) { - seg2->num_linked++; if ( seg2->link != seg1 ) { seg1->link = 0; diff --git a/src/autofit/aftypes.h b/src/autofit/aftypes.h index f6e94e1ce..ebce1a326 100644 --- a/src/autofit/aftypes.h +++ b/src/autofit/aftypes.h @@ -118,6 +118,7 @@ FT_BEGIN_HEADER #define AF_ANGLE_PI4 ( AF_ANGLE_PI / 4 ) +#if 0 /* * compute the angle of a given 2-D vector */ @@ -126,7 +127,6 @@ FT_BEGIN_HEADER FT_Pos dy ); -#if 0 /* * compute `angle2 - angle1'; the result is always within * the range [-AF_ANGLE_PI .. AF_ANGLE_PI - 1] @@ -137,6 +137,27 @@ FT_BEGIN_HEADER #endif /* 0 */ + /* return TRUE if a corner is flat, or nearly flat, this is equivalent + * to say that the angle difference between the 'in' and 'out' vectors is + * very small + */ + FT_LOCAL( FT_Int ) + af_corner_is_flat( FT_Pos x_in, + FT_Pos y_in, + FT_Pos x_out, + FT_Pos y_out ); + + /* return a value that can be -1, 0 or +1 depending on the orientation + * of a given corner. We're using the Cartesian coordinate system, + * with positive Ys going upwards. The function returns +1 when + * the corner turns to the left, -1 to the right, and 0 for undecided + */ + FT_LOCAL( FT_Int ) + af_corner_orientation( FT_Pos x_in, + FT_Pos y_in, + FT_Pos x_out, + FT_Pos y_out ); + #define AF_ANGLE_DIFF( result, angle1, angle2 ) \ FT_BEGIN_STMNT \ AF_Angle _delta = (angle2) - (angle1); \ diff --git a/src/base/ftcalc.c b/src/base/ftcalc.c index ba3d08935..f75bc9a09 100644 --- a/src/base/ftcalc.c +++ b/src/base/ftcalc.c @@ -396,7 +396,29 @@ FT_MulFix( FT_Long a, FT_Long b ) { -#if 1 + /* let's use inline assembly to speed things a bit */ +#if defined(__GNUC__) && defined(i386) + + FT_Long result; + + __asm__ __volatile__ ( + "imul %%edx\n" + "movl %%edx, %%ecx\n" + "sarl $31, %%ecx\n" + "addl $0x8000, %%ecx\n" + "addl %%ecx, %%eax\n" + "adcl $0, %%edx\n" + "shrl $16, %%eax\n" + "shll $16, %%edx\n" + "addl %%edx, %%eax\n" + "mov %%eax, %0\n" + : "=r"(result) + : "a"(a), "d"(b) + : "%ecx" + ); + return result; + +#elif 1 FT_Long sa, sb; FT_ULong ua, ub; diff --git a/src/base/ftoutln.c b/src/base/ftoutln.c index b23b16439..cef7ae7a9 100644 --- a/src/base/ftoutln.c +++ b/src/base/ftoutln.c @@ -732,7 +732,7 @@ return ( n % 2 ); } - + static FT_Bool ft_contour_enclosed( FT_Outline* outline, FT_UShort c ) @@ -1012,11 +1012,25 @@ ++next; } +#if 1 + { + FT_Pos dx1 = prev->x - xmin_point->x; + FT_Pos dy1 = prev->y - xmin_point->y; + FT_Pos dx2 = next->x - xmin_point->x; + FT_Pos dy2 = next->y - xmin_point->y; + + if ( dy1*dx2 > dy2*dx1 ) + return FT_ORIENTATION_POSTSCRIPT; + else + return FT_ORIENTATION_TRUETYPE; + } +#else if ( FT_Atan2( prev->x - xmin_point->x, prev->y - xmin_point->y ) > FT_Atan2( next->x - xmin_point->x, next->y - xmin_point->y ) ) return FT_ORIENTATION_POSTSCRIPT; else return FT_ORIENTATION_TRUETYPE; +#endif } diff --git a/src/gzip/ftgzip.c b/src/gzip/ftgzip.c index 6f7bad777..f3ab4f98b 100644 --- a/src/gzip/ftgzip.c +++ b/src/gzip/ftgzip.c @@ -554,6 +554,27 @@ } + static FT_ULong + ft_gzip_get_uncompressed_size( FT_Stream stream ) + { + FT_Error error; + FT_ULong old_pos; + FT_ULong result = 0; + + old_pos = stream->pos; + if ( !FT_Stream_Seek( stream, stream->size - 4 ) ) + { + result = (FT_ULong)FT_Stream_ReadLong( stream, &error ); + if ( error ) + result = 0; + + FT_Stream_Seek( stream, old_pos ); + } + + return result; + } + + FT_EXPORT_DEF( FT_Error ) FT_Stream_OpenGzip( FT_Stream stream, FT_Stream source ) @@ -586,6 +607,47 @@ stream->descriptor.pointer = zip; } + /* ok, here's a trick to try to dramatically improve the performance + * of dealing with small files. If the original stream size is less + * than a certain threshold, we try to load the whole font file in + * memory. this saves us from the 32KB buffer needed to inflate the + * file anyway, plus the two 4KB intermediate input/output buffers + * used in the FT_GZipFile structure. + */ + { + FT_ULong zip_size = ft_gzip_get_uncompressed_size( source ); + + if ( zip_size != 0 && zip_size < 40*1024 ) + { + FT_Byte* zip_buff; + + if ( !FT_ALLOC( zip_buff, zip_size ) ) + { + FT_ULong count; + + count = ft_gzip_file_io( zip, 0, zip_buff, zip_size ); + if ( count == zip_size ) + { + ft_gzip_file_done( zip ); + FT_FREE( zip ); + + stream->descriptor.pointer = NULL; + + stream->size = zip_size; + stream->pos = 0; + stream->base = zip_buff; + stream->read = NULL; + stream->close = ft_gzip_stream_close; + + goto Exit; + } + ft_gzip_file_io( zip, 0, NULL, 0 ); + FT_FREE( zip_buff ); + } + error = 0; + } + } + stream->size = 0x7FFFFFFFL; /* don't know the real size! */ stream->pos = 0; stream->base = 0; diff --git a/src/psaux/psconv.c b/src/psaux/psconv.c index 010d08cb5..bfb679b7f 100644 --- a/src/psaux/psconv.c +++ b/src/psaux/psconv.c @@ -331,11 +331,48 @@ FT_UInt n ) { FT_Byte* p; - FT_UInt r = 0; + FT_UInt r = 0; + FT_UInt w = 0; + FT_UInt pad = 0x01; n *= 2; - for ( p = *cursor; r < n && p < limit; p++ ) +#if 1 + p = *cursor; + if ( n > (FT_UInt)(limit-p) ) + n = (FT_UInt)(limit - p); + + /* we try to process two nibbles at a time to be as fast as possible + */ + for ( ; r < n; r++ ) + { + FT_UInt c = p[r]; + + if ( IS_PS_SPACE(c) ) + continue; + + if ( c OP 0x80 ) + break; + + c = ft_char_table[ c & 0x7F ]; + if ( (unsigned)c >= 16 ) + break; + + pad = (pad << 4) | c; + if ( pad & 0x100 ) + { + buffer[w++] = (FT_Byte)pad; + pad = 0x01; + } + } + + if ( pad != 0x01 ) + buffer[w++] = (FT_Byte)(pad << 4); + + *cursor = p+r; + return w; +#else + for ( r = 0; r < n; r++ ) { FT_Char c; @@ -348,10 +385,10 @@ c = ft_char_table[*p & 0x7f]; - if ( c < 0 || c >= 16 ) + if ( (unsigned)c >= 16 ) break; - if ( r % 2 ) + if ( r & 1 ) { *buffer = (FT_Byte)(*buffer + c); buffer++; @@ -365,6 +402,7 @@ *cursor = p; return ( r + 1 ) / 2; +#endif } @@ -377,9 +415,25 @@ { FT_Byte* p; FT_UInt r; - FT_UShort s = *seed; + FT_UInt s = *seed; +#if 1 + p = *cursor; + if ( n > (FT_UInt)(limit - p) ) + n = (FT_UInt)(limit - p); + for ( r = 0; r < n; r++ ) + { + FT_UInt val = p[r]; + FT_UInt b = ( val ^ (s >> 8) ); + + s = ( (val + s)*52845U + 22719 ) & 0xFFFFU; + buffer[r] = (FT_Byte) b; + } + + *cursor = p + n; + *seed = (FT_UShort)s; +#else for ( r = 0, p = *cursor; r < n && p < limit; r++, p++ ) { FT_Byte b = (FT_Byte)( *p ^ ( s >> 8 ) ); @@ -388,9 +442,9 @@ s = (FT_UShort)( ( *p + s ) * 52845U + 22719 ); *buffer++ = b; } - *cursor = p; *seed = s; +#endif return r; } diff --git a/src/truetype/ttgload.c b/src/truetype/ttgload.c index 158111384..26c6429ed 100644 --- a/src/truetype/ttgload.c +++ b/src/truetype/ttgload.c @@ -188,6 +188,9 @@ if ( FT_STREAM_SEEK( offset ) || FT_FRAME_ENTER( byte_count ) ) return error; + loader->cursor = stream->cursor; + loader->limit = stream->limit; + return TT_Err_Ok; } @@ -205,26 +208,26 @@ FT_CALLBACK_DEF( FT_Error ) TT_Load_Glyph_Header( TT_Loader loader ) { - FT_Stream stream = loader->stream; - FT_Int byte_len = loader->byte_len - 10; + FT_Byte* p = loader->cursor; + FT_Byte* limit = loader->limit; - if ( byte_len < 0 ) + if ( p + 10 > limit ) return TT_Err_Invalid_Outline; - loader->n_contours = FT_GET_SHORT(); + loader->n_contours = FT_NEXT_SHORT(p); - loader->bbox.xMin = FT_GET_SHORT(); - loader->bbox.yMin = FT_GET_SHORT(); - loader->bbox.xMax = FT_GET_SHORT(); - loader->bbox.yMax = FT_GET_SHORT(); + loader->bbox.xMin = FT_NEXT_SHORT(p); + loader->bbox.yMin = FT_NEXT_SHORT(p); + loader->bbox.xMax = FT_NEXT_SHORT(p); + loader->bbox.yMax = FT_NEXT_SHORT(p); FT_TRACE5(( " # of contours: %d\n", loader->n_contours )); FT_TRACE5(( " xMin: %4d xMax: %4d\n", loader->bbox.xMin, loader->bbox.xMax )); FT_TRACE5(( " yMin: %4d yMax: %4d\n", loader->bbox.yMin, loader->bbox.yMax )); - loader->byte_len = byte_len; + loader->cursor = p; return TT_Err_Ok; } @@ -234,14 +237,14 @@ TT_Load_Simple_Glyph( TT_Loader load ) { FT_Error error; - FT_Stream stream = load->stream; + FT_Byte* p = load->cursor; + FT_Byte* limit = load->limit; FT_GlyphLoader gloader = load->gloader; FT_Int n_contours = load->n_contours; FT_Outline* outline; TT_Face face = (TT_Face)load->face; FT_UShort n_ins; FT_Int n, n_points; - FT_Int byte_len = load->byte_len; FT_Byte *flag, *flag_limit; FT_Byte c, count; @@ -260,12 +263,11 @@ cont_limit = cont + n_contours; /* check space for contours array + instructions count */ - byte_len -= 2 * ( n_contours + 1 ); - if ( byte_len < 0 ) + if ( n_contours >= 0xFFF || p + (n_contours+1)*2 > limit ) goto Invalid_Outline; for ( ; cont < cont_limit; cont++ ) - cont[0] = FT_GET_USHORT(); + cont[0] = FT_NEXT_USHORT(p); n_points = 0; if ( n_contours > 0 ) @@ -287,7 +289,10 @@ load->glyph->control_len = 0; load->glyph->control_data = 0; - n_ins = FT_GET_USHORT(); + if ( p+2 > limit ) + goto Invalid_Outline; + + n_ins = FT_NEXT_USHORT(p); FT_TRACE5(( " Instructions size: %u\n", n_ins )); @@ -298,8 +303,7 @@ goto Fail; } - byte_len -= (FT_Int)n_ins; - if ( byte_len < 0 ) + if ( (limit - p) < n_ins ) { FT_TRACE0(( "TT_Load_Simple_Glyph: Instruction count mismatch!\n" )); error = TT_Err_Too_Many_Hints; @@ -313,12 +317,12 @@ load->glyph->control_len = n_ins; load->glyph->control_data = load->exec->glyphIns; - FT_MEM_COPY( load->exec->glyphIns, stream->cursor, (FT_Long)n_ins ); + FT_MEM_COPY( load->exec->glyphIns, p, (FT_Long)n_ins ); } #endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */ - stream->cursor += (FT_Int)n_ins; + p += n_ins; /* reading the point tags */ flag = (FT_Byte*)outline->tags; @@ -328,16 +332,16 @@ while ( flag < flag_limit ) { - if ( --byte_len < 0 ) + if ( p+1 > limit ) goto Invalid_Outline; - *flag++ = c = FT_GET_BYTE(); + *flag++ = c = FT_NEXT_BYTE(p); if ( c & 8 ) { - if ( --byte_len < 0 ) + if ( p+1 > limit ) goto Invalid_Outline; - count = FT_GET_BYTE(); + count = FT_NEXT_BYTE(p); if ( flag + (FT_Int)count > flag_limit ) goto Invalid_Outline; @@ -346,23 +350,6 @@ } } - /* check that there is enough room to load the coordinates */ - for ( flag = (FT_Byte*)outline->tags; flag < flag_limit; flag++ ) - { - if ( *flag & 2 ) - byte_len -= 1; - else if ( ( *flag & 16 ) == 0 ) - byte_len -= 2; - - if ( *flag & 4 ) - byte_len -= 1; - else if ( ( *flag & 32 ) == 0 ) - byte_len -= 2; - } - - if ( byte_len < 0 ) - goto Invalid_Outline; - /* reading the X coordinates */ vec = outline->points; @@ -377,12 +364,20 @@ if ( *flag & 2 ) { - y = (FT_Pos)FT_GET_BYTE(); + if ( p+1 > limit ) + goto Invalid_Outline; + + y = (FT_Pos)FT_NEXT_BYTE(p); if ( ( *flag & 16 ) == 0 ) y = -y; } else if ( ( *flag & 16 ) == 0 ) - y = (FT_Pos)FT_GET_SHORT(); + { + if ( p+2 > limit ) + goto Invalid_Outline; + + y = (FT_Pos)FT_NEXT_SHORT(p); + } x += y; vec->x = x; @@ -402,12 +397,20 @@ if ( *flag & 4 ) { - y = (FT_Pos)FT_GET_BYTE(); + if ( p+1 > limit ) + goto Invalid_Outline; + + y = (FT_Pos)FT_NEXT_BYTE(p); if ( ( *flag & 32 ) == 0 ) y = -y; } else if ( ( *flag & 32 ) == 0 ) - y = (FT_Pos)FT_GET_SHORT(); + { + if ( p+2 > limit ) + goto Invalid_Outline; + + y = (FT_Pos)FT_NEXT_SHORT(p); + } x += y; vec->y = x; @@ -420,7 +423,7 @@ outline->n_points = (FT_UShort)n_points; outline->n_contours = (FT_Short) n_contours; - load->byte_len = byte_len; + load->cursor = p; Fail: return error; @@ -435,11 +438,11 @@ TT_Load_Composite_Glyph( TT_Loader loader ) { FT_Error error; - FT_Stream stream = loader->stream; + FT_Byte* p = loader->cursor; + FT_Byte* limit = loader->limit; FT_GlyphLoader gloader = loader->gloader; FT_SubGlyph subglyph; FT_UInt num_subglyphs; - FT_Int byte_len = loader->byte_len; num_subglyphs = 0; @@ -447,6 +450,7 @@ do { FT_Fixed xx, xy, yy, yx; + FT_UInt count; /* check that we can load a new subglyph */ @@ -455,41 +459,40 @@ goto Fail; /* check space */ - byte_len -= 4; - if ( byte_len < 0 ) + if ( p+4 > limit ) goto Invalid_Composite; subglyph = gloader->current.subglyphs + num_subglyphs; subglyph->arg1 = subglyph->arg2 = 0; - subglyph->flags = FT_GET_USHORT(); - subglyph->index = FT_GET_USHORT(); + subglyph->flags = FT_NEXT_USHORT(p); + subglyph->index = FT_NEXT_USHORT(p); /* check space */ - byte_len -= 2; + count = 2; if ( subglyph->flags & ARGS_ARE_WORDS ) - byte_len -= 2; + count += 2; if ( subglyph->flags & WE_HAVE_A_SCALE ) - byte_len -= 2; + count += 2; else if ( subglyph->flags & WE_HAVE_AN_XY_SCALE ) - byte_len -= 4; + count += 4; else if ( subglyph->flags & WE_HAVE_A_2X2 ) - byte_len -= 8; + count += 8; - if ( byte_len < 0 ) + if ( p + count > limit ) goto Invalid_Composite; /* read arguments */ if ( subglyph->flags & ARGS_ARE_WORDS ) { - subglyph->arg1 = FT_GET_SHORT(); - subglyph->arg2 = FT_GET_SHORT(); + subglyph->arg1 = FT_NEXT_SHORT(p); + subglyph->arg2 = FT_NEXT_SHORT(p); } else { - subglyph->arg1 = FT_GET_CHAR(); - subglyph->arg2 = FT_GET_CHAR(); + subglyph->arg1 = FT_NEXT_CHAR(p); + subglyph->arg2 = FT_NEXT_CHAR(p); } /* read transform */ @@ -498,20 +501,20 @@ if ( subglyph->flags & WE_HAVE_A_SCALE ) { - xx = (FT_Fixed)FT_GET_SHORT() << 2; + xx = (FT_Fixed)FT_NEXT_SHORT(p) << 2; yy = xx; } else if ( subglyph->flags & WE_HAVE_AN_XY_SCALE ) { - xx = (FT_Fixed)FT_GET_SHORT() << 2; - yy = (FT_Fixed)FT_GET_SHORT() << 2; + xx = (FT_Fixed)FT_NEXT_SHORT(p) << 2; + yy = (FT_Fixed)FT_NEXT_SHORT(p) << 2; } else if ( subglyph->flags & WE_HAVE_A_2X2 ) { - xx = (FT_Fixed)FT_GET_SHORT() << 2; - yx = (FT_Fixed)FT_GET_SHORT() << 2; - xy = (FT_Fixed)FT_GET_SHORT() << 2; - yy = (FT_Fixed)FT_GET_SHORT() << 2; + xx = (FT_Fixed)FT_NEXT_SHORT(p) << 2; + yx = (FT_Fixed)FT_NEXT_SHORT(p) << 2; + xy = (FT_Fixed)FT_NEXT_SHORT(p) << 2; + yy = (FT_Fixed)FT_NEXT_SHORT(p) << 2; } subglyph->transform.xx = xx; @@ -533,12 +536,12 @@ /* we will process them later... */ /* */ loader->ins_pos = (FT_ULong)( FT_STREAM_POS() + - stream->cursor - stream->limit ); + p - limit ); } #endif - loader->byte_len = byte_len; + loader->cursor = p; Fail: return error; diff --git a/src/type1/t1gload.c b/src/type1/t1gload.c index 28190001f..804713f62 100644 --- a/src/type1/t1gload.c +++ b/src/type1/t1gload.c @@ -310,11 +310,14 @@ #if 1 /* apply the font matrix, if any */ - FT_Outline_Transform( &glyph->root.outline, &font_matrix ); - - FT_Outline_Translate( &glyph->root.outline, - font_offset.x, - font_offset.y ); + if ( font_matrix.xx != 0x10000L || font_matrix.yy != font_matrix.xx || + font_matrix.xy != 0 || font_matrix.yx != 0 ) + FT_Outline_Transform( &glyph->root.outline, &font_matrix ); + + if ( font_offset.x || font_offset.y ) + FT_Outline_Translate( &glyph->root.outline, + font_offset.x, + font_offset.y ); advance.x = metrics->horiAdvance; advance.y = 0; -- cgit v1.2.1