From: Robert Roebling Date: Sun, 3 Sep 2000 16:51:07 +0000 (+0000) Subject: Added FreeType II beta 8. X-Git-Url: https://git.saurik.com/wxWidgets.git/commitdiff_plain/cabec8729e0b28f790d4a7f068a25697b9aa9dab?hp=1e1af41e4b811fa4e927b61234c6fd90e254ec09 Added FreeType II beta 8. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@8247 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- diff --git a/src/freetype/autohint/CatharonLicense.txt b/src/freetype/autohint/CatharonLicense.txt new file mode 100644 index 0000000000..e68bc23050 --- /dev/null +++ b/src/freetype/autohint/CatharonLicense.txt @@ -0,0 +1,123 @@ + The Catharon Open Source LICENSE + ---------------------------- + + 2000-Jul-04 + + Copyright (C) 2000 by Catharon Productions, Inc. + + + +Introduction +============ + + This license applies to source files distributed by Catharon + Productions, Inc. in several archive packages. This license + applies to all files found in such packages which do not fall + under their own explicit license. + + This license was inspired by the BSD, Artistic, and IJG + (Independent JPEG Group) licenses, which all encourage inclusion + and use of free software in commercial and freeware products + alike. As a consequence, its main points are that: + + o We don't promise that this software works. However, we are + interested in any kind of bug reports. (`as is' distribution) + + o You can use this software for whatever you want, in parts or + full form, without having to pay us. (`royalty-free' usage) + + o You may not pretend that you wrote this software. If you use + it, or only parts of it, in a program, you must acknowledge + somewhere in your documentation that you have used the + Catharon Code. (`credits') + + We specifically permit and encourage the inclusion of this + software, with or without modifications, in commercial products. + We disclaim all warranties covering the packages distributed by + Catharon Productions, Inc. and assume no liability related to + their use. + + +Legal Terms +=========== + +0. Definitions +-------------- + + Throughout this license, the terms `Catharon Package', `package', + and `Catharon Code' refer to the set of files originally + distributed by Catharon Productions, Inc. + + `You' refers to the licensee, or person using the project, where + `using' is a generic term including compiling the project's source + code as well as linking it to form a `program' or `executable'. + This program is referred to as `a program using one of the + Catharon Packages'. + + This license applies to all files distributed in the original + Catharon Package(s), including all source code, binaries and + documentation, unless otherwise stated in the file in its + original, unmodified form as distributed in the original archive. + If you are unsure whether or not a particular file is covered by + this license, you must contact us to verify this. + + The Catharon Packages are copyright (C) 2000 by Catharon + Productions, Inc. All rights reserved except as specified below. + +1. No Warranty +-------------- + + THE CATHARON PACKAGES ARE PROVIDED `AS IS' WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE. IN NO EVENT WILL ANY OF THE AUTHORS OR COPYRIGHT HOLDERS + BE LIABLE FOR ANY DAMAGES CAUSED BY THE USE OF OR THE INABILITY TO + USE THE CATHARON PACKAGE. + +2. Redistribution +----------------- + + This license grants a worldwide, royalty-free, perpetual and + irrevocable right and license to use, execute, perform, compile, + display, copy, create derivative works of, distribute and + sublicense the Catharon Packages (in both source and object code + forms) and derivative works thereof for any purpose; and to + authorize others to exercise some or all of the rights granted + herein, subject to the following conditions: + + o Redistribution of source code must retain this license file + (`license.txt') unaltered; any additions, deletions or changes + to the original files must be clearly indicated in + accompanying documentation. The copyright notices of the + unaltered, original files must be preserved in all copies of + source files. + + o Redistribution in binary form must provide a disclaimer that + states that the software is based in part on the work of + Catharon Productions, Inc. in the distribution documentation. + + These conditions apply to any software derived from or based on + the Catharon Packages, not just the unmodified files. If you use + our work, you must acknowledge us. However, no fee need be paid + to us. + +3. Advertising +-------------- + + Neither Catharon Productions, Inc. and contributors nor you shall + use the name of the other for commercial, advertising, or + promotional purposes without specific prior written permission. + + We suggest, but do not require, that you use the following phrase + to refer to this software in your documentation: 'this software is + based in part on the Catharon Typography Project'. + + As you have not signed this license, you are not required to + accept it. However, as the Catharon Packages are copyrighted + material, only this license, or another one contracted with the + authors, grants you the right to use, distribute, and modify it. + Therefore, by using, distributing, or modifying the Catharon + Packages, you indicate that you understand and accept all the + terms of this license. + +--- end of license.txt --- diff --git a/src/freetype/autohint/ahangles.c b/src/freetype/autohint/ahangles.c new file mode 100644 index 0000000000..2f759edd5c --- /dev/null +++ b/src/freetype/autohint/ahangles.c @@ -0,0 +1,137 @@ +/***************************************************************************/ +/* */ +/* ahangles.h */ +/* */ +/* A routine used to compute vector angles with limited accuracy */ +/* and very high speed (body). */ +/* */ +/* Copyright 2000 Catharon Productions Inc. */ +/* Author: David Turner */ +/* */ +/* This file is part of the Catharon Typography Project and shall only */ +/* be used, modified, and distributed under the terms of the Catharon */ +/* Open Source License that should come with this file under the name */ +/* `CatharonLicense.txt'. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/* Note that this license is compatible with the FreeType license. */ +/* */ +/***************************************************************************/ + + +#ifdef FT_FLAT_COMPILE + +#include "ahangles.h" + +#else + +#include + +#endif + + + /* the following table has been automatically generated with */ + /* the `mather.py' Python script */ + + const AH_Angle ah_arctan[1L << AH_ATAN_BITS] = + { + 0, 0, 1, 1, 1, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 5, + 5, 5, 6, 6, 6, 7, 7, 7, + 8, 8, 8, 9, 9, 9, 10, 10, + 10, 10, 11, 11, 11, 12, 12, 12, + 13, 13, 13, 14, 14, 14, 14, 15, + 15, 15, 16, 16, 16, 17, 17, 17, + 18, 18, 18, 18, 19, 19, 19, 20, + 20, 20, 21, 21, 21, 21, 22, 22, + 22, 23, 23, 23, 24, 24, 24, 24, + 25, 25, 25, 26, 26, 26, 26, 27, + 27, 27, 28, 28, 28, 28, 29, 29, + 29, 30, 30, 30, 30, 31, 31, 31, + 31, 32, 32, 32, 33, 33, 33, 33, + 34, 34, 34, 34, 35, 35, 35, 35, + 36, 36, 36, 36, 37, 37, 37, 38, + 38, 38, 38, 39, 39, 39, 39, 40, + 40, 40, 40, 41, 41, 41, 41, 42, + 42, 42, 42, 42, 43, 43, 43, 43, + 44, 44, 44, 44, 45, 45, 45, 45, + 46, 46, 46, 46, 46, 47, 47, 47, + 47, 48, 48, 48, 48, 48, 49, 49, + 49, 49, 50, 50, 50, 50, 50, 51, + 51, 51, 51, 51, 52, 52, 52, 52, + 52, 53, 53, 53, 53, 53, 54, 54, + 54, 54, 54, 55, 55, 55, 55, 55, + 56, 56, 56, 56, 56, 57, 57, 57, + 57, 57, 57, 58, 58, 58, 58, 58, + 59, 59, 59, 59, 59, 59, 60, 60, + 60, 60, 60, 61, 61, 61, 61, 61, + 61, 62, 62, 62, 62, 62, 62, 63, + 63, 63, 63, 63, 63, 64, 64, 64 + }; + + + LOCAL_FUNC + AH_Angle ah_angle( FT_Vector* v ) + { + FT_Pos dx, dy; + AH_Angle angle; + + + dx = v->x; + dy = v->y; + + /* check trivial cases */ + if ( dy == 0 ) + { + angle = 0; + if ( dx < 0 ) + angle = AH_PI; + return angle; + } + else if ( dx == 0 ) + { + angle = AH_HALF_PI; + if ( dy < 0 ) + angle = -AH_HALF_PI; + return angle; + } + + angle = 0; + if ( dx < 0 ) + { + dx = -v->x; + dy = -v->y; + angle = AH_PI; + } + + if ( dy < 0 ) + { + FT_Pos tmp; + + + tmp = dx; + dx = -dy; + dy = tmp; + angle -= AH_HALF_PI; + } + + if ( dx == 0 && dy == 0 ) + return 0; + + if ( dx == dy ) + angle += AH_PI / 4; + else if ( dx > dy ) + angle += ah_arctan[FT_DivFix( dy, dx ) >> ( 16 - AH_ATAN_BITS )]; + else + angle += AH_HALF_PI - + ah_arctan[FT_DivFix( dx, dy ) >> ( 16 - AH_ATAN_BITS )]; + + if ( angle > AH_PI ) + angle -= AH_2PI; + + return angle; + } + + +/* END */ diff --git a/src/freetype/autohint/ahangles.h b/src/freetype/autohint/ahangles.h new file mode 100644 index 0000000000..4eb36bf4d2 --- /dev/null +++ b/src/freetype/autohint/ahangles.h @@ -0,0 +1,63 @@ +/***************************************************************************/ +/* */ +/* ahangles.h */ +/* */ +/* A routine used to compute vector angles with limited accuracy */ +/* and very high speed (specification). */ +/* */ +/* Copyright 2000 Catharon Productions Inc. */ +/* Author: David Turner */ +/* */ +/* This file is part of the Catharon Typography Project and shall only */ +/* be used, modified, and distributed under the terms of the Catharon */ +/* Open Source License that should come with this file under the name */ +/* `CatharonLicense.txt'. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/* Note that this license is compatible with the FreeType license. */ +/* */ +/***************************************************************************/ + + +#ifndef AHANGLES_H +#define AHANGLES_H + + +#ifdef FT_FLAT_COMPILE + +#include "ahtypes.h" + +#else + +#include + +#endif + + +#include + + + /* PI expressed in ah_angles -- we don't really need an important */ + /* precision, so 256 should be enough */ +#define AH_PI 256 +#define AH_2PI ( AH_PI * 2 ) +#define AH_HALF_PI ( AH_PI / 2 ) +#define AH_2PIMASK ( AH_2PI - 1 ) + + /* the number of bits used to express an arc tangent; */ + /* see the structure of the lookup table */ +#define AH_ATAN_BITS 8 + + extern + const AH_Angle ah_arctan[1L << AH_ATAN_BITS]; + + + LOCAL_DEF + AH_Angle ah_angle( FT_Vector* v ); + + +#endif /* AHANGLES_H */ + + +/* END */ diff --git a/src/freetype/autohint/ahglobal.c b/src/freetype/autohint/ahglobal.c new file mode 100644 index 0000000000..892ca86174 --- /dev/null +++ b/src/freetype/autohint/ahglobal.c @@ -0,0 +1,402 @@ +/***************************************************************************/ +/* */ +/* ahglobal.c */ +/* */ +/* Routines used to compute global metrics automatically (body). */ +/* */ +/* Copyright 2000 Catharon Productions Inc. */ +/* Author: David Turner */ +/* */ +/* This file is part of the Catharon Typography Project and shall only */ +/* be used, modified, and distributed under the terms of the Catharon */ +/* Open Source License that should come with this file under the name */ +/* `CatharonLicense.txt'. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/* Note that this license is compatible with the FreeType license. */ +/* */ +/***************************************************************************/ + + +#ifdef FT_FLAT_COMPILE + +#include "ahglobal.h" +#include "ahglyph.h" + +#else + +#include +#include + +#endif + + +#define MAX_TEST_CHARACTERS 12 + + static + const char* blue_chars[ah_blue_max] = + { + "THEZOCQS", + "HEZLOCUS", + "xzroesc", + "xzroesc", + "pqgjy" + }; + + + /* simple insertion sort */ + static + void sort_values( FT_Int count, + FT_Pos* table ) + { + FT_Int i, j, swap; + + + for ( i = 1; i < count; i++ ) + { + for ( j = i; j > 1; j-- ) + { + if ( table[j] > table[j - 1] ) + break; + + swap = table[j]; + table[j] = table[j - 1]; + table[j - 1] = swap; + } + } + } + + + static + FT_Error ah_hinter_compute_blues( AH_Hinter* hinter ) + { + AH_Blue blue; + AH_Globals* globals = &hinter->globals->design; + FT_Pos flats [MAX_TEST_CHARACTERS]; + FT_Pos rounds[MAX_TEST_CHARACTERS]; + FT_Int num_flats; + FT_Int num_rounds; + + FT_Face face; + FT_GlyphSlot glyph; + FT_Error error; + FT_CharMap charmap; + + + face = hinter->face; + glyph = face->glyph; + + /* save current charmap */ + charmap = face->charmap; + + /* do we have a Unicode charmap in there? */ + error = FT_Select_Charmap( face, ft_encoding_unicode ); + if ( error ) + goto Exit; + + /* we compute the blues simply by loading each character from the */ + /* 'blue_chars[blues]' string, then compute its top-most and */ + /* bottom-most points */ + + AH_LOG(( "blue zones computation\n" )); + AH_LOG(( "------------------------------------------------\n" )); + + for ( blue = ah_blue_capital_top; blue < ah_blue_max; blue++ ) + { + const char* p = blue_chars[blue]; + const char* limit = p + MAX_TEST_CHARACTERS; + FT_Pos *blue_ref, *blue_shoot; + + + AH_LOG(( "blue %3d: ", blue )); + + num_flats = 0; + num_rounds = 0; + + for ( ; p < limit; p++ ) + { + FT_UInt glyph_index; + FT_Vector* extremum; + FT_Vector* points; + FT_Vector* point_limit; + FT_Vector* point; + FT_Bool round; + + + /* exit if we reach the end of the string */ + if ( !*p ) + break; + + AH_LOG(( "`%c'", *p )); + + /* load the character in the face -- skip unknown or empty ones */ + glyph_index = FT_Get_Char_Index( face, (FT_UInt)*p ); + if ( glyph_index == 0 ) + continue; + + error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE ); + if ( error || glyph->outline.n_points <= 0 ) + continue; + + /* now compute min or max point indices and coordinates */ + points = glyph->outline.points; + point_limit = points + glyph->outline.n_points; + point = points; + extremum = point; + point++; + + if ( AH_IS_TOP_BLUE( blue ) ) + { + for ( ; point < point_limit; point++ ) + if ( point->y > extremum->y ) + extremum = point; + } + else + { + for ( ; point < point_limit; point++ ) + if ( point->y < extremum->y ) + extremum = point; + } + + AH_LOG(( "%5d", (int)extremum->y )); + + /* now, check whether the point belongs to a straight or round */ + /* segment; we first need to find in which contour the extremum */ + /* lies, then see its previous and next points */ + { + FT_Int index = extremum - points; + FT_Int n; + FT_Int first, last, prev, next, end; + FT_Pos dist; + + + last = -1; + first = 0; + + for ( n = 0; n < glyph->outline.n_contours; n++ ) + { + end = glyph->outline.contours[n]; + if ( end >= index ) + { + last = end; + break; + } + first = end + 1; + } + + /* XXX: should never happen! */ + if ( last < 0 ) + continue; + + /* now look for the previous and next points that are not on the */ + /* same Y coordinate. Threshold the `closeness'... */ + + prev = index; + next = prev; + + do + { + if ( prev > first ) + prev--; + else + prev = last; + + dist = points[prev].y - extremum->y; + if ( dist < -5 || dist > 5 ) + break; + + } while ( prev != index ); + + do + { + if ( next < last ) + next++; + else + next = first; + + dist = points[next].y - extremum->y; + if ( dist < -5 || dist > 5 ) + break; + + } while ( next != index ); + + /* now, set the `round' flag depending on the segment's kind */ + round = + FT_CURVE_TAG( glyph->outline.tags[prev] ) != FT_Curve_Tag_On || + FT_CURVE_TAG( glyph->outline.tags[next] ) != FT_Curve_Tag_On ; + + AH_LOG(( "%c ", round ? 'r' : 'f' )); + } + + if ( round ) + rounds[num_rounds++] = extremum->y; + else + flats[num_flats++] = extremum->y; + } + + AH_LOG(( "\n" )); + + /* we have computed the contents of the `rounds' and `flats' tables, */ + /* now determine the reference and overshoot position of the blue; */ + /* we simply take the median value after a simple short */ + sort_values( num_rounds, rounds ); + sort_values( num_flats, flats ); + + blue_ref = globals->blue_refs + blue; + blue_shoot = globals->blue_shoots + blue; + if ( num_flats == 0 && num_rounds == 0 ) + { + *blue_ref = -10000; + *blue_shoot = -10000; + } + else if ( num_flats == 0 ) + { + *blue_ref = + *blue_shoot = rounds[num_rounds / 2]; + } + else if ( num_rounds == 0 ) + { + *blue_ref = + *blue_shoot = flats[num_flats / 2]; + } + else + { + *blue_ref = flats[num_flats / 2]; + *blue_shoot = rounds[num_rounds / 2]; + } + + /* there are sometimes problems: if the overshoot position of top */ + /* zones is under its reference position, or the opposite for bottom */ + /* zones. We must thus check everything there and correct the errors */ + if ( *blue_shoot != *blue_ref ) + { + FT_Pos ref = *blue_ref; + FT_Pos shoot = *blue_shoot; + FT_Bool over_ref = ( shoot > ref ); + + + if ( AH_IS_TOP_BLUE( blue ) ^ over_ref ) + *blue_shoot = *blue_ref = ( shoot + ref ) / 2; + } + + AH_LOG(( "-- ref = %ld, shoot = %ld\n", *blue_ref, *blue_shoot )); + } + + /* reset original face charmap */ + FT_Set_Charmap( face, charmap ); + error = 0; + + Exit: + return error; + } + + + static + FT_Error ah_hinter_compute_widths( AH_Hinter* hinter ) + { + /* scan the array of segments in each direction */ + AH_Outline* outline = hinter->glyph; + AH_Segment* segments; + AH_Segment* limit; + AH_Globals* globals = &hinter->globals->design; + FT_Pos* widths; + FT_Int dimension; + FT_Int* p_num_widths; + FT_Error error = 0; + FT_Pos edge_distance_threshold = 32000; + + + globals->num_widths = 0; + globals->num_heights = 0; + + /* For now, compute the standard width and height from the `o' */ + /* character. I started computing the stem width of the `i' and the */ + /* stem height of the "-", but it wasn't too good. Moreover, we now */ + /* have a single character that gives us standard width and height. */ + { + FT_UInt glyph_index; + + + glyph_index = FT_Get_Char_Index( hinter->face, 'o' ); + if ( glyph_index == 0 ) + return 0; + + error = FT_Load_Glyph( hinter->face, glyph_index, FT_LOAD_NO_SCALE ); + if ( error ) + goto Exit; + + error = ah_outline_load( hinter->glyph, hinter->face ); + if ( error ) + goto Exit; + + ah_outline_compute_segments( hinter->glyph ); + ah_outline_link_segments( hinter->glyph ); + } + + segments = outline->horz_segments; + limit = segments + outline->num_hsegments; + widths = globals->heights; + p_num_widths = &globals->num_heights; + + for ( dimension = 1; dimension >= 0; dimension-- ) + { + AH_Segment* seg = segments; + AH_Segment* link; + FT_Int num_widths = 0; + + + for ( ; seg < limit; seg++ ) + { + link = seg->link; + /* we only consider stem segments there! */ + if ( link && link->link == seg && link > seg ) + { + FT_Int dist; + + + dist = seg->pos - link->pos; + if ( dist < 0 ) + dist = -dist; + + if ( num_widths < 12 ) + widths[num_widths++] = dist; + } + } + + sort_values( num_widths, widths ); + *p_num_widths = num_widths; + + /* we will now try to find the smallest width */ + if ( num_widths > 0 && widths[0] < edge_distance_threshold ) + edge_distance_threshold = widths[0]; + + segments = outline->vert_segments; + limit = segments + outline->num_vsegments; + widths = globals->widths; + p_num_widths = &globals->num_widths; + + } + + /* Now, compute the edge distance threshold as a fraction of the */ + /* smallest width in the font. Set it in `hinter.glyph' too! */ + if ( edge_distance_threshold == 32000 ) + edge_distance_threshold = 50; + + /* let's try 20% */ + hinter->glyph->edge_distance_threshold = edge_distance_threshold / 5; + + Exit: + return error; + } + + + LOCAL_FUNC + FT_Error ah_hinter_compute_globals( AH_Hinter* hinter ) + { + return ah_hinter_compute_widths( hinter ) || + ah_hinter_compute_blues ( hinter ); + } + + +/* END */ diff --git a/src/freetype/autohint/ahglobal.h b/src/freetype/autohint/ahglobal.h new file mode 100644 index 0000000000..79e73586f9 --- /dev/null +++ b/src/freetype/autohint/ahglobal.h @@ -0,0 +1,52 @@ +/***************************************************************************/ +/* */ +/* ahglobal.h */ +/* */ +/* Routines used to compute global metrics automatically */ +/* (specification). */ +/* */ +/* Copyright 2000 Catharon Productions Inc. */ +/* Author: David Turner */ +/* */ +/* This file is part of the Catharon Typography Project and shall only */ +/* be used, modified, and distributed under the terms of the Catharon */ +/* Open Source License that should come with this file under the name */ +/* `CatharonLicense.txt'. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/* Note that this license is compatible with the FreeType license. */ +/* */ +/***************************************************************************/ + + +#ifndef AHGLOBAL_H +#define AHGLOBAL_H + +#ifdef FT_FLAT_COMPILE + +#include "ahtypes.h" + +#else + +#include + +#endif + + +#include /* for LOCAL_DEF/LOCAL_FUNC */ + + +#define AH_IS_TOP_BLUE( b ) ( (b) == ah_blue_capital_top || \ + (b) == ah_blue_small_top ) + + + /* compute global metrics automatically */ + LOCAL_DEF + FT_Error ah_hinter_compute_globals( AH_Hinter* hinter ); + + +#endif /* AHGLOBAL_H */ + + +/* END */ diff --git a/src/freetype/autohint/ahglyph.c b/src/freetype/autohint/ahglyph.c new file mode 100644 index 0000000000..348ee8e32d --- /dev/null +++ b/src/freetype/autohint/ahglyph.c @@ -0,0 +1,1299 @@ +/***************************************************************************/ +/* */ +/* ahglyph.c */ +/* */ +/* Routines used to load and analyze a given glyph before hinting */ +/* (body). */ +/* */ +/* Copyright 2000 Catharon Productions Inc. */ +/* Author: David Turner */ +/* */ +/* This file is part of the Catharon Typography Project and shall only */ +/* be used, modified, and distributed under the terms of the Catharon */ +/* Open Source License that should come with this file under the name */ +/* `CatharonLicense.txt'. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/* Note that this license is compatible with the FreeType license. */ +/* */ +/***************************************************************************/ + + +#ifdef FT_FLAT_COMPILE + +#include "ahglyph.h" +#include "ahangles.h" +#include "ahglobal.h" + +#else + +#include +#include +#include + +#endif + + +#include + + +#define xxxAH_DEBUG_GLYPH + + + /* compute the direction value of a given vector.. */ + static + AH_Direction ah_compute_direction( FT_Pos dx, + FT_Pos dy ) + { + AH_Direction dir; + FT_Pos ax = ABS( dx ); + FT_Pos ay = ABS( dy ); + + + dir = ah_dir_none; + + /* test for vertical direction */ + if ( ax * 12 < ay ) + { + dir = dy > 0 ? ah_dir_up : ah_dir_down; + } + /* test for horizontal direction */ + else if ( ay * 12 < ax ) + { + dir = dx > 0 ? ah_dir_right : ah_dir_left; + } + + return dir; + } + + + /*************************************************************************/ + /* */ + /* */ + /* ah_outline_new */ + /* */ + /* */ + /* Creates a new and empty AH_Outline object. */ + /* */ + LOCAL_FUNC + FT_Error ah_outline_new( FT_Memory memory, + AH_Outline** aoutline ) + { + FT_Error error; + AH_Outline* outline; + + + if ( !ALLOC( outline, sizeof ( *outline ) ) ) + { + outline->memory = memory; + *aoutline = outline; + } + + return error; + } + + + /*************************************************************************/ + /* */ + /* */ + /* ah_outline_done */ + /* */ + /* */ + /* Destroys a given AH_Outline object. */ + /* */ + LOCAL_FUNC + void ah_outline_done( AH_Outline* outline ) + { + FT_Memory memory = outline->memory; + + + FREE( outline->horz_edges ); + FREE( outline->horz_segments ); + FREE( outline->contours ); + FREE( outline->points ); + + FREE( outline ); + } + + + /*************************************************************************/ + /* */ + /* */ + /* ah_outline_save */ + /* */ + /* */ + /* Saves the content of a given AH_Outline object into a face's glyph */ + /* slot. */ + /* */ + LOCAL_FUNC + void ah_outline_save( AH_Outline* outline, + AH_Loader* gloader ) + { + AH_Point* point = outline->points; + AH_Point* limit = point + outline->num_points; + FT_Vector* vec = gloader->current.outline.points; + char* tag = gloader->current.outline.tags; + + + /* we assume that the glyph loader has already been checked for storage */ + for ( ; point < limit; point++, vec++, tag++ ) + { + vec->x = point->x; + vec->y = point->y; + + if ( point->flags & ah_flah_conic ) + tag[0] = FT_Curve_Tag_Conic; + else if ( point->flags & ah_flah_cubic ) + tag[0] = FT_Curve_Tag_Cubic; + else + tag[0] = FT_Curve_Tag_On; + } + } + + + /*************************************************************************/ + /* */ + /* */ + /* ah_outline_load */ + /* */ + /* */ + /* Loads an unscaled outline from a glyph slot into an AH_Outline */ + /* object. */ + /* */ + LOCAL_FUNC + FT_Error ah_outline_load( AH_Outline* outline, + FT_Face face ) + { + FT_Memory memory = outline->memory; + FT_Error error = FT_Err_Ok; + FT_Outline* source = &face->glyph->outline; + FT_Int num_points = source->n_points; + FT_Int num_contours = source->n_contours; + AH_Point* points; + + + /* check arguments */ + if ( !face || + !face->size || + face->glyph->format != ft_glyph_format_outline ) + return FT_Err_Invalid_Argument; + + /* first of all, reallocate the contours array if necessary */ + if ( num_contours > outline->max_contours ) + { + FT_Int new_contours = ( num_contours + 3 ) & -4; + + + if ( REALLOC_ARRAY( outline->contours, outline->max_contours, + new_contours, AH_Point* ) ) + goto Exit; + + outline->max_contours = new_contours; + } + + /* then, realloc the points, segments & edges arrays if needed */ + if ( num_points > outline->max_points ) + { + FT_Int news = ( num_points + 7 ) & -8; + FT_Int max = outline->max_points; + + + if ( REALLOC_ARRAY( outline->points, max, news, AH_Point ) || + REALLOC_ARRAY( outline->horz_edges, max, news, AH_Edge ) || + REALLOC_ARRAY( outline->horz_segments, max, news, AH_Segment ) ) + goto Exit; + + /* readjust some pointers */ + outline->vert_edges = outline->horz_edges + ( news >> 1 ); + outline->vert_segments = outline->horz_segments + ( news >> 1 ); + outline->max_points = news; + } + + outline->num_points = num_points; + outline->num_contours = num_contours; + + outline->num_hedges = 0; + outline->num_vedges = 0; + outline->num_hsegments = 0; + outline->num_vsegments = 0; + + /* Compute the vertical and horizontal major directions; this is */ + /* currently done by inspecting the `ft_outline_reverse_fill' flag. */ + /* However, some fonts have improper glyphs, and it'd be a good idea */ + /* to be able to re-compute these values on the fly. */ + outline->vert_major_dir = ah_dir_up; + outline->horz_major_dir = ah_dir_left; + + if ( source->flags & ft_outline_reverse_fill ) + { + outline->vert_major_dir = ah_dir_down; + outline->horz_major_dir = ah_dir_right; + } + + outline->x_scale = face->size->metrics.x_scale; + outline->y_scale = face->size->metrics.y_scale; + + points = outline->points; + + { + /* do one thing at a time -- it is easier to understand, and */ + /* the code is clearer */ + AH_Point* point = points; + AH_Point* limit = point + outline->num_points; + + + /* compute coordinates */ + { + FT_Vector* vec = source->points; + FT_Fixed x_scale = outline->x_scale; + FT_Fixed y_scale = outline->y_scale; + + + for (; point < limit; vec++, point++ ) + { + point->fx = vec->x; + point->fy = vec->y; + point->ox = point->x = FT_MulFix( vec->x, x_scale ); + point->oy = point->y = FT_MulFix( vec->y, y_scale ); + + point->flags = 0; + } + } + + /* compute Bezier flags */ + { + char* tag = source->tags; + + + for ( point = points; point < limit; point++, tag++ ) + { + switch ( FT_CURVE_TAG( *tag ) ) + { + case FT_Curve_Tag_Conic: + point->flags = ah_flah_conic; break; + case FT_Curve_Tag_Cubic: + point->flags = ah_flah_cubic; break; + default: + ; + } + } + } + + /* compute `next' and `prev' */ + { + FT_Int contour_index; + AH_Point* prev; + AH_Point* first; + AH_Point* end; + + + contour_index = 0; + + first = points; + end = points + source->contours[0]; + prev = end; + + for ( point = points; point < limit; point++ ) + { + point->prev = prev; + if ( point < end ) + { + point->next = point + 1; + prev = point; + } + else + { + point->next = first; + contour_index++; + if ( point + 1 < limit ) + { + end = points + source->contours[contour_index]; + first = point + 1; + prev = end; + } + } + } + } + + /* set-up the contours array */ + { + AH_Point** contour = outline->contours; + AH_Point** limit = contour + outline->num_contours; + short* end = source->contours; + short index = 0; + + + for ( ; contour < limit; contour++, end++ ) + { + contour[0] = points + index; + index = end[0] + 1; + } + } + + /* compute directions of in & out vectors */ + { + for ( point = points; point < limit; point++ ) + { + AH_Point* prev; + AH_Point* next; + FT_Vector vec; + + + prev = point->prev; + vec.x = point->fx - prev->fx; + vec.y = point->fy - prev->fy; + + point->in_dir = ah_compute_direction( vec.x, vec.y ); + +#ifndef AH_OPTION_NO_WEAK_INTERPOLATION + point->in_angle = ah_angle( &vec ); +#endif + + next = point->next; + vec.x = next->fx - point->fx; + vec.y = next->fy - point->fy; + + point->out_dir = ah_compute_direction( vec.x, vec.y ); + +#ifndef AH_OPTION_NO_WEAK_INTERPOLATION + point->out_angle = ah_angle( &vec ); + + { + AH_Angle delta = point->in_angle - point->out_angle; + + + if ( delta < 0 ) + delta = -delta; + if ( delta < 2 ) + point->flags |= ah_flah_weak_interpolation; + } + +#if 0 + if ( point->flags & ( ah_flah_conic | ah_flah_cubic ) ) + point->flags |= ah_flah_weak_interpolation; +#endif + +#endif /* !AH_OPTION_NO_WEAK_INTERPOLATION */ + +#ifdef AH_OPTION_NO_STRONG_INTERPOLATION + point->flags |= ah_flah_weak_interpolation; +#endif + } + } + } + + Exit: + return error; + } + + + LOCAL_FUNC + void ah_setup_uv( AH_Outline* outline, + AH_UV source ) + { + AH_Point* point = outline->points; + AH_Point* limit = point + outline->num_points; + + + for ( ; point < limit; point++ ) + { + FT_Pos u, v; + + + switch ( source ) + { + case ah_uv_fxy: + u = point->fx; + v = point->fy; + break; + case ah_uv_fyx: + u = point->fy; + v = point->fx; + break; + case ah_uv_oxy: + u = point->ox; + v = point->oy; + break; + case ah_uv_oyx: + u = point->oy; + v = point->ox; + break; + case ah_uv_yx: + u = point->y; + v = point->x; + break; + case ah_uv_ox: + u = point->x; + v = point->ox; + break; + case ah_uv_oy: + u = point->y; + v = point->oy; + break; + default: + u = point->x; + v = point->y; + break; + } + point->u = u; + point->v = v; + } + } + + + LOCAL_FUNC + void ah_outline_compute_segments( AH_Outline* outline ) + { + int dimension; + AH_Segment* segments; + FT_Int* p_num_segments; + AH_Direction segment_dir; + AH_Direction major_dir; + + + segments = outline->horz_segments; + p_num_segments = &outline->num_hsegments; + major_dir = ah_dir_right; /* This value must be positive! */ + segment_dir = major_dir; + + /* set up (u,v) in each point */ + ah_setup_uv( outline, ah_uv_fyx ); + + for ( dimension = 1; dimension >= 0; dimension-- ) + { + AH_Point** contour = outline->contours; + AH_Point** contour_limit = contour + outline->num_contours; + AH_Segment* segment = segments; + FT_Int num_segments = 0; + +#ifdef AH_HINT_METRICS + AH_Point* min_point = 0; + AH_Point* max_point = 0; + FT_Pos min_coord = 32000; + FT_Pos max_coord = -32000; +#endif + + + /* do each contour separately */ + for ( ; contour < contour_limit; contour++ ) + { + AH_Point* point = contour[0]; + AH_Point* last = point->prev; + int on_edge = 0; + FT_Pos min_pos = +32000; /* minimum segment pos != min_coord */ + FT_Pos max_pos = -32000; /* maximum segment pos != max_coord */ + FT_Bool passed; + + +#ifdef AH_HINT_METRICS + if ( point->u < min_coord ) + { + min_coord = point->u; + min_point = point; + } + if ( point->u > max_coord ) + { + max_coord = point->u; + max_point = point; + } +#endif + + if ( point == last ) /* skip singletons -- just in case? */ + continue; + + if ( ABS( last->out_dir ) == major_dir && + ABS( point->out_dir ) == major_dir ) + { + /* we are already on an edge, try to locate its start */ + last = point; + + for (;;) + { + point = point->prev; + if ( ABS( point->out_dir ) != major_dir ) + { + point = point->next; + break; + } + if ( point == last ) + break; + } + + } + + last = point; + passed = 0; + + for (;;) + { + FT_Pos u, v; + + + if ( on_edge ) + { + u = point->u; + if ( u < min_pos ) + min_pos = u; + if ( u > max_pos ) + max_pos = u; + + if ( point->out_dir != segment_dir || point == last ) + { + /* we are just leaving an edge; record a new segment! */ + segment->last = point; + segment->pos = ( min_pos + max_pos ) >> 1; + + /* a segment is round if either its first or last point */ + /* is a control point */ + if ( ( segment->first->flags | point->flags ) & + ah_flah_control ) + segment->flags |= ah_edge_round; + + /* compute segment size */ + min_pos = max_pos = point->v; + + v = segment->first->v; + if ( v < min_pos ) + min_pos = v; + if ( v > max_pos ) + max_pos = v; + + segment->min_coord = min_pos; + segment->max_coord = max_pos; + + on_edge = 0; + num_segments++; + segment++; + /* fallthrough */ + } + } + + /* now exit if we are at the start/end point */ + if ( point == last ) + { + if ( passed ) + break; + passed = 1; + } + + if ( !on_edge && ABS( point->out_dir ) == major_dir ) + { + /* this is the start of a new segment! */ + segment_dir = point->out_dir; + + /* clear all segment fields */ + memset( segment, 0, sizeof ( *segment ) ); + + segment->dir = segment_dir; + segment->flags = ah_edge_normal; + min_pos = max_pos = point->u; + segment->first = point; + segment->last = point; + segment->contour = contour; + on_edge = 1; + + if ( point == max_point ) + max_point = 0; + + if ( point == min_point ) + min_point = 0; + } + + point = point->next; + } + + } /* contours */ + +#ifdef AH_HINT_METRICS + /* we need to ensure that there are edges on the left-most and */ + /* right-most points of the glyph in order to hint the metrics; */ + /* we do this by inserting fake segments when needed */ + if ( dimension == 0 ) + { + AH_Point* point = outline->points; + AH_Point* limit = point + outline->num_points; + + AH_Point* min_point = 0; + AH_Point* max_point = 0; + FT_Pos min_pos = 32000; + FT_Pos max_pos = -32000; + + + /* compute minimum and maximum points */ + for ( ; point < limit; point++ ) + { + FT_Pos x = point->fx; + + + if ( x < min_pos ) + { + min_pos = x; + min_point = point; + } + if ( x > max_pos ) + { + max_pos = x; + max_point = point; + } + } + + /* insert minimum segment */ + if ( min_point ) + { + /* clear all segment fields */ + memset( segment, 0, sizeof ( *segment ) ); + + segment->dir = segment_dir; + segment->flags = ah_edge_normal; + segment->first = min_point; + segment->last = min_point; + segment->pos = min_pos; + + num_segments++; + segment++; + } + + /* insert maximum segment */ + if ( max_point ) + { + /* clear all segment fields */ + memset( segment, 0, sizeof ( *segment ) ); + + segment->dir = segment_dir; + segment->flags = ah_edge_normal; + segment->first = max_point; + segment->last = max_point; + segment->pos = max_pos; + + num_segments++; + segment++; + } + } +#endif /* AH_HINT_METRICS */ + + *p_num_segments = num_segments; + + segments = outline->vert_segments; + major_dir = ah_dir_up; + p_num_segments = &outline->num_vsegments; + ah_setup_uv( outline, ah_uv_fxy ); + } + } + + + LOCAL_FUNC + void ah_outline_link_segments( AH_Outline* outline ) + { + AH_Segment* segments; + AH_Segment* limit; + int dimension; + + + ah_setup_uv( outline, ah_uv_fyx ); + + segments = outline->horz_segments; + limit = segments + outline->num_hsegments; + + for ( dimension = 1; dimension >= 0; dimension-- ) + { + AH_Segment* seg1; + AH_Segment* seg2; + + + /* now compare each segment to the others */ + for ( seg1 = segments; seg1 < limit; seg1++ ) + { + FT_Pos best_score = 32000; + AH_Segment* best_segment = 0; + + + /* the fake segments are introduced to hint the metrics -- */ + /* we must never link them to anything */ + if ( seg1->first == seg1->last ) + continue; + + for ( seg2 = segments; seg2 < limit; seg2++ ) + if ( seg1 != seg2 && seg1->dir + seg2->dir == 0 ) + { + FT_Pos pos1 = seg1->pos; + FT_Pos pos2 = seg2->pos; + FT_Bool is_dir; + FT_Bool is_pos; + + + /* check that the segments are correctly oriented and */ + /* positioned to form a black distance */ + + is_dir = ( seg1->dir == outline->horz_major_dir || + seg1->dir == outline->vert_major_dir ); + is_pos = pos1 > pos2; + + if ( pos1 == pos2 || !(is_dir ^ is_pos) ) + continue; + + /* Check the two segments. We now have a better algorithm */ + /* that doesn't rely on the segment points themselves but */ + /* on their relative position. This gets rids of many */ + /* unpleasant artefacts and incorrect stem/serifs */ + /* computations. */ + + /* first of all, compute the size of the `common' height */ + { + FT_Pos min = seg1->min_coord; + FT_Pos max = seg1->max_coord; + FT_Pos len, score; + FT_Pos size1, size2; + + + size1 = max - min; + size2 = seg2->max_coord - seg2->min_coord; + + if ( min < seg2->min_coord ) + min = seg2->min_coord; + + if ( max < seg2->max_coord ) + max = seg2->max_coord; + + len = max - min; + score = seg2->pos - seg1->pos; + if ( score < 0 ) + score = -score; + + /* before comparing the scores, take care that the segments */ + /* are really facing each other (often not for italics..) */ + if ( 4 * len >= size1 && 4 * len >= size2 ) + if ( score < best_score ) + { + best_score = score; + best_segment = seg2; + } + } + } + + if ( best_segment ) + { + seg1->link = best_segment; + seg1->score = best_score; + + best_segment->num_linked++; + } + + + } /* edges 1 */ + + /* now, compute the `serif' segments */ + for ( seg1 = segments; seg1 < limit; seg1++ ) + { + seg2 = seg1->link; + + if ( seg2 && seg2->link != seg1 ) + { + seg1->link = 0; + seg1->serif = seg2->link; + } + } + + ah_setup_uv( outline, ah_uv_fxy ); + + segments = outline->vert_segments; + limit = segments + outline->num_vsegments; + } + } + + +#ifdef AH_DEBUG_GLYPH + + /* A function used to dump the array of linked segments */ + void ah_dump_segments( AH_Outline* outline ) + { + AH_Segment* segments; + AH_Segment* limit; + AH_Point* points; + FT_Int dimension; + + + points = outline->points; + segments = outline->horz_segments; + limit = segments + outline->num_hsegments; + + for ( dimension = 1; dimension >= 0; dimension-- ) + { + AH_Segment* seg; + + + printf ( "Table of %s segments:\n", + !dimension ? "vertical" : "horizontal" ); + printf ( " [ index | pos | dir | link | serif |" + " numl | first | start ]\n" ); + + for ( seg = segments; seg < limit; seg++ ) + { + printf ( " [ %5d | %4d | %5s | %4d | %5d | %4d | %5d | %5d ]\n", + seg - segments, + (int)seg->pos, + seg->dir == ah_dir_up + ? "up" + : ( seg->dir == ah_dir_down + ? "down" + : ( seg->dir == ah_dir_left + ? "left" + : ( seg->dir == ah_dir_right + ? "right" + : "none" ) ) ), + seg->link ? (seg->link-segments) : -1, + seg->serif ? (seg->serif-segments) : -1, + (int)seg->num_linked, + seg->first - points, + seg->last - points ); + } + + segments = outline->vert_segments; + limit = segments + outline->num_vsegments; + } + } + +#endif /* AH_DEBUG_GLYPH */ + + + static + void ah_outline_compute_edges( AH_Outline* outline ) + { + AH_Edge* edges; + AH_Segment* segments; + AH_Segment* segment_limit; + AH_Direction up_dir; + FT_Int* p_num_edges; + FT_Int dimension; + FT_Fixed scale; + FT_Pos edge_distance_threshold; + + + edges = outline->horz_edges; + segments = outline->horz_segments; + segment_limit = segments + outline->num_hsegments; + p_num_edges = &outline->num_hedges; + up_dir = ah_dir_right; + scale = outline->y_scale; + + for ( dimension = 1; dimension >= 0; dimension-- ) + { + AH_Edge* edge; + AH_Edge* edge_limit; /* really == edge + num_edges */ + AH_Segment* seg; + + + /*********************************************************************/ + /* */ + /* We will begin by generating a sorted table of edges for the */ + /* current direction. To do so, we simply scan each segment and try */ + /* to find an edge in our table that corresponds to its position. */ + /* */ + /* If no edge is found, we create and insert a new edge in the */ + /* sorted table. Otherwise, we simply add the segment to the edge's */ + /* list which will be processed in the second step to compute the */ + /* edge's properties. */ + /* */ + /* Note that the edges table is sorted along the segment/edge */ + /* position. */ + /* */ + /*********************************************************************/ + + edge_distance_threshold = FT_MulFix( outline->edge_distance_threshold, + scale ); + if ( edge_distance_threshold > 64 / 4 ) + edge_distance_threshold = 64 / 4; + + edge_limit = edges; + for ( seg = segments; seg < segment_limit; seg++ ) + { + AH_Edge* found = 0; + + + /* look for an edge corresponding to the segment */ + for ( edge = edges; edge < edge_limit; edge++ ) + { + FT_Pos dist; + + + dist = seg->pos - edge->fpos; + if ( dist < 0 ) + dist = -dist; + + dist = FT_MulFix( dist, scale ); + if ( dist < edge_distance_threshold ) + { + found = edge; + break; + } + } + + if ( !found ) + { + /* insert a new edge in the list and */ + /* sort according to the position */ + while ( edge > edges && edge[-1].fpos > seg->pos ) + { + edge[0] = edge[-1]; + edge--; + } + edge_limit++; + + /* clear all edge fields */ + memset( edge, 0, sizeof ( *edge ) ); + + /* add the segment to the new edge's list */ + edge->first = seg; + edge->last = seg; + edge->fpos = seg->pos; + edge->opos = edge->pos = FT_MulFix( seg->pos, scale ); + seg->edge_next = seg; + } + else + { + /* if an edge was found, simply add the segment to the edge's */ + /* list */ + seg->edge_next = edge->first; + edge->last->edge_next = seg; + edge->last = seg; + } + } + + *p_num_edges = edge_limit - edges; + + + /*********************************************************************/ + /* */ + /* Good, we will now compute each edge's properties according to */ + /* segments found on its position. Basically, these are: */ + /* */ + /* - edge's main direction */ + /* - stem edge, serif edge or both (which defaults to stem then) */ + /* - rounded edge, straigth or both (which defaults to straight) */ + /* - link for edge */ + /* */ + /*********************************************************************/ + + /* first of all, set the `edge' field in each segment -- this is */ + /* required in order to compute edge links */ + for ( edge = edges; edge < edge_limit; edge++ ) + { + seg = edge->first; + if ( seg ) + do + { + seg->edge = edge; + seg = seg->edge_next; + } + while ( seg != edge->first ); + } + + /* now, compute each edge properties */ + for ( edge = edges; edge < edge_limit; edge++ ) + { + int is_round = 0; /* does it contain round segments? */ + int is_straight = 0; /* does it contain straight segments? */ + int ups = 0; /* number of upwards segments */ + int downs = 0; /* number of downwards segments */ + + + seg = edge->first; + + do + { + FT_Bool is_serif; + + + /* check for roundness of segment */ + if ( seg->flags & ah_edge_round ) + is_round++; + else + is_straight++; + + /* check for segment direction */ + if ( seg->dir == up_dir ) + ups += seg->max_coord-seg->min_coord; + else + downs += seg->max_coord-seg->min_coord; + + /* check for links -- if seg->serif is set, then seg->link must */ + /* be ignored */ + is_serif = seg->serif && seg->serif->edge != edge; + + if ( seg->link || is_serif ) + { + AH_Edge* edge2; + AH_Segment* seg2; + + + edge2 = edge->link; + seg2 = seg->link; + + if ( is_serif ) + { + seg2 = seg->serif; + edge2 = edge->serif; + } + + if ( edge2 ) + { + FT_Pos edge_delta; + FT_Pos seg_delta; + + + edge_delta = edge->fpos - edge2->fpos; + if ( edge_delta < 0 ) + edge_delta = -edge_delta; + + seg_delta = seg->pos - seg2->pos; + if ( seg_delta < 0 ) + seg_delta = -seg_delta; + + if ( seg_delta < edge_delta ) + edge2 = seg2->edge; + } + else + edge2 = seg2->edge; + + if ( is_serif ) + edge->serif = edge2; + else + edge->link = edge2; + } + + seg = seg->edge_next; + + } while ( seg != edge->first ); + + /* set the round/straight flags */ + edge->flags = ah_edge_normal; + + if ( is_straight == 0 && is_round ) + edge->flags |= ah_edge_round; + + /* set the edge's main direction */ + edge->dir = ah_dir_none; + + if ( ups > downs ) + edge->dir = up_dir; + + else if ( ups < downs ) + edge->dir = - up_dir; + + else if ( ups == downs ) + edge->dir = 0; /* both up and down !! */ + + /* gets rid of serifs if link is set */ + /* XXX: This gets rid of many unpleasant artefacts! */ + /* Example: the `c' in cour.pfa at size 13 */ + + if ( edge->serif && edge->link ) + edge->serif = 0; + } + + edges = outline->vert_edges; + segments = outline->vert_segments; + segment_limit = segments + outline->num_vsegments; + p_num_edges = &outline->num_vedges; + up_dir = ah_dir_up; + scale = outline->x_scale; + } + } + + + /*************************************************************************/ + /* */ + /* */ + /* ah_outline_detect_features */ + /* */ + /* */ + /* Performs feature detection on a given AH_Outline object. */ + /* */ + LOCAL_FUNC + void ah_outline_detect_features( AH_Outline* outline ) + { + ah_outline_compute_segments( outline ); + ah_outline_link_segments ( outline ); + ah_outline_compute_edges ( outline ); + } + + + /*************************************************************************/ + /* */ + /* */ + /* ah_outline_compute_blue_edges */ + /* */ + /* */ + /* Computes the `blue edges' in a given outline (i.e. those that must */ + /* be snapped to a blue zone edge (top or bottom). */ + /* */ + LOCAL_FUNC + void ah_outline_compute_blue_edges( AH_Outline* outline, + AH_Face_Globals* face_globals ) + { + AH_Edge* edge = outline->horz_edges; + AH_Edge* limit = edge + outline->num_hedges; + AH_Globals* globals = &face_globals->design; + FT_Fixed y_scale = outline->y_scale; + + + /* compute for each horizontal edge, which blue zone is closer */ + for ( ; edge < limit; edge++ ) + { + AH_Blue blue; + FT_Pos* best_blue = 0; + FT_Pos best_dist; /* initial threshold */ + + + /* compute the initial threshold as a fraction of the EM size */ + best_dist = FT_MulFix( face_globals->face->units_per_EM / 40, y_scale ); + if ( best_dist > 64 / 4 ) + best_dist = 64 / 4; + + for ( blue = ah_blue_capital_top; blue < ah_blue_max; blue++ ) + { + /* if it is a top zone, check for right edges -- if it is a bottom */ + /* zone, check for left edges */ + /* */ + /* of course, that's for TrueType XXX */ + FT_Bool is_top_blue = AH_IS_TOP_BLUE( blue ); + FT_Bool is_major_dir = edge->dir == outline->horz_major_dir; + + + /* if it is a top zone, the edge must be against the major */ + /* direction; if it is a bottom zone, it must be in the major */ + /* direction */ + if ( is_top_blue ^ is_major_dir ) + { + FT_Pos dist; + FT_Pos* blue_pos = globals->blue_refs + blue; + + + /* first of all, compare it to the reference position */ + dist = edge->fpos - *blue_pos; + if ( dist < 0 ) + dist = -dist; + + dist = FT_MulFix( dist, y_scale ); + if ( dist < best_dist ) + { + best_dist = dist; + best_blue = blue_pos; + } + + /* now, compare it to the overshoot position if the edge is */ + /* rounded, and if the edge is over the reference position of a */ + /* top zone, or under the reference position of a bottom zone */ + if ( edge->flags & ah_edge_round && dist != 0 ) + { + FT_Bool is_under_ref = edge->fpos < *blue_pos; + + + if ( is_top_blue ^ is_under_ref ) + { + blue_pos = globals->blue_shoots + blue; + dist = edge->fpos - *blue_pos; + if ( dist < 0 ) + dist = -dist; + + dist = FT_MulFix( dist, y_scale ); + if ( dist < best_dist ) + { + best_dist = dist; + best_blue = blue_pos; + } + } + } + } + } + + if ( best_blue ) + edge->blue_edge = best_blue; + } + } + + + /*************************************************************************/ + /* */ + /* */ + /* ah_outline_scale_blue_edges */ + /* */ + /* */ + /* This functions must be called before hinting in order to re-adjust */ + /* the contents of the detected edges (basically change the `blue */ + /* edge' pointer from `design units' to `scaled ones'). */ + /* */ + LOCAL_FUNC + void ah_outline_scale_blue_edges( AH_Outline* outline, + AH_Face_Globals* globals ) + { + AH_Edge* edge = outline->horz_edges; + AH_Edge* limit = edge + outline->num_hedges; + FT_Int delta; + + + delta = globals->scaled.blue_refs - globals->design.blue_refs; + + for ( ; edge < limit; edge++ ) + { + if ( edge->blue_edge ) + edge->blue_edge += delta; + } + } + + +#ifdef AH_DEBUG_GLYPH + + void ah_dump_edges( AH_Outline* outline ) + { + AH_Edge* edges; + AH_Edge* limit; + AH_Segment* segments; + FT_Int dimension; + + + edges = outline->horz_edges; + limit = edges + outline->num_hedges; + segments = outline->horz_segments; + + for ( dimension = 1; dimension >= 0; dimension-- ) + { + AH_Edge* edge; + + + printf ( "Table of %s edges:\n", + !dimension ? "vertical" : "horizontal" ); + printf ( " [ index | pos | dir | link |" + " serif | blue | opos | pos ]\n" ); + + for ( edge = edges; edge < limit; edge++ ) + { + printf ( " [ %5d | %4d | %5s | %4d | %5d | %c | %5.2f | %5.2f ]\n", + edge - edges, + (int)edge->fpos, + edge->dir == ah_dir_up + ? "up" + : ( edge->dir == ah_dir_down + ? "down" + : ( edge->dir == ah_dir_left + ? "left" + : ( edge->dir == ah_dir_right + ? "right" + : "none" ) ) ), + edge->link ? ( edge->link - edges ) : -1, + edge->serif ? ( edge->serif - edges ) : -1, + edge->blue_edge ? 'y' : 'n', + edge->opos / 64.0, + edge->pos / 64.0 ); + } + + edges = outline->vert_edges; + limit = edges + outline->num_vedges; + segments = outline->vert_segments; + } + } + +#endif /* AH_DEBUG_GLYPH */ + + +/* END */ diff --git a/src/freetype/autohint/ahglyph.h b/src/freetype/autohint/ahglyph.h new file mode 100644 index 0000000000..66fd5e3155 --- /dev/null +++ b/src/freetype/autohint/ahglyph.h @@ -0,0 +1,93 @@ +/***************************************************************************/ +/* */ +/* ahglyph.h */ +/* */ +/* Routines used to load and analyze a given glyph before hinting */ +/* (specification). */ +/* */ +/* Copyright 2000 Catharon Productions Inc. */ +/* Author: David Turner */ +/* */ +/* This file is part of the Catharon Typography Project and shall only */ +/* be used, modified, and distributed under the terms of the Catharon */ +/* Open Source License that should come with this file under the name */ +/* `CatharonLicense.txt'. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/* Note that this license is compatible with the FreeType license. */ +/* */ +/***************************************************************************/ + + +#ifndef AHGLYPH_H +#define AHGLYPH_H + +#ifdef FT_FLAT_COMPILE + +#include "ahtypes.h" + +#else + +#include + +#endif + + + typedef enum AH_UV_ + { + ah_uv_fxy, + ah_uv_fyx, + ah_uv_oxy, + ah_uv_oyx, + ah_uv_ox, + ah_uv_oy, + ah_uv_yx, + ah_uv_xy /* should always be last! */ + + } AH_UV; + + + LOCAL_DEF + void ah_setup_uv( AH_Outline* outline, + AH_UV source ); + + + /* AH_Outline functions - they should be typically called in this order */ + + LOCAL_DEF + FT_Error ah_outline_new( FT_Memory memory, + AH_Outline** aoutline ); + + LOCAL_DEF + FT_Error ah_outline_load( AH_Outline* outline, + FT_Face face ); + + LOCAL_DEF + void ah_outline_compute_segments( AH_Outline* outline ); + + LOCAL_DEF + void ah_outline_link_segments( AH_Outline* outline ); + + LOCAL_DEF + void ah_outline_detect_features( AH_Outline* outline ); + + LOCAL_DEF + void ah_outline_compute_blue_edges( AH_Outline* outline, + AH_Face_Globals* globals ); + + LOCAL_DEF + void ah_outline_scale_blue_edges( AH_Outline* outline, + AH_Face_Globals* globals ); + + LOCAL_DEF + void ah_outline_save( AH_Outline* outline, AH_Loader* loader ); + + LOCAL_DEF + void ah_outline_done( AH_Outline* outline ); + + +#endif /* AHGLYPH_H */ + + +/* END */ diff --git a/src/freetype/autohint/ahhint.c b/src/freetype/autohint/ahhint.c new file mode 100644 index 0000000000..f50f8839de --- /dev/null +++ b/src/freetype/autohint/ahhint.c @@ -0,0 +1,1398 @@ +/***************************************************************************/ +/* */ +/* ahhint.c */ +/* */ +/* Glyph hinter (body). */ +/* */ +/* Copyright 2000 Catharon Productions Inc. */ +/* Author: David Turner */ +/* */ +/* This file is part of the Catharon Typography Project and shall only */ +/* be used, modified, and distributed under the terms of the Catharon */ +/* Open Source License that should come with this file under the name */ +/* `CatharonLicense.txt'. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/* Note that this license is compatible with the FreeType license. */ +/* */ +/***************************************************************************/ + + +#ifdef FT_FLAT_COMPILE + +#include "ahhint.h" +#include "ahglyph.h" +#include "ahangles.h" + +#else + +#include +#include +#include + +#endif + +#include + + +#define FACE_GLOBALS( face ) ((AH_Face_Globals*)(face)->autohint.data) + +#define AH_USE_IUP + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** Hinting routines ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + + static int disable_horz_edges = 0; + static int disable_vert_edges = 0; + + + /* snap a given width in scaled coordinates to one of the */ + /* current standard widths */ + static + FT_Pos ah_snap_width( FT_Pos* widths, + FT_Int count, + FT_Pos width ) + { + int n; + FT_Pos best = 64 + 32 + 2; + FT_Pos reference = width; + + + for ( n = 0; n < count; n++ ) + { + FT_Pos w; + FT_Pos dist; + + + w = widths[n]; + dist = width - w; + if ( dist < 0 ) + dist = -dist; + if ( dist < best ) + { + best = dist; + reference = w; + } + } + + if ( width >= reference ) + { + width -= 0x21; + if ( width < reference ) + width = reference; + } + else + { + width += 0x21; + if ( width > reference ) + width = reference; + } + + return width; + } + + + /* align one stem edge relative to the previous stem edge */ + static + void ah_align_linked_edge( AH_Hinter* hinter, + AH_Edge* base_edge, + AH_Edge* stem_edge, + int vertical ) + { + FT_Pos dist = stem_edge->opos - base_edge->opos; + AH_Globals* globals = &hinter->globals->scaled; + FT_Pos sign = 1; + + + if ( dist < 0 ) + { + dist = -dist; + sign = -1; + } + + if ( vertical ) + { + dist = ah_snap_width( globals->heights, globals->num_heights, dist ); + + /* in the case of vertical hinting, always round */ + /* the stem heights to integer pixels */ + if ( dist >= 64 ) + dist = ( dist + 16 ) & -64; + else + dist = 64; + } + else + { + dist = ah_snap_width( globals->widths, globals->num_widths, dist ); + + if ( hinter->flags & ah_hinter_monochrome ) + { + /* monochrome horizontal hinting: snap widths to integer pixels */ + /* with a different threshold */ + if ( dist < 64 ) + dist = 64; + else + dist = ( dist + 32 ) & -64; + } + else + { + /* for horizontal anti-aliased hinting, we adopt a more subtle */ + /* approach: we strengthen small stems, round stems whose size */ + /* is between 1 and 2 pixels to an integer, otherwise nothing */ + if ( dist < 48 ) + dist = ( dist + 64 ) >> 1; + + else if ( dist < 128 ) + dist = ( dist + 42 ) & -64; + } + } + + stem_edge->pos = base_edge->pos + sign * dist; + } + + + static + void ah_align_serif_edge( AH_Hinter* hinter, + AH_Edge* base, + AH_Edge* serif ) + { + FT_Pos dist; + FT_Pos sign = 1; + + UNUSED( hinter ); + + + dist = serif->opos - base->opos; + if ( dist < 0 ) + { + dist = -dist; + sign = -1; + } + + /* do not strengthen serifs */ + if ( base->flags & ah_edge_done ) + { + if ( dist > 64 ) + dist = ( dist + 16 ) & -64; + + else if ( dist <= 32 ) + dist = ( dist + 33 ) >> 1; + } + + serif->pos = base->pos + sign * dist; + } + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** E D G E H I N T I N G ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /* Another alternative edge hinting algorithm */ + static + void ah_hint_edges_3( AH_Hinter* hinter ) + { + AH_Edge* edges; + AH_Edge* edge_limit; + AH_Outline* outline = hinter->glyph; + FT_Int dimension; + + + edges = outline->horz_edges; + edge_limit = edges + outline->num_hedges; + + for ( dimension = 1; dimension >= 0; dimension-- ) + { + AH_Edge* edge; + AH_Edge* before = 0; + AH_Edge* after = 0; + AH_Edge* anchor = 0; + int has_serifs = 0; + + + if ( disable_vert_edges && !dimension ) + goto Next_Dimension; + + if ( disable_horz_edges && dimension ) + goto Next_Dimension; + + /* we begin by aligning all stems relative to the blue zone */ + /* if needed -- that's only for horizontal edges */ + if ( dimension ) + { + for ( edge = edges; edge < edge_limit; edge++ ) + { + FT_Pos* blue; + AH_Edge *edge1, *edge2; + + + if ( edge->flags & ah_edge_done ) + continue; + + blue = edge->blue_edge; + edge1 = 0; + edge2 = edge->link; + + if ( blue ) + { + edge1 = edge; + } + else if (edge2 && edge2->blue_edge) + { + blue = edge2->blue_edge; + edge1 = edge2; + edge2 = edge; + } + + if ( !edge1 ) + continue; + + edge1->pos = blue[0]; + edge1->flags |= ah_edge_done; + + if ( edge2 && !edge2->blue_edge ) + { + ah_align_linked_edge( hinter, edge1, edge2, dimension ); + edge2->flags |= ah_edge_done; + } + + if ( !anchor ) + anchor = edge; + } + } + + /* now, we will align all stem edges, trying to maintain the */ + /* relative order of stems in the glyph.. */ + before = 0; + after = 0; + for ( edge = edges; edge < edge_limit; edge++ ) + { + AH_Edge *edge2; + + + if ( edge->flags & ah_edge_done ) + continue; + + /* skip all non-stem edges */ + edge2 = edge->link; + if ( !edge2 ) + { + has_serifs++; + continue; + } + + /* now, align the stem */ + + /* this should not happen, but it's better to be safe.. */ + if ( edge2->blue_edge || edge2 < edge ) + { + +#if 0 + printf( "strange blue alignement, edge %d to %d\n", + edge - edges, edge2 - edges ); +#endif + + ah_align_linked_edge( hinter, edge2, edge, dimension ); + edge->flags |= ah_edge_done; + continue; + } + + { + FT_Bool min = 0; + FT_Pos delta; + + if ( !anchor ) + { + edge->pos = ( edge->opos + 32 ) & -64; + anchor = edge; + } + else + edge->pos = anchor->pos + + ( ( edge->opos - anchor->opos + 32 ) & -64 ); + + edge->flags |= ah_edge_done; + + if ( edge > edges && edge->pos < edge[-1].pos ) + { + edge->pos = edge[-1].pos; + min = 1; + } + + ah_align_linked_edge( hinter, edge, edge2, dimension ); + delta = 0; + if ( edge2 + 1 < edge_limit && + edge2[1].flags & ah_edge_done ) + delta = edge2[1].pos - edge2->pos; + + if ( delta < 0 ) + { + edge2->pos += delta; + if ( !min ) + edge->pos += delta; + } + edge2->flags |= ah_edge_done; + } + } + + if ( !has_serifs ) + goto Next_Dimension; + + /* now, hint the remaining edges (serifs and single) in order */ + /* to complete our processing */ + for ( edge = edges; edge < edge_limit; edge++ ) + { + if ( edge->flags & ah_edge_done ) + continue; + + if ( edge->serif ) + { + ah_align_serif_edge( hinter, edge->serif, edge ); + } + else if ( !anchor ) + { + edge->pos = ( edge->opos + 32 ) & -64; + anchor = edge; + } + else + edge->pos = anchor->pos + + ( ( edge->opos-anchor->opos + 32 ) & -64 ); + + edge->flags |= ah_edge_done; + + if ( edge > edges && edge->pos < edge[-1].pos ) + edge->pos = edge[-1].pos; + + if ( edge + 1 < edge_limit && + edge[1].flags & ah_edge_done && + edge->pos > edge[1].pos ) + edge->pos = edge[1].pos; + } + + Next_Dimension: + edges = outline->vert_edges; + edge_limit = edges + outline->num_vedges; + } + } + + + LOCAL_FUNC + void ah_hinter_hint_edges( AH_Hinter* hinter, + int no_horz_edges, + int no_vert_edges ) + { + disable_horz_edges = no_horz_edges; + disable_vert_edges = no_vert_edges; + + /* AH_Interpolate_Blue_Edges( hinter ); -- doesn't seem to help */ + /* reduce the problem of the disappearing eye in the `e' of Times... */ + /* also, creates some artifacts near the blue zones? */ + { + ah_hint_edges_3( hinter ); + +#if 0 + /* outline optimizer removed temporarily */ + if ( hinter->flags & ah_hinter_optimize ) + { + AH_Optimizer opt; + + + if ( !AH_Optimizer_Init( &opt, hinter->glyph, hinter->memory ) ) + { + AH_Optimizer_Compute( &opt ); + AH_Optimizer_Done( &opt ); + } + } +#endif + + } + } + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** P O I N T H I N T I N G ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + static + void ah_hinter_align_edge_points( AH_Hinter* hinter ) + { + AH_Outline* outline = hinter->glyph; + AH_Edge* edges; + AH_Edge* edge_limit; + FT_Int dimension; + + + edges = outline->horz_edges; + edge_limit = edges + outline->num_hedges; + + for ( dimension = 1; dimension >= 0; dimension-- ) + { + AH_Edge* edge; + AH_Edge* before; + AH_Edge* after; + + + before = 0; + after = 0; + + edge = edges; + for ( ; edge < edge_limit; edge++ ) + { + /* move the points of each segment */ + /* in each edge to the edge's position */ + AH_Segment* seg = edge->first; + + + do + { + AH_Point* point = seg->first; + + + for (;;) + { + if ( dimension ) + { + point->y = edge->pos; + point->flags |= ah_flah_touch_y; + } + else + { + point->x = edge->pos; + point->flags |= ah_flah_touch_x; + } + + if ( point == seg->last ) + break; + + point = point->next; + } + + seg = seg->edge_next; + + } while ( seg != edge->first ); + } + + edges = outline->vert_edges; + edge_limit = edges + outline->num_vedges; + } + } + + + /* hint the strong points -- this is equivalent to the TrueType `IP' */ + static + void ah_hinter_align_strong_points( AH_Hinter* hinter ) + { + AH_Outline* outline = hinter->glyph; + FT_Int dimension; + AH_Edge* edges; + AH_Edge* edge_limit; + AH_Point* points; + AH_Point* point_limit; + AH_Flags touch_flag; + + + points = outline->points; + point_limit = points + outline->num_points; + + edges = outline->horz_edges; + edge_limit = edges + outline->num_hedges; + touch_flag = ah_flah_touch_y; + + for ( dimension = 1; dimension >= 0; dimension-- ) + { + AH_Point* point; + AH_Edge* edge; + AH_Edge* before; + AH_Edge* after; + + + before = 0; + after = 0; + + if ( edges < edge_limit ) + for ( point = points; point < point_limit; point++ ) + { + FT_Pos u, ou, fu; /* point position */ + FT_Pos delta; + + + if ( point->flags & touch_flag ) + continue; + +#ifndef AH_OPTION_NO_WEAK_INTERPOLATION + /* if this point is candidate to weak interpolation, we will */ + /* interpolate it after all strong points have been processed */ + if ( point->flags & ah_flah_weak_interpolation ) + continue; +#endif + + if ( dimension ) + { + u = point->fy; + ou = point->oy; + } + else + { + u = point->fx; + ou = point->ox; + } + + fu = u; + + /* is the point before the first edge? */ + edge = edges; + delta = edge->fpos - u; + if ( delta >= 0 ) + { + u = edge->pos - ( edge->opos - ou ); + goto Store_Point; + } + + /* is the point after the last edge ? */ + edge = edge_limit - 1; + delta = u - edge->fpos; + if ( delta >= 0 ) + { + u = edge->pos + ( ou - edge->opos ); + goto Store_Point; + } + + /* otherwise, interpolate the point in between */ + { + AH_Edge* before = 0; + AH_Edge* after = 0; + + + for ( edge = edges; edge < edge_limit; edge++ ) + { + if ( u == edge->fpos ) + { + u = edge->pos; + goto Store_Point; + } + if ( u < edge->fpos ) + break; + before = edge; + } + + for ( edge = edge_limit - 1; edge >= edges; edge-- ) + { + if ( u == edge->fpos ) + { + u = edge->pos; + goto Store_Point; + } + if ( u > edge->fpos ) + break; + after = edge; + } + + /* assert( before && after && before != after ) */ + u = before->pos + FT_MulDiv( fu - before->fpos, + after->pos - before->pos, + after->fpos - before->fpos ); + } + + Store_Point: + + /* save the point position */ + if ( dimension ) + point->y = u; + else + point->x = u; + + point->flags |= touch_flag; + } + + edges = outline->vert_edges; + edge_limit = edges + outline->num_vedges; + touch_flag = ah_flah_touch_x; + } + } + + +#ifndef AH_OPTION_NO_WEAK_INTERPOLATION + + static + void ah_iup_shift( AH_Point* p1, + AH_Point* p2, + AH_Point* ref ) + { + AH_Point* p; + FT_Pos delta = ref->u - ref->v; + + + for ( p = p1; p < ref; p++ ) + p->u = p->v + delta; + + for ( p = ref + 1; p <= p2; p++ ) + p->u = p->v + delta; + } + + + static + void ah_iup_interp( AH_Point* p1, + AH_Point* p2, + AH_Point* ref1, + AH_Point* ref2 ) + { + AH_Point* p; + FT_Pos u; + FT_Pos v1 = ref1->v; + FT_Pos v2 = ref2->v; + FT_Pos d1 = ref1->u - v1; + FT_Pos d2 = ref2->u - v2; + + + if ( p1 > p2 ) + return; + + if ( v1 == v2 ) + { + for ( p = p1; p <= p2; p++ ) + { + FT_Pos u = p->v; + + + if ( u <= v1 ) + u += d1; + else + u += d2; + + p->u = u; + } + return; + } + + if ( v1 < v2 ) + { + for ( p = p1; p <= p2; p++ ) + { + u = p->v; + + if ( u <= v1 ) + u += d1; + else if ( u >= v2 ) + u += d2; + else + u = ref1->u + FT_MulDiv( u - v1, ref2->u - ref1->u, v2 - v1 ); + + p->u = u; + } + } + else + { + for ( p = p1; p <= p2; p++ ) + { + u = p->v; + + if ( u <= v2 ) + u += d2; + else if ( u >= v1 ) + u += d1; + else + u = ref1->u + FT_MulDiv( u - v1, ref2->u - ref1->u, v2 - v1 ); + + p->u = u; + } + } + } + + + /* interpolate weak points -- this is equivalent to the TrueType `IUP' */ + static + void ah_hinter_align_weak_points( AH_Hinter* hinter ) + { + AH_Outline* outline = hinter->glyph; + FT_Int dimension; + AH_Edge* edges; + AH_Edge* edge_limit; + AH_Point* points; + AH_Point* point_limit; + AH_Point** contour_limit; + AH_Flags touch_flag; + + + points = outline->points; + point_limit = points + outline->num_points; + + /* PASS 1: Move segment points to edge positions */ + + edges = outline->horz_edges; + edge_limit = edges + outline->num_hedges; + touch_flag = ah_flah_touch_y; + + contour_limit = outline->contours + outline->num_contours; + + ah_setup_uv( outline, ah_uv_oy ); + + for ( dimension = 1; dimension >= 0; dimension-- ) + { + AH_Point* point; + AH_Point* end_point; + AH_Point* first_point; + AH_Point** contour; + + + point = points; + contour = outline->contours; + + for ( ; contour < contour_limit; contour++ ) + { + point = *contour; + end_point = point->prev; + first_point = point; + + while ( point <= end_point && !( point->flags & touch_flag ) ) + point++; + + if ( point <= end_point ) + { + AH_Point* first_touched = point; + AH_Point* cur_touched = point; + + + point++; + while ( point <= end_point ) + { + if ( point->flags & touch_flag ) + { + /* we found two successive touched points; we interpolate */ + /* all contour points between them */ + ah_iup_interp( cur_touched + 1, point - 1, + cur_touched, point ); + cur_touched = point; + } + point++; + } + + if ( cur_touched == first_touched ) + { + /* this is a special case: only one point was touched in the */ + /* contour; we thus simply shift the whole contour */ + ah_iup_shift( first_point, end_point, cur_touched ); + } + else + { + /* now interpolate after the last touched point to the end */ + /* of the contour */ + ah_iup_interp( cur_touched + 1, end_point, + cur_touched, first_touched ); + + /* if the first contour point isn't touched, interpolate */ + /* from the contour start to the first touched point */ + if ( first_touched > points ) + ah_iup_interp( first_point, first_touched - 1, + cur_touched, first_touched ); + } + } + } + + /* now save the interpolated values back to x/y */ + if ( dimension ) + { + for ( point = points; point < point_limit; point++ ) + point->y = point->u; + + touch_flag = ah_flah_touch_x; + ah_setup_uv( outline, ah_uv_ox ); + } + else + { + for ( point = points; point < point_limit; point++ ) + point->x = point->u; + + break; /* exit loop */ + } + } + } + +#endif /* !AH_OPTION_NO_WEAK_INTERPOLATION */ + + + LOCAL_FUNC + void ah_hinter_align_points( AH_Hinter* hinter ) + { + ah_hinter_align_edge_points( hinter ); + +#ifndef AH_OPTION_NO_STRONG_INTERPOLATION + ah_hinter_align_strong_points( hinter ); +#endif + +#ifndef AH_OPTION_NO_WEAK_INTERPOLATION + ah_hinter_align_weak_points( hinter ); +#endif + } + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** H I N T E R O B J E C T M E T H O D S ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /* scale and fit the global metrics */ + static + void ah_hinter_scale_globals( AH_Hinter* hinter, + FT_Fixed x_scale, + FT_Fixed y_scale ) + { + FT_Int n; + AH_Face_Globals* globals = hinter->globals; + AH_Globals* design = &globals->design; + AH_Globals* scaled = &globals->scaled; + + + /* copy content */ + *scaled = *design; + + /* scale the standard widths & heights */ + for ( n = 0; n < design->num_widths; n++ ) + scaled->widths[n] = FT_MulFix( design->widths[n], x_scale ); + + for ( n = 0; n < design->num_heights; n++ ) + scaled->heights[n] = FT_MulFix( design->heights[n], y_scale ); + + /* scale the blue zones */ + for ( n = 0; n < ah_blue_max; n++ ) + { + FT_Pos delta, delta2; + + + delta = design->blue_shoots[n] - design->blue_refs[n]; + delta2 = delta; + if ( delta < 0 ) + delta2 = -delta2; + delta2 = FT_MulFix( delta2, y_scale ); + + if ( delta2 < 32 ) + delta2 = 0; + else if ( delta2 < 64 ) + delta2 = 32 + ( ( ( delta2 - 32 ) + 16 ) & -32 ); + else + delta2 = ( delta2 + 32 ) & -64; + + if ( delta < 0 ) + delta2 = -delta2; + + scaled->blue_refs[n] = + ( FT_MulFix( design->blue_refs[n], y_scale ) + 32 ) & -64; + scaled->blue_shoots[n] = scaled->blue_refs[n] + delta2; + } + + globals->x_scale = x_scale; + globals->y_scale = y_scale; + } + + + static + void ah_hinter_align( AH_Hinter* hinter ) + { + ah_hinter_align_edge_points( hinter ); + ah_hinter_align_points( hinter ); + } + + + /* finalize a hinter object */ + void ah_hinter_done( AH_Hinter* hinter ) + { + if ( hinter ) + { + FT_Memory memory = hinter->memory; + + + ah_loader_done( hinter->loader ); + ah_outline_done( hinter->glyph ); + + /* note: the `globals' pointer is _not_ owned by the hinter */ + /* but by the current face object, we don't need to */ + /* release it */ + hinter->globals = 0; + hinter->face = 0; + + FREE( hinter ); + } + } + + + /* create a new empty hinter object */ + FT_Error ah_hinter_new( FT_Library library, + AH_Hinter** ahinter ) + { + AH_Hinter* hinter = 0; + FT_Memory memory = library->memory; + FT_Error error; + + + *ahinter = 0; + + /* allocate object */ + if ( ALLOC( hinter, sizeof ( *hinter ) ) ) + goto Exit; + + hinter->memory = memory; + hinter->flags = 0; + + /* allocate outline and loader */ + error = ah_outline_new( memory, &hinter->glyph ) || + ah_loader_new ( memory, &hinter->loader ) || + ah_loader_create_extra( hinter->loader ); + if ( error ) + goto Exit; + + *ahinter = hinter; + + Exit: + if ( error ) + ah_hinter_done( hinter ); + + return error; + } + + + /* create a face's autohint globals */ + FT_Error ah_hinter_new_face_globals( AH_Hinter* hinter, + FT_Face face, + AH_Globals* globals ) + { + FT_Error error; + FT_Memory memory = hinter->memory; + AH_Face_Globals* face_globals; + + + if ( ALLOC( face_globals, sizeof ( *face_globals ) ) ) + goto Exit; + + hinter->face = face; + hinter->globals = face_globals; + + if ( globals ) + face_globals->design = *globals; + else + ah_hinter_compute_globals( hinter ); + + face->autohint.data = face_globals; + face->autohint.finalizer = (FT_Generic_Finalizer) + ah_hinter_done_face_globals; + face_globals->face = face; + + Exit: + return error; + } + + + /* discard a face's autohint globals */ + void ah_hinter_done_face_globals( AH_Face_Globals* globals ) + { + FT_Face face = globals->face; + FT_Memory memory = face->memory; + + + FREE( globals ); + } + + + static + FT_Error ah_hinter_load( AH_Hinter* hinter, + FT_UInt glyph_index, + FT_UInt load_flags, + FT_UInt depth ) + { + FT_Face face = hinter->face; + FT_GlyphSlot slot = face->glyph; + FT_Fixed x_scale = face->size->metrics.x_scale; + FT_Fixed y_scale = face->size->metrics.y_scale; + FT_Glyph_Metrics metrics; /* temporary metrics */ + FT_Error error; + AH_Outline* outline = hinter->glyph; + AH_Loader* gloader = hinter->loader; + FT_Bool no_horz_hints = + ( load_flags & AH_HINT_NO_HORZ_EDGES ) != 0; + FT_Bool no_vert_hints = + ( load_flags & AH_HINT_NO_VERT_EDGES ) != 0; + + + /* load the glyph */ + error = FT_Load_Glyph( face, glyph_index, load_flags ); + if ( error ) + goto Exit; + + /* save current glyph metrics */ + metrics = slot->metrics; + + switch ( slot->format ) + { + case ft_glyph_format_outline: + /* first of all, copy the outline points in the loader's current */ + /* extra points, which is used to keep original glyph coordinates */ + error = ah_loader_check_points( gloader, slot->outline.n_points + 2, + slot->outline.n_contours ); + if ( error ) + goto Exit; + + MEM_Copy( gloader->current.extra_points, slot->outline.points, + slot->outline.n_points * sizeof ( FT_Vector ) ); + + MEM_Copy( gloader->current.outline.contours, slot->outline.contours, + slot->outline.n_contours * sizeof ( short ) ); + + MEM_Copy( gloader->current.outline.tags, slot->outline.tags, + slot->outline.n_points * sizeof ( char ) ); + + gloader->current.outline.n_points = slot->outline.n_points; + gloader->current.outline.n_contours = slot->outline.n_contours; + + /* compute original phantom points */ + hinter->pp1.x = 0; + hinter->pp1.y = 0; + hinter->pp2.x = FT_MulFix( slot->metrics.horiAdvance, x_scale ); + hinter->pp2.y = 0; + + /* be sure to check for spacing glyphs */ + if ( slot->outline.n_points == 0 ) + goto Hint_Metrics; + + /* now, load the slot image into the auto-outline, and run the */ + /* automatic hinting process */ + error = ah_outline_load( outline, face ); /* XXX: change to slot */ + if ( error ) + goto Exit; + + /* perform feature detection */ + ah_outline_detect_features( outline ); + + if ( !no_horz_hints ) + { + ah_outline_compute_blue_edges( outline, hinter->globals ); + ah_outline_scale_blue_edges( outline, hinter->globals ); + } + + /* perform alignment control */ + ah_hinter_hint_edges( hinter, no_horz_hints, no_vert_hints ); + ah_hinter_align( hinter ); + + /* now save the current outline into the loader's current table */ + ah_outline_save( outline, gloader ); + + /* we now need to hint the metrics according to the change in */ + /* width/positioning that occured during the hinting process */ + { + FT_Pos old_width, new_width; + FT_Pos old_advance, new_advance; + FT_Pos old_lsb, new_lsb; + AH_Edge* edge1 = outline->vert_edges; /* leftmost edge */ + AH_Edge* edge2 = edge1 + + outline->num_vedges - 1; /* rightmost edge */ + + + old_width = edge2->opos - edge1->opos; + new_width = edge2->pos - edge1->pos; + + old_advance = hinter->pp2.x; + old_lsb = edge1->opos; + new_lsb = edge1->pos; + + new_advance = old_advance + + ( new_width + new_lsb - old_width - old_lsb ); + + hinter->pp1.x = ( ( new_lsb - old_lsb ) + 32 ) & -64; + hinter->pp2.x = ( ( edge2->pos + + ( old_advance - edge2->opos ) ) + 32 ) & -64; + } + + /* good, we simply add the glyph to our loader's base */ + ah_loader_add( gloader ); + break; + + case ft_glyph_format_composite: + { + FT_UInt nn, num_subglyphs = slot->num_subglyphs; + FT_UInt num_base_subgs, start_point, start_contour; + FT_SubGlyph* subglyph; + + + start_point = gloader->base.outline.n_points; + start_contour = gloader->base.outline.n_contours; + + /* first of all, copy the subglyph descriptors in the glyph loader */ + error = ah_loader_check_subglyphs( gloader, num_subglyphs ); + if ( error ) + goto Exit; + + MEM_Copy( gloader->current.subglyphs, slot->subglyphs, + num_subglyphs * sizeof ( FT_SubGlyph ) ); + + gloader->current.num_subglyphs = num_subglyphs; + num_base_subgs = gloader->base.num_subglyphs; + + /* now, read each subglyph independently */ + for ( nn = 0; nn < num_subglyphs; nn++ ) + { + FT_Vector pp1, pp2; + FT_Pos x, y; + FT_UInt num_points, num_new_points, num_base_points; + + + /* gloader.current.subglyphs can change during glyph loading due */ + /* to re-allocation -- we must recompute the current subglyph on */ + /* each iteration */ + subglyph = gloader->base.subglyphs + num_base_subgs + nn; + + pp1 = hinter->pp1; + pp2 = hinter->pp2; + + num_base_points = gloader->base.outline.n_points; + + error = ah_hinter_load( hinter, subglyph->index, + load_flags, depth + 1 ); + if ( error ) + goto Exit; + + /* recompute subglyph pointer */ + subglyph = gloader->base.subglyphs + num_base_subgs + nn; + + if ( subglyph->flags & FT_SUBGLYPH_FLAG_USE_MY_METRICS ) + { + pp1 = hinter->pp1; + pp2 = hinter->pp2; + } + else + { + hinter->pp1 = pp1; + hinter->pp2 = pp2; + } + + num_points = gloader->base.outline.n_points; + num_new_points = num_points - num_base_points; + + /* now perform the transform required for this subglyph */ + + if ( subglyph->flags & ( FT_SUBGLYPH_FLAG_SCALE | + FT_SUBGLYPH_FLAG_XY_SCALE | + FT_SUBGLYPH_FLAG_2X2 ) ) + { + FT_Vector* cur = gloader->base.outline.points + + num_base_points; + FT_Vector* org = gloader->base.extra_points + + num_base_points; + FT_Vector* limit = cur + num_new_points; + + + for ( ; cur < limit; cur++, org++ ) + { + FT_Vector_Transform( cur, &subglyph->transform ); + FT_Vector_Transform( org, &subglyph->transform ); + } + } + + /* apply offset */ + + if ( !( subglyph->flags & FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES ) ) + { + FT_Int k = subglyph->arg1; + FT_UInt l = subglyph->arg2; + FT_Vector* p1; + FT_Vector* p2; + + + if ( start_point + k >= num_base_points || + l >= (FT_UInt)num_new_points ) + { + error = FT_Err_Invalid_Composite; + goto Exit; + } + + l += num_base_points; + + /* for now, only use the current point coordinates */ + /* we may consider another approach in the near future */ + p1 = gloader->base.outline.points + start_point + k; + p2 = gloader->base.outline.points + start_point + l; + + x = p1->x - p2->x; + y = p1->y - p2->y; + } + else + { + x = FT_MulFix( subglyph->arg1, x_scale ); + y = FT_MulFix( subglyph->arg2, y_scale ); + + x = ( x + 32 ) & -64; + y = ( y + 32 ) & -64; + } + + { + FT_Outline dummy = gloader->base.outline; + + + dummy.points += num_base_points; + dummy.n_points = num_new_points; + + FT_Outline_Translate( &dummy, x, y ); + } + } + } + break; + + default: + /* we don't support other formats (yet?) */ + error = FT_Err_Unimplemented_Feature; + } + + Hint_Metrics: + if ( depth == 0 ) + { + FT_BBox bbox; + + + /* we must translate our final outline by -pp1.x, and compute */ + /* the new metrics */ + if ( hinter->pp1.x ) + FT_Outline_Translate( &gloader->base.outline, -hinter->pp1.x, 0 ); + + FT_Outline_Get_CBox( &gloader->base.outline, &bbox ); + bbox.xMin &= -64; + bbox.yMin &= -64; + bbox.xMax = ( bbox.xMax + 63 ) & -64; + bbox.yMax = ( bbox.yMax + 63 ) & -64; + + slot->metrics.width = bbox.xMax - bbox.xMin; + slot->metrics.height = bbox.yMax - bbox.yMin; + slot->metrics.horiBearingX = bbox.xMin; + slot->metrics.horiBearingY = bbox.yMax; + slot->metrics.horiAdvance = hinter->pp2.x - hinter->pp1.x; + /* XXX: TO DO - slot->linearHoriAdvance */ + + /* now copy outline into glyph slot */ + ah_loader_rewind( slot->loader ); + error = ah_loader_copy_points( slot->loader, gloader ); + if ( error ) + goto Exit; + + slot->outline = slot->loader->base.outline; + slot->format = ft_glyph_format_outline; + } + + Exit: + return error; + } + + + /* load and hint a given glyph */ + FT_Error ah_hinter_load_glyph( AH_Hinter* hinter, + FT_GlyphSlot slot, + FT_Size size, + FT_UInt glyph_index, + FT_Int load_flags ) + { + FT_Face face = slot->face; + FT_Error error; + FT_Fixed x_scale = size->metrics.x_scale; + FT_Fixed y_scale = size->metrics.y_scale; + AH_Face_Globals* face_globals = FACE_GLOBALS( face ); + + + /* first of all, we need to check that we're using the correct face and */ + /* global hints to load the glyph */ + if ( hinter->face != face || hinter->globals != face_globals ) + { + hinter->face = face; + if ( !face_globals ) + { + error = ah_hinter_new_face_globals( hinter, face, 0 ); + if ( error ) + goto Exit; + } + hinter->globals = FACE_GLOBALS( face ); + face_globals = FACE_GLOBALS( face ); + } + + /* now, we must check the current character pixel size to see if we */ + /* need to rescale the global metrics */ + if ( face_globals->x_scale != x_scale || + face_globals->y_scale != y_scale ) + ah_hinter_scale_globals( hinter, x_scale, y_scale ); + + load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_RECURSE; + + ah_loader_rewind( hinter->loader ); + + error = ah_hinter_load( hinter, glyph_index, load_flags, 0 ); + + Exit: + return error; + } + + + /* retrieve a face's autohint globals for client applications */ + void ah_hinter_get_global_hints( AH_Hinter* hinter, + FT_Face face, + void** global_hints, + long* global_len ) + { + AH_Globals* globals = 0; + FT_Memory memory = hinter->memory; + FT_Error error; + + + /* allocate new master globals */ + if ( ALLOC( globals, sizeof ( *globals ) ) ) + goto Fail; + + /* compute face globals if needed */ + if ( !FACE_GLOBALS( face ) ) + { + error = ah_hinter_new_face_globals( hinter, face, 0 ); + if ( error ) + goto Fail; + } + + *globals = FACE_GLOBALS( face )->design; + *global_hints = globals; + *global_len = sizeof( *globals ); + + return; + + Fail: + FREE( globals ); + + *global_hints = 0; + *global_len = 0; + } + + + void ah_hinter_done_global_hints( AH_Hinter* hinter, + void* global_hints ) + { + FT_Memory memory = hinter->memory; + + + FREE( global_hints ); + } + + +/* END */ diff --git a/src/freetype/autohint/ahhint.h b/src/freetype/autohint/ahhint.h new file mode 100644 index 0000000000..bb297fb80f --- /dev/null +++ b/src/freetype/autohint/ahhint.h @@ -0,0 +1,72 @@ +/***************************************************************************/ +/* */ +/* ahhint.h */ +/* */ +/* Glyph hinter (declaration). */ +/* */ +/* Copyright 2000 Catharon Productions Inc. */ +/* Author: David Turner */ +/* */ +/* This file is part of the Catharon Typography Project and shall only */ +/* be used, modified, and distributed under the terms of the Catharon */ +/* Open Source License that should come with this file under the name */ +/* `CatharonLicense.txt'. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/* Note that this license is compatible with the FreeType license. */ +/* */ +/***************************************************************************/ + + +#ifndef AHHINT_H +#define AHHINT_H + + +#ifdef FT_FLAT_COMPILE + +#include "ahglobal.h" + +#else + +#include + +#endif + + +#define AH_HINT_DEFAULT 0 +#define AH_HINT_NO_ALIGNMENT 1 +#define AH_HINT_NO_HORZ_EDGES 0x20000L +#define AH_HINT_NO_VERT_EDGES 0x40000L + + + /* create a new empty hinter object */ + FT_Error ah_hinter_new( FT_Library library, + AH_Hinter** ahinter ); + + /* Load a hinted glyph in the hinter */ + FT_Error ah_hinter_load_glyph( AH_Hinter* hinter, + FT_GlyphSlot slot, + FT_Size size, + FT_UInt glyph_index, + FT_Int load_flags ); + + /* finalize a hinter object */ + void ah_hinter_done( AH_Hinter* hinter ); + + LOCAL_DEF + void ah_hinter_done_face_globals( AH_Face_Globals* globals ); + + void ah_hinter_get_global_hints( AH_Hinter* hinter, + FT_Face face, + void** global_hints, + long* global_len ); + + void ah_hinter_done_global_hints( AH_Hinter* hinter, + void* global_hints ); + + +#endif /* AHHINT_H */ + + +/* END */ diff --git a/src/freetype/autohint/ahloader.h b/src/freetype/autohint/ahloader.h new file mode 100644 index 0000000000..4a8563c0aa --- /dev/null +++ b/src/freetype/autohint/ahloader.h @@ -0,0 +1,124 @@ +/***************************************************************************/ +/* */ +/* ahloader.h */ +/* */ +/* Glyph loader for the auto-hinting module (declaration only). */ +/* */ +/* Copyright 2000 Catharon Productions Inc. */ +/* Author: David Turner */ +/* */ +/* This file is part of the Catharon Typography Project and shall only */ +/* be used, modified, and distributed under the terms of the Catharon */ +/* Open Source License that should come with this file under the name */ +/* `CatharonLicense.txt'. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/* Note that this license is compatible with the FreeType license. */ +/* */ +/***************************************************************************/ + + + /*************************************************************************/ + /* */ + /* This defines the AH_GlyphLoader type in two different ways: */ + /* */ + /* - If the module is compiled within FreeType 2, the type is simply a */ + /* typedef to FT_GlyphLoader. */ + /* */ + /* - If the module is compiled as a standalone object, AH_GlyphLoader */ + /* has its own implementation. */ + /* */ + /*************************************************************************/ + + +#ifndef AHLOADER_H +#define AHLOADER_H + + +#ifdef _STANDALONE_ + + typedef struct AH_GlyphLoad_ + { + FT_Outline outline; /* outline */ + FT_UInt num_subglyphs; /* number of subglyphs */ + FT_SubGlyph* subglyphs; /* subglyphs */ + FT_Vector* extra_points; /* extra points table */ + + } AH_GlyphLoad; + + + struct AH_GlyphLoader_ + { + FT_Memory memory; + FT_UInt max_points; + FT_UInt max_contours; + FT_UInt max_subglyphs; + FT_Bool use_extra; + + AH_GlyphLoad base; + AH_GlyphLoad current; + + void* other; /* for possible future extensions */ + }; + + + LOCAL_DEF + FT_Error AH_GlyphLoader_New( FT_Memory memory, + AH_GlyphLoader** aloader ); + + LOCAL_DEF + FT_Error AH_GlyphLoader_Create_Extra( AH_GlyphLoader* loader ); + + LOCAL_DEF + void AH_GlyphLoader_Done( AH_GlyphLoader* loader ); + + LOCAL_DEF + void AH_GlyphLoader_Reset( AH_GlyphLoader* loader ); + + LOCAL_DEF + void AH_GlyphLoader_Rewind( AH_GlyphLoader* loader ); + + LOCAL_DEF + FT_Error AH_GlyphLoader_Check_Points( AH_GlyphLoader* loader, + FT_UInt n_points, + FT_UInt n_contours ); + + LOCAL_DEF + FT_Error AH_GlyphLoader_Check_Subglyphs( AH_GlyphLoader* loader, + FT_UInt n_subs ); + + LOCAL_DEF + void AH_GlyphLoader_Prepare( AH_GlyphLoader* loader ); + + LOCAL_DEF + void AH_GlyphLoader_Add( AH_GlyphLoader* loader ); + + LOCAL_DEF + FT_Error AH_GlyphLoader_Copy_Points( AH_GlyphLoader* target, + FT_GlyphLoader* source ); + +#else /* _STANDALONE */ + +#include + + #define AH_Load FT_GlyphLoad + #define AH_Loader FT_GlyphLoader + + #define ah_loader_new FT_GlyphLoader_New + #define ah_loader_done FT_GlyphLoader_Done + #define ah_loader_reset FT_GlyphLoader_Reset + #define ah_loader_rewind FT_GlyphLoader_Rewind + #define ah_loader_create_extra FT_GlyphLoader_Create_Extra + #define ah_loader_check_points FT_GlyphLoader_Check_Points + #define ah_loader_check_subglyphs FT_GlyphLoader_Check_Subglyphs + #define ah_loader_prepare FT_GlyphLoader_Prepare + #define ah_loader_add FT_GlyphLoader_Add + #define ah_loader_copy_points FT_GlyphLoader_Copy_Points + +#endif /* _STANDALONE_ */ + +#endif /* AHLOADER_H */ + + +/* END */ diff --git a/src/freetype/autohint/ahmodule.c b/src/freetype/autohint/ahmodule.c new file mode 100644 index 0000000000..85755681ee --- /dev/null +++ b/src/freetype/autohint/ahmodule.c @@ -0,0 +1,127 @@ +/***************************************************************************/ +/* */ +/* ahmodule.c */ +/* */ +/* Auto-hinting module implementation (declaration). */ +/* */ +/* Copyright 2000 Catharon Productions Inc. */ +/* Author: David Turner */ +/* */ +/* This file is part of the Catharon Typography Project and shall only */ +/* be used, modified, and distributed under the terms of the Catharon */ +/* Open Source License that should come with this file under the name */ +/* `CatharonLicense.txt'. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/* Note that this license is compatible with the FreeType license. */ +/* */ +/***************************************************************************/ + + +#include + + +#ifdef FT_FLAT_COMPILE + +#include "ahhint.h" + +#else + +#include + +#endif + + + typedef struct FT_AutoHinterRec_ + { + FT_ModuleRec root; + AH_Hinter* hinter; + + } FT_AutoHinterRec; + + + static + FT_Error ft_autohinter_init( FT_AutoHinter module ) + { + return ah_hinter_new( module->root.library, &module->hinter ); + } + + + static + void ft_autohinter_done( FT_AutoHinter module ) + { + ah_hinter_done( module->hinter ); + } + + + static + FT_Error ft_autohinter_load( FT_AutoHinter module, + FT_GlyphSlot slot, + FT_Size size, + FT_UInt glyph_index, + FT_ULong load_flags ) + { + return ah_hinter_load_glyph( module->hinter, + slot, size, glyph_index, load_flags ); + } + + + static + void ft_autohinter_reset( FT_AutoHinter module, + FT_Face face ) + { + UNUSED( module ); + + if ( face->autohint.data ) + ah_hinter_done_face_globals( (AH_Face_Globals*)(face->autohint.data) ); + } + + + static + void ft_autohinter_get_globals( FT_AutoHinter module, + FT_Face face, + void** global_hints, + long* global_len ) + { + ah_hinter_get_global_hints( module->hinter, face, + global_hints, global_len ); + } + + + static + void ft_autohinter_done_globals( FT_AutoHinter module, + void* global_hints ) + { + ah_hinter_done_global_hints( module->hinter, global_hints ); + } + + + static + const FT_AutoHinter_Interface autohinter_interface = + { + ft_autohinter_reset, + ft_autohinter_load, + ft_autohinter_get_globals, + ft_autohinter_done_globals + }; + + + const FT_Module_Class autohint_module_class = + { + ft_module_hinter, + sizeof ( FT_AutoHinterRec ), + + "autohinter", + 0x10000L, /* version 1.0 of the autohinter */ + 0x20000L, /* requires FreeType 2.0 or above */ + + (const void*)&autohinter_interface, + + (FT_Module_Constructor)ft_autohinter_init, + (FT_Module_Destructor) ft_autohinter_done, + (FT_Module_Requester) 0 + }; + + +/* END */ diff --git a/src/freetype/autohint/ahmodule.h b/src/freetype/autohint/ahmodule.h new file mode 100644 index 0000000000..28b07538bc --- /dev/null +++ b/src/freetype/autohint/ahmodule.h @@ -0,0 +1,32 @@ +/***************************************************************************/ +/* */ +/* ahmodule.h */ +/* */ +/* Auto-hinting module (declaration). */ +/* */ +/* Copyright 2000 Catharon Productions Inc. */ +/* Author: David Turner */ +/* */ +/* This file is part of the Catharon Typography Project and shall only */ +/* be used, modified, and distributed under the terms of the Catharon */ +/* Open Source License that should come with this file under the name */ +/* `CatharonLicense.txt'. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/* Note that this license is compatible with the FreeType license. */ +/* */ +/***************************************************************************/ + + +#ifndef AHMODULE_H +#define AHMODULE_H + +#include + + FT_EXPORT_VAR( const FT_Module_Class ) autohint_module_class; + +#endif /* AHMODULE_H */ + + +/* END */ diff --git a/src/freetype/autohint/ahoptim.c b/src/freetype/autohint/ahoptim.c new file mode 100644 index 0000000000..d301dd7eee --- /dev/null +++ b/src/freetype/autohint/ahoptim.c @@ -0,0 +1,889 @@ +/***************************************************************************/ +/* */ +/* ahoptim.c */ +/* */ +/* FreeType auto hinting outline optimization (body). */ +/* */ +/* Copyright 2000 Catharon Productions Inc. */ +/* Author: David Turner */ +/* */ +/* This file is part of the Catharon Typography Project and shall only */ +/* be used, modified, and distributed under the terms of the Catharon */ +/* Open Source License that should come with this file under the name */ +/* `CatharonLicense.txt'. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/* Note that this license is compatible with the FreeType license. */ +/* */ +/***************************************************************************/ + + + /*************************************************************************/ + /* */ + /* This module is in charge of optimising the outlines produced by the */ + /* auto-hinter in direct mode. This is required at small pixel sizes in */ + /* order to ensure coherent spacing, among other things.. */ + /* */ + /* The technique used in this module is a simplified simulated */ + /* annealing. */ + /* */ + /*************************************************************************/ + + +#include /* for ALLOC_ARRAY() and FREE() */ + + +#ifdef FT_FLAT_COMPILE + +#include "ahoptim.h" + +#else + +#include + +#endif + + + /* define this macro to use brute force optimisation -- this is slow, */ + /* but a good way to perfect the distortion function `by hand' through */ + /* tweaking */ +#define AH_BRUTE_FORCE + + +#define xxxAH_DEBUG_OPTIM + + +#undef LOG +#ifdef AH_DEBUG_OPTIM + +#define LOG( x ) optim_log##x + +#else + +#define LOG( x ) + +#endif /* AH_DEBUG_OPTIM */ + + +#ifdef AH_DEBUG_OPTIM + +#include +#include +#include + +#define FLOAT( x ) ( (float)( (x) / 64.0 ) ) + + static + void optim_log( const char* fmt, ... ) + { + va_list ap; + + + va_start( ap, fmt ); + vprintf( fmt, ap ); + va_end( ap ); + } + + + static + void AH_Dump_Stems( AH_Optimizer* optimizer ) + { + int n; + AH_Stem* stem; + + + stem = optimizer->stems; + for ( n = 0; n < optimizer->num_stems; n++, stem++ ) + { + LOG(( " %c%2d [%.1f:%.1f]={%.1f:%.1f}=" + "<%1.f..%1.f> force=%.1f speed=%.1f\n", + optimizer->vertical ? 'V' : 'H', n, + FLOAT( stem->edge1->opos ), FLOAT( stem->edge2->opos ), + FLOAT( stem->edge1->pos ), FLOAT( stem->edge2->pos ), + FLOAT( stem->min_pos ), FLOAT( stem->max_pos ), + FLOAT( stem->force ), FLOAT( stem->velocity ) )); + } + } + + + static + void AH_Dump_Stems2( AH_Optimizer* optimizer ) + { + int n; + AH_Stem* stem; + + + stem = optimizer->stems; + for ( n = 0; n < optimizer->num_stems; n++, stem++ ) + { + LOG(( " %c%2d [%.1f]=<%1.f..%1.f> force=%.1f speed=%.1f\n", + optimizer->vertical ? 'V' : 'H', n, + FLOAT( stem->pos ), + FLOAT( stem->min_pos ), FLOAT( stem->max_pos ), + FLOAT( stem->force ), FLOAT( stem->velocity ) )); + } + } + + + static + void AH_Dump_Springs( AH_Optimizer* optimizer ) + { + int n; + AH_Spring* spring; + AH_Stem* stems; + + + spring = optimizer->springs; + stems = optimizer->stems; + LOG(( "%cSprings ", optimizer->vertical ? 'V' : 'H' )); + + for ( n = 0; n < optimizer->num_springs; n++, spring++ ) + { + LOG(( " [%d-%d:%.1f:%1.f:%.1f]", + spring->stem1 - stems, spring->stem2 - stems, + FLOAT( spring->owidth ), + FLOAT( spring->stem2->pos - + ( spring->stem1->pos + spring->stem1->width ) ), + FLOAT( spring->tension ) )); + } + + LOG(( "\n" )); + } + +#endif /* AH_DEBUG_OPTIM */ + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** COMPUTE STEMS AND SPRINGS IN AN OUTLINE ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + static + int valid_stem_segments( AH_Segment* seg1, + AH_Segment* seg2 ) + { + return seg1->serif == 0 && + seg2 && + seg2->link == seg1 && + seg1->pos < seg2->pos && + seg1->min_coord <= seg2->max_coord && + seg2->min_coord <= seg1->max_coord; + } + + + /* compute all stems in an outline */ + static + int optim_compute_stems( AH_Optimizer* optimizer ) + { + AH_Outline* outline = optimizer->outline; + FT_Fixed scale; + FT_Memory memory = optimizer->memory; + FT_Error error = 0; + FT_Int dimension; + AH_Edge* edges; + AH_Edge* edge_limit; + AH_Stem** p_stems; + FT_Int* p_num_stems; + + + edges = outline->horz_edges; + edge_limit = edges + outline->num_hedges; + scale = outline->y_scale; + + p_stems = &optimizer->horz_stems; + p_num_stems = &optimizer->num_hstems; + + for ( dimension = 1; dimension >= 0; dimension-- ) + { + AH_Stem* stems = 0; + FT_Int num_stems = 0; + AH_Edge* edge; + + + /* first of all, count the number of stems in this direction */ + for ( edge = edges; edge < edge_limit; edge++ ) + { + AH_Segment* seg = edge->first; + + + do + { + if (valid_stem_segments( seg, seg->link ) ) + num_stems++; + + seg = seg->edge_next; + + } while ( seg != edge->first ); + } + + /* now allocate the stems and build their table */ + if ( num_stems > 0 ) + { + AH_Stem* stem; + + + if ( ALLOC_ARRAY( stems, num_stems, AH_Stem ) ) + goto Exit; + + stem = stems; + for ( edge = edges; edge < edge_limit; edge++ ) + { + AH_Segment* seg = edge->first; + AH_Segment* seg2; + + + do + { + seg2 = seg->link; + if ( valid_stem_segments( seg, seg2 ) ) + { + AH_Edge* edge1 = seg->edge; + AH_Edge* edge2 = seg2->edge; + + + stem->edge1 = edge1; + stem->edge2 = edge2; + stem->opos = edge1->opos; + stem->pos = edge1->pos; + stem->owidth = edge2->opos - edge1->opos; + stem->width = edge2->pos - edge1->pos; + + /* compute min_coord and max_coord */ + { + FT_Pos min_coord = seg->min_coord; + FT_Pos max_coord = seg->max_coord; + + + if ( seg2->min_coord > min_coord ) + min_coord = seg2->min_coord; + + if ( seg2->max_coord < max_coord ) + max_coord = seg2->max_coord; + + stem->min_coord = min_coord; + stem->max_coord = max_coord; + } + + /* compute minimum and maximum positions for stem -- */ + /* note that the left-most/bottom-most stem has always */ + /* a fixed position */ + if ( stem == stems || edge1->blue_edge || edge2->blue_edge ) + { + /* this stem cannot move; it is snapped to a blue edge */ + stem->min_pos = stem->pos; + stem->max_pos = stem->pos; + } + else + { + /* this edge can move; compute its min and max positions */ + FT_Pos pos1 = stem->opos; + FT_Pos pos2 = pos1 + stem->owidth - stem->width; + FT_Pos min1 = pos1 & -64; + FT_Pos min2 = pos2 & -64; + + + stem->min_pos = min1; + stem->max_pos = min1 + 64; + if ( min2 < min1 ) + stem->min_pos = min2; + else + stem->max_pos = min2 + 64; + + /* XXX: just to see what it does */ + stem->max_pos += 64; + + /* just for the case where direct hinting did some */ + /* incredible things (e.g. blue edge shifts) */ + if ( stem->min_pos > stem->pos ) + stem->min_pos = stem->pos; + + if ( stem->max_pos < stem->pos ) + stem->max_pos = stem->pos; + } + + stem->velocity = 0; + stem->force = 0; + + stem++; + } + seg = seg->edge_next; + + } while ( seg != edge->first ); + } + } + + *p_stems = stems; + *p_num_stems = num_stems; + + edges = outline->vert_edges; + edge_limit = edges + outline->num_vedges; + scale = outline->x_scale; + + p_stems = &optimizer->vert_stems; + p_num_stems = &optimizer->num_vstems; + } + + Exit: + +#ifdef AH_DEBUG_OPTIM + AH_Dump_Stems( optimizer ); +#endif + + return error; + } + + + /* returns the spring area between two stems, 0 if none */ + static + FT_Pos stem_spring_area( AH_Stem* stem1, + AH_Stem* stem2 ) + { + FT_Pos area1 = stem1->max_coord - stem1->min_coord; + FT_Pos area2 = stem2->max_coord - stem2->min_coord; + FT_Pos min = stem1->min_coord; + FT_Pos max = stem1->max_coord; + FT_Pos area; + + + /* order stems */ + if ( stem2->opos <= stem1->opos + stem1->owidth ) + return 0; + + if ( min < stem2->min_coord ) + min = stem2->min_coord; + + if ( max < stem2->max_coord ) + max = stem2->max_coord; + + area = ( max-min ); + if ( 2 * area < area1 && 2 * area < area2 ) + area = 0; + + return area; + } + + + /* compute all springs in an outline */ + static + int optim_compute_springs( AH_Optimizer* optimizer ) + { + /* basically, a spring exists between two stems if most of their */ + /* surface is aligned */ + FT_Memory memory = optimizer->memory; + + AH_Stem* stems; + AH_Stem* stem_limit; + AH_Stem* stem; + int dimension; + int error = 0; + + FT_Int* p_num_springs; + AH_Spring** p_springs; + + + stems = optimizer->horz_stems; + stem_limit = stems + optimizer->num_hstems; + + p_springs = &optimizer->horz_springs; + p_num_springs = &optimizer->num_hsprings; + + for ( dimension = 1; dimension >= 0; dimension-- ) + { + FT_Int num_springs = 0; + AH_Spring* springs = 0; + + + /* first of all, count stem springs */ + for ( stem = stems; stem + 1 < stem_limit; stem++ ) + { + AH_Stem* stem2; + + + for ( stem2 = stem+1; stem2 < stem_limit; stem2++ ) + if ( stem_spring_area( stem, stem2 ) ) + num_springs++; + } + + /* then allocate and build the springs table */ + if ( num_springs > 0 ) + { + AH_Spring* spring; + + + /* allocate table of springs */ + if ( ALLOC_ARRAY( springs, num_springs, AH_Spring ) ) + goto Exit; + + /* fill the springs table */ + spring = springs; + for ( stem = stems; stem+1 < stem_limit; stem++ ) + { + AH_Stem* stem2; + FT_Pos area; + + + for ( stem2 = stem + 1; stem2 < stem_limit; stem2++ ) + { + area = stem_spring_area( stem, stem2 ); + if ( area ) + { + /* add a new spring here */ + spring->stem1 = stem; + spring->stem2 = stem2; + spring->owidth = stem2->opos - ( stem->opos + stem->owidth ); + spring->tension = 0; + + spring++; + } + } + } + } + *p_num_springs = num_springs; + *p_springs = springs; + + stems = optimizer->vert_stems; + stem_limit = stems + optimizer->num_vstems; + + p_springs = &optimizer->vert_springs; + p_num_springs = &optimizer->num_vsprings; + } + + Exit: + +#ifdef AH_DEBUG_OPTIM + AH_Dump_Springs( optimizer ); +#endif + + return error; + } + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** OPTIMIZE THROUGH MY STRANGE SIMULATED ANNEALING ALGO ;-) ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + +#ifndef AH_BRUTE_FORCE + + /* compute all spring tensions */ + static + void optim_compute_tensions( AH_Optimizer* optimizer ) + { + AH_Spring* spring = optimizer->springs; + AH_Spring* limit = spring + optimizer->num_springs; + + + for ( ; spring < limit; spring++ ) + { + AH_Stem* stem1 = spring->stem1; + AH_Stem* stem2 = spring->stem2; + FT_Int status; + + FT_Pos width; + FT_Pos tension; + FT_Pos sign; + + + /* compute the tension; it simply is -K*(new_width-old_width) */ + width = stem2->pos - ( stem1->pos + stem1->width ); + tension = width - spring->owidth; + + sign = 1; + if ( tension < 0 ) + { + sign = -1; + tension = -tension; + } + + if ( width <= 0 ) + tension = 32000; + else + tension = ( tension << 10 ) / width; + + tension = -sign * FT_MulFix( tension, optimizer->tension_scale ); + spring->tension = tension; + + /* now, distribute tension among the englobing stems, if they */ + /* are able to move */ + status = 0; + if ( stem1->pos <= stem1->min_pos ) + status |= 1; + if ( stem2->pos >= stem2->max_pos ) + status |= 2; + + if ( !status ) + tension /= 2; + + if ( ( status & 1 ) == 0 ) + stem1->force -= tension; + + if ( ( status & 2 ) == 0 ) + stem2->force += tension; + } + } + + + /* compute all stem movements -- returns 0 if nothing moved */ + static + int optim_compute_stem_movements( AH_Optimizer* optimizer ) + { + AH_Stem* stems = optimizer->stems; + AH_Stem* limit = stems + optimizer->num_stems; + AH_Stem* stem = stems; + int moved = 0; + + + /* set initial forces to velocity */ + for ( stem = stems; stem < limit; stem++ ) + { + stem->force = stem->velocity; + stem->velocity /= 2; /* XXX: Heuristics */ + } + + /* compute the sum of forces applied on each stem */ + optim_compute_tensions( optimizer ); + +#ifdef AH_DEBUG_OPTIM + AH_Dump_Springs( optimizer ); + AH_Dump_Stems2( optimizer ); +#endif + + /* now, see whether something can move */ + for ( stem = stems; stem < limit; stem++ ) + { + if ( stem->force > optimizer->tension_threshold ) + { + /* there is enough tension to move the stem to the right */ + if ( stem->pos < stem->max_pos ) + { + stem->pos += 64; + stem->velocity = stem->force / 2; + moved = 1; + } + else + stem->velocity = 0; + } + else if ( stem->force < optimizer->tension_threshold ) + { + /* there is enough tension to move the stem to the left */ + if ( stem->pos > stem->min_pos ) + { + stem->pos -= 64; + stem->velocity = stem->force / 2; + moved = 1; + } + else + stem->velocity = 0; + } + } + + /* return 0 if nothing moved */ + return moved; + } + +#endif /* AH_BRUTE_FORCE */ + + + /* compute current global distortion from springs */ + static + FT_Pos optim_compute_distortion( AH_Optimizer* optimizer ) + { + AH_Spring* spring = optimizer->springs; + AH_Spring* limit = spring + optimizer->num_springs; + FT_Pos distortion = 0; + + + for ( ; spring < limit; spring++ ) + { + AH_Stem* stem1 = spring->stem1; + AH_Stem* stem2 = spring->stem2; + FT_Pos width; + + width = stem2->pos - ( stem1->pos + stem1->width ); + width -= spring->owidth; + if ( width < 0 ) + width = -width; + + distortion += width; + } + + return distortion; + } + + + /* record stems configuration in `best of' history */ + static + void optim_record_configuration( AH_Optimizer* optimizer ) + { + FT_Pos distortion; + AH_Configuration* configs = optimizer->configs; + AH_Configuration* limit = configs + optimizer->num_configs; + AH_Configuration* config; + + + distortion = optim_compute_distortion( optimizer ); + LOG(( "config distortion = %.1f ", FLOAT( distortion * 64 ) )); + + /* check that we really need to add this configuration to our */ + /* sorted history */ + if ( limit > configs && limit[-1].distortion < distortion ) + { + LOG(( "ejected\n" )); + return; + } + + /* add new configuration at the end of the table */ + { + int n; + + + config = limit; + if ( optimizer->num_configs < AH_MAX_CONFIGS ) + optimizer->num_configs++; + else + config--; + + config->distortion = distortion; + + for ( n = 0; n < optimizer->num_stems; n++ ) + config->positions[n] = optimizer->stems[n].pos; + } + + /* move the current configuration towards the front of the list */ + /* when necessary -- yes this is slow bubble sort ;-) */ + while ( config > configs && config[0].distortion < config[-1].distortion ) + { + AH_Configuration temp; + + + config--; + temp = config[0]; + config[0] = config[1]; + config[1] = temp; + } + LOG(( "recorded!\n" )); + } + + +#ifdef AH_BRUTE_FORCE + + /* optimize outline in a single direction */ + static + void optim_compute( AH_Optimizer* optimizer ) + { + int n; + FT_Bool moved; + + AH_Stem* stem = optimizer->stems; + AH_Stem* limit = stem + optimizer->num_stems; + + + /* empty, exit */ + if ( stem >= limit ) + return; + + optimizer->num_configs = 0; + + stem = optimizer->stems; + for ( ; stem < limit; stem++ ) + stem->pos = stem->min_pos; + + do + { + /* record current configuration */ + optim_record_configuration( optimizer ); + + /* now change configuration */ + moved = 0; + for ( stem = optimizer->stems; stem < limit; stem++ ) + { + if ( stem->pos < stem->max_pos ) + { + stem->pos += 64; + moved = 1; + break; + } + + stem->pos = stem->min_pos; + } + } while ( moved ); + + /* now, set the best stem positions */ + for ( n = 0; n < optimizer->num_stems; n++ ) + { + AH_Stem* stem = optimizer->stems + n; + FT_Pos pos = optimizer->configs[0].positions[n]; + + + stem->edge1->pos = pos; + stem->edge2->pos = pos + stem->width; + + stem->edge1->flags |= ah_edge_done; + stem->edge2->flags |= ah_edge_done; + } + } + +#else /* AH_BRUTE_FORCE */ + + /* optimize outline in a single direction */ + static + void optim_compute( AH_Optimizer* optimizer ) + { + int n, counter, counter2; + + + optimizer->num_configs = 0; + optimizer->tension_scale = 0x80000L; + optimizer->tension_threshold = 64; + + /* record initial configuration threshold */ + optim_record_configuration( optimizer ); + + counter = 0; + for ( counter2 = optimizer->num_stems*8; counter2 >= 0; counter2-- ) + { + if ( counter == 0 ) + counter = 2 * optimizer->num_stems; + + if ( !optim_compute_stem_movements( optimizer ) ) + break; + + optim_record_configuration( optimizer ); + + counter--; + if ( counter == 0 ) + optimizer->tension_scale /= 2; + } + + /* now, set the best stem positions */ + for ( n = 0; n < optimizer->num_stems; n++ ) + { + AH_Stem* stem = optimizer->stems + n; + FT_Pos pos = optimizer->configs[0].positions[n]; + + + stem->edge1->pos = pos; + stem->edge2->pos = pos + stem->width; + + stem->edge1->flags |= ah_edge_done; + stem->edge2->flags |= ah_edge_done; + } + } + +#endif /* AH_BRUTE_FORCE */ + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** HIGH-LEVEL OPTIMIZER API ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /* releases the optimization data */ + void AH_Optimizer_Done( AH_Optimizer* optimizer ) + { + if ( optimizer ) + { + FT_Memory memory = optimizer->memory; + + + FREE( optimizer->horz_stems ); + FREE( optimizer->vert_stems ); + FREE( optimizer->horz_springs ); + FREE( optimizer->vert_springs ); + FREE( optimizer->positions ); + } + } + + + /* loads the outline into the optimizer */ + int AH_Optimizer_Init( AH_Optimizer* optimizer, + AH_Outline* outline, + FT_Memory memory ) + { + FT_Error error; + + + MEM_Set( optimizer, 0, sizeof ( *optimizer ) ); + optimizer->outline = outline; + optimizer->memory = memory; + + LOG(( "initializing new optimizer\n" )); + /* compute stems and springs */ + error = optim_compute_stems ( optimizer ) || + optim_compute_springs( optimizer ); + if ( error ) + goto Fail; + + /* allocate stem positions history and configurations */ + { + int n, max_stems; + + + max_stems = optimizer->num_hstems; + if ( max_stems < optimizer->num_vstems ) + max_stems = optimizer->num_vstems; + + if ( ALLOC_ARRAY( optimizer->positions, + max_stems * AH_MAX_CONFIGS, FT_Pos ) ) + goto Fail; + + optimizer->num_configs = 0; + for ( n = 0; n < AH_MAX_CONFIGS; n++ ) + optimizer->configs[n].positions = optimizer->positions + + n * max_stems; + } + + return error; + + Fail: + AH_Optimizer_Done( optimizer ); + return error; + } + + + /* compute optimal outline */ + void AH_Optimizer_Compute( AH_Optimizer* optimizer ) + { + optimizer->num_stems = optimizer->num_hstems; + optimizer->stems = optimizer->horz_stems; + optimizer->num_springs = optimizer->num_hsprings; + optimizer->springs = optimizer->horz_springs; + + if ( optimizer->num_springs > 0 ) + { + LOG(( "horizontal optimization ------------------------\n" )); + optim_compute( optimizer ); + } + + optimizer->num_stems = optimizer->num_vstems; + optimizer->stems = optimizer->vert_stems; + optimizer->num_springs = optimizer->num_vsprings; + optimizer->springs = optimizer->vert_springs; + + if ( optimizer->num_springs ) + { + LOG(( "vertical optimization --------------------------\n" )); + optim_compute( optimizer ); + } + } + + +/* END */ diff --git a/src/freetype/autohint/ahoptim.h b/src/freetype/autohint/ahoptim.h new file mode 100644 index 0000000000..a1f52bf68f --- /dev/null +++ b/src/freetype/autohint/ahoptim.h @@ -0,0 +1,136 @@ +/***************************************************************************/ +/* */ +/* ahoptim.h */ +/* */ +/* FreeType auto hinting outline optimization (declaration). */ +/* */ +/* Copyright 2000 Catharon Productions Inc. */ +/* Author: David Turner */ +/* */ +/* This file is part of the Catharon Typography Project and shall only */ +/* be used, modified, and distributed under the terms of the Catharon */ +/* Open Source License that should come with this file under the name */ +/* `CatharonLicense.txt'. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/* Note that this license is compatible with the FreeType license. */ +/* */ +/***************************************************************************/ + + +#ifndef AHOPTIM_H +#define AHOPTIM_H + + +#ifdef FT_FLAT_COMPILE + +#include "ahtypes.h" + +#else + +#include + +#endif + + + /* the maximal number of stem configurations to record */ + /* during optimization */ +#define AH_MAX_CONFIGS 8 + + + typedef struct AH_Stem_ + { + FT_Pos pos; /* current position */ + FT_Pos velocity; /* current velocity */ + FT_Pos force; /* sum of current forces */ + FT_Pos width; /* normalized width */ + + FT_Pos min_pos; /* minimum grid position */ + FT_Pos max_pos; /* maximum grid position */ + + AH_Edge* edge1; /* left/bottom edge */ + AH_Edge* edge2; /* right/top edge */ + + FT_Pos opos; /* original position */ + FT_Pos owidth; /* original width */ + + FT_Pos min_coord; /* minimum coordinate */ + FT_Pos max_coord; /* maximum coordinate */ + + } AH_Stem; + + + /* A spring between two stems */ + typedef struct AH_Spring_ + { + AH_Stem* stem1; + AH_Stem* stem2; + FT_Pos owidth; /* original width */ + FT_Pos tension; /* current tension */ + + } AH_Spring; + + + /* A configuration records the position of each stem at a given time */ + /* as well as the associated distortion */ + typedef struct AH_Configuration_ + { + FT_Pos* positions; + FT_Long distortion; + + } AH_Configuration; + + + typedef struct AH_Optimizer_ + { + FT_Memory memory; + AH_Outline* outline; + + FT_Int num_hstems; + AH_Stem* horz_stems; + + FT_Int num_vstems; + AH_Stem* vert_stems; + + FT_Int num_hsprings; + FT_Int num_vsprings; + AH_Spring* horz_springs; + AH_Spring* vert_springs; + + FT_Int num_configs; + AH_Configuration configs[AH_MAX_CONFIGS]; + FT_Pos* positions; + + /* during each pass, use these instead */ + FT_Int num_stems; + AH_Stem* stems; + + FT_Int num_springs; + AH_Spring* springs; + FT_Bool vertical; + + FT_Fixed tension_scale; + FT_Pos tension_threshold; + + } AH_Optimizer; + + + /* loads the outline into the optimizer */ + int AH_Optimizer_Init( AH_Optimizer* optimizer, + AH_Outline* outline, + FT_Memory memory ); + + + /* compute optimal outline */ + void AH_Optimizer_Compute( AH_Optimizer* optimizer ); + + + /* release the optimization data */ + void AH_Optimizer_Done( AH_Optimizer* optimizer ); + + +#endif /* AHOPTIM_H */ + + +/* END */ diff --git a/src/freetype/autohint/ahtypes.h b/src/freetype/autohint/ahtypes.h new file mode 100644 index 0000000000..3372ea9af6 --- /dev/null +++ b/src/freetype/autohint/ahtypes.h @@ -0,0 +1,492 @@ +/***************************************************************************/ +/* */ +/* ahtypes.h */ +/* */ +/* General types and definitions for the auto-hint module */ +/* (specification only). */ +/* */ +/* Copyright 2000 Catharon Productions Inc. */ +/* Author: David Turner */ +/* */ +/* This file is part of the Catharon Typography Project and shall only */ +/* be used, modified, and distributed under the terms of the Catharon */ +/* Open Source License that should come with this file under the name */ +/* `CatharonLicense.txt'. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/* Note that this license is compatible with the FreeType license. */ +/* */ +/***************************************************************************/ + + +#ifndef AHTYPES_H +#define AHTYPES_H + + +#include /* for freetype.h + LOCAL_DEF etc. */ + + +#ifdef FT_FLAT_COMPILE + +#include "ahloader.h" + +#else + +#include + +#endif + + +#define xxAH_DEBUG + + +#ifdef AH_DEBUG + +#include + +#define AH_LOG( x ) printf##x + +#else + +#define AH_LOG( x ) do ; while ( 0 ) /* nothing */ + +#endif + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** COMPILE-TIME BUILD OPTIONS ****/ + /**** ****/ + /**** Toggle these configuration macros to experiment with `features' ****/ + /**** of the auto-hinter. ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* If this option is defined, only strong interpolation will be used to */ + /* place the points between edges. Otherwise, `smooth' points are */ + /* detected and later hinted through weak interpolation to correct some */ + /* unpleasant artefacts. */ + /* */ +#undef AH_OPTION_NO_WEAK_INTERPOLATION + + + /*************************************************************************/ + /* */ + /* If this option is defined, only weak interpolation will be used to */ + /* place the points between edges. Otherwise, `strong' points are */ + /* detected and later hinted through strong interpolation to correct */ + /* some unpleasant artefacts. */ + /* */ +#undef AH_OPTION_NO_STRONG_INTERPOLATION + + + /*************************************************************************/ + /* */ + /* Undefine this macro if you don't want to hint the metrics. There is */ + /* no reason to do this (at least for non-CJK scripts), except for */ + /* experimentation. */ + /* */ +#define AH_HINT_METRICS + + + /*************************************************************************/ + /* */ + /* Define this macro if you do not want to insert extra edges at a */ + /* glyph's x and y extremum (if there isn't one already available). */ + /* This helps to reduce a number of artefacts and allows hinting of */ + /* metrics. */ + /* */ +#undef AH_OPTION_NO_EXTREMUM_EDGES + + + /* don't touch for now */ +#define AH_MAX_WIDTHS 12 +#define AH_MAX_HEIGHTS 12 + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** TYPE DEFINITIONS ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /* see agangles.h */ + typedef FT_Int AH_Angle; + + + /* hint flags */ +#define ah_flah_none 0 + + /* bezier control points flags */ +#define ah_flah_conic 1 +#define ah_flah_cubic 2 +#define ah_flah_control ( ah_flah_conic | ah_flah_cubic ) + + /* extrema flags */ +#define ah_flah_extrema_x 4 +#define ah_flah_extrema_y 8 + + /* roundness */ +#define ah_flah_round_x 16 +#define ah_flah_round_y 32 + + /* touched */ +#define ah_flah_touch_x 64 +#define ah_flah_touch_y 128 + + /* weak interpolation */ +#define ah_flah_weak_interpolation 256 + + typedef FT_Int AH_Flags; + + + /* edge hint flags */ +#define ah_edge_normal 0 +#define ah_edge_round 1 +#define ah_edge_serif 2 +#define ah_edge_done 4 + + typedef FT_Int AH_Edge_Flags; + + + /* hint directions -- the values are computed so that two vectors are */ + /* in opposite directions iff `dir1+dir2 == 0' */ +#define ah_dir_none 4 +#define ah_dir_right 1 +#define ah_dir_left -1 +#define ah_dir_up 2 +#define ah_dir_down -2 + + typedef FT_Int AH_Direction; + + + typedef struct AH_Point AH_Point; + typedef struct AH_Segment AH_Segment; + typedef struct AH_Edge AH_Edge; + + + /*************************************************************************/ + /* */ + /* */ + /* AH_Point */ + /* */ + /* */ + /* A structure used to model an outline point to the AH_Outline type. */ + /* */ + /* */ + /* flags :: The current point hint flags. */ + /* */ + /* ox, oy :: The current original scaled coordinates. */ + /* */ + /* fx, fy :: The current coordinates in font units. */ + /* */ + /* x, y :: The current hinter coordinates. */ + /* */ + /* u, v :: Point coordinates -- meaning varies with context. */ + /* */ + /* in_dir :: The direction of the inwards vector (prev->point). */ + /* */ + /* out_dir :: The direction of the outwards vector (point->next). */ + /* */ + /* in_angle :: The angle of the inwards vector. */ + /* */ + /* out_angle :: The angle of the outwards vector. */ + /* */ + /* next :: The next point in same contour. */ + /* */ + /* prev :: The previous point in same contour. */ + /* */ + struct AH_Point + { + AH_Flags flags; /* point flags used by hinter */ + FT_Pos ox, oy; + FT_Pos fx, fy; + FT_Pos x, y; + FT_Pos u, v; + + AH_Direction in_dir; /* direction of inwards vector */ + AH_Direction out_dir; /* direction of outwards vector */ + + AH_Angle in_angle; + AH_Angle out_angle; + + AH_Point* next; /* next point in contour */ + AH_Point* prev; /* previous point in contour */ + }; + + + /*************************************************************************/ + /* */ + /* */ + /* AH_Segment */ + /* */ + /* */ + /* A structure used to describe an edge segment to the auto-hinter. */ + /* A segment is simply a sequence of successive points located on the */ + /* same horizontal or vertical `position', in a given direction. */ + /* */ + /* */ + /* flags :: The segment edge flags (straight, rounded, etc.). */ + /* */ + /* dir :: The segment direction. */ + /* */ + /* first :: The first point in the segment. */ + /* */ + /* last :: The last point in the segment. */ + /* */ + /* contour :: A pointer to the first point of the segment's */ + /* contour. */ + /* */ + /* pos :: The segment position in font units. */ + /* */ + /* size :: The segment size. */ + /* */ + /* edge :: The edge of the current segment. */ + /* */ + /* edge_next :: The next segment on the same edge. */ + /* */ + /* link :: The pairing segment for this edge. */ + /* */ + /* serif :: The primary segment for serifs. */ + /* */ + /* num_linked :: The number of other segments that link to this one. */ + /* */ + /* score :: Used to score the segment when selecting them. */ + /* */ + struct AH_Segment + { + AH_Edge_Flags flags; + AH_Direction dir; + + AH_Point* first; /* first point in edge segment */ + AH_Point* last; /* last point in edge segment */ + AH_Point** contour; /* ptr to first point of segment's contour */ + + FT_Pos pos; /* position of segment */ + FT_Pos min_coord; /* minimum coordinate of segment */ + FT_Pos max_coord; /* maximum coordinate of segment */ + + AH_Edge* edge; + AH_Segment* edge_next; + + AH_Segment* link; /* link segment */ + AH_Segment* serif; /* primary segment for serifs */ + FT_Pos num_linked; /* number of linked segments */ + FT_Int score; + }; + + + /*************************************************************************/ + /* */ + /* */ + /* AH_Edge */ + /* */ + /* */ + /* A structure used to describe an edge, which really is a horizontal */ + /* or vertical coordinate to be hinted depending on the segments */ + /* located on it. */ + /* */ + /* */ + /* flags :: The segment edge flags (straight, rounded, etc.). */ + /* */ + /* dir :: The main segment direction on this edge. */ + /* */ + /* first :: The first edge segment. */ + /* */ + /* last :: The last edge segment. */ + /* */ + /* fpos :: The original edge position in font units. */ + /* */ + /* opos :: The original scaled edge position. */ + /* */ + /* pos :: The hinted edge position. */ + /* */ + /* link :: The linked edge. */ + /* */ + /* serif :: The serif edge. */ + /* */ + /* num_paired :: The number of other edges that pair to this one. */ + /* */ + /* score :: Used to score the edge when selecting them. */ + /* */ + /* blue_edge :: Indicate the blue zone edge this edge is related to. */ + /* Only set for some of the horizontal edges in a Latin */ + /* font. */ + /* */ + struct AH_Edge + { + AH_Edge_Flags flags; + AH_Direction dir; + + AH_Segment* first; + AH_Segment* last; + + FT_Pos fpos; + FT_Pos opos; + FT_Pos pos; + + AH_Edge* link; + AH_Edge* serif; + FT_Int num_linked; + + FT_Int score; + FT_Pos* blue_edge; + }; + + + /* an outline as seen by the hinter */ + typedef struct AH_Outline_ + { + FT_Memory memory; + + AH_Direction vert_major_dir; /* vertical major direction */ + AH_Direction horz_major_dir; /* horizontal major direction */ + + FT_Fixed x_scale; + FT_Fixed y_scale; + FT_Pos edge_distance_threshold; + + FT_Int max_points; + FT_Int num_points; + AH_Point* points; + + FT_Int max_contours; + FT_Int num_contours; + AH_Point** contours; + + FT_Int num_hedges; + AH_Edge* horz_edges; + + FT_Int num_vedges; + AH_Edge* vert_edges; + + FT_Int num_hsegments; + AH_Segment* horz_segments; + + FT_Int num_vsegments; + AH_Segment* vert_segments; + + } AH_Outline; + + +#define ah_blue_capital_top 0 /* THEZOCQS */ +#define ah_blue_capital_bottom ( ah_blue_capital_top + 1 ) /* HEZLOCUS */ +#define ah_blue_small_top ( ah_blue_capital_bottom + 1 ) /* xzroesc */ +#define ah_blue_small_bottom ( ah_blue_small_top + 1 ) /* xzroesc */ +#define ah_blue_small_minor ( ah_blue_small_bottom + 1 ) /* pqgjy */ +#define ah_blue_max ( ah_blue_small_minor + 1 ) + + typedef FT_Int AH_Blue; + + +#define ah_hinter_monochrome 1 +#define ah_hinter_optimize 2 + + typedef FT_Int AH_Hinter_Flags; + + + /*************************************************************************/ + /* */ + /* */ + /* AH_Globals */ + /* */ + /* */ + /* Holds the global metrics for a given font face (be it in design */ + /* units or scaled pixel values). */ + /* */ + /* */ + /* num_widths :: The number of widths. */ + /* */ + /* num_heights :: The number of heights. */ + /* */ + /* widths :: Snap widths, including standard one. */ + /* */ + /* heights :: Snap height, including standard one. */ + /* */ + /* blue_refs :: The reference positions of blue zones. */ + /* */ + /* blue_shoots :: The overshoot positions of blue zones. */ + /* */ + typedef struct AH_Globals_ + { + FT_Int num_widths; + FT_Int num_heights; + + FT_Pos widths [AH_MAX_WIDTHS]; + FT_Pos heights[AH_MAX_HEIGHTS]; + + FT_Pos blue_refs [ah_blue_max]; + FT_Pos blue_shoots[ah_blue_max]; + + } AH_Globals; + + + /*************************************************************************/ + /* */ + /* */ + /* AH_Face_Globals */ + /* */ + /* */ + /* Holds the complete global metrics for a given font face (i.e., the */ + /* design units version + a scaled version + the current scales */ + /* used). */ + /* */ + /* */ + /* face :: A handle to the source face object */ + /* */ + /* design :: The globals in font design units. */ + /* */ + /* scaled :: Scaled globals in sub-pixel values. */ + /* */ + /* x_scale :: The current horizontal scale. */ + /* */ + /* y_scale :: The current vertical scale. */ + /* */ + typedef struct AH_Face_Globals_ + { + FT_Face face; + AH_Globals design; + AH_Globals scaled; + FT_Fixed x_scale; + FT_Fixed y_scale; + FT_Bool control_overshoot; + + } AH_Face_Globals; + + + typedef struct AH_Hinter + { + FT_Memory memory; + AH_Hinter_Flags flags; + + FT_Int algorithm; + FT_Face face; + + AH_Face_Globals* globals; + + AH_Outline* glyph; + + AH_Loader* loader; + FT_Vector pp1; + FT_Vector pp2; + + } AH_Hinter; + + +#endif /* AHTYPES_H */ + + +/* END */ diff --git a/src/freetype/autohint/autohint.c b/src/freetype/autohint/autohint.c new file mode 100644 index 0000000000..5916b63302 --- /dev/null +++ b/src/freetype/autohint/autohint.c @@ -0,0 +1,43 @@ +/***************************************************************************/ +/* */ +/* autohint.c */ +/* */ +/* Automatic Hinting wrapper (body only). */ +/* */ +/* Copyright 2000 Catharon Productions Inc. */ +/* Author: David Turner */ +/* */ +/* This file is part of the Catharon Typography Project and shall only */ +/* be used, modified, and distributed under the terms of the Catharon */ +/* Open Source License that should come with this file under the name */ +/* `CatharonLicense.txt'. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/* Note that this license is compatible with the FreeType license. */ +/* */ +/***************************************************************************/ + + +#define FT_MAKE_OPTION_SINGLE_OBJECT + +#ifdef FT_FLAT_COMPILE + +#include "ahangles.c" +#include "ahglyph.c" +#include "ahglobal.c" +#include "ahhint.c" +#include "ahmodule.c" + +#else + +#include +#include +#include +#include +#include + +#endif + + +/* END */ diff --git a/src/freetype/autohint/mather.py b/src/freetype/autohint/mather.py new file mode 100644 index 0000000000..b416fdfcb6 --- /dev/null +++ b/src/freetype/autohint/mather.py @@ -0,0 +1,78 @@ +#!/usr/bin/env python +# + +# +# autohint math table builder +# + + +# Copyright 1996-2000 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +import math + +ag_pi = 256 + +def print_arctan( atan_bits ): + atan_base = 1 << atan_bits + + print " static AH_Angle ag_arctan[1L << AG_ATAN_BITS] =" + print " {" + + count = 0 + line = " " + + for n in range( atan_base ): + comma = "," + if ( n == atan_base - 1 ): + comma = "" + + angle = math.atan( n * 1.0 / atan_base ) / math.pi * ag_pi + line = line + " " + repr( int( angle + 0.5 ) ) + comma + count = count + 1; + if ( count == 8 ): + count = 0 + print line + line = " " + + if ( count > 0 ): + print line + print " };" + + +# This routine is not used currently. +# +def print_sines(): + print " static FT_Fixed ah_sines[AG_HALF_PI + 1] =" + print " {" + + count = 0 + line = " " + + for n in range( ag_pi / 2 ): + sinus = math.sin( n * math.pi / ag_pi ) + line = line + " " + repr( int( 65536.0 * sinus ) ) + "," + count = count + 1 + if ( count == 8 ): + count = 0 + print line + line = " " + + if ( count > 0 ): + print line + print " 65536" + print " };" + + +print_arctan( 8 ) +print + + +# END diff --git a/src/freetype/autohint/module.mk b/src/freetype/autohint/module.mk new file mode 100644 index 0000000000..71e5ee3524 --- /dev/null +++ b/src/freetype/autohint/module.mk @@ -0,0 +1,7 @@ +make_module_list: add_autohint_module + +add_autohint_module: + $(OPEN_DRIVER)autohint_module_class$(CLOSE_DRIVER) + $(ECHO_DRIVER)autohint $(ECHO_DRIVER_DESC)automatic hinting module$(ECHO_DRIVER_DONE) + +# EOF diff --git a/src/freetype/autohint/rules.mk b/src/freetype/autohint/rules.mk new file mode 100644 index 0000000000..87f7849adc --- /dev/null +++ b/src/freetype/autohint/rules.mk @@ -0,0 +1,77 @@ +# +# FreeType 2 auto-hinter module configuration rules +# + + +# Copyright 2000 Catharon Productions Inc. +# Author: David Turner +# +# This file is part of the Catharon Typography Project and shall only +# be used, modified, and distributed under the terms of the Catharon +# Open Source License that should come with this file under the name +# `CatharonLicense.txt'. By continuing to use, modify, or distribute +# this file you indicate that you have read the license and +# understand and accept it fully. +# +# Note that this license is compatible with the FreeType license. + + +# AUTO driver directory +# +AUTO_DIR := $(SRC_)autohint +AUTO_DIR_ := $(AUTO_DIR)$(SEP) + + +# compilation flags for the driver +# +AUTO_COMPILE := $(FT_COMPILE) + + +# AUTO driver sources (i.e., C files) +# +AUTO_DRV_SRC := $(AUTO_DIR_)ahangles.c \ + $(AUTO_DIR_)ahglobal.c \ + $(AUTO_DIR_)ahglyph.c \ + $(AUTO_DIR_)ahhint.c \ + $(AUTO_DIR_)ahmodule.c + +# AUTO driver headers +# +AUTO_DRV_H := $(AUTO_DRV_SRC:%c=%h) \ + $(AUTO_DIR_)ahloader.h \ + $(AUTO_DIR_)ahtypes.h + + +# AUTO driver object(s) +# +# AUTO_DRV_OBJ_M is used during `multi' builds. +# AUTO_DRV_OBJ_S is used during `single' builds. +# +AUTO_DRV_OBJ_M := $(AUTO_DRV_SRC:$(AUTO_DIR_)%.c=$(OBJ_)%.$O) +AUTO_DRV_OBJ_S := $(OBJ_)autohint.$O + +# AUTO driver source file for single build +# +AUTO_DRV_SRC_S := $(AUTO_DIR_)autohint.c + + +# AUTO driver - single object +# +$(AUTO_DRV_OBJ_S): $(AUTO_DRV_SRC_S) $(AUTO_DRV_SRC) \ + $(FREETYPE_H) $(AUTO_DRV_H) + $(AUTO_COMPILE) $T$@ $(AUTO_DRV_SRC_S) + + +# AUTO driver - multiple objects +# +$(OBJ_)%.$O: $(AUTO_DIR_)%.c $(FREETYPE_H) $(AUTO_DRV_H) + $(AUTO_COMPILE) $T$@ $< + + +# update main driver object lists +# +DRV_OBJS_S += $(AUTO_DRV_OBJ_S) +DRV_OBJS_M += $(AUTO_DRV_OBJ_M) + + +# EOF diff --git a/src/freetype/base/ftbase.c b/src/freetype/base/ftbase.c new file mode 100644 index 0000000000..a110af42b4 --- /dev/null +++ b/src/freetype/base/ftbase.c @@ -0,0 +1,42 @@ +/***************************************************************************/ +/* */ +/* ftbase.c */ +/* */ +/* Single object library component (body only). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifdef FT_FLAT_COMPILE + +#include "ftcalc.c" +#include "ftobjs.c" +#include "ftstream.c" +#include "ftlist.c" +#include "ftoutln.c" +#include "ftextend.c" +#include "ftnames.c" + +#else /* FT_FLAT_COMPILE */ + +#include +#include +#include +#include +#include +#include +#include + +#endif /* FT_FLAT_COMPILE */ + + +/* END */ diff --git a/src/freetype/base/ftcalc.c b/src/freetype/base/ftcalc.c new file mode 100644 index 0000000000..d27de26524 --- /dev/null +++ b/src/freetype/base/ftcalc.c @@ -0,0 +1,773 @@ +/***************************************************************************/ +/* */ +/* ftcalc.c */ +/* */ +/* Arithmetic computations (body). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + /*************************************************************************/ + /* */ + /* Support for 1-complement arithmetic has been totally dropped in this */ + /* release. You can still write your own code if you need it. */ + /* */ + /*************************************************************************/ + + /*************************************************************************/ + /* */ + /* Implementing basic computation routines. */ + /* */ + /* FT_MulDiv(), FT_MulFix(), and FT_DivFix() are declared in freetype.h. */ + /* */ + /*************************************************************************/ + + +#include +#include +#include /* for ABS() */ + + + /*************************************************************************/ + /* */ + /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ + /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ + /* messages during execution. */ + /* */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_calc + + +#ifdef FT_CONFIG_OPTION_OLD_CALCS + + static const FT_Long ft_square_roots[63] = + { + 1L, 1L, 2L, 3L, 4L, 5L, 8L, 11L, + 16L, 22L, 32L, 45L, 64L, 90L, 128L, 181L, + 256L, 362L, 512L, 724L, 1024L, 1448L, 2048L, 2896L, + 4096L, 5892L, 8192L, 11585L, 16384L, 23170L, 32768L, 46340L, + + 65536L, 92681L, 131072L, 185363L, 262144L, 370727L, + 524288L, 741455L, 1048576L, 1482910L, 2097152L, 2965820L, + 4194304L, 5931641L, 8388608L, 11863283L, 16777216L, 23726566L, + + 33554432L, 47453132L, 67108864L, 94906265L, + 134217728L, 189812531L, 268435456L, 379625062L, + 536870912L, 759250125L, 1073741824L, 1518500250L, + 2147483647L + }; + +#else + + /*************************************************************************/ + /* */ + /* */ + /* FT_Sqrt32 */ + /* */ + /* */ + /* Computes the square root of an Int32 integer (which will be */ + /* handled as an unsigned long value). */ + /* */ + /* */ + /* x :: The value to compute the root for. */ + /* */ + /* */ + /* The result of `sqrt(x)'. */ + /* */ + FT_EXPORT_FUNC( FT_Int32 ) FT_Sqrt32( FT_Int32 x ) + { + FT_ULong val, root, newroot, mask; + + + root = 0; + mask = 0x40000000L; + val = (FT_ULong)x; + + do + { + newroot = root + mask; + if ( newroot <= val ) + { + val -= newroot; + root = newroot + mask; + } + + root >>= 1; + mask >>= 2; + + } while ( mask != 0 ); + + return root; + } + +#endif /* FT_CONFIG_OPTION_OLD_CALCS */ + + +#ifdef FT_LONG64 + + /*************************************************************************/ + /* */ + /* */ + /* FT_MulDiv */ + /* */ + /* */ + /* A very simple function used to perform the computation `(a*b)/c' */ + /* with maximal accuracy (it uses a 64-bit intermediate integer */ + /* whenever necessary). */ + /* */ + /* This function isn't necessarily as fast as some processor specific */ + /* operations, but is at least completely portable. */ + /* */ + /* */ + /* a :: The first multiplier. */ + /* b :: The second multiplier. */ + /* c :: The divisor. */ + /* */ + /* */ + /* The result of `(a*b)/c'. This function never traps when trying to */ + /* divide by zero; it simply returns `MaxInt' or `MinInt' depending */ + /* on the signs of `a' and `b'. */ + /* */ + FT_EXPORT_FUNC( FT_Long ) FT_MulDiv( FT_Long a, + FT_Long b, + FT_Long c ) + { + FT_Int s; + + + s = 1; + if ( a < 0 ) { a = -a; s = -s; } + if ( b < 0 ) { b = -b; s = -s; } + if ( c < 0 ) { c = -c; s = -s; } + + return s * ( c > 0 ? ( (FT_Int64)a * b + ( c >> 1 ) ) / c + : 0x7FFFFFFFL ); + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_MulFix */ + /* */ + /* */ + /* A very simple function used to perform the computation */ + /* `(a*b)/0x10000' with maximal accuracy. Most of the time this is */ + /* used to multiply a given value by a 16.16 fixed float factor. */ + /* */ + /* */ + /* a :: The first multiplier. */ + /* b :: The second multiplier. Use a 16.16 factor here whenever */ + /* possible (see note below). */ + /* */ + /* */ + /* The result of `(a*b)/0x10000'. */ + /* */ + /* */ + /* This function has been optimized for the case where the absolute */ + /* value of `a' is less than 2048, and `b' is a 16.16 scaling factor. */ + /* As this happens mainly when scaling from notional units to */ + /* fractional pixels in FreeType, it resulted in noticeable speed */ + /* improvements between versions 2.x and 1.x. */ + /* */ + /* As a conclusion, always try to place a 16.16 factor as the */ + /* _second_ argument of this function; this can make a great */ + /* difference. */ + /* */ + FT_EXPORT_FUNC( FT_Long ) FT_MulFix( FT_Long a, + FT_Long b ) + { + FT_Int s; + + + s = 1; + if ( a < 0 ) { a = -a; s = -s; } + if ( b < 0 ) { b = -b; s = -s; } + + return s * (FT_Long)( ( (FT_Int64)a * b + 0x8000 ) >> 16 ); + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_DivFix */ + /* */ + /* */ + /* A very simple function used to perform the computation */ + /* `(a*0x10000)/b' with maximal accuracy. Most of the time, this is */ + /* used to divide a given value by a 16.16 fixed float factor. */ + /* */ + /* */ + /* a :: The first multiplier. */ + /* b :: The second multiplier. Use a 16.16 factor here whenever */ + /* possible (see note below). */ + /* */ + /* */ + /* The result of `(a*0x10000)/b'. */ + /* */ + /* */ + /* The optimization for FT_DivFix() is simple: If (a << 16) fits in */ + /* 32 bits, then the division is computed directly. Otherwise, we */ + /* use a specialized version of the old FT_MulDiv64(). */ + /* */ + FT_EXPORT_FUNC( FT_Long ) FT_DivFix( FT_Long a, + FT_Long b ) + { + FT_Int32 s; + FT_UInt32 q; + + + s = a; a = ABS(a); + s ^= b; b = ABS(b); + + if ( b == 0 ) + /* check for division by 0 */ + q = 0x7FFFFFFFL; + else + /* compute result directly */ + q = ( (FT_Int64)a << 16 ) / b; + + return (FT_Int32)( s < 0 ? -q : q ); + } + + +#ifdef FT_CONFIG_OPTION_OLD_CALCS + + /* a helper function for FT_Sqrt64() */ + + static + int ft_order64( FT_Int64 z ) + { + int j = 0; + + + while ( z ) + { + z = (unsigned FT_INT64)z >> 1; + j++; + } + return j - 1; + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Sqrt64 */ + /* */ + /* */ + /* Computes the square root of a 64-bit value. That sounds stupid, */ + /* but it is needed to obtain maximal accuracy in the TrueType */ + /* bytecode interpreter. */ + /* */ + /* */ + /* l :: A 64-bit integer. */ + /* */ + /* */ + /* The 32-bit square-root. */ + /* */ + FT_EXPORT_FUNC( FT_Int32 ) FT_Sqrt64( FT_Int64 l ) + { + FT_Int64 r, s; + + + if ( l <= 0 ) return 0; + if ( l == 1 ) return 1; + + r = ft_square_roots[ft_order64( l )]; + + do + { + s = r; + r = ( r + l / r ) >> 1; + + } while ( r > s || r * r > l ); + + return r; + } + +#endif /* FT_CONFIG_OPTION_OLD_CALCS */ + + +#else /* FT_LONG64 */ + + + /*************************************************************************/ + /* */ + /* */ + /* FT_MulDiv */ + /* */ + /* */ + /* A very simple function used to perform the computation `(a*b)/c' */ + /* with maximal accuracy (it uses a 64-bit intermediate integer */ + /* whenever necessary). */ + /* */ + /* This function isn't necessarily as fast as some processor specific */ + /* operations, but is at least completely portable. */ + /* */ + /* */ + /* a :: The first multiplier. */ + /* b :: The second multiplier. */ + /* c :: The divisor. */ + /* */ + /* */ + /* The result of `(a*b)/c'. This function never traps when trying to */ + /* divide by zero; it simply returns `MaxInt' or `MinInt' depending */ + /* on the signs of `a' and `b'. */ + /* */ + /* */ + /* The FT_MulDiv() function has been optimized thanks to ideas from */ + /* Graham Asher. The trick is to optimize computation if everything */ + /* fits within 32 bits (a rather common case). */ + /* */ + /* We compute `a*b+c/2', then divide it by `c' (positive values). */ + /* */ + /* 46340 is FLOOR(SQRT(2^31-1)). */ + /* */ + /* if ( a <= 46340 && b <= 46340 ) then ( a*b <= 0x7FFEA810 ) */ + /* */ + /* 0x7FFFFFFF - 0x7FFEA810 = 0x157F0 */ + /* */ + /* if ( c < 0x157F0*2 ) then ( a*b+c/2 <= 0x7FFFFFFF ) */ + /* */ + /* and 2*0x157F0 = 176096. */ + /* */ + FT_EXPORT_FUNC( FT_Long ) FT_MulDiv( FT_Long a, + FT_Long b, + FT_Long c ) + { + long s; + + + if ( a == 0 || b == c ) + return a; + + s = a; a = ABS( a ); + s ^= b; b = ABS( b ); + s ^= c; c = ABS( c ); + + if ( a <= 46340 && b <= 46340 && c <= 176095L && c > 0 ) + { + a = ( a * b + ( c >> 1 ) ) / c; + } + else if ( c > 0 ) + { + FT_Int64 temp, temp2; + + + FT_MulTo64( a, b, &temp ); + temp2.hi = (FT_Int32)( c >> 31 ); + temp2.lo = (FT_UInt32)( c / 2 ); + FT_Add64( &temp, &temp2, &temp ); + a = FT_Div64by32( &temp, c ); + } + else + a = 0x7FFFFFFFL; + + return ( s < 0 ? -a : a ); + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_MulFix */ + /* */ + /* */ + /* A very simple function used to perform the computation */ + /* `(a*b)/0x10000' with maximal accuracy. Most of the time, this is */ + /* used to multiply a given value by a 16.16 fixed float factor. */ + /* */ + /* */ + /* a :: The first multiplier. */ + /* b :: The second multiplier. Use a 16.16 factor here whenever */ + /* possible (see note below). */ + /* */ + /* */ + /* The result of `(a*b)/0x10000'. */ + /* */ + /* */ + /* The optimization for FT_MulFix() is different. We could simply be */ + /* happy by applying the same principles as with FT_MulDiv(), because */ + /* */ + /* c = 0x10000 < 176096 */ + /* */ + /* However, in most cases, we have a `b' with a value around 0x10000 */ + /* which is greater than 46340. */ + /* */ + /* According to some testing, most cases have `a' < 2048, so a good */ + /* idea is to use bounds like 2048 and 1048576 (=floor((2^31-1)/2048) */ + /* for `a' and `b', respectively. */ + /* */ + FT_EXPORT_FUNC( FT_Long ) FT_MulFix( FT_Long a, + FT_Long b ) + { + FT_Long s; + FT_ULong ua, ub; + + + if ( a == 0 || b == 0x10000L ) + return a; + + s = a; a = ABS(a); + s ^= b; b = ABS(b); + + ua = (FT_ULong)a; + ub = (FT_ULong)b; + + if ( ua <= 2048 && ub <= 1048576L ) + { + ua = ( ua * ub + 0x8000 ) >> 16; + } + else + { + FT_ULong al = ua & 0xFFFF; + + + ua = ( ua >> 16 ) * ub + + al * ( ub >> 16 ) + + ( al * ( ub & 0xFFFF ) >> 16 ); + } + + return ( s < 0 ? -(FT_Long)ua : ua ); + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_DivFix */ + /* */ + /* */ + /* A very simple function used to perform the computation */ + /* `(a*0x10000)/b' with maximal accuracy. Most of the time, this is */ + /* used to divide a given value by a 16.16 fixed float factor. */ + /* */ + /* */ + /* a :: The first multiplier. */ + /* b :: The second multiplier. Use a 16.16 factor here whenever */ + /* possible (see note below). */ + /* */ + /* */ + /* The result of `(a*0x10000)/b'. */ + /* */ + /* */ + /* The optimization for FT_DivFix() is simple: If (a << 16) fits into */ + /* 32 bits, then the division is computed directly. Otherwise, we */ + /* use a specialized version of the old FT_MulDiv64(). */ + /* */ + FT_EXPORT_FUNC( FT_Long ) FT_DivFix( FT_Long a, + FT_Long b ) + { + FT_Int32 s; + FT_UInt32 q; + + + s = a; a = ABS(a); + s ^= b; b = ABS(b); + + if ( b == 0 ) + { + /* check for division by 0 */ + q = 0x7FFFFFFFL; + } + else if ( ( a >> 16 ) == 0 ) + { + /* compute result directly */ + q = (FT_UInt32)( a << 16 ) / (FT_UInt32)b; + } + else + { + /* we need more bits; we have to do it by hand */ + FT_UInt32 c; + + + q = ( a / b ) << 16; + c = a % b; + + /* we must compute C*0x10000/B: we simply shift C and B so */ + /* C becomes smaller than 16 bits */ + while ( c >> 16 ) + { + c >>= 1; + b <<= 1; + } + + q += ( c << 16 ) / b; + } + + return ( s < 0 ? -(FT_Int32)q : (FT_Int32)q ); + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Add64 */ + /* */ + /* */ + /* Add two Int64 values. */ + /* */ + /* */ + /* x :: A pointer to the first value to be added. */ + /* y :: A pointer to the second value to be added. */ + /* */ + /* */ + /* z :: A pointer to the result of `x + y'. */ + /* */ + /* */ + /* Will be wrapped by the ADD_64() macro. */ + /* */ + FT_EXPORT_FUNC( void ) FT_Add64( FT_Int64* x, + FT_Int64* y, + FT_Int64* z ) + { + register FT_UInt32 lo, hi; + + + lo = x->lo + y->lo; + hi = x->hi + y->hi + ( lo < x->lo ); + + z->lo = lo; + z->hi = hi; + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_MulTo64 */ + /* */ + /* */ + /* Multiplies two Int32 integers. Returns an Int64 integer. */ + /* */ + /* */ + /* x :: The first multiplier. */ + /* y :: The second multiplier. */ + /* */ + /* */ + /* z :: A pointer to the result of `x * y'. */ + /* */ + /* */ + /* Will be wrapped by the MUL_64() macro. */ + /* */ + FT_EXPORT_FUNC( void ) FT_MulTo64( FT_Int32 x, + FT_Int32 y, + FT_Int64* z ) + { + FT_Int32 s; + + + s = x; x = ABS( x ); + s ^= y; y = ABS( y ); + + { + FT_UInt32 lo1, hi1, lo2, hi2, lo, hi, i1, i2; + + + lo1 = x & 0x0000FFFF; hi1 = x >> 16; + lo2 = y & 0x0000FFFF; hi2 = y >> 16; + + lo = lo1 * lo2; + i1 = lo1 * hi2; + i2 = lo2 * hi1; + hi = hi1 * hi2; + + /* Check carry overflow of i1 + i2 */ + i1 += i2; + if ( i1 < i2 ) + hi += 1L << 16; + + hi += i1 >> 16; + i1 = i1 << 16; + + /* Check carry overflow of i1 + lo */ + lo += i1; + hi += ( lo < i1 ); + + z->lo = lo; + z->hi = hi; + } + + if ( s < 0 ) + { + z->lo = (FT_UInt32)-(FT_Int32)z->lo; + z->hi = ~z->hi + !( z->lo ); + } + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Div64by32 */ + /* */ + /* */ + /* Divides an Int64 value by an Int32 value. Returns an Int32 */ + /* integer. */ + /* */ + /* */ + /* x :: A pointer to the dividend. */ + /* y :: The divisor. */ + /* */ + /* */ + /* The result of `x / y'. */ + /* */ + /* */ + /* Will be wrapped by the DIV_64() macro. */ + /* */ + FT_EXPORT_FUNC( FT_Int32 ) FT_Div64by32( FT_Int64* x, + FT_Int32 y ) + { + FT_Int32 s; + FT_UInt32 q, r, i, lo; + + + s = x->hi; + if ( s < 0 ) + { + x->lo = (FT_UInt32)-(FT_Int32)x->lo; + x->hi = ~x->hi + !( x->lo ); + } + s ^= y; y = ABS( y ); + + /* Shortcut */ + if ( x->hi == 0 ) + { + if ( y > 0 ) + q = x->lo / y; + else + q = 0x7FFFFFFFL; + + return ( s < 0 ? -(FT_Int32)q : (FT_Int32)q ); + } + + r = x->hi; + lo = x->lo; + + if ( r >= (FT_UInt32)y ) /* we know y is to be treated as unsigned here */ + return ( s < 0 ? 0x80000001UL : 0x7FFFFFFFUL ); + /* Return Max/Min Int32 if division overflow. */ + /* This includes division by zero! */ + q = 0; + for ( i = 0; i < 32; i++ ) + { + r <<= 1; + q <<= 1; + r |= lo >> 31; + + if ( r >= (FT_UInt32)y ) + { + r -= y; + q |= 1; + } + lo <<= 1; + } + + return ( s < 0 ? -(FT_Int32)q : (FT_Int32)q ); + } + + +#ifdef FT_CONFIG_OPTION_OLD_CALCS + + + /* two helper functions for FT_Sqrt64() */ + + static + void FT_Sub64( FT_Int64* x, + FT_Int64* y, + FT_Int64* z ) + { + register FT_UInt32 lo, hi; + + + lo = x->lo - y->lo; + hi = x->hi - y->hi - ( (FT_Int32)lo < 0 ); + + z->lo = lo; + z->hi = hi; + } + + + static + int ft_order64( FT_Int64* z ) + { + FT_UInt32 i; + int j; + + + i = z->lo; + j = 0; + if ( z->hi ) + { + i = z->hi; + j = 32; + } + + while ( i > 0 ) + { + i >>= 1; + j++; + } + return j - 1; + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Sqrt64 */ + /* */ + /* */ + /* Computes the square root of a 64-bits value. That sounds stupid, */ + /* but it is needed to obtain maximal accuracy in the TrueType */ + /* bytecode interpreter. */ + /* */ + /* */ + /* z :: A pointer to a 64-bit integer. */ + /* */ + /* */ + /* The 32-bit square-root. */ + /* */ + FT_EXPORT_FUNC( FT_Int32 ) FT_Sqrt64( FT_Int64* l ) + { + FT_Int64 l2; + FT_Int32 r, s; + + + if ( (FT_Int32)l->hi < 0 || + ( l->hi == 0 && l->lo == 0 ) ) + return 0; + + s = ft_order64( l ); + if ( s == 0 ) + return 1; + + r = ft_square_roots[s]; + do + { + s = r; + r = ( r + FT_Div64by32( l, r ) ) >> 1; + FT_MulTo64( r, r, &l2 ); + FT_Sub64 ( l, &l2, &l2 ); + + } while ( r > s || (FT_Int32)l2.hi < 0 ); + + return r; + } + +#endif /* FT_CONFIG_OPTION_OLD_CALCS */ + +#endif /* FT_LONG64 */ + + +/* END */ diff --git a/src/freetype/base/ftdebug.c b/src/freetype/base/ftdebug.c new file mode 100644 index 0000000000..32da7897ef --- /dev/null +++ b/src/freetype/base/ftdebug.c @@ -0,0 +1,124 @@ +/***************************************************************************/ +/* */ +/* ftdebug.c */ +/* */ +/* Debugging and logging component (body). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + + /*************************************************************************/ + /* */ + /* This component contains various macros and functions used to ease the */ + /* debugging of the FreeType engine. Its main purpose is in assertion */ + /* checking, tracing, and error detection. */ + /* */ + /* There are now three debugging modes: */ + /* */ + /* - trace mode */ + /* */ + /* Error and trace messages are sent to the log file (which can be the */ + /* standard error output). */ + /* */ + /* - error mode */ + /* */ + /* Only error messages are generated. */ + /* */ + /* - release mode: */ + /* */ + /* No error message is sent or generated. The code is free from any */ + /* debugging parts. */ + /* */ + /*************************************************************************/ + + +#include + +#ifdef FT_DEBUG_LEVEL_TRACE + char ft_trace_levels[trace_max]; +#endif + + +#if defined( FT_DEBUG_LEVEL_ERROR ) || defined( FT_DEBUG_LEVEL_TRACE ) + + +#include +#include +#include + + + FT_EXPORT_FUNC( void ) FT_Message( const char* fmt, ... ) + { + va_list ap; + + + va_start( ap, fmt ); + vprintf( fmt, ap ); + va_end( ap ); + } + + + FT_EXPORT_FUNC( void ) FT_Panic( const char* fmt, ... ) + { + va_list ap; + + + va_start( ap, fmt ); + vprintf( fmt, ap ); + va_end( ap ); + + exit( EXIT_FAILURE ); + } + + +#ifdef FT_DEBUG_LEVEL_TRACE + + + /*************************************************************************/ + /* */ + /* */ + /* FT_SetTraceLevel */ + /* */ + /* */ + /* Sets the trace level for debugging. */ + /* */ + /* */ + /* component :: The component which should be traced. See ftdebug.h */ + /* for a complete list. If set to `trace_any', all */ + /* components will be traced. */ + /* level :: The tracing level. */ + /* */ + FT_EXPORT_FUNC( void ) FT_SetTraceLevel( FT_Trace component, + char level ) + { + if ( component >= trace_max ) + return; + + /* if component is `trace_any', change _all_ levels at once */ + if ( component == trace_any ) + { + int n; + + + for ( n = trace_any; n < trace_max; n++ ) + ft_trace_levels[n] = level; + } + else /* otherwise, only change individual component */ + ft_trace_levels[component] = level; + } + +#endif /* FT_DEBUG_LEVEL_TRACE */ + +#endif /* FT_DEBUG_LEVEL_TRACE || FT_DEBUG_LEVEL_ERROR */ + + +/* END */ diff --git a/src/freetype/base/ftextend.c b/src/freetype/base/ftextend.c new file mode 100644 index 0000000000..f298b19a8a --- /dev/null +++ b/src/freetype/base/ftextend.c @@ -0,0 +1,332 @@ +/***************************************************************************/ +/* */ +/* ftextend.h */ +/* */ +/* FreeType extensions implementation (body). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + /*************************************************************************/ + /* */ + /* This is an updated version of the extension component, now located */ + /* in the main library's source directory. It allows the dynamic */ + /* registration/use of various face object extensions through a simple */ + /* API. */ + /* */ + /*************************************************************************/ + + +#include +#include + + + /*************************************************************************/ + /* */ + /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ + /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ + /* messages during execution. */ + /* */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_extend + + + typedef struct FT_Extension_Registry_ + { + FT_Int num_extensions; + FT_Long cur_offset; + FT_Extension_Class classes[FT_MAX_EXTENSIONS]; + + } FT_Extension_Registry; + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Init_Extensions */ + /* */ + /* */ + /* Initializes the extension component. */ + /* */ + /* */ + /* driver :: A handle to the driver object. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + LOCAL_FUNC + FT_Error FT_Init_Extensions( FT_Driver driver ) + { + FT_Error error; + FT_Memory memory; + FT_Extension_Registry* registry; + + + memory = driver->root.library->memory; + if ( ALLOC( registry, sizeof ( *registry ) ) ) + return error; + + registry->num_extensions = 0; + registry->cur_offset = 0; + driver->extensions = registry; + + FT_TRACE2(( "FT_Init_Extensions: success\n" )); + + return FT_Err_Ok; + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Done_Extensions */ + /* */ + /* */ + /* Finalizes the extension component. */ + /* */ + /* */ + /* driver :: A handle to the driver object. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + LOCAL_FUNC + FT_Error FT_Done_Extensions( FT_Driver driver ) + { + FT_Memory memory = driver->root.memory; + + + FREE( driver->extensions ); + return FT_Err_Ok; + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Register_Extension */ + /* */ + /* */ + /* Registers a new extension. */ + /* */ + /* */ + /* driver :: A handle to the driver object. */ + /* class :: A pointer to a class describing the extension. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT_FUNC( FT_Error ) FT_Register_Extension( + FT_Driver driver, + FT_Extension_Class* clazz ) + { + FT_Extension_Registry* registry; + + + if ( !driver ) + return FT_Err_Invalid_Driver_Handle; + + if ( !clazz ) + return FT_Err_Invalid_Argument; + + registry = (FT_Extension_Registry*)driver->extensions; + if ( registry ) + { + FT_Int n = registry->num_extensions; + FT_Extension_Class* cur = registry->classes + n; + + + if ( n >= FT_MAX_EXTENSIONS ) + return FT_Err_Too_Many_Extensions; + + *cur = *clazz; + + cur->offset = registry->cur_offset; + + registry->num_extensions++; + registry->cur_offset += + ( cur->size + FT_ALIGNMENT - 1 ) & -FT_ALIGNMENT; + + FT_TRACE1(( "FT_Register_Extension: `%s' successfully registered\n", + cur->id )); + } + + return FT_Err_Ok; + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Get_Extension */ + /* */ + /* */ + /* Queries an extension block by an extension ID string. */ + /* */ + /* */ + /* face :: A handle to the face object. */ + /* extension_id :: An ID string identifying the extension. */ + /* */ + /* */ + /* extension_interface :: A generic pointer, usually pointing to a */ + /* table of functions implementing the */ + /* extension interface. */ + /* */ + /* */ + /* A generic pointer to the extension block. */ + /* */ + FT_EXPORT_FUNC( void* ) FT_Get_Extension( + FT_Face face, + const char* extension_id, + void** extension_interface ) + { + FT_Extension_Registry* registry; + + + if ( !face || !extension_id || !extension_interface ) + return 0; + + registry = (FT_Extension_Registry*)face->driver->extensions; + if ( registry && face->extensions ) + { + FT_Extension_Class* cur = registry->classes; + FT_Extension_Class* limit = cur + registry->num_extensions; + + + for ( ; cur < limit; cur++ ) + if ( strcmp( cur->id, extension_id ) == 0 ) + { + *extension_interface = cur->interface; + + FT_TRACE1(( "FT_Get_Extension: got `%s'\n", extension_id )); + + return (void*)((char*)face->extensions + cur->offset); + } + } + + /* could not find the extension id */ + + FT_ERROR(( "FT_Get_Extension: couldn't find `%s'\n", extension_id )); + + *extension_interface = 0; + + return 0; + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Destroy_Extensions */ + /* */ + /* */ + /* Destroys all extensions within a face object. */ + /* */ + /* */ + /* face :: A handle to the face object. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* Called by the face object destructor. */ + /* */ + LOCAL_FUNC + FT_Error FT_Destroy_Extensions( FT_Face face ) + { + FT_Extension_Registry* registry; + FT_Memory memory; + + + registry = (FT_Extension_Registry*)face->driver->extensions; + if ( registry && face->extensions ) + { + FT_Extension_Class* cur = registry->classes; + FT_Extension_Class* limit = cur + registry->num_extensions; + + + for ( ; cur < limit; cur++ ) + { + char* ext = (char*)face->extensions + cur->offset; + + if ( cur->finalize ) + cur->finalize( ext, face ); + } + + memory = face->driver->root.memory; + FREE( face->extensions ); + } + + return FT_Err_Ok; + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Create_Extensions */ + /* */ + /* */ + /* Creates an extension object within a face object for all */ + /* registered extensions. */ + /* */ + /* */ + /* face :: A handle to the face object. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* Called by the face object constructor. */ + /* */ + LOCAL_FUNC + FT_Error FT_Create_Extensions( FT_Face face ) + { + FT_Extension_Registry* registry; + FT_Memory memory; + FT_Error error; + + + face->extensions = 0; + + /* load extensions registry; exit successfully if none is there */ + + registry = (FT_Extension_Registry*)face->driver->extensions; + if ( !registry ) + return FT_Err_Ok; + + memory = face->driver->root.memory; + if ( ALLOC( face->extensions, registry->cur_offset ) ) + return error; + + { + FT_Extension_Class* cur = registry->classes; + FT_Extension_Class* limit = cur + registry->num_extensions; + + + for ( ; cur < limit; cur++ ) + { + char* ext = (char*)face->extensions + cur->offset; + + if ( cur->init ) + { + error = cur->init( ext, face ); + if ( error ) + break; + } + } + } + + return error; + } + + +/* END */ diff --git a/src/freetype/base/ftglyph.c b/src/freetype/base/ftglyph.c new file mode 100644 index 0000000000..4052e6e4f8 --- /dev/null +++ b/src/freetype/base/ftglyph.c @@ -0,0 +1,1184 @@ +/***************************************************************************/ +/* */ +/* ftglyph.c */ +/* */ +/* FreeType convenience functions to handle glyphs (body). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + /*************************************************************************/ + /* */ + /* This file contains the definition of several convenience functions */ + /* that can be used by client applications to easily retrieve glyph */ + /* bitmaps and outlines from a given face. */ + /* */ + /* These functions should be optional if you are writing a font server */ + /* or text layout engine on top of FreeType. However, they are pretty */ + /* handy for many other simple uses of the library. */ + /* */ + /*************************************************************************/ + + +#include +#include +#include + + + /*************************************************************************/ + /* */ + /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ + /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ + /* messages during execution. */ + /* */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_glyph + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** Convenience functions ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Matrix_Multiply */ + /* */ + /* */ + /* Performs the matrix operation `b = a*b'. */ + /* */ + /* */ + /* a :: A pointer to matrix `a'. */ + /* */ + /* */ + /* b :: A pointer to matrix `b'. */ + /* */ + /* */ + /* Yes. */ + /* */ + /* */ + /* The result is undefined if either `a' or `b' is zero. */ + /* */ + FT_EXPORT_FUNC( void ) FT_Matrix_Multiply( FT_Matrix* a, + FT_Matrix* b ) + { + FT_Fixed xx, xy, yx, yy; + + + if ( !a || !b ) + return; + + xx = FT_MulFix( a->xx, b->xx ) + FT_MulFix( a->xy, b->yx ); + xy = FT_MulFix( a->xx, b->xy ) + FT_MulFix( a->xy, b->yy ); + yx = FT_MulFix( a->yx, b->xx ) + FT_MulFix( a->yy, b->yx ); + yy = FT_MulFix( a->yx, b->xy ) + FT_MulFix( a->yy, b->yy ); + + b->xx = xx; b->xy = xy; + b->yx = yx; b->yy = yy; + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Matrix_Invert */ + /* */ + /* */ + /* Inverts a 2x2 matrix. Returns an error if it can't be inverted. */ + /* */ + /* */ + /* matrix :: A pointer to the target matrix. Remains untouched in */ + /* case of error. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* Yes. */ + /* */ + FT_EXPORT_FUNC( FT_Error ) FT_Matrix_Invert( FT_Matrix* matrix ) + { + FT_Pos delta, xx, yy; + + + if ( !matrix ) + return FT_Err_Invalid_Argument; + + /* compute discriminant */ + delta = FT_MulFix( matrix->xx, matrix->yy ) - + FT_MulFix( matrix->xy, matrix->yx ); + + if ( !delta ) + return FT_Err_Invalid_Argument; /* matrix can't be inverted */ + + matrix->xy = - FT_DivFix( matrix->xy, delta ); + matrix->yx = - FT_DivFix( matrix->yx, delta ); + + xx = matrix->xx; + yy = matrix->yy; + + matrix->xx = FT_DivFix( yy, delta ); + matrix->yy = FT_DivFix( xx, delta ); + + return FT_Err_Ok; + } + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** FT_BitmapGlyph support ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + static + FT_Error ft_bitmap_copy( FT_Memory memory, + FT_Bitmap* source, + FT_Bitmap* target ) + { + FT_Error error; + FT_Int pitch = source->pitch; + FT_ULong size; + + + *target = *source; + + if ( pitch < 0 ) + pitch = -pitch; + + size = (FT_ULong)( pitch * source->rows ); + + if ( !ALLOC( target->buffer, size ) ) + MEM_Copy( source->buffer, target->buffer, size ); + + return error; + } + + + static + FT_Error ft_bitmap_glyph_init( FT_BitmapGlyph glyph, + FT_GlyphSlot slot ) + { + FT_Error error = FT_Err_Ok; + FT_Library library = FT_GLYPH(glyph)->library; + FT_Memory memory = library->memory; + + + if ( slot->format != ft_glyph_format_bitmap ) + { + error = FT_Err_Invalid_Glyph_Format; + goto Exit; + } + + /* grab the bitmap in the slot - do lazy copying whenever possible */ + glyph->bitmap = slot->bitmap; + glyph->left = slot->bitmap_left; + glyph->top = slot->bitmap_top; + + if ( slot->flags & ft_glyph_own_bitmap ) + slot->flags &= ~ft_glyph_own_bitmap; + else + { + /* copy the bitmap into a new buffer */ + error = ft_bitmap_copy( memory, &slot->bitmap, &glyph->bitmap ); + } + + Exit: + return error; + } + + + static + FT_Error ft_bitmap_glyph_copy( FT_BitmapGlyph source, + FT_BitmapGlyph target ) + { + FT_Memory memory = source->root.library->memory; + + + target->left = source->left; + target->top = source->top; + + return ft_bitmap_copy( memory, &source->bitmap, &target->bitmap ); + } + + + static + void ft_bitmap_glyph_done( FT_BitmapGlyph glyph ) + { + FT_Memory memory = FT_GLYPH(glyph)->library->memory; + + + FREE( glyph->bitmap.buffer ); + } + + + static + void ft_bitmap_glyph_bbox( FT_BitmapGlyph glyph, + FT_BBox* cbox ) + { + cbox->xMin = glyph->left << 6; + cbox->xMax = cbox->xMin + ( glyph->bitmap.width << 6 ); + cbox->yMax = glyph->top << 6; + cbox->yMin = cbox->xMax - ( glyph->bitmap.rows << 6 ); + } + + + const FT_Glyph_Class ft_bitmap_glyph_class = + { + sizeof( FT_BitmapGlyphRec ), + ft_glyph_format_bitmap, + + (FT_Glyph_Init_Func) ft_bitmap_glyph_init, + (FT_Glyph_Done_Func) ft_bitmap_glyph_done, + (FT_Glyph_Copy_Func) ft_bitmap_glyph_copy, + (FT_Glyph_Transform_Func)0, + (FT_Glyph_BBox_Func) ft_bitmap_glyph_bbox, + (FT_Glyph_Prepare_Func) 0 + }; + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** FT_OutlineGlyph support ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + + static + FT_Error ft_outline_glyph_init( FT_OutlineGlyph glyph, + FT_GlyphSlot slot ) + { + FT_Error error = FT_Err_Ok; + FT_Library library = FT_GLYPH(glyph)->library; + FT_Outline* source = &slot->outline; + FT_Outline* target = &glyph->outline; + + + /* check format in glyph slot */ + if ( slot->format != ft_glyph_format_outline ) + { + error = FT_Err_Invalid_Glyph_Format; + goto Exit; + } + + /* allocate new outline */ + error = FT_Outline_New( library, source->n_points, source->n_contours, + &glyph->outline ); + if ( error ) + goto Exit; + + /* copy it */ + MEM_Copy( target->points, source->points, + source->n_points * sizeof ( FT_Vector ) ); + + MEM_Copy( target->tags, source->tags, + source->n_points * sizeof ( FT_Byte ) ); + + MEM_Copy( target->contours, source->contours, + source->n_contours * sizeof ( FT_Short ) ); + + /* copy all flags, except the `ft_outline_owner' one */ + target->flags = source->flags | ft_outline_owner; + + Exit: + return error; + } + + + static + void ft_outline_glyph_done( FT_OutlineGlyph glyph ) + { + FT_Outline_Done( FT_GLYPH( glyph )->library, &glyph->outline ); + } + + + static + FT_Error ft_outline_glyph_copy( FT_OutlineGlyph source, + FT_OutlineGlyph target ) + { + FT_Error error; + FT_Library library = FT_GLYPH( source )->library; + + + error = FT_Outline_New( library, source->outline.n_points, + source->outline.n_contours, &target->outline ); + if ( !error ) + FT_Outline_Copy( &source->outline, &target->outline ); + + return error; + } + + + static + void ft_outline_glyph_transform( FT_OutlineGlyph glyph, + FT_Matrix* matrix, + FT_Vector* delta ) + { + if ( matrix ) + FT_Outline_Transform( &glyph->outline, matrix ); + + if ( delta ) + FT_Outline_Translate( &glyph->outline, delta->x, delta->y ); + } + + + static + void ft_outline_glyph_bbox( FT_OutlineGlyph glyph, + FT_BBox* bbox ) + { + FT_Outline_Get_CBox( &glyph->outline, bbox ); + } + + + static + FT_Error ft_outline_glyph_prepare( FT_OutlineGlyph glyph, + FT_GlyphSlot slot ) + { + slot->format = ft_glyph_format_outline; + slot->outline = glyph->outline; + slot->outline.flags &= ~ft_outline_owner; + + return FT_Err_Ok; + } + + + const FT_Glyph_Class ft_outline_glyph_class = + { + sizeof( FT_OutlineGlyphRec ), + ft_glyph_format_outline, + + (FT_Glyph_Init_Func) ft_outline_glyph_init, + (FT_Glyph_Done_Func) ft_outline_glyph_done, + (FT_Glyph_Copy_Func) ft_outline_glyph_copy, + (FT_Glyph_Transform_Func)ft_outline_glyph_transform, + (FT_Glyph_BBox_Func) ft_outline_glyph_bbox, + (FT_Glyph_Prepare_Func) ft_outline_glyph_prepare + }; + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** FT_Glyph class and API ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + static + FT_Error ft_new_glyph( FT_Library library, + const FT_Glyph_Class* clazz, + FT_Glyph* aglyph ) + { + FT_Memory memory = library->memory; + FT_Error error; + FT_Glyph glyph; + + + *aglyph = 0; + + if ( !ALLOC( glyph, clazz->glyph_size ) ) + { + glyph->library = library; + glyph->clazz = clazz; + glyph->format = clazz->glyph_format; + + *aglyph = glyph; + } + + return error; + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Glyph_Copy */ + /* */ + /* */ + /* A function used to copy a glyph image. */ + /* */ + /* */ + /* source :: A handle to the source glyph object. */ + /* */ + /* */ + /* target :: A handle to the target glyph object. 0 in case of */ + /* error. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT_FUNC( FT_Error ) FT_Glyph_Copy( FT_Glyph source, + FT_Glyph* target ) + { + FT_Glyph copy; + FT_Error error; + const FT_Glyph_Class* clazz; + + + /* check arguments */ + if ( !target || !source || !source->clazz ) + { + error = FT_Err_Invalid_Argument; + goto Exit; + } + + *target = 0; + + clazz = source->clazz; + error = ft_new_glyph( source->library, clazz, © ); + if ( error ) + goto Exit; + + if ( clazz->glyph_copy ) + error = clazz->glyph_copy( source, copy ); + + if ( error ) + FT_Done_Glyph( copy ); + else + *target = copy; + + Exit: + return error; + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Get_Glyph */ + /* */ + /* */ + /* A function used to extract a glyph image from a slot. */ + /* */ + /* */ + /* slot :: A handle to the source glyph slot. */ + /* */ + /* */ + /* aglyph :: A handle to the glyph object. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT_FUNC( FT_Error ) FT_Get_Glyph( FT_GlyphSlot slot, + FT_Glyph* aglyph ) + { + FT_Library library = slot->library; + FT_Error error; + FT_Glyph glyph; + + const FT_Glyph_Class* clazz = 0; + + + if ( !slot ) + return FT_Err_Invalid_Slot_Handle; + + if ( !aglyph ) + return FT_Err_Invalid_Argument; + + /* if it is a bitmap, that's easy :-) */ + if ( slot->format == ft_glyph_format_bitmap ) + clazz = &ft_bitmap_glyph_class; + + /* it it is an outline too */ + else if ( slot->format == ft_glyph_format_outline ) + clazz = &ft_outline_glyph_class; + + else + { + /* try to find a renderer that supports the glyph image format */ + FT_Renderer render = FT_Lookup_Renderer( library, slot->format, 0 ); + + + if ( render ) + clazz = &render->glyph_class; + } + + if ( !clazz ) + { + error = FT_Err_Invalid_Glyph_Format; + goto Exit; + } + + /* create FT_Glyph object */ + error = ft_new_glyph( library, clazz, &glyph ); + if ( error ) + goto Exit; + + /* copy advance while converting it to 16.16 format */ + glyph->advance.x = slot->advance.x << 10; + glyph->advance.y = slot->advance.y << 10; + + /* now import the image from the glyph slot */ + error = clazz->glyph_init( glyph, slot ); + + /* if an error occurred, destroy the glyph */ + if ( error ) + FT_Done_Glyph( glyph ); + else + *aglyph = glyph; + + Exit: + return error; + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Glyph_Transform */ + /* */ + /* */ + /* Transforms a glyph image if its format is scalable. */ + /* */ + /* */ + /* glyph :: A handle to the target glyph object. */ + /* */ + /* matrix :: A pointer to a 2x2 matrix to apply. */ + /* */ + /* delta :: A pointer to a 2d vector to apply. Coordinates are */ + /* expressed in 1/64th of a pixel. */ + /* */ + /* */ + /* FreeType error code (the glyph format is not scalable if it is */ + /* not zero). */ + /* */ + /* */ + /* The 2x2 transformation matrix is also applied to the glyph's */ + /* advance vector. */ + /* */ + FT_EXPORT_FUNC( FT_Error ) FT_Glyph_Transform( FT_Glyph glyph, + FT_Matrix* matrix, + FT_Vector* delta ) + { + const FT_Glyph_Class* clazz; + FT_Error error = FT_Err_Ok; + + + if ( !glyph || !glyph->clazz ) + error = FT_Err_Invalid_Argument; + else + { + clazz = glyph->clazz; + if ( clazz->glyph_transform ) + { + /* transform glyph image */ + clazz->glyph_transform( glyph, matrix, delta ); + + /* transform advance vector */ + if ( matrix ) + FT_Vector_Transform( &glyph->advance, matrix ); + } + else + error = FT_Err_Invalid_Glyph_Format; + } + return error; + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Glyph_Get_CBox */ + /* */ + /* */ + /* Returns the glyph image's bounding box. */ + /* */ + /* */ + /* glyph :: A handle to the source glyph object. */ + /* */ + /* mode :: A set of bit flags that indicate how to interpret the */ + /* returned bounding box values. */ + /* */ + /* */ + /* box :: The glyph bounding box. Coordinates are expressed in */ + /* 1/64th of pixels if it is grid-fitted. */ + /* */ + /* */ + /* Coordinates are relative to the glyph origin, using the Y-upwards */ + /* convention. */ + /* */ + /* If `ft_glyph_bbox_subpixels' is set in `mode', the bbox */ + /* coordinates are returned in 26.6 pixels (i.e. 1/64th of pixels). */ + /* Otherwise, coordinates are expressed in integer pixels. */ + /* */ + /* Note that the maximum coordinates are exclusive, which means that */ + /* one can compute the width and height of the glyph image (be it in */ + /* integer or 26.6 pixels) as: */ + /* */ + /* width = bbox.xMax - bbox.xMin; */ + /* height = bbox.yMax - bbox.yMin; */ + /* */ + /* Note also that for 26.6 coordinates, if the */ + /* `ft_glyph_bbox_gridfit' flag is set in `mode;, the coordinates */ + /* will also be grid-fitted, which corresponds to: */ + /* */ + /* bbox.xMin = FLOOR(bbox.xMin); */ + /* bbox.yMin = FLOOR(bbox.yMin); */ + /* bbox.xMax = CEILING(bbox.xMax); */ + /* bbox.yMax = CEILING(bbox.yMax); */ + /* */ + /* The default value (0) for `bbox_mode' is `ft_glyph_bbox_pixels'. */ + /* */ + FT_EXPORT_FUNC( void ) FT_Glyph_Get_CBox( FT_Glyph glyph, + FT_UInt bbox_mode, + FT_BBox* cbox ) + { + const FT_Glyph_Class* clazz; + FT_Error error = FT_Err_Ok; + + + if ( !cbox || !glyph || !glyph->clazz ) + error = FT_Err_Invalid_Argument; + else + { + clazz = glyph->clazz; + if ( !clazz->glyph_bbox ) + error = FT_Err_Invalid_Glyph_Format; + else + { + /* retrieve bbox in 26.6 coordinates */ + clazz->glyph_bbox( glyph, cbox ); + + /* perform grid fitting if needed */ + if ( bbox_mode & ft_glyph_bbox_gridfit ) + { + cbox->xMin &= -64; + cbox->yMin &= -64; + cbox->xMax = ( cbox->xMax + 63 ) & -64; + cbox->yMax = ( cbox->yMax + 63 ) & -64; + } + + /* convert to integer pixels if needed */ + if ( !( bbox_mode & ft_glyph_bbox_subpixels ) ) + { + cbox->xMin >>= 6; + cbox->yMin >>= 6; + cbox->xMax >>= 6; + cbox->yMax >>= 6; + } + } + } + return; + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Glyph_To_Bitmap */ + /* */ + /* */ + /* Converts a given glyph object to a bitmap glyph object. */ + /* */ + /* */ + /* glyph :: A pointer to a handle to the target glyph. */ + /* */ + /* */ + /* render_mode :: A set of bit flags that describe how the data is */ + /* */ + /* */ + /* origin :: A pointer to a vector used to translate the glyph */ + /* image before rendering. Can be 0 (if no */ + /* translation). The origin is expressed in */ + /* 26.6 pixels. */ + /* */ + /* destroy :: A boolean that indicates that the original glyph */ + /* image should be destroyed by this function. It is */ + /* never destroyed in case of error. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* The glyph image is translated with the `origin' vector before */ + /* rendering. In case of error, it it translated back to its */ + /* original position and the glyph is left untouched. */ + /* */ + /* The first parameter is a pointer to a FT_Glyph handle, that will */ + /* be replaced by this function. Typically, you would use (omitting */ + /* error handling): */ + /* */ + /* */ + /* { */ + /* FT_Glyph glyph; */ + /* FT_BitmapGlyph glyph_bitmap; */ + /* */ + /* */ + /* // load glyph */ + /* error = FT_Load_Char( face, glyph_index, FT_LOAD_DEFAUT ); */ + /* */ + /* // extract glyph image */ + /* error = FT_Get_Glyph( face->glyph, &glyph ); */ + /* */ + /* // convert to a bitmap (default render mode + destroy old) */ + /* if ( glyph->format != ft_glyph_format_bitmap ) */ + /* { */ + /* error = FT_Glyph_To_Bitmap( &glyph, ft_render_mode_default, */ + /* 0, 1 ); */ + /* if ( error ) // glyph unchanged */ + /* ... */ + /* } */ + /* */ + /* // access bitmap content by typecasting */ + /* glyph_bitmap = (FT_BitmapGlyph)glyph; */ + /* */ + /* // do funny stuff with it, like blitting/drawing */ + /* ... */ + /* */ + /* // discard glyph image (bitmap or not) */ + /* FT_Done_Glyph( glyph ); */ + /* } */ + /* */ + /* */ + /* This function will always fail if the glyph's format isn't */ + /* scalable. */ + /* */ + FT_EXPORT_FUNC( FT_Error ) FT_Glyph_To_Bitmap( FT_Glyph* the_glyph, + FT_ULong render_mode, + FT_Vector* origin, + FT_Bool destroy ) + { + FT_GlyphSlotRec dummy; + FT_Error error; + FT_Glyph glyph; + FT_BitmapGlyph bitmap; + + const FT_Glyph_Class* clazz; + + + /* check argument */ + if ( !the_glyph ) + goto Bad; + + /* we render the glyph into a glyph bitmap using a `dummy' glyph slot */ + /* then calling FT_Render_Glyph_Internal() */ + + glyph = *the_glyph; + if ( !glyph ) + goto Bad; + + clazz = glyph->clazz; + if ( !clazz || !clazz->glyph_prepare ) + goto Bad; + + MEM_Set( &dummy, 0, sizeof ( dummy ) ); + dummy.library = glyph->library; + dummy.format = clazz->glyph_format; + + /* if `origin' is set, translate the glyph image */ + if ( origin ) + FT_Glyph_Transform( glyph, 0, origin ); + + /* create result bitmap glyph */ + error = ft_new_glyph( glyph->library, &ft_bitmap_glyph_class, + (FT_Glyph*)&bitmap ); + if ( error ) + goto Exit; + + /* prepare dummy slot for rendering */ + error = clazz->glyph_prepare( glyph, &dummy ) || + FT_Render_Glyph_Internal( glyph->library, &dummy, render_mode ); + + if ( !destroy && origin ) + { + FT_Vector v; + + + v.x = -origin->x; + v.y = -origin->y; + FT_Glyph_Transform( glyph, 0, &v ); + } + + /* in case of succes, copy the bitmap to the glyph bitmap */ + if ( !error ) + { + error = ft_bitmap_glyph_init( bitmap, &dummy ); + if ( error ) + { + /* this should never happen, but let's be safe */ + FT_Done_Glyph( FT_GLYPH( bitmap ) ); + goto Exit; + } + + if ( destroy ) + FT_Done_Glyph( glyph ); + + *the_glyph = FT_GLYPH( bitmap ); + } + + Exit: + return error; + + Bad: + error = FT_Err_Invalid_Argument; + goto Exit; + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Done_Glyph */ + /* */ + /* */ + /* Destroys a given glyph. */ + /* */ + /* */ + /* glyph :: A handle to the target glyph object. */ + /* */ + FT_EXPORT_FUNC( void ) FT_Done_Glyph( FT_Glyph glyph ) + { + if ( glyph ) + { + FT_Memory memory = glyph->library->memory; + const FT_Glyph_Class* clazz = glyph->clazz; + + + if ( clazz->glyph_done ) + clazz->glyph_done( glyph ); + + FREE( glyph ); + } + } + + +#if 0 + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** EXPERIMENTAL EMBOLDENING/OUTLINING SUPPORT ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + /* Compute the norm of a vector */ + +#ifdef FT_CONFIG_OPTION_OLD_CALCS + + 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 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 */ + return ft_test_extrema( outline, indices.xMin ) || + ft_test_extrema( outline, indices.yMin ) || + ft_test_extrema( outline, indices.xMax ) || + ft_test_extrema( outline, indices.yMax ) || + 1; /* this is an empty glyph? */ + } + + + static + FT_Error ft_embolden( FT_Face original, + FT_Outline* outline, + FT_Pos* advance ) + { + FT_Vector u, v; + FT_Vector* points; + FT_Vector cur, prev, next; + FT_Pos distance; + int c, n, first, orientation; + + FT_UNUSED( advance ); + + + /* compute control distance */ + distance = FT_MulFix( original->em_size / 60, + original->size->metrics.y_scale ); + + orientation = ft_get_orientation( &original->glyph->outline ); + + points = original->glyph->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->flags[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; + } + +#endif /* 0 -- EXPERIMENTAL STUFF! */ + + +/* END */ diff --git a/src/freetype/base/ftinit.c b/src/freetype/base/ftinit.c new file mode 100644 index 0000000000..cc754eb856 --- /dev/null +++ b/src/freetype/base/ftinit.c @@ -0,0 +1,155 @@ +/***************************************************************************/ +/* */ +/* ftinit.c */ +/* */ +/* FreeType initialization layer (body). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + /*************************************************************************/ + /* */ + /* The purpose of this file is to implement the following two */ + /* functions: */ + /* */ + /* FT_Add_Default_Modules(): */ + /* This function is used to add the set of default modules to a */ + /* fresh new library object. The set is taken from the header file */ + /* `freetype/config/ftmodule.h'. See the document `FreeType 2.0 */ + /* Build System' for more information. */ + /* */ + /* FT_Init_FreeType(): */ + /* This function creates a system object for the current platform, */ + /* builds a library out of it, then calls FT_Default_Drivers(). */ + /* */ + /* Note that even if FT_Init_FreeType() uses the implementation of the */ + /* system object defined at build time, client applications are still */ + /* able to provide their own `ftsystem.c'. */ + /* */ + /*************************************************************************/ + + +#include +#include +#include +#include + + + /*************************************************************************/ + /* */ + /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ + /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ + /* messages during execution. */ + /* */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_init + +#undef FT_USE_MODULE +#define FT_USE_MODULE( x ) extern const FT_Module_Class* x; + +#ifdef macintosh + FT_USE_MODULE(fond_driver_class) +#endif +#include + +#undef FT_USE_MODULE +#define FT_USE_MODULE( x ) (const FT_Module_Class*)&x, + +static +const FT_Module_Class* ft_default_modules[] = + { +#ifdef macintosh + FT_USE_MODULE(fond_driver_class) +#endif +#include + 0 + }; + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Add_Default_Modules */ + /* */ + /* */ + /* Adds the set of default drivers to a given library object. */ + /* This is only useful when you create a library object with */ + /* FT_New_Library() (usually to plug a custom memory manager). */ + /* */ + /* */ + /* library :: A handle to a new library object. */ + /* */ + FT_EXPORT_FUNC( void ) FT_Add_Default_Modules( FT_Library library ) + { + FT_Error error; + const FT_Module_Class** cur; + + + /* test for valid `library' delayed to FT_Add_Module() */ + + cur = ft_default_modules; + while ( *cur ) + { + error = FT_Add_Module( library, *cur ); + /* notify errors, but don't stop */ + if ( error ) + { + FT_ERROR(( "FT_Add_Default_Module: Cannot install `%s', error = %x\n", + (*cur)->module_name, error )); + } + cur++; + } + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Init_FreeType */ + /* */ + /* */ + /* Initializes a new FreeType library object. The set of drivers */ + /* that are registered by this function is determined at build time. */ + /* */ + /* */ + /* library :: A handle to a new library object. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT_FUNC( FT_Error ) FT_Init_FreeType( FT_Library* library ) + { + FT_Error error; + FT_Memory memory; + + + /* First of all, allocate a new system object -- this function is part */ + /* of the system-specific component, i.e. `ftsystem.c'. */ + + memory = FT_New_Memory(); + if ( !memory ) + { + FT_ERROR(( "FT_Init_FreeType: cannot find memory manager\n" )); + return FT_Err_Unimplemented_Feature; + } + + /* build a library out of it, then fill it with the set of */ + /* default drivers. */ + + error = FT_New_Library( memory, library ); + if ( !error ) + FT_Add_Default_Modules( *library ); + + return error; + } + + +/* END */ diff --git a/src/freetype/base/ftlist.c b/src/freetype/base/ftlist.c new file mode 100644 index 0000000000..0158ba4434 --- /dev/null +++ b/src/freetype/base/ftlist.c @@ -0,0 +1,301 @@ +/***************************************************************************/ +/* */ +/* ftlist.c */ +/* */ +/* Generic list support for FreeType (body). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + /*************************************************************************/ + /* */ + /* This file implements functions relative to list processing. Its */ + /* data structures are defined in `freetype/internal/ftlist.h'. */ + /* */ + /*************************************************************************/ + + +#include +#include +#include + + + /*************************************************************************/ + /* */ + /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ + /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ + /* messages during execution. */ + /* */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_list + + + /*************************************************************************/ + /* */ + /* */ + /* FT_List_Find */ + /* */ + /* */ + /* Finds the list node for a given listed object. */ + /* */ + /* */ + /* list :: A pointer to the parent list. */ + /* data :: The address of the listed object. */ + /* */ + /* */ + /* List node. NULL if it wasn't found. */ + /* */ + BASE_FUNC( FT_ListNode ) FT_List_Find( FT_List list, + void* data ) + { + FT_ListNode cur; + + + cur = list->head; + while ( cur ) + { + if ( cur->data == data ) + return cur; + + cur = cur->next; + } + + return (FT_ListNode)0; + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_List_Add */ + /* */ + /* */ + /* Appends an element to the end of a list. */ + /* */ + /* */ + /* list :: A pointer to the parent list. */ + /* node :: The node to append. */ + /* */ + BASE_FUNC( void ) FT_List_Add( FT_List list, + FT_ListNode node ) + { + FT_ListNode before = list->tail; + + + node->next = 0; + node->prev = before; + + if ( before ) + before->next = node; + else + list->head = node; + + list->tail = node; + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_List_Insert */ + /* */ + /* */ + /* Inserts an element at the head of a list. */ + /* */ + /* */ + /* list :: A pointer to parent list. */ + /* node :: The node to insert. */ + /* */ + BASE_FUNC( void ) FT_List_Insert( FT_List list, + FT_ListNode node ) + { + FT_ListNode after = list->head; + + + node->next = after; + node->prev = 0; + + if ( !after ) + list->tail = node; + else + after->prev = node; + + list->head = node; + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_List_Remove */ + /* */ + /* */ + /* Removes a node from a list. This function doesn't check whether */ + /* the node is in the list! */ + /* */ + /* */ + /* node :: The node to remove. */ + /* */ + /* */ + /* list :: A pointer to the parent list. */ + /* */ + BASE_FUNC( void ) FT_List_Remove( FT_List list, + FT_ListNode node ) + { + FT_ListNode before, after; + + + before = node->prev; + after = node->next; + + if ( before ) + before->next = after; + else + list->head = after; + + if ( after ) + after->prev = before; + else + list->tail = before; + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_List_Up */ + /* */ + /* */ + /* Moves a node to the head/top of a list. Used to maintain LRU */ + /* lists. */ + /* */ + /* */ + /* list :: A pointer to the parent list. */ + /* node :: The node to move. */ + /* */ + BASE_FUNC( void ) FT_List_Up( FT_List list, + FT_ListNode node ) + { + FT_ListNode before, after; + + + before = node->prev; + after = node->next; + + /* check whether we are already on top of the list */ + if ( !before ) + return; + + before->next = after; + + if ( after ) + after->prev = before; + else + list->tail = before; + + node->prev = 0; + node->next = list->head; + list->head->prev = node; + list->head = node; + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_List_Iterate */ + /* */ + /* */ + /* Parses a list and calls a given iterator function on each element. */ + /* Note that parsing is stopped as soon as one of the iterator calls */ + /* returns a non-zero value. */ + /* */ + /* */ + /* list :: A handle to the list. */ + /* iterator :: An interator function, called on each node of the */ + /* list. */ + /* user :: A user-supplied field which is passed as the second */ + /* argument to the iterator. */ + /* */ + /* */ + /* The result (a FreeType error code) of the last iterator call. */ + /* */ + BASE_FUNC( FT_Error ) FT_List_Iterate( FT_List list, + FT_List_Iterator iterator, + void* user ) + { + FT_ListNode cur = list->head; + FT_Error error = FT_Err_Ok; + + + while ( cur ) + { + FT_ListNode next = cur->next; + + + error = iterator( cur, user ); + if ( error ) + break; + + cur = next; + } + + return error; + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_List_Finalize */ + /* */ + /* */ + /* Destroys all elements in the list as well as the list itself. */ + /* */ + /* */ + /* list :: A handle to the list. */ + /* */ + /* destroy :: A list destructor that will be applied to each element */ + /* of the list. */ + /* */ + /* memory :: The current memory object which handles deallocation. */ + /* */ + /* user :: A user-supplied field which is passed as the last */ + /* argument to the destructor. */ + /* */ + BASE_FUNC( void ) FT_List_Finalize( FT_List list, + FT_List_Destructor destroy, + FT_Memory memory, + void* user ) + { + FT_ListNode cur; + + + cur = list->head; + while ( cur ) + { + FT_ListNode next = cur->next; + void* data = cur->data; + + + if ( destroy ) + destroy( memory, data, user ); + + FREE( cur ); + cur = next; + } + + list->head = 0; + list->tail = 0; + } + + +/* END */ diff --git a/src/freetype/base/ftmm.c b/src/freetype/base/ftmm.c new file mode 100644 index 0000000000..0f6fddea28 --- /dev/null +++ b/src/freetype/base/ftmm.c @@ -0,0 +1,176 @@ +/***************************************************************************/ +/* */ +/* ftmm.c */ +/* */ +/* Multiple Master font support (body). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#include +#include + + + /*************************************************************************/ + /* */ + /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ + /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ + /* messages during execution. */ + /* */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_mm + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Get_Multi_Master */ + /* */ + /* */ + /* Retrieves the Multiple Master descriptor of a given font. */ + /* */ + /* */ + /* face :: A handle to the source face. */ + /* */ + /* */ + /* master :: The Multiple Masters descriptor. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT_FUNC( FT_Error ) FT_Get_Multi_Master( FT_Face face, + FT_Multi_Master* master ) + { + FT_Error error; + + + if ( !face ) + return FT_Err_Invalid_Face_Handle; + + error = FT_Err_Invalid_Argument; + + if ( FT_HAS_MULTIPLE_MASTERS( face ) ) + { + FT_Driver driver = face->driver; + FT_Get_MM_Func func; + + + func = (FT_Get_MM_Func)driver->root.clazz->get_interface( + FT_MODULE( driver ), "get_mm" ); + if ( func ) + error = func( face, master ); + } + + return error; + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Set_MM_Design_Coordinates */ + /* */ + /* */ + /* For Multiple Masters fonts, choose an interpolated font design */ + /* through design coordinates. */ + /* */ + /* */ + /* face :: A handle to the source face. */ + /* */ + /* num_coords :: The number of design coordinates (must be equal to */ + /* the number of axes in the font). */ + /* */ + /* coords :: The design coordinates. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT_FUNC( FT_Error ) FT_Set_MM_Design_Coordinates( + FT_Face face, + FT_UInt num_coords, + FT_Long* coords ) + { + FT_Error error; + + + if ( !face ) + return FT_Err_Invalid_Face_Handle; + + error = FT_Err_Invalid_Argument; + + if ( FT_HAS_MULTIPLE_MASTERS( face ) ) + { + FT_Driver driver = face->driver; + FT_Set_MM_Design_Func func; + + + func = (FT_Set_MM_Design_Func)driver->root.clazz->get_interface( + FT_MODULE( driver ), "set_mm_design" ); + if ( func ) + error = func( face, num_coords, coords ); + } + + return error; + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Set_MM_Blend_Coordinates */ + /* */ + /* */ + /* For Multiple Masters fonts, choose an interpolated font design */ + /* through normalized blend coordinates. */ + /* */ + /* */ + /* face :: A handle to the source face. */ + /* */ + /* num_coords :: The number of design coordinates (must be equal to */ + /* the number of axes in the font). */ + /* */ + /* coords :: The design coordinates (each one must be between 0 */ + /* and 1.0). */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT_FUNC( FT_Error ) FT_Set_MM_Blend_Coordinates( + FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ) + { + FT_Error error; + + + if ( !face ) + return FT_Err_Invalid_Face_Handle; + + error = FT_Err_Invalid_Argument; + + if ( FT_HAS_MULTIPLE_MASTERS( face ) ) + { + FT_Driver driver = face->driver; + FT_Set_MM_Blend_Func func; + + + func = (FT_Set_MM_Blend_Func)driver->root.clazz->get_interface( + FT_MODULE( driver ), "set_mm_blend" ); + if ( func ) + error = func( face, num_coords, coords ); + } + + return error; + } + + +/* END */ diff --git a/src/freetype/base/ftnames.c b/src/freetype/base/ftnames.c new file mode 100644 index 0000000000..43a0d12d07 --- /dev/null +++ b/src/freetype/base/ftnames.c @@ -0,0 +1,70 @@ +/***************************************************************************/ +/* */ +/* ftnames.c */ +/* */ +/* Simple interface to access SFNT name tables (which are used */ +/* to hold font names, copyright info, notices, etc.). */ +/* */ +/* This is _not_ used to retrieve glyph names! */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#include +#include + + +#ifdef FT_CONFIG_OPTION_SFNT_NAMES + + + FT_EXPORT_FUNC( FT_UInt ) FT_Get_Sfnt_Name_Count( FT_Face face ) + { + return face && ( FT_IS_SFNT( face ) ? ((TT_Face)face)->num_names : 0 ); + } + + + FT_EXPORT_FUNC( FT_Error ) FT_Get_Sfnt_Name( FT_Face face, + FT_UInt index, + FT_SfntName* aname ) + { + FT_Error error = FT_Err_Invalid_Argument; + + + if ( aname && face && FT_IS_SFNT( face ) ) + { + TT_Face ttface = (TT_Face)face; + + + if ( index < ttface->num_names ) + { + TT_NameRec* name = ttface->name_table.names + index; + + + aname->platform_id = name->platformID; + aname->encoding_id = name->encodingID; + aname->language_id = name->languageID; + aname->name_id = name->nameID; + aname->string = (FT_Byte*)name->string; + aname->string_len = name->stringLength; + + error = FT_Err_Ok; + } + } + + return error; + } + + +#endif /* FT_CONFIG_OPTION_SFNT_NAMES */ + + +/* END */ diff --git a/src/freetype/base/ftobjs.c b/src/freetype/base/ftobjs.c new file mode 100644 index 0000000000..de74882554 --- /dev/null +++ b/src/freetype/base/ftobjs.c @@ -0,0 +1,3246 @@ +/***************************************************************************/ +/* */ +/* ftobjs.c */ +/* */ +/* The FreeType private base classes (body). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#include +#include +#include +#include + +#include + +#include /* for strcmp() */ + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** M E M O R Y ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + /*************************************************************************/ + /* */ + /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ + /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ + /* messages during execution. */ + /* */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_memory + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Alloc */ + /* */ + /* */ + /* Allocates a new block of memory. The returned area is always */ + /* zero-filled; this is a strong convention in many FreeType parts. */ + /* */ + /* */ + /* memory :: A handle to a given `memory object' which handles */ + /* allocation. */ + /* */ + /* size :: The size in bytes of the block to allocate. */ + /* */ + /* */ + /* P :: A pointer to the fresh new block. It should be set to */ + /* NULL if `size' is 0, or in case of error. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + BASE_FUNC( FT_Error ) FT_Alloc( FT_Memory memory, + FT_Long size, + void** P ) + { + FT_Assert( P != 0 ); + + if ( size > 0 ) + { + *P = memory->alloc( memory, size ); + if ( !*P ) + { + FT_ERROR(( "FT_Alloc:" )); + FT_ERROR(( " Out of memory? (%ld requested)\n", + size )); + + return FT_Err_Out_Of_Memory; + } + MEM_Set( *P, 0, size ); + } + else + *P = NULL; + + FT_TRACE7(( "FT_Alloc:" )); + FT_TRACE7(( " size = %ld, block = 0x%08p, ref = 0x%08p\n", + size, *P, P )); + + return FT_Err_Ok; + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Realloc */ + /* */ + /* */ + /* Reallocates a block of memory pointed to by `*P' to `Size' bytes */ + /* from the heap, possibly changing `*P'. */ + /* */ + /* */ + /* memory :: A handle to a given `memory object' which handles */ + /* reallocation. */ + /* */ + /* current :: The current block size in bytes. */ + /* */ + /* size :: The new block size in bytes. */ + /* */ + /* */ + /* P :: A pointer to the fresh new block. It should be set to */ + /* NULL if `size' is 0, or in case of error. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* All callers of FT_Realloc() _must_ provide the current block size */ + /* as well as the new one. */ + /* */ + BASE_FUNC( FT_Error ) FT_Realloc( FT_Memory memory, + FT_Long current, + FT_Long size, + void** P ) + { + void* Q; + + + FT_Assert( P != 0 ); + + /* if the original pointer is NULL, call FT_Alloc() */ + if ( !*P ) + return FT_Alloc( memory, size, P ); + + /* if the new block if zero-sized, clear the current one */ + if ( size <= 0 ) + { + FT_Free( memory, P ); + return FT_Err_Ok; + } + + Q = memory->realloc( memory, current, size, *P ); + if ( !Q ) + goto Fail; + + *P = Q; + return FT_Err_Ok; + + Fail: + FT_ERROR(( "FT_Realloc:" )); + FT_ERROR(( " Failed (current %ld, requested %ld)\n", + current, size )); + return FT_Err_Out_Of_Memory; + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Free */ + /* */ + /* */ + /* Releases a given block of memory allocated through FT_Alloc(). */ + /* */ + /* */ + /* memory :: A handle to a given `memory object' which handles */ + /* memory deallocation */ + /* */ + /* P :: This is the _address_ of a _pointer_ which points to the */ + /* allocated block. It is always set to NULL on exit. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* If P or *P are NULL, this function should return successfully. */ + /* This is a strong convention within all of FreeType and its */ + /* drivers. */ + /* */ + BASE_FUNC( void ) FT_Free( FT_Memory memory, + void** P ) + { + FT_TRACE7(( "FT_Free:" )); + FT_TRACE7(( " Freeing block 0x%08p, ref 0x%08p\n", + P, P ? *P : (void*)0 )); + + if ( P && *P ) + { + memory->free( memory, *P ); + *P = 0; + } + } + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** S T R E A M ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* */ + /* ft_new_input_stream */ + /* */ + /* */ + /* Creates a new input stream object from an FT_Open_Args structure. */ + /* */ + /* */ + /* The function expects a valid `astream' parameter. */ + /* */ + static + FT_Error ft_new_input_stream( FT_Library library, + FT_Open_Args* args, + FT_Stream* astream ) + { + FT_Error error; + FT_Memory memory; + FT_Stream stream; + + + if ( !library ) + return FT_Err_Invalid_Library_Handle; + + if ( !args ) + return FT_Err_Invalid_Argument; + + *astream = 0; + memory = library->memory; + if ( ALLOC( stream, sizeof ( *stream ) ) ) + goto Exit; + + stream->memory = memory; + + /* now, look at the stream flags */ + if ( args->flags & ft_open_memory ) + { + error = 0; + FT_New_Memory_Stream( library, + args->memory_base, + args->memory_size, + stream ); + } + else if ( args->flags & ft_open_pathname ) + { + error = FT_New_Stream( args->pathname, stream ); + stream->pathname.pointer = args->pathname; + } + else if ( args->flags & ft_open_stream && args->stream ) + { + *stream = *(args->stream); + stream->memory = memory; + } + else + error = FT_Err_Invalid_Argument; + + if ( error ) + FREE( stream ); + + *astream = stream; + + Exit: + return error; + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Done_Stream */ + /* */ + /* */ + /* Closes and destroys a stream object. */ + /* */ + /* */ + /* stream :: The stream to be closed and destroyed. */ + /* */ + FT_EXPORT_FUNC( void ) FT_Done_Stream( FT_Stream stream ) + { + if ( stream && stream->close ) + stream->close( stream ); + } + + + static + void ft_done_stream( FT_Stream* astream ) + { + FT_Stream stream = *astream; + FT_Memory memory = stream->memory; + + + if ( stream->close ) + stream->close( stream ); + + FREE( stream ); + *astream = 0; + } + + +#undef FT_COMPONENT +#define FT_COMPONENT trace_objs + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** G L Y P H L O A D E R ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* The glyph loader is a simple object which is used to load a set of */ + /* glyphs easily. It is critical for the correct loading of composites. */ + /* */ + /* Ideally, one can see it as a stack of abstract `glyph' objects. */ + /* */ + /* loader.base Is really the bottom of the stack. It describes a */ + /* single glyph image made of the juxtaposition of */ + /* several glyphs (those `in the stack'). */ + /* */ + /* loader.current Describes the top of the stack, on which a new */ + /* glyph can be loaded. */ + /* */ + /* Rewind Clears the stack. */ + /* Prepare Set up `loader.current' for addition of a new glyph */ + /* image. */ + /* Add Add the `current' glyph image to the `base' one, */ + /* and prepare for another one. */ + /* */ + /* The glyph loader is now a base object. Each driver used to */ + /* re-implement it in one way or the other, which wasted code and */ + /* energy. */ + /* */ + /*************************************************************************/ + + + /* create a new glyph loader */ + BASE_FUNC( FT_Error ) FT_GlyphLoader_New( FT_Memory memory, + FT_GlyphLoader** aloader ) + { + FT_GlyphLoader* loader; + FT_Error error; + + + if ( !ALLOC( loader, sizeof ( *loader ) ) ) + { + loader->memory = memory; + *aloader = loader; + } + return error; + } + + + /* rewind the glyph loader - reset counters to 0 */ + BASE_FUNC( void ) FT_GlyphLoader_Rewind( FT_GlyphLoader* loader ) + { + FT_GlyphLoad* base = &loader->base; + FT_GlyphLoad* current = &loader->current; + + + base->outline.n_points = 0; + base->outline.n_contours = 0; + base->num_subglyphs = 0; + + *current = *base; + } + + + /* reset the glyph loader, frees all allocated tables */ + /* and starts from zero */ + BASE_FUNC( void ) FT_GlyphLoader_Reset( FT_GlyphLoader* loader ) + { + FT_Memory memory = loader->memory; + + + FREE( loader->base.outline.points ); + FREE( loader->base.outline.tags ); + FREE( loader->base.outline.contours ); + FREE( loader->base.extra_points ); + FREE( loader->base.subglyphs ); + + loader->max_points = 0; + loader->max_contours = 0; + loader->max_subglyphs = 0; + + FT_GlyphLoader_Rewind( loader ); + } + + + /* delete a glyph loader */ + BASE_FUNC( void ) FT_GlyphLoader_Done( FT_GlyphLoader* loader ) + { + if ( loader ) + { + FT_Memory memory = loader->memory; + + + FT_GlyphLoader_Reset( loader ); + FREE( loader ); + } + } + + + /* re-adjust the `current' outline fields */ + static + void FT_GlyphLoader_Adjust_Points( FT_GlyphLoader* loader ) + { + FT_Outline* base = &loader->base.outline; + FT_Outline* current = &loader->current.outline; + + + current->points = base->points + base->n_points; + current->tags = base->tags + base->n_points; + current->contours = base->contours + base->n_contours; + + /* handle extra points table - if any */ + if ( loader->use_extra ) + loader->current.extra_points = + loader->base.extra_points + base->n_points; + } + + + BASE_FUNC( FT_Error ) FT_GlyphLoader_Create_Extra( + FT_GlyphLoader* loader ) + { + FT_Error error; + FT_Memory memory = loader->memory; + + + if ( !ALLOC_ARRAY( loader->base.extra_points, + loader->max_points, FT_Vector ) ) + { + loader->use_extra = 1; + FT_GlyphLoader_Adjust_Points( loader ); + } + return error; + } + + + /* re-adjust the `current' subglyphs field */ + static + void FT_GlyphLoader_Adjust_Subglyphs( FT_GlyphLoader* loader ) + { + FT_GlyphLoad* base = &loader->base; + FT_GlyphLoad* current = &loader->current; + + + current->subglyphs = base->subglyphs + base->num_subglyphs; + } + + + /* Ensure that we can add `n_points' and `n_contours' to our glyph. this */ + /* function reallocates its outline tables if necessary. Note that it */ + /* DOESN'T change the number of points within the loader! */ + /* */ + BASE_FUNC( FT_Error ) FT_GlyphLoader_Check_Points( + FT_GlyphLoader* loader, + FT_UInt n_points, + FT_UInt n_contours ) + { + FT_Memory memory = loader->memory; + FT_Error error = FT_Err_Ok; + FT_Outline* base = &loader->base.outline; + FT_Outline* current = &loader->current.outline; + FT_Bool adjust = 1; + + FT_UInt new_max; + + + /* check points & tags */ + new_max = base->n_points + current->n_points + n_points; + if ( new_max > loader->max_points ) + { + new_max = ( new_max + 7 ) & -8; + if ( REALLOC_ARRAY( base->points, base->n_points, + new_max, FT_Vector ) || + REALLOC_ARRAY( base->tags, base->n_points, + new_max, FT_Byte ) ) + goto Exit; + + if ( loader->use_extra && + REALLOC_ARRAY( loader->base.extra_points, base->n_points, + new_max, FT_Vector ) ) + goto Exit; + + adjust = 1; + loader->max_points = new_max; + } + + /* check contours */ + new_max = base->n_contours + current->n_contours + + n_contours; + if ( new_max > loader->max_contours ) + { + new_max = ( new_max + 3 ) & -4; + if ( REALLOC_ARRAY( base->contours, base->n_contours, + new_max, FT_Short ) ) + goto Exit; + + adjust = 1; + loader->max_contours = new_max; + } + + if ( adjust ) + FT_GlyphLoader_Adjust_Points( loader ); + + Exit: + return error; + } + + + /* Ensure that we can add `n_subglyphs' to our glyph. this function */ + /* reallocates its subglyphs table if necessary. Note that it DOES */ + /* NOT change the number of subglyphs within the loader! */ + /* */ + BASE_FUNC( FT_Error ) FT_GlyphLoader_Check_Subglyphs( + FT_GlyphLoader* loader, + FT_UInt n_subs ) + { + FT_Memory memory = loader->memory; + FT_Error error = FT_Err_Ok; + FT_UInt new_max; + + FT_GlyphLoad* base = &loader->base; + FT_GlyphLoad* current = &loader->current; + + + new_max = base->num_subglyphs + current->num_subglyphs + n_subs; + if ( new_max > loader->max_subglyphs ) + { + new_max = ( new_max + 1 ) & -2; + if ( REALLOC_ARRAY( base->subglyphs, base->num_subglyphs, + new_max, FT_SubGlyph ) ) + goto Exit; + + loader->max_subglyphs = new_max; + + FT_GlyphLoader_Adjust_Subglyphs( loader ); + } + + Exit: + return error; + } + + + /* prepare loader for the addition of a new glyph on top of the base one */ + BASE_FUNC( void ) FT_GlyphLoader_Prepare( FT_GlyphLoader* loader ) + { + FT_GlyphLoad* current = &loader->current; + + + current->outline.n_points = 0; + current->outline.n_contours = 0; + current->num_subglyphs = 0; + + FT_GlyphLoader_Adjust_Points ( loader ); + FT_GlyphLoader_Adjust_Subglyphs( loader ); + } + + + /* add current glyph to the base image - and prepare for another */ + BASE_FUNC( void ) FT_GlyphLoader_Add( FT_GlyphLoader* loader ) + { + FT_GlyphLoad* base = &loader->base; + FT_GlyphLoad* current = &loader->current; + + FT_UInt n_curr_contours = current->outline.n_contours; + FT_UInt n_base_points = base->outline.n_points; + FT_UInt n; + + + base->outline.n_points += current->outline.n_points; + base->outline.n_contours += current->outline.n_contours; + base->num_subglyphs += current->num_subglyphs; + + /* adjust contours count in newest outline */ + for ( n = 0; n < n_curr_contours; n++ ) + current->outline.contours[n] += n_base_points; + + /* prepare for another new glyph image */ + FT_GlyphLoader_Prepare( loader ); + } + + + BASE_FUNC( FT_Error ) FT_GlyphLoader_Copy_Points( FT_GlyphLoader* target, + FT_GlyphLoader* source ) + { + FT_Error error; + FT_UInt num_points = source->base.outline.n_points; + FT_UInt num_contours = source->base.outline.n_contours; + + + error = FT_GlyphLoader_Check_Points( target, num_points, num_contours ); + if ( !error ) + { + FT_Outline* out = &target->base.outline; + FT_Outline* in = &source->base.outline; + + + MEM_Copy( out->points, in->points, + num_points * sizeof ( FT_Vector ) ); + MEM_Copy( out->tags, in->tags, + num_points * sizeof ( char ) ); + MEM_Copy( out->contours, in->contours, + num_contours * sizeof ( short ) ); + + /* do we need to copy the extra points? */ + if ( target->use_extra && source->use_extra ) + MEM_Copy( target->base.extra_points, source->base.extra_points, + num_points * sizeof ( FT_Vector ) ); + + out->n_points = num_points; + out->n_contours = num_contours; + + FT_GlyphLoader_Adjust_Points( target ); + } + + return error; + } + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** FACE, SIZE & GLYPH SLOT OBJECTS ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + static + FT_Error ft_glyphslot_init( FT_GlyphSlot slot ) + { + FT_Driver driver = slot->face->driver; + FT_Driver_Class* clazz = driver->clazz; + FT_Memory memory = driver->root.memory; + FT_Error error = FT_Err_Ok; + + + slot->library = driver->root.library; + + if ( FT_DRIVER_USES_OUTLINES( driver ) ) + error = FT_GlyphLoader_New( memory, &slot->loader ); + + if ( !error && clazz->init_slot ) + error = clazz->init_slot( slot ); + + return error; + } + + + static + void ft_glyphslot_clear( FT_GlyphSlot slot ) + { + /* free bitmap if needed */ + if ( slot->flags & ft_glyph_own_bitmap ) + { + FT_Memory memory = FT_FACE_MEMORY( slot->face ); + + + FREE( slot->bitmap.buffer ); + slot->flags &= ~ft_glyph_own_bitmap; + } + + /* clear all public fields in the glyph slot */ + MEM_Set( &slot->metrics, 0, sizeof ( slot->metrics ) ); + MEM_Set( &slot->outline, 0, sizeof ( slot->outline ) ); + MEM_Set( &slot->bitmap, 0, sizeof ( slot->bitmap ) ); + + slot->bitmap_left = 0; + slot->bitmap_top = 0; + slot->num_subglyphs = 0; + slot->subglyphs = 0; + slot->control_data = 0; + slot->control_len = 0; + slot->other = 0; + slot->format = ft_glyph_format_none; + + slot->linearHoriAdvance = 0; + slot->linearVertAdvance = 0; + } + + + static + void ft_glyphslot_done( FT_GlyphSlot slot ) + { + FT_Driver driver = slot->face->driver; + FT_Driver_Class* clazz = driver->clazz; + FT_Memory memory = driver->root.memory; + + + /* free bitmap buffer if needed */ + if ( slot->flags & ft_glyph_own_bitmap ) + FREE( slot->bitmap.buffer ); + + /* free glyph loader */ + if ( FT_DRIVER_USES_OUTLINES( driver ) ) + { + FT_GlyphLoader_Done( slot->loader ); + slot->loader = 0; + } + + if ( clazz->done_slot ) + clazz->done_slot( slot ); + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_New_GlyphSlot */ + /* */ + /* */ + /* It is sometimes useful to have more than one glyph slot for a */ + /* given face object. This function is used to create additional */ + /* slots. All of them are automatically discarded when the face is */ + /* destroyed. */ + /* */ + /* */ + /* face :: A handle to a parent face object. */ + /* */ + /* */ + /* aslot :: A handle to a new glyph slot object. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT_FUNC( FT_Error ) FT_New_GlyphSlot( FT_Face face, + FT_GlyphSlot* aslot ) + { + FT_Error error; + FT_Driver driver; + FT_Driver_Class* clazz; + FT_Memory memory; + FT_GlyphSlot slot; + + + if ( !face || !aslot || !face->driver ) + return FT_Err_Invalid_Argument; + + *aslot = 0; + + driver = face->driver; + clazz = driver->clazz; + memory = driver->root.memory; + + FT_TRACE4(( "FT_New_GlyphSlot: Creating new slot object\n" )); + if ( !ALLOC( slot, clazz->slot_object_size ) ) + { + slot->face = face; + + error = ft_glyphslot_init( slot ); + if ( error ) + { + ft_glyphslot_done( slot ); + FREE( slot ); + goto Exit; + } + + *aslot = slot; + } + + Exit: + FT_TRACE4(( "FT_New_GlyphSlot: Return %d\n", error )); + return error; + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Done_GlyphSlot */ + /* */ + /* */ + /* Destroys a given glyph slot. Remember however that all slots are */ + /* automatically destroyed with its parent. Using this function is */ + /* not always mandatory. */ + /* */ + /* */ + /* slot :: A handle to a target glyph slot. */ + /* */ + FT_EXPORT_FUNC( void ) FT_Done_GlyphSlot( FT_GlyphSlot slot ) + { + if ( slot ) + { + FT_Driver driver = slot->face->driver; + FT_Memory memory = driver->root.memory; + FT_GlyphSlot* parent; + FT_GlyphSlot cur; + + + /* Remove slot from its parent face's list */ + parent = &slot->face->glyph; + cur = *parent; + + while ( cur ) + { + if ( cur == slot ) + { + *parent = cur->next; + ft_glyphslot_done( slot ); + FREE( slot ); + break; + } + cur = cur->next; + } + } + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Set_Transform */ + /* */ + /* */ + /* A function used to set the transformation that is applied to glyph */ + /* images just before they are converted to bitmaps in a glyph slot */ + /* when FT_Render_Glyph() is called. */ + /* */ + /* */ + /* face :: A handle to the source face object. */ + /* */ + /* */ + /* matrix :: A pointer to the transformation's 2x2 matrix. Use 0 for */ + /* the identity matrix. */ + /* delta :: A pointer to the translation vector. Use 0 for the null */ + /* vector. */ + /* */ + /* */ + /* The transformation is only applied to scalable image formats after */ + /* the glyph has been loaded. It means that hinting is unaltered by */ + /* the transformation and is performed on the character size given in */ + /* the last call to FT_Set_Char_Sizes() or FT_Set_Pixel_Sizes(). */ + /* */ + FT_EXPORT_FUNC( void ) FT_Set_Transform( FT_Face face, + FT_Matrix* matrix, + FT_Vector* delta ) + { + if ( !face ) + return; + + face->transform_flags = 0; + + if ( !matrix ) + { + face->transform_matrix.xx = 0x10000L; + face->transform_matrix.xy = 0; + face->transform_matrix.yx = 0; + face->transform_matrix.yy = 0x10000L; + matrix = &face->transform_matrix; + } + else + face->transform_matrix = *matrix; + + /* set transform_flags bit flag 0 if `matrix' isn't the identity */ + if ( ( matrix->xy | matrix->yx ) || + matrix->xx != 0x10000L || + matrix->yy != 0x10000L ) + face->transform_flags |= 1; + + if ( !delta ) + { + face->transform_delta.x = 0; + face->transform_delta.y = 0; + delta = &face->transform_delta; + } + else + face->transform_delta = *delta; + + /* set transform_flags bit flag 1 if `delta' isn't the null vector */ + if ( delta->x | delta->y ) + face->transform_flags |= 2; + } + + + static FT_Renderer ft_lookup_glyph_renderer( FT_GlyphSlot slot ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Load_Glyph */ + /* */ + /* */ + /* A function used to load a single glyph within a given glyph slot, */ + /* for a given size. */ + /* */ + /* */ + /* face :: A handle to the target face object where the glyph */ + /* will be loaded. */ + /* */ + /* glyph_index :: The index of the glyph in the font file. */ + /* */ + /* load_flags :: A flag indicating what to load for this glyph. The */ + /* FT_LOAD_XXX constants can be used to control the */ + /* glyph loading process (e.g., whether the outline */ + /* should be scaled, whether to load bitmaps or not, */ + /* whether to hint the outline, etc). */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* If the glyph image is not a bitmap, and if the bit flag */ + /* FT_LOAD_IGNORE_TRANSFORM is unset, the glyph image will be */ + /* transformed with the information passed to a previous call to */ + /* FT_Set_Transform. */ + /* */ + /* Note that this also transforms the `face.glyph.advance' field, but */ + /* *not* the values in `face.glyph.metrics'. */ + /* */ + FT_EXPORT_FUNC( FT_Error ) FT_Load_Glyph( FT_Face face, + FT_UInt glyph_index, + FT_Int load_flags ) + { + FT_Error error; + FT_Driver driver; + FT_GlyphSlot slot; + FT_Library library; + FT_Bool autohint; + FT_Module hinter; + + + if ( !face || !face->size || !face->glyph ) + return FT_Err_Invalid_Face_Handle; + + if ( glyph_index >= (FT_UInt)face->num_glyphs ) + return FT_Err_Invalid_Argument; + + slot = face->glyph; + ft_glyphslot_clear( slot ); + + driver = face->driver; + + /* when the flag NO_RECURSE is set, we disable hinting and scaling */ + if ( load_flags & FT_LOAD_NO_RECURSE ) + load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING; + + /* do we need to load the glyph through the auto-hinter? */ + library = driver->root.library; + hinter = library->auto_hinter; + autohint = hinter && + !( load_flags & ( FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING ) ); + if ( autohint ) + { + if ( FT_DRIVER_HAS_HINTER( driver ) && + !( load_flags & FT_LOAD_FORCE_AUTOHINT ) ) + autohint = 0; + } + + if ( autohint ) + { + FT_AutoHinter_Interface* hinting; + + + hinting = (FT_AutoHinter_Interface*)hinter->clazz->module_interface; + error = hinting->load_glyph( (FT_AutoHinter)hinter, slot, face->size, + glyph_index, load_flags ); + } + else + error = driver->clazz->load_glyph( slot, + face->size, + glyph_index, + load_flags ); + if ( error ) + goto Exit; + + /* compute the advance */ + if ( load_flags & FT_LOAD_VERTICAL_LAYOUT ) + { + slot->advance.x = 0; + slot->advance.y = slot->metrics.vertAdvance; + } + else + { + slot->advance.x = slot->metrics.horiAdvance; + slot->advance.y = 0; + } + + /* now, transform the glyph image when needed */ + if ( face->transform_flags ) + { + /* get renderer */ + FT_Renderer renderer = ft_lookup_glyph_renderer( slot ); + + + if ( renderer ) + error = renderer->clazz->transform_glyph( renderer, slot, + &face->transform_matrix, + &face->transform_delta ); + /* transform advance */ + FT_Vector_Transform( &slot->advance, &face->transform_matrix ); + } + + /* do we need to render the image now? */ + if ( !error && + slot->format != ft_glyph_format_bitmap && + slot->format != ft_glyph_format_composite && + load_flags & FT_LOAD_RENDER ) + { + error = FT_Render_Glyph( slot, + ( load_flags & FT_LOAD_MONOCHROME ) + ? ft_render_mode_mono + : ft_render_mode_normal ); + } + + Exit: + return error; + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Load_Char */ + /* */ + /* */ + /* A function used to load a single glyph within a given glyph slot, */ + /* for a given size, according to its character code. */ + /* */ + /* */ + /* face :: A handle to a target face object where the glyph */ + /* will be loaded. */ + /* */ + /* char_code :: The glyph's character code, according to the */ + /* current charmap used in the face. */ + /* */ + /* load_flags :: A flag indicating what to load for this glyph. The */ + /* FT_LOAD_XXX constants can be used to control the */ + /* glyph loading process (e.g., whether the outline */ + /* should be scaled, whether to load bitmaps or not, */ + /* whether to hint the outline, etc). */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* If the face has no current charmap, or if the character code */ + /* is not defined in the charmap, this function will return an */ + /* error. */ + /* */ + /* If the glyph image is not a bitmap, and if the bit flag */ + /* FT_LOAD_IGNORE_TRANSFORM is unset, the glyph image will be */ + /* transformed with the information passed to a previous call to */ + /* FT_Set_Transform(). */ + /* */ + /* Note that this also transforms the `face.glyph.advance' field, but */ + /* *not* the values in `face.glyph.metrics'. */ + /* */ + FT_EXPORT_FUNC( FT_Error ) FT_Load_Char( FT_Face face, + FT_ULong char_code, + FT_Int load_flags ) + { + FT_UInt glyph_index; + + + if ( !face ) + return FT_Err_Invalid_Face_Handle; + + glyph_index = (FT_UInt)char_code; + if ( face->charmap ) + glyph_index = FT_Get_Char_Index( face, char_code ); + + return FT_Load_Glyph( face, glyph_index, load_flags ); + } + + + /* destructor for sizes list */ + static + void destroy_size( FT_Memory memory, + FT_Size size, + FT_Driver driver ) + { + /* finalize client-specific data */ + if ( size->generic.finalizer ) + size->generic.finalizer( size ); + + /* finalize format-specific stuff */ + if ( driver->clazz->done_size ) + driver->clazz->done_size( size ); + + FREE( size ); + } + + + /* destructor for faces list */ + static + void destroy_face( FT_Memory memory, + FT_Face face, + FT_Driver driver ) + { + FT_Driver_Class* clazz = driver->clazz; + + + /* discard auto-hinting data */ + if ( face->autohint.finalizer ) + face->autohint.finalizer( face->autohint.data ); + + /* Discard glyph slots for this face */ + /* Beware! FT_Done_GlyphSlot() changes the field `face->slot' */ + while ( face->glyph ) + FT_Done_GlyphSlot( face->glyph ); + + /* Discard all sizes for this face */ + FT_List_Finalize( &face->sizes_list, + (FT_List_Destructor)destroy_size, + memory, + driver ); + face->size = 0; + + /* Now discard client data */ + if ( face->generic.finalizer ) + face->generic.finalizer( face ); + + /* finalize format-specific stuff */ + if ( clazz->done_face ) + clazz->done_face( face ); + + /* close the stream for this face if needed */ + if ( ( face->face_flags & FT_FACE_FLAG_EXTERNAL_STREAM ) == 0 ) + ft_done_stream( &face->stream ); + + /* get rid of it */ + FREE( face ); + } + + + static + void Destroy_Driver( FT_Driver driver ) + { + FT_List_Finalize( &driver->faces_list, + (FT_List_Destructor)destroy_face, + driver->root.memory, + driver ); + + /* check whether we need to drop the driver's glyph loader */ + if ( FT_DRIVER_USES_OUTLINES( driver ) ) + FT_GlyphLoader_Done( driver->glyph_loader ); + } + + + /*************************************************************************/ + /* */ + /* */ + /* open_face */ + /* */ + /* */ + /* This function does some work for FT_Open_Face(). */ + /* */ + static + FT_Error open_face( FT_Driver driver, + FT_Stream stream, + FT_Long face_index, + FT_Int num_params, + FT_Parameter* params, + FT_Face* aface ) + { + FT_Memory memory; + FT_Driver_Class* clazz; + FT_Face face = 0; + FT_Error error; + + + clazz = driver->clazz; + memory = driver->root.memory; + + /* allocate the face object and perform basic initialization */ + if ( ALLOC( face, clazz->face_object_size ) ) + goto Fail; + + face->driver = driver; + face->memory = memory; + face->stream = stream; + + error = clazz->init_face( stream, + face, + face_index, + num_params, + params ); + if ( error ) + goto Fail; + + *aface = face; + + Fail: + if ( error ) + { + clazz->done_face( face ); + FREE( face ); + *aface = 0; + } + + return error; + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_New_Face */ + /* */ + /* */ + /* Creates a new face object from a given resource and typeface index */ + /* using a pathname to the font file. */ + /* */ + /* */ + /* library :: A handle to the library resource. */ + /* */ + /* */ + /* pathname :: A path to the font file. */ + /* */ + /* face_index :: The index of the face within the resource. The */ + /* first face has index 0. */ + /* */ + /* aface :: A handle to a new face object. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* Unlike FreeType 1.x, this function automatically creates a glyph */ + /* slot for the face object which can be accessed directly through */ + /* `face->glyph'. */ + /* */ + /* Note that additional slots can be added to each face with the */ + /* FT_New_GlyphSlot() API function. Slots are linked in a single */ + /* list through their `next' field. */ + /* */ + /* FT_New_Face() can be used to determine and/or check the font */ + /* format of a given font resource. If the `face_index' field is */ + /* negative, the function will _not_ return any face handle in */ + /* `*face'. Its return value should be 0 if the resource is */ + /* recognized, or non-zero if not. */ + /* */ + FT_EXPORT_FUNC( FT_Error ) FT_New_Face( FT_Library library, + const char* pathname, + FT_Long face_index, + FT_Face* aface ) + { + FT_Open_Args args; + + + /* test for valid `library' and `aface' delayed to FT_Open_Face() */ + if ( !pathname ) + return FT_Err_Invalid_Argument; + + args.flags = ft_open_pathname; + args.pathname = (char*)pathname; + + return FT_Open_Face( library, &args, face_index, aface ); + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_New_Memory_Face */ + /* */ + /* */ + /* Creates a new face object from a given resource and typeface index */ + /* using a font file already loaded into memory. */ + /* */ + /* */ + /* library :: A handle to the library resource. */ + /* */ + /* */ + /* file_base :: A pointer to the beginning of the font data. */ + /* */ + /* file_size :: The size of the memory chunk used by the font data. */ + /* */ + /* face_index :: The index of the face within the resource. The */ + /* first face has index 0. */ + /* */ + /* face :: A handle to a new face object. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* Unlike FreeType 1.x, this function automatically creates a glyph */ + /* slot for the face object which can be accessed directly through */ + /* `face->glyph'. */ + /* */ + /* Note that additional slots can be added to each face with the */ + /* FT_New_GlyphSlot() API function. Slots are linked in a single */ + /* list through their `next' field. */ + /* */ + /* FT_New_Memory_Face() can be used to determine and/or check the */ + /* font format of a given font resource. If the `face_index' field */ + /* is negative, the function will _not_ return any face handle in */ + /* `*face'. Its return value should be 0 if the resource is */ + /* recognized, or non-zero if not. */ + /* */ + FT_EXPORT_FUNC( FT_Error ) FT_New_Memory_Face( FT_Library library, + FT_Byte* file_base, + FT_Long file_size, + FT_Long face_index, + FT_Face* face ) + { + FT_Open_Args args; + + + /* test for valid `library' and `face' delayed to FT_Open_Face() */ + if ( !file_base ) + return FT_Err_Invalid_Argument; + + args.flags = ft_open_memory; + args.memory_base = file_base; + args.memory_size = file_size; + + return FT_Open_Face( library, &args, face_index, face ); + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Open_Face */ + /* */ + /* */ + /* Opens a face object from a given resource and typeface index using */ + /* an `FT_Open_Args' structure. If the face object doesn't exist, it */ + /* will be created. */ + /* */ + /* */ + /* library :: A handle to the library resource. */ + /* */ + /* */ + /* args :: A pointer to an `FT_Open_Args' structure which must */ + /* be filled by the caller. */ + /* */ + /* face_index :: The index of the face within the resource. The */ + /* first face has index 0. */ + /* */ + /* aface :: A handle to a new face object. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* Unlike FreeType 1.x, this function automatically creates a glyph */ + /* slot for the face object which can be accessed directly through */ + /* `face->glyph'. */ + /* */ + /* Note that additional slots can be added to each face with the */ + /* FT_New_GlyphSlot() API function. Slots are linked in a single */ + /* list through their `next' field. */ + /* */ + /* FT_Open_Face() can be used to determine and/or check the font */ + /* format of a given font resource. If the `face_index' field is */ + /* negative, the function will _not_ return any face handle in */ + /* `*face'. Its return value should be 0 if the resource is */ + /* recognized, or non-zero if not. */ + /* */ + FT_EXPORT_FUNC( FT_Error ) FT_Open_Face( FT_Library library, + FT_Open_Args* args, + FT_Long face_index, + FT_Face* aface ) + { + FT_Error error; + FT_Driver driver; + FT_Memory memory; + FT_Stream stream; + FT_Face face = 0; + FT_ListNode node = 0; + + + /* test for valid `library' and `args' delayed to */ + /* ft_new_input_stream() */ + + if ( !aface ) + return FT_Err_Invalid_Argument; + + *aface = 0; + + /* create input stream */ + error = ft_new_input_stream( library, args, &stream ); + if ( error ) + goto Exit; + + memory = library->memory; + + /* If the font driver is specified in the `args' structure, use */ + /* it. Otherwise, we scan the list of registered drivers. */ + if ( args->flags & ft_open_driver && args->driver ) + { + driver = FT_DRIVER( args->driver ); + + /* not all modules are drivers, so check... */ + if ( FT_MODULE_IS_DRIVER( driver ) ) + { + FT_Int num_params = 0; + FT_Parameter* params = 0; + + + if ( args->flags & ft_open_params ) + { + num_params = args->num_params; + params = args->params; + } + + error = open_face( driver, stream, face_index, + num_params, params, &face ); + if ( !error ) + goto Success; + } + else + error = FT_Err_Invalid_Handle; + + ft_done_stream( &stream ); + goto Fail; + } + else + { + /* check each font driver for an appropriate format */ + FT_Module* cur = library->modules; + FT_Module* limit = cur + library->num_modules; + + + for ( ; cur < limit; cur++ ) + { + /* not all modules are font drivers, so check... */ + if ( FT_MODULE_IS_DRIVER( cur[0] ) ) + { + FT_Int num_params = 0; + FT_Parameter* params = 0; + + + driver = FT_DRIVER( cur[0] ); + + if ( args->flags & ft_open_params ) + { + num_params = args->num_params; + params = args->params; + } + + error = open_face( driver, stream, face_index, + num_params, params, &face ); + if ( !error ) + goto Success; + + if ( error != FT_Err_Unknown_File_Format ) + goto Fail; + } + } + + ft_done_stream( &stream ); + + /* no driver is able to handle this format */ + error = FT_Err_Unknown_File_Format; + goto Fail; + } + + Success: + FT_TRACE4(( "FT_New_Face: New face object, adding to list\n" )); + + /* set the FT_FACE_FLAG_EXTERNAL_STREAM bit for FT_Done_Face */ + if ( args->flags & ft_open_stream && args->stream ) + face->face_flags |= FT_FACE_FLAG_EXTERNAL_STREAM; + + /* add the face object to its driver's list */ + if ( ALLOC( node, sizeof ( *node ) ) ) + goto Fail; + + node->data = face; + /* don't assume driver is the same as face->driver, so use */ + /* face->driver instead. */ + FT_List_Add( &face->driver->faces_list, node ); + + /* now allocate a glyph slot object for the face */ + { + FT_GlyphSlot slot; + + + FT_TRACE4(( "FT_Open_Face: Creating glyph slot\n" )); + + error = FT_New_GlyphSlot( face, &slot ); + if ( error ) + goto Fail; + + face->glyph = slot; + } + + /* finally, allocate a size object for the face */ + { + FT_Size size; + + + FT_TRACE4(( "FT_Open_Face: Creating size object\n" )); + + error = FT_New_Size( face, &size ); + if ( error ) + goto Fail; + + face->size = size; + } + + /* initialize transformation for convenience functions */ + face->transform_matrix.xx = 0x10000L; + face->transform_matrix.xy = 0; + face->transform_matrix.yx = 0; + face->transform_matrix.yy = 0x10000L; + + face->transform_delta.x = 0; + face->transform_delta.y = 0; + + *aface = face; + goto Exit; + + Fail: + FT_Done_Face( face ); + + Exit: + FT_TRACE4(( "FT_Open_Face: Return %d\n", error )); + + return error; + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Attach_File */ + /* */ + /* */ + /* `Attaches' a given font file to an existing face. This is usually */ + /* to read additional information for a single face object. For */ + /* example, it is used to read the AFM files that come with Type 1 */ + /* fonts in order to add kerning data and other metrics. */ + /* */ + /* */ + /* face :: The target face object. */ + /* */ + /* */ + /* filepathname :: An 8-bit pathname naming the `metrics' file. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* If your font file is in memory, or if you want to provide your */ + /* own input stream object, use FT_Attach_Stream(). */ + /* */ + /* The meaning of the `attach' action (i.e., what really happens when */ + /* the new file is read) is not fixed by FreeType itself. It really */ + /* depends on the font format (and thus the font driver). */ + /* */ + /* Client applications are expected to know what they are doing */ + /* when invoking this function. Most drivers simply do not implement */ + /* file attachments. */ + /* */ + FT_EXPORT_FUNC( FT_Error ) FT_Attach_File( FT_Face face, + const char* filepathname ) + { + FT_Open_Args open; + + + /* test for valid `face' delayed to FT_Attach_Stream() */ + + if ( !filepathname ) + return FT_Err_Invalid_Argument; + + open.flags = ft_open_pathname; + open.pathname = (char*)filepathname; + + return FT_Attach_Stream( face, &open ); + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Attach_Stream */ + /* */ + /* */ + /* This function is similar to FT_Attach_File() with the exception */ + /* that it reads the attachment from an arbitrary stream. */ + /* */ + /* */ + /* face :: The target face object. */ + /* */ + /* parameters :: A pointer to an FT_Open_Args structure used to */ + /* describe the input stream to FreeType. */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* The meaning of the `attach' (i.e. what really happens when the */ + /* new file is read) is not fixed by FreeType itself. It really */ + /* depends on the font format (and thus the font driver). */ + /* */ + /* Client applications are expected to know what they are doing */ + /* when invoking this function. Most drivers simply do not implement */ + /* file attachments. */ + /* */ + FT_EXPORT_FUNC( FT_Error ) FT_Attach_Stream( FT_Face face, + FT_Open_Args* parameters ) + { + FT_Stream stream; + FT_Error error; + FT_Driver driver; + + FT_Driver_Class* clazz; + + + /* test for valid `parameters' delayed to ft_new_input_stream() */ + + if ( !face ) + return FT_Err_Invalid_Face_Handle; + + driver = face->driver; + if ( !driver ) + return FT_Err_Invalid_Driver_Handle; + + error = ft_new_input_stream( driver->root.library, parameters, &stream ); + if ( error ) + goto Exit; + + /* we implement FT_Attach_Stream in each driver through the */ + /* `attach_file' interface */ + + error = FT_Err_Unimplemented_Feature; + clazz = driver->clazz; + if ( clazz->attach_file ) + error = clazz->attach_file( face, stream ); + + /* close the attached stream */ + if ( !parameters->stream || ( parameters->flags & ft_open_stream ) ) + ft_done_stream( &stream ); + + Exit: + return error; + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Done_Face */ + /* */ + /* */ + /* Discards a given face object, as well as all of its child slots */ + /* and sizes. */ + /* */ + /* */ + /* face :: A handle to a target face object. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT_FUNC( FT_Error ) FT_Done_Face( FT_Face face ) + { + FT_Error error; + FT_Driver driver; + FT_Memory memory; + FT_ListNode node; + + + error = FT_Err_Invalid_Face_Handle; + if ( face && face->driver ) + { + driver = face->driver; + memory = driver->root.memory; + + /* find face in driver's list */ + node = FT_List_Find( &driver->faces_list, face ); + if ( node ) + { + /* remove face object from the driver's list */ + FT_List_Remove( &driver->faces_list, node ); + FREE( node ); + + /* now destroy the object proper */ + destroy_face( memory, face, driver ); + error = FT_Err_Ok; + } + } + return error; + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_New_Size */ + /* */ + /* */ + /* Creates a new size object from a given face object. */ + /* */ + /* */ + /* face :: A handle to a parent face object. */ + /* */ + /* */ + /* asize :: A handle to a new size object. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT_FUNC( FT_Error ) FT_New_Size( FT_Face face, + FT_Size* asize ) + { + FT_Error error; + FT_Memory memory; + FT_Driver driver; + FT_Driver_Class* clazz; + + FT_Size size = 0; + FT_ListNode node = 0; + + + if ( !face ) + return FT_Err_Invalid_Face_Handle; + + if ( !asize ) + return FT_Err_Invalid_Size_Handle; + + if ( !face->driver ) + return FT_Err_Invalid_Driver_Handle; + + *asize = 0; + + driver = face->driver; + clazz = driver->clazz; + memory = face->memory; + + /* Allocate new size object and perform basic initialisation */ + if ( ALLOC( size, clazz->size_object_size ) || + ALLOC( node, sizeof ( FT_ListNodeRec ) ) ) + goto Exit; + + size->face = face; + + if ( clazz->init_size ) + error = clazz->init_size( size ); + + /* in case of success, add to the face's list */ + if ( !error ) + { + *asize = size; + node->data = size; + FT_List_Add( &face->sizes_list, node ); + } + + Exit: + if ( error ) + { + FREE( node ); + FREE( size ); + } + + return error; + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Done_Size */ + /* */ + /* */ + /* Discards a given size object. */ + /* */ + /* */ + /* size :: A handle to a target size object. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT_FUNC( FT_Error ) FT_Done_Size( FT_Size size ) + { + FT_Error error; + FT_Driver driver; + FT_Memory memory; + FT_Face face; + FT_ListNode node; + + + if ( !size ) + return FT_Err_Invalid_Size_Handle; + + face = size->face; + if ( !face ) + return FT_Err_Invalid_Face_Handle; + + driver = face->driver; + if ( !driver ) + return FT_Err_Invalid_Driver_Handle; + + memory = driver->root.memory; + + error = FT_Err_Ok; + node = FT_List_Find( &face->sizes_list, size ); + if ( node ) + { + FT_List_Remove( &face->sizes_list, node ); + FREE( node ); + + if ( face->size == size ) + { + face->size = 0; + if ( face->sizes_list.head ) + face->size = (FT_Size)(face->sizes_list.head->data); + } + + destroy_size( memory, size, driver ); + } + else + error = FT_Err_Invalid_Size_Handle; + + return FT_Err_Ok; + } + + + static + void ft_recompute_scaled_metrics( FT_Face face, + FT_Size_Metrics* metrics ) + { + /* Compute root ascender, descender, test height, and max_advance */ + + metrics->ascender = ( FT_MulFix( face->ascender, + metrics->y_scale ) + 32 ) & -64; + + metrics->descender = ( FT_MulFix( face->descender, + metrics->y_scale ) + 32 ) & -64; + + metrics->height = ( FT_MulFix( face->height, + metrics->y_scale ) + 32 ) & -64; + + metrics->max_advance = ( FT_MulFix( face->max_advance_width, + metrics->x_scale ) + 32 ) & -64; + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Set_Char_Size */ + /* */ + /* */ + /* Sets the character dimensions of a given face object. The */ + /* `char_width' and `char_height' values are used for the width and */ + /* height, respectively, expressed in 26.6 fractional points. */ + /* */ + /* If the horizontal or vertical resolution values are zero, a */ + /* default value of 72dpi is used. Similarly, if one of the */ + /* character dimensions is zero, its value is set equal to the other. */ + /* */ + /* */ + /* size :: A handle to a target size object. */ + /* */ + /* */ + /* char_width :: The character width, in 26.6 fractional points. */ + /* */ + /* char_height :: The character height, in 26.6 fractional */ + /* points. */ + /* */ + /* horz_resolution :: The horizontal resolution. */ + /* */ + /* vert_resolution :: The vertical resolution. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* When dealing with fixed-size faces (i.e., non-scalable formats), */ + /* use the function FT_Set_Pixel_Sizes(). */ + /* */ + FT_EXPORT_FUNC( FT_Error ) FT_Set_Char_Size( FT_Face face, + FT_F26Dot6 char_width, + FT_F26Dot6 char_height, + FT_UInt horz_resolution, + FT_UInt vert_resolution ) + { + FT_Error error = FT_Err_Ok; + FT_Driver driver; + FT_Memory memory; + FT_Driver_Class* clazz; + FT_Size_Metrics* metrics; + FT_Long dim_x, dim_y; + + + if ( !face || !face->size || !face->driver ) + return FT_Err_Invalid_Face_Handle; + + driver = face->driver; + metrics = &face->size->metrics; + + if ( !char_width ) + char_width = char_height; + + else if ( !char_height ) + char_height = char_width; + + if ( !horz_resolution ) + horz_resolution = 72; + + if ( !vert_resolution ) + vert_resolution = 72; + + driver = face->driver; + clazz = driver->clazz; + memory = driver->root.memory; + + /* default processing -- this can be overridden by the driver */ + if ( char_width < 1 * 64 ) + char_width = 1 * 64; + if ( char_height < 1 * 64 ) + char_height = 1 * 64; + + /* Compute pixel sizes in 26.6 units */ + dim_x = ( ( ( char_width * horz_resolution ) / 72 ) + 32 ) & -64; + dim_y = ( ( ( char_height * vert_resolution ) / 72 ) + 32 ) & -64; + + metrics->x_ppem = (FT_UShort)( dim_x >> 6 ); + metrics->y_ppem = (FT_UShort)( dim_y >> 6 ); + + metrics->x_scale = 0x10000L; + metrics->y_scale = 0x10000L; + + if ( face->face_flags & FT_FACE_FLAG_SCALABLE ) + { + metrics->x_scale = FT_DivFix( dim_x, face->units_per_EM ); + metrics->y_scale = FT_DivFix( dim_y, face->units_per_EM ); + + ft_recompute_scaled_metrics( face, metrics ); + } + + if ( clazz->set_char_sizes ) + error = clazz->set_char_sizes( face->size, + char_width, + char_height, + horz_resolution, + vert_resolution ); + return error; + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Set_Pixel_Sizes */ + /* */ + /* */ + /* Sets the character dimensions of a given face object. The width */ + /* and height are expressed in integer pixels. */ + /* */ + /* If one of the character dimensions is zero, its value is set equal */ + /* to the other. */ + /* */ + /* */ + /* face :: A handle to the target face object. */ + /* */ + /* */ + /* pixel_width :: The character width, in integer pixels. */ + /* */ + /* pixel_height :: The character height, in integer pixels. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT_FUNC( FT_Error ) FT_Set_Pixel_Sizes( FT_Face face, + FT_UInt pixel_width, + FT_UInt pixel_height ) + { + FT_Error error = FT_Err_Ok; + FT_Driver driver; + FT_Memory memory; + FT_Driver_Class* clazz; + FT_Size_Metrics* metrics = &face->size->metrics; + + + if ( !face || !face->size || !face->driver ) + return FT_Err_Invalid_Face_Handle; + + driver = face->driver; + clazz = driver->clazz; + memory = driver->root.memory; + + /* default processing -- this can be overridden by the driver */ + if ( pixel_width == 0 ) + pixel_width = pixel_height; + + else if ( pixel_height == 0 ) + pixel_height = pixel_width; + + if ( pixel_width < 1 ) + pixel_width = 1; + if ( pixel_height < 1 ) + pixel_height = 1; + + metrics->x_ppem = pixel_width; + metrics->y_ppem = pixel_height; + + if ( face->face_flags & FT_FACE_FLAG_SCALABLE ) + { + metrics->x_scale = FT_DivFix( metrics->x_ppem << 6, + face->units_per_EM ); + + metrics->y_scale = FT_DivFix( metrics->y_ppem << 6, + face->units_per_EM ); + + ft_recompute_scaled_metrics( face, metrics ); + } + + if ( clazz->set_pixel_sizes ) + error = clazz->set_pixel_sizes( face->size, + pixel_width, + pixel_height ); + return error; + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Get_Kerning */ + /* */ + /* */ + /* Returns the kerning vector between two glyphs of a same face. */ + /* */ + /* */ + /* face :: A handle to a source face object. */ + /* */ + /* left_glyph :: The index of the left glyph in the kern pair. */ + /* */ + /* right_glyph :: The index of the right glyph in the kern pair. */ + /* */ + /* kern_mode :: See FT_Kerning_Mode() for more information. */ + /* Determines the scale/dimension of the returned */ + /* kerning vector. */ + /* */ + /* */ + /* kerning :: The kerning vector. This is in font units for */ + /* scalable formats, and in pixels for fixed-sizes */ + /* formats. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* Only horizontal layouts (left-to-right & right-to-left) are */ + /* supported by this method. Other layouts, or more sophisticated */ + /* kernings, are out of the scope of this API function -- they can be */ + /* implemented through format-specific interfaces. */ + /* */ + FT_EXPORT_FUNC( FT_Error ) FT_Get_Kerning( FT_Face face, + FT_UInt left_glyph, + FT_UInt right_glyph, + FT_UInt kern_mode, + FT_Vector* kerning ) + { + FT_Error error = FT_Err_Ok; + FT_Driver driver; + FT_Memory memory; + + + if ( !face ) + return FT_Err_Invalid_Face_Handle; + + if ( !kerning ) + return FT_Err_Invalid_Argument; + + driver = face->driver; + memory = driver->root.memory; + + kerning->x = 0; + kerning->y = 0; + + if ( driver->clazz->get_kerning ) + { + error = driver->clazz->get_kerning( face, + left_glyph, + right_glyph, + kerning ); + if ( !error ) + { + if ( kern_mode != ft_kerning_unscaled ) + { + kerning->x = FT_MulFix( kerning->x, face->size->metrics.x_scale ); + kerning->y = FT_MulFix( kerning->y, face->size->metrics.y_scale ); + + if ( kern_mode != ft_kerning_unfitted ) + { + kerning->x = ( kerning->x + 32 ) & -64; + kerning->y = ( kerning->y + 32 ) & -64; + } + } + } + } + + return error; + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Select_Charmap */ + /* */ + /* */ + /* Selects a given charmap by its encoding tag (as listed in */ + /* `freetype.h'). */ + /* */ + /* */ + /* face :: A handle to the source face object. */ + /* */ + /* encoding :: A handle to the selected charmap. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* This function will return an error if no charmap in the face */ + /* corresponds to the encoding queried here. */ + /* */ + FT_EXPORT_FUNC( FT_Error ) FT_Select_Charmap( FT_Face face, + FT_Encoding encoding ) + { + FT_CharMap* cur; + FT_CharMap* limit; + + + if ( !face ) + return FT_Err_Invalid_Face_Handle; + + cur = face->charmaps; + if ( !cur ) + return FT_Err_Invalid_CharMap_Handle; + + limit = cur + face->num_charmaps; + + for ( ; cur < limit; cur++ ) + { + if ( cur[0]->encoding == encoding ) + { + face->charmap = cur[0]; + return 0; + } + } + + return FT_Err_Invalid_Argument; + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Set_Charmap */ + /* */ + /* */ + /* Selects a given charmap for character code to glyph index */ + /* decoding. */ + /* */ + /* */ + /* face :: A handle to the source face object. */ + /* charmap :: A handle to the selected charmap. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* This function will return an error if the charmap is not part of */ + /* the face (i.e., if it is not listed in the face->charmaps[] */ + /* table). */ + /* */ + FT_EXPORT_FUNC( FT_Error ) FT_Set_Charmap( FT_Face face, + FT_CharMap charmap ) + { + FT_CharMap* cur; + FT_CharMap* limit; + + + if ( !face ) + return FT_Err_Invalid_Face_Handle; + + cur = face->charmaps; + if ( !cur ) + return FT_Err_Invalid_CharMap_Handle; + + limit = cur + face->num_charmaps; + + for ( ; cur < limit; cur++ ) + { + if ( cur[0] == charmap ) + { + face->charmap = cur[0]; + return 0; + } + } + return FT_Err_Invalid_Argument; + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Get_Char_Index */ + /* */ + /* */ + /* Returns the glyph index of a given character code. This function */ + /* uses a charmap object to do the translation. */ + /* */ + /* */ + /* face :: A handle to the source face object. */ + /* */ + /* charcode :: The character code. */ + /* */ + /* */ + /* The glyph index. 0 means `undefined character code'. */ + /* */ + FT_EXPORT_FUNC( FT_UInt ) FT_Get_Char_Index( FT_Face face, + FT_ULong charcode ) + { + FT_UInt result; + FT_Driver driver; + + + result = 0; + if ( face && face->charmap ) + { + driver = face->driver; + result = driver->clazz->get_char_index( face->charmap, charcode ); + } + return result; + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Get_Glyph_Name */ + /* */ + /* */ + /* Retrieves the ASCII name of a given glyph in a face. This only */ + /* works for those faces where FT_HAS_GLYPH_NAME(face) returns true. */ + /* */ + /* */ + /* face :: A handle to a source face object. */ + /* */ + /* glyph_index :: The glyph index. */ + /* */ + /* buffer :: A pointer to a target buffer where the name will be */ + /* copied to. */ + /* */ + /* buffer_max :: The maximal number of bytes available in the */ + /* buffer. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* An error is returned if the face doesn't provide glyph names or if */ + /* the glyph index is invalid. In all cases of failure, the first */ + /* byte of `buffer' will be set to 0 to indicate an empty name. */ + /* */ + /* The glyph name is truncated to fit within the buffer if it is too */ + /* long. The returned string is always zero-terminated. */ + /* */ + /* This function is not compiled within the library if the config */ + /* macro FT_CONFIG_OPTION_NO_GLYPH_NAMES is defined in */ + /* `include/freetype/config/ftoptions.h' */ + /* */ + FT_EXPORT_FUNC( FT_Error ) FT_Get_Glyph_Name( FT_Face face, + FT_UInt glyph_index, + FT_Pointer buffer, + FT_UInt buffer_max ) + { + FT_Error error = FT_Err_Invalid_Argument; + + + /* clean up buffer */ + if ( buffer && buffer_max > 0 ) + ((FT_Byte*)buffer)[0] = 0; + + if ( face && + glyph_index < (FT_UInt)face->num_glyphs && + FT_HAS_GLYPH_NAMES( face ) ) + { + /* now, lookup for glyph name */ + FT_Driver driver = face->driver; + FT_Module_Class* clazz = FT_MODULE_CLASS( driver ); + + + if ( clazz->get_interface ) + { + FT_Glyph_Name_Requester requester; + + + requester = (FT_Glyph_Name_Requester)clazz->get_interface( + FT_MODULE( driver ), "glyph_name" ); + if ( requester ) + error = requester( face, glyph_index, buffer, buffer_max ); + } + } + + return error; + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Get_Sfnt_Table */ + /* */ + /* */ + /* Returns a pointer to a given SFNT table within a face. */ + /* */ + /* */ + /* face :: A handle to the source face object. */ + /* tag :: An index of an SFNT table. */ + /* */ + /* */ + /* A type-less pointer to the table. This will be 0 in case of */ + /* error, or if the corresponding table was not found *OR* loaded */ + /* from the file. */ + /* */ + /* */ + /* The table is owned by the face object, and disappears with it. */ + /* */ + /* This function is only useful to access SFNT tables that are loaded */ + /* by the sfnt/truetype/opentype drivers. See the FT_Sfnt_Tag */ + /* enumeration in `tttables.h' for a list. */ + /* */ + /* You can load any table with a different function.. XXX */ + /* */ + FT_EXPORT_FUNC( void* ) FT_Get_Sfnt_Table( FT_Face face, + FT_Sfnt_Tag tag ) + { + void* table = 0; + FT_Get_Sfnt_Table_Func func; + FT_Driver driver; + + + if ( !face || !FT_IS_SFNT( face ) ) + goto Exit; + + driver = face->driver; + func = (FT_Get_Sfnt_Table_Func)driver->root.clazz->get_interface( + FT_MODULE( driver ), "get_sfnt" ); + if ( func ) + table = func( face, tag ); + + Exit: + return table; + } + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** R E N D E R E R S ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + /* lookup a renderer by glyph format in the library's list */ + BASE_FUNC( FT_Renderer ) FT_Lookup_Renderer( FT_Library library, + FT_Glyph_Format format, + FT_ListNode* node ) + { + FT_ListNode cur; + FT_Renderer result = 0; + + + if ( !library ) + goto Exit; + + cur = library->renderers.head; + + if ( node ) + { + if ( *node ) + cur = (*node)->next; + *node = 0; + } + + while ( cur ) + { + FT_Renderer renderer = FT_RENDERER( cur->data ); + + + if ( renderer->glyph_format == format ) + { + if ( node ) + *node = cur; + + result = renderer; + break; + } + cur = cur->next; + } + + Exit: + return result; + } + + + static + FT_Renderer ft_lookup_glyph_renderer( FT_GlyphSlot slot ) + { + FT_Face face = slot->face; + FT_Library library = FT_FACE_LIBRARY( face ); + FT_Renderer result = library->cur_renderer; + + + if ( !result || result->glyph_format != slot->format ) + result = FT_Lookup_Renderer( library, slot->format, 0 ); + + return result; + } + + + static + void ft_set_current_renderer( FT_Library library ) + { + FT_Renderer renderer; + + + renderer = FT_Lookup_Renderer( library, ft_glyph_format_outline, 0 ); + library->cur_renderer = renderer; + } + + + static + FT_Error ft_add_renderer( FT_Module module ) + { + FT_Library library = module->library; + FT_Memory memory = library->memory; + FT_Error error; + FT_ListNode node; + + + if ( ALLOC( node, sizeof ( *node ) ) ) + goto Exit; + + { + FT_Renderer render = FT_RENDERER( module ); + FT_Renderer_Class* clazz = (FT_Renderer_Class*)module->clazz; + + + render->clazz = clazz; + render->glyph_format = clazz->glyph_format; + + /* allocate raster object if needed */ + if ( clazz->glyph_format == ft_glyph_format_outline && + clazz->raster_class->raster_new ) + { + error = clazz->raster_class->raster_new( memory, &render->raster ); + if ( error ) + goto Fail; + + render->raster_render = clazz->raster_class->raster_render; + render->render = clazz->render_glyph; + } + + /* add to list */ + node->data = module; + FT_List_Add( &library->renderers, node ); + + ft_set_current_renderer( library ); + } + + Fail: + if ( error ) + FREE( node ); + + Exit: + return error; + } + + + static + void ft_remove_renderer( FT_Module module ) + { + FT_Library library = module->library; + FT_Memory memory = library->memory; + FT_ListNode node; + + + node = FT_List_Find( &library->renderers, module ); + if ( node ) + { + FT_Renderer render = FT_RENDERER( module ); + + + /* release raster object, if any */ + if ( render->raster ) + render->clazz->raster_class->raster_done( render->raster ); + + /* remove from list */ + FT_List_Remove( &library->renderers, node ); + FREE( node ); + + ft_set_current_renderer( library ); + } + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Get_Renderer */ + /* */ + /* */ + /* Retrieves the current renderer for a given glyph format. */ + /* */ + /* */ + /* library :: A handle to the library object. */ + /* */ + /* format :: The glyph format. */ + /* */ + /* */ + /* A renderer handle. 0 if none found. */ + /* */ + /* */ + /* An error will be returned if a module already exists by that name, */ + /* or if the module requires a version of FreeType that is too great. */ + /* */ + /* To add a new renderer, simply use FT_Add_Module(). To retrieve a */ + /* renderer by its name, use FT_Get_Module(). */ + /* */ + FT_EXPORT_FUNC( FT_Renderer ) FT_Get_Renderer( FT_Library library, + FT_Glyph_Format format ) + { + /* test for valid `library' delayed to FT_Lookup_Renderer() */ + + return FT_Lookup_Renderer( library, format, 0 ); + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Set_Renderer */ + /* */ + /* */ + /* Sets the current renderer to use, and set additional mode. */ + /* */ + /* */ + /* library :: A handle to the library object. */ + /* */ + /* renderer :: A handle to the renderer object. */ + /* */ + /* num_params :: The number of additional parameters. */ + /* */ + /* parameters :: Additional parameters. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* In case of success, the renderer will be used to convert glyph */ + /* images in the renderer's known format into bitmaps. */ + /* */ + /* This doesn't change the current renderer for other formats. */ + /* */ + FT_EXPORT_DEF( FT_Error ) FT_Set_Renderer( FT_Library library, + FT_Renderer renderer, + FT_UInt num_params, + FT_Parameter* parameters ) + { + FT_ListNode node; + FT_Error error = FT_Err_Ok; + + + if ( !library ) + return FT_Err_Invalid_Library_Handle; + + if ( !renderer ) + return FT_Err_Invalid_Argument; + + node = FT_List_Find( &library->renderers, renderer ); + if ( !node ) + { + error = FT_Err_Invalid_Argument; + goto Exit; + } + + FT_List_Up( &library->renderers, node ); + + if ( renderer->glyph_format == ft_glyph_format_outline ) + library->cur_renderer = renderer; + + if ( num_params > 0 ) + { + FTRenderer_setMode set_mode = renderer->clazz->set_mode; + + + for ( ; num_params > 0; num_params-- ) + { + error = set_mode( renderer, parameters->tag, parameters->data ); + if ( error ) + break; + } + } + + Exit: + return error; + } + + + LOCAL_FUNC + FT_Error FT_Render_Glyph_Internal( FT_Library library, + FT_GlyphSlot slot, + FT_UInt render_mode ) + { + FT_Error error = FT_Err_Ok; + FT_Renderer renderer; + + + /* if it is already a bitmap, no need to do anything */ + switch ( slot->format ) + { + case ft_glyph_format_bitmap: /* already a bitmap, don't do anything */ + break; + + default: + { + FT_ListNode node = 0; + FT_Bool update = 0; + + + /* small shortcut for the very common case */ + if ( slot->format == ft_glyph_format_outline ) + { + renderer = library->cur_renderer; + node = library->renderers.head; + } + else + renderer = FT_Lookup_Renderer( library, slot->format, &node ); + + error = FT_Err_Unimplemented_Feature; + while ( renderer ) + { + error = renderer->render( renderer, slot, render_mode, 0 ); + if ( !error || error != FT_Err_Cannot_Render_Glyph ) + break; + + /* FT_Err_Cannot_Render_Glyph is returned if the render mode */ + /* is unsupported by the current renderer for this glyph image */ + /* format. */ + + /* now, look for another renderer that supports the same */ + /* format. */ + renderer = FT_Lookup_Renderer( library, slot->format, &node ); + update = 1; + } + + /* if we changed the current renderer for the glyph image format */ + /* we need to select it as the next current one */ + if ( !error && update && renderer ) + FT_Set_Renderer( library, renderer, 0, 0 ); + } + } + + return error; + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Render_Glyph */ + /* */ + /* */ + /* Converts a given glyph image to a bitmap. It does so by */ + /* inspecting the glyph image format, find the relevant renderer, and */ + /* invoke it. */ + /* */ + /* */ + /* slot :: A handle to the glyph slot containing the image to */ + /* convert. */ + /* */ + /* render_mode :: This is the render mode used to render the glyph */ + /* image into a bitmap. See FT_Render_Mode for a list */ + /* of possible values. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT_FUNC( FT_Error ) FT_Render_Glyph( FT_GlyphSlot slot, + FT_UInt render_mode ) + { + FT_Library library; + + + if ( !slot ) + return FT_Err_Invalid_Argument; + + library = FT_FACE_LIBRARY( slot->face ); + + return FT_Render_Glyph_Internal( library, slot, render_mode ); + } + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** M O D U L E S ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* */ + /* Destroy_Module */ + /* */ + /* */ + /* Destroys a given module object. For drivers, this also destroys */ + /* all child faces. */ + /* */ + /* */ + /* module :: A handle to the target driver object. */ + /* */ + /* */ + /* The driver _must_ be LOCKED! */ + /* */ + static + void Destroy_Module( FT_Module module ) + { + FT_Memory memory = module->memory; + FT_Module_Class* clazz = module->clazz; + FT_Library library = module->library; + + + /* finalize client-data - before anything else */ + if ( module->generic.finalizer ) + module->generic.finalizer( module ); + + if ( library && library->auto_hinter == module ) + library->auto_hinter = 0; + + /* if the module is a renderer */ + if ( FT_MODULE_IS_RENDERER( module ) ) + ft_remove_renderer( module ); + + /* if the module is a font driver, add some steps */ + if ( FT_MODULE_IS_DRIVER( module ) ) + Destroy_Driver( FT_DRIVER( module ) ); + + /* finalize the module object */ + if ( clazz->module_done ) + clazz->module_done( module ); + + /* discard it */ + FREE( module ); + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Add_Module */ + /* */ + /* */ + /* Adds a new module to a given library instance. */ + /* */ + /* */ + /* library :: A handle to the library object. */ + /* */ + /* clazz :: A pointer to class descriptor for the module. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* An error will be returned if a module already exists by that name, */ + /* or if the module requires a version of FreeType that is too great. */ + /* */ + FT_EXPORT_FUNC( FT_Error ) FT_Add_Module( FT_Library library, + const FT_Module_Class* clazz ) + { + FT_Error error; + FT_Memory memory; + FT_Module module; + FT_UInt nn; + + +#define FREETYPE_VER_FIXED ( ( (FT_Long)FREETYPE_MAJOR << 16 ) | \ + FREETYPE_MINOR ) + + if ( !library ) + return FT_Err_Invalid_Library_Handle; + + if ( !clazz ) + return FT_Err_Invalid_Argument; + + /* check freetype version */ + if ( clazz->module_requires > FREETYPE_VER_FIXED ) + return FT_Err_Invalid_Version; + + /* look for a module with the same name in the library's table */ + for ( nn = 0; nn < library->num_modules; nn++ ) + { + module = library->modules[nn]; + if ( strcmp( module->clazz->module_name, clazz->module_name ) == 0 ) + { + /* this installed module has the same name, compare their versions */ + if ( clazz->module_version <= module->clazz->module_version ) + return FT_Err_Lower_Module_Version; + + /* remove the module from our list, then exit the loop to replace */ + /* it by our new version.. */ + FT_Remove_Module( library, module ); + break; + } + } + + memory = library->memory; + error = FT_Err_Ok; + + if ( library->num_modules >= FT_MAX_MODULES ) + { + error = FT_Err_Too_Many_Drivers; + goto Exit; + } + + /* allocate module object */ + if ( ALLOC( module,clazz->module_size ) ) + goto Exit; + + /* base initialization */ + module->library = library; + module->memory = memory; + module->clazz = (FT_Module_Class*)clazz; + + /* check whether the module is a renderer - this must be performed */ + /* before the normal module initialization */ + if ( FT_MODULE_IS_RENDERER( module ) ) + { + /* add to the renderers list */ + error = ft_add_renderer( module ); + if ( error ) + goto Fail; + } + + /* is the module a auto-hinter? */ + if ( FT_MODULE_IS_HINTER( module ) ) + library->auto_hinter = module; + + /* if the module is a font driver */ + if ( FT_MODULE_IS_DRIVER( module ) ) + { + /* allocate glyph loader if needed */ + FT_Driver driver = FT_DRIVER( module ); + + + driver->clazz = (FT_Driver_Class*)module->clazz; + if ( FT_DRIVER_USES_OUTLINES( driver ) ) + { + error = FT_GlyphLoader_New( memory, &driver->glyph_loader ); + if ( error ) + goto Fail; + } + } + + if ( clazz->module_init ) + { + error = clazz->module_init( module ); + if ( error ) + goto Fail; + } + + /* add module to the library's table */ + library->modules[library->num_modules++] = module; + + Exit: + return error; + + Fail: + if ( FT_MODULE_IS_DRIVER( module ) ) + { + FT_Driver driver = FT_DRIVER( module ); + + + if ( FT_DRIVER_USES_OUTLINES( driver ) ) + FT_GlyphLoader_Done( driver->glyph_loader ); + } + + if ( FT_MODULE_IS_RENDERER( module ) ) + { + FT_Renderer renderer = FT_RENDERER( module ); + + + if ( renderer->raster ) + renderer->clazz->raster_class->raster_done( renderer->raster ); + } + + FREE( module ); + goto Exit; + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Get_Module */ + /* */ + /* */ + /* Finds a module by its name. */ + /* */ + /* */ + /* library :: A handle to the library object. */ + /* */ + /* module_name :: The module's name (as an ASCII string). */ + /* */ + /* */ + /* A module handle. 0 if none was found. */ + /* */ + /* */ + /* You should better be familiar with FreeType internals to know */ + /* which module to look for :-) */ + /* */ + FT_EXPORT_FUNC( FT_Module ) FT_Get_Module( FT_Library library, + const char* module_name ) + { + FT_Module result = 0; + FT_Module* cur; + FT_Module* limit; + + + if ( !library || !module_name ) + return result; + + cur = library->modules; + limit = cur + library->num_modules; + + for ( ; cur < limit; cur++ ) + if ( strcmp( cur[0]->clazz->module_name, module_name ) == 0 ) + { + result = cur[0]; + break; + } + + return result; + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Get_Module_Interface */ + /* */ + /* */ + /* Finds a module and returns its specific interface as a typeless */ + /* pointer. */ + /* */ + /* */ + /* library :: A handle to the library object. */ + /* */ + /* module_name :: The module's name (as an ASCII string). */ + /* */ + /* */ + /* A module-specific interface if available, 0 otherwise. */ + /* */ + /* */ + /* You should better be familiar with FreeType internals to know */ + /* which module to look for, and what its interface is :-) */ + /* */ + BASE_FUNC( const void* ) FT_Get_Module_Interface( FT_Library library, + const char* mod_name ) + { + FT_Module module; + + + /* test for valid `library' delayed to FT_Get_Module() */ + + module = FT_Get_Module( library, mod_name ); + + return module ? module->clazz->module_interface : 0; + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Remove_Module */ + /* */ + /* */ + /* Removes a given module from a library instance. */ + /* */ + /* */ + /* library :: A handle to a library object. */ + /* */ + /* module :: A handle to a module object. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* The module object is destroyed by the function in case of success. */ + /* */ + FT_EXPORT_FUNC( FT_Error ) FT_Remove_Module( FT_Library library, + FT_Module module ) + { + /* try to find the module from the table, then remove it from there */ + + if ( !library ) + return FT_Err_Invalid_Library_Handle; + + if ( module ) + { + FT_Module* cur = library->modules; + FT_Module* limit = cur + library->num_modules; + + + for ( ; cur < limit; cur++ ) + { + if ( cur[0] == module ) + { + /* remove it from the table */ + library->num_modules--; + limit--; + while ( cur < limit ) + { + cur[0] = cur[1]; + cur++; + } + limit[0] = 0; + + /* destroy the module */ + Destroy_Module( module ); + + return FT_Err_Ok; + } + } + } + return FT_Err_Invalid_Driver_Handle; + } + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** L I B R A R Y ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* */ + /* FT_New_Library */ + /* */ + /* */ + /* This function is used to create a new FreeType library instance */ + /* from a given memory object. It is thus possible to use libraries */ + /* with distinct memory allocators within the same program. */ + /* */ + /* */ + /* memory :: A handle to the original memory object. */ + /* */ + /* */ + /* alibrary :: A pointer to handle of a new library object. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT_FUNC( FT_Error ) FT_New_Library( FT_Memory memory, + FT_Library* alibrary ) + { + FT_Library library = 0; + FT_Error error; + + + if ( !memory ) + return FT_Err_Invalid_Argument; + + /* first of all, allocate the library object */ + if ( ALLOC( library, sizeof ( *library ) ) ) + return error; + + library->memory = memory; + + /* allocate the render pool */ + library->raster_pool_size = FT_RENDER_POOL_SIZE; + if ( ALLOC( library->raster_pool, FT_RENDER_POOL_SIZE ) ) + goto Fail; + + /* That's ok now */ + *alibrary = library; + + return FT_Err_Ok; + + Fail: + FREE( library ); + return error; + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Done_Library */ + /* */ + /* */ + /* Discards a given library object. This closes all drivers and */ + /* discards all resource objects. */ + /* */ + /* */ + /* library :: A handle to the target library. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT_FUNC( FT_Error ) FT_Done_Library( FT_Library library ) + { + FT_Memory memory; + FT_UInt n; + + + if ( !library ) + return FT_Err_Invalid_Library_Handle; + + memory = library->memory; + + /* Discard client-data */ + if ( library->generic.finalizer ) + library->generic.finalizer( library ); + + /* Close all modules in the library */ + for ( n = 0; n < library->num_modules; n++ ) + { + FT_Module module = library->modules[n]; + + + if ( module ) + { + Destroy_Module( module ); + library->modules[n] = 0; + } + } + + /* Destroy raster objects */ + FREE( library->raster_pool ); + library->raster_pool_size = 0; + + FREE( library ); + return FT_Err_Ok; + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Set_Debug_Hook */ + /* */ + /* */ + /* Sets a debug hook function for debugging the interpreter of a font */ + /* format. */ + /* */ + /* */ + /* library :: A handle to the library object. */ + /* */ + /* hook_index :: The index of the debug hook. You should use the */ + /* values defined in ftobjs.h, e.g. */ + /* FT_DEBUG_HOOK_TRUETYPE */ + /* */ + /* debug_hook :: The function used to debug the interpreter. */ + /* */ + /* */ + /* Currently, four debug hook slots are available, but only two (for */ + /* the TrueType and the Type 1 interpreter) are defined. */ + /* */ + FT_EXPORT_FUNC( void ) FT_Set_Debug_Hook( FT_Library library, + FT_UInt hook_index, + FT_DebugHook_Func debug_hook ) + { + if ( library && debug_hook && + hook_index < + ( sizeof ( library->debug_hooks ) / sizeof ( void* ) ) ) + library->debug_hooks[hook_index] = debug_hook; + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Done_FreeType */ + /* */ + /* */ + /* Destroys a given FreeType library object and all of its childs, */ + /* including resources, drivers, faces, sizes, etc. */ + /* */ + /* */ + /* library :: A handle to the target library object. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT_FUNC( FT_Error ) FT_Done_FreeType( FT_Library library ) + { + /* test for valid `library' delayed to FT_Done_Library() */ + + /* Discard the library object */ + FT_Done_Library( library ); + + return FT_Err_Ok; + } + + +/* END */ diff --git a/src/freetype/base/ftoutln.c b/src/freetype/base/ftoutln.c new file mode 100644 index 0000000000..20292d0c3a --- /dev/null +++ b/src/freetype/base/ftoutln.c @@ -0,0 +1,842 @@ +/***************************************************************************/ +/* */ +/* ftoutln.c */ +/* */ +/* FreeType outline management (body). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + + /*************************************************************************/ + /* */ + /* All functions are declared in freetype.h. */ + /* */ + /*************************************************************************/ + + +#include +#include + + + /*************************************************************************/ + /* */ + /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ + /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ + /* messages during execution. */ + /* */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_outline + + + static + const FT_Outline null_outline = { 0, 0, 0, 0, 0, 0 }; + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Outline_Decompose */ + /* */ + /* */ + /* Walks over an outline's structure to decompose it into individual */ + /* segments and Bezier arcs. This function is also able to emit */ + /* `move to' and `close to' operations to indicate the start and end */ + /* of new contours in the outline. */ + /* */ + /* */ + /* outline :: A pointer to the source target. */ + /* */ + /* interface :: A table of `emitters', i.e,. function pointers called */ + /* during decomposition to indicate path operations. */ + /* */ + /* user :: A typeless pointer which is passed to each emitter */ + /* during the decomposition. It can be used to store */ + /* the state during the decomposition. */ + /* */ + /* */ + /* FreeType error code. 0 means sucess. */ + /* */ + FT_EXPORT_FUNC( FT_Error ) FT_Outline_Decompose( + FT_Outline* outline, + FT_Outline_Funcs* interface, + void* user ) + { +#undef SCALED +#define SCALED( x ) ( ( (x) << shift ) - delta ) + + FT_Vector v_last; + FT_Vector v_control; + FT_Vector v_start; + + FT_Vector* point; + FT_Vector* limit; + char* tags; + + FT_Error error; + + FT_Int n; /* index of contour in outline */ + FT_UInt first; /* index of first point in contour */ + char tag; /* current point's state */ + + FT_Int shift; + FT_Pos delta; + + + if ( !outline || !interface ) + return FT_Err_Invalid_Argument; + + shift = interface->shift; + delta = interface->delta; + first = 0; + + for ( n = 0; n < outline->n_contours; n++ ) + { + FT_Int last; /* index of last point in contour */ + + + last = outline->contours[n]; + limit = outline->points + last; + + v_start = outline->points[first]; + v_last = outline->points[last]; + + v_start.x = SCALED( v_start.x ); v_start.y = SCALED( v_start.y ); + v_last.x = SCALED( v_last.x ); v_last.y = SCALED( v_last.y ); + + v_control = v_start; + + point = outline->points + first; + tags = outline->tags + first; + tag = FT_CURVE_TAG( tags[0] ); + + /* A contour cannot start with a cubic control point! */ + if ( tag == FT_Curve_Tag_Cubic ) + goto Invalid_Outline; + + /* check first point to determine origin */ + if ( tag == FT_Curve_Tag_Conic ) + { + /* first point is conic control. Yes, this happens. */ + if ( FT_CURVE_TAG( outline->tags[last] ) == FT_Curve_Tag_On ) + { + /* start at last point if it is on the curve */ + v_start = v_last; + limit--; + } + else + { + /* if both first and last points are conic, */ + /* start at their middle and record its position */ + /* for closure */ + v_start.x = ( v_start.x + v_last.x ) / 2; + v_start.y = ( v_start.y + v_last.y ) / 2; + + v_last = v_start; + } + point--; + tags--; + } + + error = interface->move_to( &v_start, user ); + if ( error ) + goto Exit; + + while ( point < limit ) + { + point++; + tags++; + + tag = FT_CURVE_TAG( tags[0] ); + switch ( tag ) + { + case FT_Curve_Tag_On: /* emit a single line_to */ + { + FT_Vector vec; + + + vec.x = SCALED( point->x ); + vec.y = SCALED( point->y ); + + error = interface->line_to( &vec, user ); + if ( error ) + goto Exit; + continue; + } + + case FT_Curve_Tag_Conic: /* consume conic arcs */ + v_control.x = SCALED( point->x ); + v_control.y = SCALED( point->y ); + + Do_Conic: + if ( point < limit ) + { + FT_Vector vec; + FT_Vector v_middle; + + + point++; + tags++; + tag = FT_CURVE_TAG( tags[0] ); + + vec.x = SCALED( point->x ); + vec.y = SCALED( point->y ); + + if ( tag == FT_Curve_Tag_On ) + { + error = interface->conic_to( &v_control, &vec, user ); + if ( error ) + goto Exit; + continue; + } + + if ( tag != FT_Curve_Tag_Conic ) + goto Invalid_Outline; + + v_middle.x = ( v_control.x + vec.x ) / 2; + v_middle.y = ( v_control.y + vec.y ) / 2; + + error = interface->conic_to( &v_control, &v_middle, user ); + if ( error ) + goto Exit; + + v_control = vec; + goto Do_Conic; + } + + error = interface->conic_to( &v_control, &v_start, user ); + goto Close; + + default: /* FT_Curve_Tag_Cubic */ + { + FT_Vector vec1, vec2; + + + if ( point + 1 > limit || + FT_CURVE_TAG( tags[1] ) != FT_Curve_Tag_Cubic ) + goto Invalid_Outline; + + point += 2; + tags += 2; + + vec1.x = SCALED( point[-2].x ); vec1.y = SCALED( point[-2].y ); + vec2.x = SCALED( point[-1].x ); vec2.y = SCALED( point[-1].y ); + + if ( point <= limit ) + { + FT_Vector vec; + + + vec.x = SCALED( point->x ); + vec.y = SCALED( point->y ); + + error = interface->cubic_to( &vec1, &vec2, &vec, user ); + if ( error ) + goto Exit; + continue; + } + + error = interface->cubic_to( &vec1, &vec2, &v_start, user ); + goto Close; + } + } + } + + /* close the contour with a line segment */ + error = interface->line_to( &v_start, user ); + + Close: + if ( error ) + goto Exit; + + first = last + 1; + } + + return 0; + + Exit: + return error; + + Invalid_Outline: + return FT_Err_Invalid_Outline; + } + + + FT_EXPORT_FUNC( FT_Error ) FT_Outline_New_Internal( + FT_Memory memory, + FT_UInt numPoints, + FT_Int numContours, + FT_Outline* outline ) + { + FT_Error error; + + + if ( !outline || !memory ) + return FT_Err_Invalid_Argument; + + *outline = null_outline; + + if ( ALLOC_ARRAY( outline->points, numPoints * 2L, FT_Pos ) || + ALLOC_ARRAY( outline->tags, numPoints, FT_Byte ) || + ALLOC_ARRAY( outline->contours, numContours, FT_UShort ) ) + goto Fail; + + outline->n_points = (FT_UShort)numPoints; + outline->n_contours = (FT_Short)numContours; + outline->flags |= ft_outline_owner; + + return FT_Err_Ok; + + Fail: + outline->flags |= ft_outline_owner; + FT_Outline_Done_Internal( memory, outline ); + + return error; + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Outline_New */ + /* */ + /* */ + /* Creates a new outline of a given size. */ + /* */ + /* */ + /* library :: A handle to the library object from where the */ + /* outline is allocated. Note however that the new */ + /* outline will NOT necessarily be FREED, when */ + /* destroying the library, by FT_Done_FreeType(). */ + /* */ + /* numPoints :: The maximal number of points within the outline. */ + /* */ + /* numContours :: The maximal number of contours within the outline. */ + /* */ + /* */ + /* outline :: A handle to the new outline. NULL in case of */ + /* error. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* No. */ + /* */ + /* */ + /* The reason why this function takes a `library' parameter is simply */ + /* to use the library's memory allocator. */ + /* */ + FT_EXPORT_FUNC( FT_Error ) FT_Outline_New( FT_Library library, + FT_UInt numPoints, + FT_Int numContours, + FT_Outline* outline ) + { + if ( !library ) + return FT_Err_Invalid_Library_Handle; + + return FT_Outline_New_Internal( library->memory, numPoints, + numContours, outline ); + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Outline_Copy */ + /* */ + /* */ + /* Copies an outline into another one. Both objects must have the */ + /* same sizes (number of points & number of contours) when this */ + /* function is called. */ + /* */ + /* */ + /* source :: A handle to the source outline. */ + /* */ + /* */ + /* target :: A handle to the target outline. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT_FUNC( FT_Error ) FT_Outline_Copy( FT_Outline* source, + FT_Outline* target ) + { + FT_Int is_owner; + + + if ( !source || !target || + source->n_points != target->n_points || + source->n_contours != target->n_contours ) + return FT_Err_Invalid_Argument; + + MEM_Copy( target->points, source->points, + source->n_points * sizeof ( FT_Vector ) ); + + MEM_Copy( target->tags, source->tags, + source->n_points * sizeof ( FT_Byte ) ); + + MEM_Copy( target->contours, source->contours, + source->n_contours * sizeof ( FT_Short ) ); + + /* copy all flags, except the `ft_outline_owner' one */ + is_owner = target->flags & ft_outline_owner; + target->flags = source->flags; + + target->flags &= ~ft_outline_owner; + target->flags |= is_owner; + + return FT_Err_Ok; + } + + + FT_EXPORT_FUNC( FT_Error ) FT_Outline_Done_Internal( FT_Memory memory, + FT_Outline* outline ) + { + if ( outline ) + { + if ( outline->flags & ft_outline_owner ) + { + FREE( outline->points ); + FREE( outline->tags ); + FREE( outline->contours ); + } + *outline = null_outline; + + return FT_Err_Ok; + } + else + return FT_Err_Invalid_Argument; + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Outline_Done */ + /* */ + /* */ + /* Destroys an outline created with FT_Outline_New(). */ + /* */ + /* */ + /* library :: A handle of the library object used to allocate the */ + /* outline. */ + /* */ + /* outline :: A pointer to the outline object to be discarded. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* No. */ + /* */ + /* */ + /* If the outline's `owner' field is not set, only the outline */ + /* descriptor will be released. */ + /* */ + /* The reason why this function takes an `outline' parameter is */ + /* simply to use FT_Free(). */ + /* */ + FT_EXPORT_FUNC( FT_Error ) FT_Outline_Done( FT_Library library, + FT_Outline* outline ) + { + /* check for valid `outline' in FT_Outline_Done_Internal() */ + + if ( !library ) + return FT_Err_Invalid_Library_Handle; + + return FT_Outline_Done_Internal( library->memory, outline ); + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Outline_Get_CBox */ + /* */ + /* */ + /* Returns an outline's `control box'. The control box encloses all */ + /* the outline's points, including Bezier control points. Though it */ + /* coincides with the exact bounding box for most glyphs, it can be */ + /* slightly larger in some situations (like when rotating an outline */ + /* which contains Bezier outside arcs). */ + /* */ + /* Computing the control box is very fast, while getting the bounding */ + /* box can take much more time as it needs to walk over all segments */ + /* and arcs in the outline. To get the latter, you can use the */ + /* `ftbbox' component which is dedicated to this single task. */ + /* */ + /* */ + /* outline :: A pointer to the source outline descriptor. */ + /* */ + /* */ + /* cbox :: The outline's control box. */ + /* */ + /* */ + /* Yes. */ + /* */ + FT_EXPORT_FUNC( void ) FT_Outline_Get_CBox( FT_Outline* outline, + FT_BBox* cbox ) + { + FT_Pos xMin, yMin, xMax, yMax; + + + if ( outline && cbox ) + { + if ( outline->n_points == 0 ) + { + xMin = 0; + yMin = 0; + xMax = 0; + yMax = 0; + } + else + { + FT_Vector* vec = outline->points; + FT_Vector* limit = vec + outline->n_points; + + + xMin = xMax = vec->x; + yMin = yMax = vec->y; + vec++; + + for ( ; vec < limit; vec++ ) + { + FT_Pos x, y; + + + x = vec->x; + if ( x < xMin ) xMin = x; + if ( x > xMax ) xMax = x; + + y = vec->y; + if ( y < yMin ) yMin = y; + if ( y > yMax ) yMax = y; + } + } + cbox->xMin = xMin; + cbox->xMax = xMax; + cbox->yMin = yMin; + cbox->yMax = yMax; + } + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Outline_Translate */ + /* */ + /* */ + /* Applies a simple translation to the points of an outline. */ + /* */ + /* */ + /* outline :: A pointer to the target outline descriptor. */ + /* */ + /* xOffset :: The horizontal offset. */ + /* */ + /* yOffset :: The vertical offset. */ + /* */ + /* */ + /* Yes. */ + /* */ + FT_EXPORT_FUNC( void ) FT_Outline_Translate( FT_Outline* outline, + FT_Pos xOffset, + FT_Pos yOffset ) + { + FT_UShort n; + FT_Vector* vec = outline->points; + + + for ( n = 0; n < outline->n_points; n++ ) + { + vec->x += xOffset; + vec->y += yOffset; + vec++; + } + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Outline_Reverse */ + /* */ + /* */ + /* Reverses the drawing direction of an outline. This is used to */ + /* ensure consistent fill conventions for mirrored glyphs. */ + /* */ + /* */ + /* outline :: A pointer to the target outline descriptor. */ + /* */ + /* */ + /* This functions toggles the bit flag `ft_outline_reverse_fill' in */ + /* the outline's `flags' field. */ + /* */ + FT_EXPORT_FUNC( void ) FT_Outline_Reverse( FT_Outline* outline ) + { + FT_UShort n; + FT_Int first, last; + + + first = 0; + + for ( n = 0; n < outline->n_contours; n++ ) + { + last = outline->contours[n]; + + /* reverse point table */ + { + FT_Vector* p = outline->points + first; + FT_Vector* q = outline->points + last; + FT_Vector swap; + + + while ( p < q ) + { + swap = *p; + *p = *q; + *q = swap; + p++; + q--; + } + } + + /* reverse tags table */ + { + char* p = outline->tags + first; + char* q = outline->tags + last; + char swap; + + + while ( p < q ) + { + swap = *p; + *p = *q; + *q = swap; + p++; + q--; + } + } + + first = last + 1; + } + + outline->flags ^= ft_outline_reverse_fill; + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Outline_Render */ + /* */ + /* */ + /* Renders an outline within a bitmap using the current scan-convert. */ + /* This functions uses an FT_Raster_Params structure as an argument, */ + /* allowing advanced features like direct composition, translucency, */ + /* etc. */ + /* */ + /* */ + /* library :: A handle to a FreeType library object. */ + /* */ + /* outline :: A pointer to the source outline descriptor. */ + /* */ + /* params :: A pointer to a FT_Raster_Params structure used to */ + /* describe the rendering operation. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* YES. Rendering is synchronized, so that concurrent calls to the */ + /* scan-line converter will be serialized. */ + /* */ + /* */ + /* You should know what you are doing and how FT_Raster_Params works */ + /* to use this function. */ + /* */ + /* The field `params.source' will be set to `outline' before the scan */ + /* converter is called, which means that the value you give to it is */ + /* actually ignored. */ + /* */ + FT_EXPORT_FUNC( FT_Error ) FT_Outline_Render( FT_Library library, + FT_Outline* outline, + FT_Raster_Params* params ) + { + FT_Error error; + FT_Bool update = 0; + FT_Renderer renderer; + FT_ListNode node; + + + if ( !library ) + return FT_Err_Invalid_Library_Handle; + + if ( !params ) + return FT_Err_Invalid_Argument; + + renderer = library->cur_renderer; + node = library->renderers.head; + + params->source = (void*)outline; + + error = FT_Err_Cannot_Render_Glyph; + while ( renderer ) + { + error = renderer->raster_render( renderer->raster, params ); + if ( !error || error != FT_Err_Cannot_Render_Glyph ) + break; + + /* FT_Err_Cannot_Render_Glyph is returned if the render mode */ + /* is unsupported by the current renderer for this glyph image */ + /* format */ + + /* now, look for another renderer that supports the same */ + /* format */ + renderer = FT_Lookup_Renderer( library, ft_glyph_format_outline, + &node ); + update = 1; + } + + /* if we changed the current renderer for the glyph image format */ + /* we need to select it as the next current one */ + if ( !error && update && renderer ) + FT_Set_Renderer( library, renderer, 0, 0 ); + + return error; + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Outline_Get_Bitmap */ + /* */ + /* */ + /* Renders an outline within a bitmap. The outline's image is simply */ + /* OR-ed to the target bitmap. */ + /* */ + /* */ + /* library :: A handle to a FreeType library object. */ + /* */ + /* outline :: A pointer to the source outline descriptor. */ + /* */ + /* map :: A pointer to the target bitmap descriptor. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* YES. Rendering is synchronized, so that concurrent calls to the */ + /* scan-line converter will be serialized. */ + /* */ + /* */ + /* This function does NOT CREATE the bitmap, it only renders an */ + /* outline image within the one you pass to it! */ + /* */ + /* It will use the raster correponding to the default glyph format. */ + /* */ + FT_EXPORT_FUNC( FT_Error ) FT_Outline_Get_Bitmap( FT_Library library, + FT_Outline* outline, + FT_Bitmap* bitmap ) + { + FT_Raster_Params params; + + + if ( !bitmap ) + return FT_Err_Invalid_Argument; + + /* other checks are delayed to FT_Outline_Render() */ + + params.target = bitmap; + params.flags = 0; + + if ( bitmap->pixel_mode == ft_pixel_mode_grays ) + params.flags |= ft_raster_flag_aa; + + return FT_Outline_Render( library, outline, ¶ms ); + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Vector_Transform */ + /* */ + /* */ + /* Transforms a single vector through a 2x2 matrix. */ + /* */ + /* */ + /* vector :: The target vector to transform. */ + /* */ + /* */ + /* matrix :: A pointer to the source 2x2 matrix. */ + /* */ + /* */ + /* Yes. */ + /* */ + /* */ + /* The result is undefined if either `vector' or `matrix' is invalid. */ + /* */ + FT_EXPORT_FUNC( void ) FT_Vector_Transform( FT_Vector* vector, + FT_Matrix* matrix ) + { + FT_Pos xz, yz; + + + if ( !vector || !matrix ) + return; + + xz = FT_MulFix( vector->x, matrix->xx ) + + FT_MulFix( vector->y, matrix->xy ); + + yz = FT_MulFix( vector->x, matrix->yx ) + + FT_MulFix( vector->y, matrix->yy ); + + vector->x = xz; + vector->y = yz; + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Outline_Transform */ + /* */ + /* */ + /* Applies a simple 2x2 matrix to all of an outline's points. Useful */ + /* for applying rotations, slanting, flipping, etc. */ + /* */ + /* */ + /* outline :: A pointer to the target outline descriptor. */ + /* */ + /* matrix :: A pointer to the transformation matrix. */ + /* */ + /* */ + /* Yes. */ + /* */ + /* */ + /* You can use FT_Outline_Translate() if you need to translate the */ + /* outline's points. */ + /* */ + FT_EXPORT_FUNC( void ) FT_Outline_Transform( FT_Outline* outline, + FT_Matrix* matrix ) + { + FT_Vector* vec = outline->points; + FT_Vector* limit = vec + outline->n_points; + + + for ( ; vec < limit; vec++ ) + FT_Vector_Transform( vec, matrix ); + } + +/* END */ diff --git a/src/freetype/base/ftstream.c b/src/freetype/base/ftstream.c new file mode 100644 index 0000000000..768586ebbf --- /dev/null +++ b/src/freetype/base/ftstream.c @@ -0,0 +1,818 @@ +/***************************************************************************/ +/* */ +/* ftstream.c */ +/* */ +/* I/O stream support (body). */ +/* */ +/* Copyright 2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#include +#include + + + /*************************************************************************/ + /* */ + /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ + /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ + /* messages during execution. */ + /* */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_stream + + + BASE_FUNC( void ) FT_New_Memory_Stream( FT_Library library, + FT_Byte* base, + FT_ULong size, + FT_Stream stream ) + { + stream->memory = library->memory; + stream->base = base; + stream->size = size; + stream->pos = 0; + stream->cursor = 0; + stream->read = 0; + stream->close = 0; + } + + + BASE_FUNC( FT_Error ) FT_Seek_Stream( FT_Stream stream, + FT_ULong pos ) + { + FT_Error error; + + + stream->pos = pos; + + if ( stream->read ) + { + if ( stream->read( stream, pos, 0, 0 ) ) + { + FT_ERROR(( "FT_Seek_Stream:" )); + FT_ERROR(( " invalid i/o; pos = 0x%lx, size = 0x%lx\n", + pos, stream->size )); + + error = FT_Err_Invalid_Stream_Operation; + } + else + error = FT_Err_Ok; + } + /* note that seeking to the first position after the file is valid */ + else if ( pos > stream->size ) + { + FT_ERROR(( "FT_Seek_Stream:" )); + FT_ERROR(( " invalid i/o; pos = 0x%lx, size = 0x%lx\n", + pos, stream->size )); + + error = FT_Err_Invalid_Stream_Operation; + } + + else + error = FT_Err_Ok; + + return error; + } + + + BASE_FUNC( FT_Error ) FT_Skip_Stream( FT_Stream stream, + FT_Long distance ) + { + return FT_Seek_Stream( stream, (FT_ULong)( stream->pos + distance ) ); + } + + + BASE_FUNC( FT_Long ) FT_Stream_Pos( FT_Stream stream ) + { + return stream->pos; + } + + + BASE_FUNC( FT_Error ) FT_Read_Stream( FT_Stream stream, + FT_Byte* buffer, + FT_ULong count ) + { + return FT_Read_Stream_At( stream, stream->pos, buffer, count ); + } + + + BASE_FUNC( FT_Error ) FT_Read_Stream_At( FT_Stream stream, + FT_ULong pos, + FT_Byte* buffer, + FT_ULong count ) + { + FT_Error error = FT_Err_Ok; + FT_ULong read_bytes; + + + if ( pos >= stream->size ) + { + FT_ERROR(( "FT_Read_Stream_At:" )); + FT_ERROR(( " invalid i/o; pos = 0x%lx, size = 0x%lx\n", + pos, stream->size )); + + return FT_Err_Invalid_Stream_Operation; + } + + if ( stream->read ) + read_bytes = stream->read( stream, pos, buffer, count ); + else + { + read_bytes = stream->size - pos; + if ( read_bytes > count ) + read_bytes = count; + + MEM_Copy( buffer, stream->base + pos, read_bytes ); + } + + stream->pos = pos + read_bytes; + + if ( read_bytes < count ) + { + FT_ERROR(( "FT_Read_Stream_At:" )); + FT_ERROR(( " invalid read; expected %lu bytes, got %lu\n", + count, read_bytes )); + + error = FT_Err_Invalid_Stream_Operation; + } + + return error; + } + + + BASE_FUNC( FT_Error ) FT_Extract_Frame( FT_Stream stream, + FT_ULong count, + FT_Byte** pbytes ) + { + FT_Error error; + + + error = FT_Access_Frame( stream, count ); + if ( !error ) + { + *pbytes = (FT_Byte*)stream->cursor; + + /* equivalent to FT_Forget_Frame(), with no memory block release */ + stream->cursor = 0; + stream->limit = 0; + } + + return error; + } + + + BASE_FUNC( void ) FT_Release_Frame( FT_Stream stream, + FT_Byte** pbytes ) + { + if ( stream->read ) + { + FT_Memory memory = stream->memory; + + + FREE( *pbytes ); + } + *pbytes = 0; + } + + + BASE_FUNC( FT_Error ) FT_Access_Frame( FT_Stream stream, + FT_ULong count ) + { + FT_Error error = FT_Err_Ok; + FT_ULong read_bytes; + + + /* check for nested frame access */ + FT_Assert( stream && stream->cursor == 0 ); + + if ( stream->read ) + { + /* allocate the frame in memory */ + FT_Memory memory = stream->memory; + + + if ( ALLOC( stream->base, count ) ) + goto Exit; + + /* read it */ + read_bytes = stream->read( stream, stream->pos, + stream->base, count ); + if ( read_bytes < count ) + { + FT_ERROR(( "FT_Access_Frame:" )); + FT_ERROR(( " invalid read; expected %lu bytes, got %lu\n", + count, read_bytes )); + + FREE( stream->base ); + error = FT_Err_Invalid_Stream_Operation; + } + stream->cursor = stream->base; + stream->limit = stream->cursor + count; + stream->pos += read_bytes; + } + else + { + /* check current and new position */ + if ( stream->pos >= stream->size || + stream->pos + count > stream->size ) + { + FT_ERROR(( "FT_Access_Frame:" )); + FT_ERROR(( " invalid i/o; pos = 0x%lx, count = %lu, size = 0x%lx\n", + stream->pos, count, stream->size )); + + error = FT_Err_Invalid_Stream_Operation; + goto Exit; + } + + /* set cursor */ + stream->cursor = stream->base + stream->pos; + stream->limit = stream->cursor + count; + stream->pos += count; + } + + Exit: + return error; + } + + + BASE_FUNC( void ) FT_Forget_Frame( FT_Stream stream ) + { + /* IMPORTANT: The assertion stream->cursor != 0 was removed, given */ + /* that it is possible to access a frame of length 0 in */ + /* some weird fonts (usually, when accessing an array of */ + /* 0 records, like in some strange kern tables). */ + /* */ + /* In this case, the loader code handles the 0-length table */ + /* gracefully; however, stream.cursor is really set to 0 by the */ + /* FT_Access_Frame() call, and this is not an error. */ + /* */ + FT_Assert( stream ); + + if ( stream->read ) + { + FT_Memory memory = stream->memory; + + + FREE( stream->base ); + } + stream->cursor = 0; + stream->limit = 0; + } + + + BASE_FUNC( FT_Char ) FT_Get_Char( FT_Stream stream ) + { + FT_Char result; + + + FT_Assert( stream && stream->cursor ); + + result = 0; + if ( stream->cursor < stream->limit ) + result = *stream->cursor++; + + return result; + } + + + BASE_FUNC( FT_Short ) FT_Get_Short( FT_Stream stream ) + { + FT_Byte* p; + FT_Short result; + + + FT_Assert( stream && stream->cursor ); + + result = 0; + p = stream->cursor; + if ( p + 1 < stream->limit ) + result = NEXT_Short( p ); + stream->cursor = p; + + return result; + } + + + BASE_FUNC( FT_Short ) FT_Get_ShortLE( FT_Stream stream ) + { + FT_Byte* p; + FT_Short result; + + + FT_Assert( stream && stream->cursor ); + + result = 0; + p = stream->cursor; + if ( p + 1 < stream->limit ) + result = NEXT_ShortLE( p ); + stream->cursor = p; + + return result; + } + + + BASE_FUNC( FT_Long ) FT_Get_Offset( FT_Stream stream ) + { + FT_Byte* p; + FT_Long result; + + + FT_Assert( stream && stream->cursor ); + + result = 0; + p = stream->cursor; + if ( p + 2 < stream->limit ) + result = NEXT_Offset( p ); + stream->cursor = p; + return result; + } + + + BASE_FUNC( FT_Long ) FT_Get_Long( FT_Stream stream ) + { + FT_Byte* p; + FT_Long result; + + + FT_Assert( stream && stream->cursor ); + + result = 0; + p = stream->cursor; + if ( p + 3 < stream->limit ) + result = NEXT_Long( p ); + stream->cursor = p; + return result; + } + + + BASE_FUNC( FT_Long ) FT_Get_LongLE( FT_Stream stream ) + { + FT_Byte* p; + FT_Long result; + + + FT_Assert( stream && stream->cursor ); + + result = 0; + p = stream->cursor; + if ( p + 3 < stream->limit ) + result = NEXT_LongLE( p ); + stream->cursor = p; + return result; + } + + + BASE_FUNC( FT_Char ) FT_Read_Char( FT_Stream stream, + FT_Error* error ) + { + FT_Byte result = 0; + + + FT_Assert( stream ); + + *error = FT_Err_Ok; + + if ( stream->read ) + { + if ( stream->read( stream, stream->pos, &result, 1L ) != 1L ) + goto Fail; + } + else + { + if ( stream->pos < stream->size ) + result = stream->base[stream->pos]; + else + goto Fail; + } + stream->pos++; + + return result; + + Fail: + *error = FT_Err_Invalid_Stream_Operation; + FT_ERROR(( "FT_Read_Char:" )); + FT_ERROR(( " invalid i/o; pos = 0x%lx, size = 0x%lx\n", + stream->pos, stream->size )); + + return 0; + } + + + BASE_FUNC( FT_Short ) FT_Read_Short( FT_Stream stream, + FT_Error* error ) + { + FT_Byte reads[2]; + FT_Byte* p = 0; + FT_Short result = 0; + + + FT_Assert( stream ); + + *error = FT_Err_Ok; + + if ( stream->pos + 1 < stream->size ) + { + if ( stream->read ) + { + if ( stream->read( stream, stream->pos, reads, 2L ) != 2L ) + goto Fail; + + p = reads; + } + else + { + p = stream->base + stream->pos; + } + + if ( p ) + result = NEXT_Short( p ); + } + else + goto Fail; + + stream->pos += 2; + + return result; + + Fail: + *error = FT_Err_Invalid_Stream_Operation; + FT_ERROR(( "FT_Read_Short:" )); + FT_ERROR(( " invalid i/o; pos = 0x%lx, size = 0x%lx\n", + stream->pos, stream->size )); + + return 0; + } + + + BASE_FUNC( FT_Short ) FT_Read_ShortLE( FT_Stream stream, + FT_Error* error ) + { + FT_Byte reads[2]; + FT_Byte* p = 0; + FT_Short result = 0; + + + FT_Assert( stream ); + + *error = FT_Err_Ok; + + if ( stream->pos + 1 < stream->size ) + { + if ( stream->read ) + { + if ( stream->read( stream, stream->pos, reads, 2L ) != 2L ) + goto Fail; + + p = reads; + } + else + { + p = stream->base + stream->pos; + } + + if ( p ) + result = NEXT_ShortLE( p ); + } + else + goto Fail; + + stream->pos += 2; + + return result; + + Fail: + *error = FT_Err_Invalid_Stream_Operation; + FT_ERROR(( "FT_Read_Short:" )); + FT_ERROR(( " invalid i/o; pos = 0x%lx, size = 0x%lx\n", + stream->pos, stream->size )); + + return 0; + } + + + BASE_FUNC( FT_Long ) FT_Read_Offset( FT_Stream stream, + FT_Error* error ) + { + FT_Byte reads[3]; + FT_Byte* p = 0; + FT_Long result = 0; + + + FT_Assert( stream ); + + *error = FT_Err_Ok; + + if ( stream->pos + 2 < stream->size ) + { + if ( stream->read ) + { + if (stream->read( stream, stream->pos, reads, 3L ) != 3L ) + goto Fail; + + p = reads; + } + else + { + p = stream->base + stream->pos; + } + + if ( p ) + result = NEXT_Offset( p ); + } + else + goto Fail; + + stream->pos += 3; + + return result; + + Fail: + *error = FT_Err_Invalid_Stream_Operation; + FT_ERROR(( "FT_Read_Offset:" )); + FT_ERROR(( " invalid i/o; pos = 0x%lx, size = 0x%lx\n", + stream->pos, stream->size )); + + return 0; + } + + + BASE_FUNC( FT_Long ) FT_Read_Long( FT_Stream stream, + FT_Error* error ) + { + FT_Byte reads[4]; + FT_Byte* p = 0; + FT_Long result = 0; + + + FT_Assert( stream ); + + *error = FT_Err_Ok; + + if ( stream->pos + 3 < stream->size ) + { + if ( stream->read ) + { + if ( stream->read( stream, stream->pos, reads, 4L ) != 4L ) + goto Fail; + + p = reads; + } + else + { + p = stream->base + stream->pos; + } + + if ( p ) + result = NEXT_Long( p ); + } + else + goto Fail; + + stream->pos += 4; + + return result; + + Fail: + FT_ERROR(( "FT_Read_Long:" )); + FT_ERROR(( " invalid i/o; pos = 0x%lx, size = 0x%lx\n", + stream->pos, stream->size )); + *error = FT_Err_Invalid_Stream_Operation; + + return 0; + } + + + BASE_FUNC( FT_Long ) FT_Read_LongLE( FT_Stream stream, + FT_Error* error ) + { + FT_Byte reads[4]; + FT_Byte* p = 0; + FT_Long result = 0; + + + FT_Assert( stream ); + + *error = FT_Err_Ok; + + if ( stream->pos + 3 < stream->size ) + { + if ( stream->read ) + { + if ( stream->read( stream, stream->pos, reads, 4L ) != 4L ) + goto Fail; + + p = reads; + } + else + { + p = stream->base + stream->pos; + } + + if ( p ) + result = NEXT_LongLE( p ); + } + else + goto Fail; + + stream->pos += 4; + + return result; + + Fail: + FT_ERROR(( "FT_Read_Long:" )); + FT_ERROR(( " invalid i/o; pos = 0x%lx, size = 0x%lx\n", + stream->pos, stream->size )); + *error = FT_Err_Invalid_Stream_Operation; + + return 0; + } + + + BASE_FUNC( FT_Error ) FT_Read_Fields( FT_Stream stream, + const FT_Frame_Field* fields, + void* structure ) + { + FT_Error error; + FT_Bool frame_accessed = 0; + + + if ( !fields || !stream ) + return FT_Err_Invalid_Argument; + + error = FT_Err_Ok; + do + { + FT_ULong value; + FT_Int sign_shift; + FT_Byte* p; + + + switch ( fields->value ) + { + case ft_frame_start: /* access a new frame */ + error = FT_Access_Frame( stream, fields->offset ); + if ( error ) + goto Exit; + + frame_accessed = 1; + fields++; + continue; /* loop! */ + + case ft_frame_bytes: /* read a byte sequence */ + case ft_frame_skip: /* skip some bytes */ + { + FT_Int len = fields->size; + + + if ( stream->cursor + len > stream->limit ) + { + error = FT_Err_Invalid_Stream_Operation; + goto Exit; + } + + if ( fields->value == ft_frame_bytes ) + { + p = (FT_Byte*)structure + fields->offset; + MEM_Copy( p, stream->cursor, len ); + } + stream->cursor += len; + fields++; + continue; + } + + case ft_frame_byte: + case ft_frame_schar: /* read a single byte */ + value = GET_Byte(); + sign_shift = 24; + break; + + case ft_frame_short_be: + case ft_frame_ushort_be: /* read a 2-byte big-endian short */ + value = GET_UShort(); + sign_shift = 16; + break; + + case ft_frame_short_le: + case ft_frame_ushort_le: /* read a 2-byte little-endian short */ + { + FT_Byte* p; + + + value = 0; + p = stream->cursor; + + if ( p + 1 < stream->limit ) + { + value = ( FT_UShort)p[0] | ((FT_UShort)p[1] << 8 ); + stream->cursor += 2; + } + sign_shift = 16; + break; + } + + case ft_frame_long_be: + case ft_frame_ulong_be: /* read a 4-byte big-endian long */ + value = GET_ULong(); + sign_shift = 0; + break; + + case ft_frame_long_le: + case ft_frame_ulong_le: /* read a 4-byte little-endian long */ + { + FT_Byte* p; + + + value = 0; + p = stream->cursor; + + if ( p + 3 < stream->limit ) + { + value = (FT_ULong)p[0] | + ( (FT_ULong)p[1] << 8 ) | + ( (FT_ULong)p[2] << 16 ) | + ( (FT_ULong)p[3] << 24 ); + stream->cursor += 4; + } + sign_shift = 0; + break; + } + + case ft_frame_off3_be: + case ft_frame_uoff3_be: /* read a 3-byte big-endian long */ + value = GET_UOffset(); + sign_shift = 8; + break; + + case ft_frame_off3_le: + case ft_frame_uoff3_le: /* read a 3-byte little-endian long */ + { + FT_Byte* p; + + + value = 0; + p = stream->cursor; + + if ( p + 2 < stream->limit ) + { + value = (FT_ULong)p[0] | + ( (FT_ULong)p[1] << 8 ) | + ( (FT_ULong)p[2] << 16 ); + stream->cursor += 3; + } + sign_shift = 8; + break; + } + + default: + /* otherwise, exit the loop */ + goto Exit; + } + + /* now, compute the signed value is necessary */ + if ( fields->value & FT_FRAME_OP_SIGNED ) + value = (FT_ULong)( (FT_Int32)( value << sign_shift ) >> sign_shift ); + + /* finally, store the value in the object */ + + p = (FT_Byte*)structure + fields->offset; + switch ( fields->size ) + { + case 1: + *(FT_Byte*)p = (FT_Byte)value; + break; + + case 2: + *(FT_UShort*)p = (FT_UShort)value; + break; + + case 4: + *(FT_UInt32*)p = (FT_UInt32)value; + break; + + default: /* for 64-bit systems */ + *(FT_ULong*)p = (FT_ULong)value; + } + + /* go to next field */ + fields++; + } + while ( 1 ); + + Exit: + /* close the frame if it was opened by this read */ + if ( frame_accessed ) + FT_Forget_Frame( stream ); + + return error; + } + + +/* END */ diff --git a/src/freetype/base/ftsystem.c b/src/freetype/base/ftsystem.c new file mode 100644 index 0000000000..b99b0eaae4 --- /dev/null +++ b/src/freetype/base/ftsystem.c @@ -0,0 +1,299 @@ +/***************************************************************************/ +/* */ +/* ftsystem.c */ +/* */ +/* ANSI-specific FreeType low-level system interface (body). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + /*************************************************************************/ + /* */ + /* This file contains the default interface used by FreeType to access */ + /* low-level, i.e. memory management, i/o access as well as thread */ + /* synchronisation. It can be replaced by user-specific routines if */ + /* necessary. */ + /* */ + /*************************************************************************/ + + +#include +#include +#include +#include +#include + +#include +#include +#include + + + /*************************************************************************/ + /* */ + /* MEMORY MANAGEMENT INTERFACE */ + /* */ + /*************************************************************************/ + + /*************************************************************************/ + /* */ + /* It is not necessary to do any error checking for the */ + /* allocation-related functions. This will be done by the higher level */ + /* routines like FT_Alloc() or FT_Realloc(). */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* */ + /* ft_alloc */ + /* */ + /* */ + /* The memory allocation function. */ + /* */ + /* */ + /* memory :: A pointer to the memory object. */ + /* */ + /* size :: The requested size in bytes. */ + /* */ + /* */ + /* block :: The address of newly allocated block. */ + /* */ + static + void* ft_alloc( FT_Memory memory, + long size ) + { + FT_UNUSED( memory ); + + return malloc( size ); + } + + + /*************************************************************************/ + /* */ + /* */ + /* ft_realloc */ + /* */ + /* */ + /* The memory reallocation function. */ + /* */ + /* */ + /* memory :: A pointer to the memory object. */ + /* */ + /* cur_size :: The current size of the allocated memory block. */ + /* */ + /* new_size :: The newly requested size in bytes. */ + /* */ + /* block :: The current address of the block in memory. */ + /* */ + /* */ + /* The address of the reallocated memory block. */ + /* */ + static + void* ft_realloc( FT_Memory memory, + long cur_size, + long new_size, + void* block ) + { + FT_UNUSED( memory ); + FT_UNUSED( cur_size ); + + return realloc( block, new_size ); + } + + + /*************************************************************************/ + /* */ + /* */ + /* ft_free */ + /* */ + /* */ + /* The memory release function. */ + /* */ + /* */ + /* memory :: A pointer to the memory object. */ + /* */ + /* block :: The address of block in memory to be freed. */ + /* */ + static + void ft_free( FT_Memory memory, + void* block ) + { + FT_UNUSED( memory ); + + free( block ); + } + + + /*************************************************************************/ + /* */ + /* RESOURCE MANAGEMENT INTERFACE */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ + /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ + /* messages during execution. */ + /* */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_io + + /* We use the macro STREAM_FILE for convenience to extract the */ + /* system-specific stream handle from a given FreeType stream object */ +#define STREAM_FILE( stream ) ( (FILE*)stream->descriptor.pointer ) + + + /*************************************************************************/ + /* */ + /* */ + /* ft_close_stream */ + /* */ + /* */ + /* The function to close a stream. */ + /* */ + /* */ + /* stream :: A pointer to the stream object. */ + /* */ + static + void ft_close_stream( FT_Stream stream ) + { + fclose( STREAM_FILE( stream ) ); + + stream->descriptor.pointer = NULL; + stream->size = 0; + stream->base = 0; + } + + + /*************************************************************************/ + /* */ + /* */ + /* ft_io_stream */ + /* */ + /* */ + /* The function to open a stream. */ + /* */ + /* */ + /* stream :: A pointer to the stream object. */ + /* */ + /* offset :: The position in the data stream to start reading. */ + /* */ + /* buffer :: The address of buffer to store the read data. */ + /* */ + /* count :: The number of bytes to read from the stream. */ + /* */ + /* */ + /* The number of bytes actually read. */ + /* */ + static + unsigned long ft_io_stream( FT_Stream stream, + unsigned long offset, + unsigned char* buffer, + unsigned long count ) + { + FILE* file; + + + file = STREAM_FILE( stream ); + + fseek( file, offset, SEEK_SET ); + + return (unsigned long)fread( buffer, 1, count, file ); + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_New_Stream */ + /* */ + /* */ + /* Creates a new stream object. */ + /* */ + /* */ + /* filepathname :: The name of the stream (usually a file) to be */ + /* opened. */ + /* */ + /* stream :: A pointer to the stream object. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT_FUNC( FT_Error ) FT_New_Stream( const char* filepathname, + FT_Stream stream ) + { + FILE* file; + + + if ( !stream ) + return FT_Err_Invalid_Stream_Handle; + + file = fopen( filepathname, "rb" ); + if ( !file ) + { + FT_ERROR(( "FT_New_Stream:" )); + FT_ERROR(( " could not open `%s'\n", filepathname )); + + return FT_Err_Cannot_Open_Resource; + } + + fseek( file, 0, SEEK_END ); + stream->size = ftell( file ); + fseek( file, 0, SEEK_SET ); + + stream->descriptor.pointer = file; + stream->pathname.pointer = (char*)filepathname; + stream->pos = 0; + + stream->read = ft_io_stream; + stream->close = ft_close_stream; + + FT_TRACE1(( "FT_New_Stream:" )); + FT_TRACE1(( " opened `%s' (%d bytes) successfully\n", + filepathname, stream->size )); + + return FT_Err_Ok; + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_New_Memory */ + /* */ + /* */ + /* Creates a new memory object. */ + /* */ + /* */ + /* A pointer to the new memory object. 0 in case of error. */ + /* */ + FT_EXPORT_FUNC( FT_Memory ) FT_New_Memory( void ) + { + FT_Memory memory; + + + memory = (FT_Memory)malloc( sizeof ( *memory ) ); + if ( memory ) + { + memory->user = 0; + memory->alloc = ft_alloc; + memory->realloc = ft_realloc; + memory->free = ft_free; + } + + return memory; + } + + +/* END */ diff --git a/src/freetype/base/rules.mk b/src/freetype/base/rules.mk new file mode 100644 index 0000000000..1763a09817 --- /dev/null +++ b/src/freetype/base/rules.mk @@ -0,0 +1,83 @@ +# +# FreeType 2 base layer configuration rules +# + + +# Copyright 1996-2000 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +# It sets the following variables which are used by the master Makefile +# after the call: +# +# BASE_OBJ_S: The single-object base layer. +# BASE_OBJ_M: A list of all objects for a multiple-objects build. +# BASE_EXT_OBJ: A list of base layer extensions, i.e., components found +# in `freetype/src/base' which are not compiled within the +# base layer proper. +# +# BASE_H is defined in freetype.mk to simplify the dependency rules. + + +BASE_COMPILE := $(FT_COMPILE) $I$(SRC_)base + + +# Base layer sources +# +# ftsystem, ftinit, and ftdebug are handled by freetype.mk +# +BASE_SRC := $(BASE_)ftcalc.c \ + $(BASE_)ftextend.c \ + $(BASE_)ftlist.c \ + $(BASE_)ftobjs.c \ + $(BASE_)ftstream.c \ + $(BASE_)ftoutln.c + +# Base layer `extensions' sources +# +# An extension is added to the library file (.a or .lib) as a separate +# object. It will then be linked to the final executable only if one of its +# symbols is used by the application. +# +BASE_EXT_SRC := $(BASE_)ftglyph.c \ + $(BASE_)ftmm.c + +# Default extensions objects +# +BASE_EXT_OBJ := $(BASE_EXT_SRC:$(BASE_)%.c=$(OBJ_)%.$O) + + +# Base layer object(s) +# +# BASE_OBJ_M is used during `multi' builds (each base source file compiles +# to a single object file). +# +# BASE_OBJ_S is used during `single' builds (the whole base layer is +# compiled as a single object file using ftbase.c). +# +BASE_OBJ_M := $(BASE_SRC:$(BASE_)%.c=$(OBJ_)%.$O) +BASE_OBJ_S := $(OBJ_)ftbase.$O + +# Base layer root source file for single build +# +BASE_SRC_S := $(BASE_)ftbase.c + + +# Base layer - single object build +# +$(BASE_OBJ_S): $(BASE_SRC_S) $(BASE_SRC) $(FREETYPE_H) + $(BASE_COMPILE) $T$@ $(BASE_SRC_S) + + +# Multiple objects build + extensions +# +$(OBJ_)%.$O: $(BASE_)%.c $(FREETYPE_H) + $(BASE_COMPILE) $T$@ $< + +# EOF diff --git a/src/freetype/cff/cff.c b/src/freetype/cff/cff.c new file mode 100644 index 0000000000..5a987f1cdf --- /dev/null +++ b/src/freetype/cff/cff.c @@ -0,0 +1,40 @@ +/***************************************************************************/ +/* */ +/* cff.c */ +/* */ +/* FreeType OpenType driver component (body only). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#define FT_MAKE_OPTION_SINGLE_OBJECT + +#ifdef FT_FLAT_COMPILE + +#include "t2driver.c" /* driver interface */ +#include "t2parse.c" /* token parser */ +#include "t2load.c" /* tables loader */ +#include "t2objs.c" /* object management */ +#include "t2gload.c" /* glyph loader */ + +#else + +#include /* driver interface */ +#include /* token parser */ +#include /* tables loader */ +#include /* object management */ +#include /* glyph loader */ + +#endif + + +/* END */ diff --git a/src/freetype/cff/module.mk b/src/freetype/cff/module.mk new file mode 100644 index 0000000000..9bc5c8f722 --- /dev/null +++ b/src/freetype/cff/module.mk @@ -0,0 +1,7 @@ +make_module_list: add_cff_driver + +add_cff_driver: + $(OPEN_DRIVER)cff_driver_class$(CLOSE_DRIVER) + $(ECHO_DRIVER)cff $(ECHO_DRIVER_DESC)OpenType fonts with extension *.otf$(ECHO_DRIVER_DONE) + +# EOF diff --git a/src/freetype/cff/rules.mk b/src/freetype/cff/rules.mk new file mode 100644 index 0000000000..ba87af5f18 --- /dev/null +++ b/src/freetype/cff/rules.mk @@ -0,0 +1,69 @@ +# +# FreeType 2 OpenType/CFF driver configuration rules +# + + +# Copyright 1996-2000 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +# OpenType driver directory +# +T2_DIR := $(SRC_)cff +T2_DIR_ := $(T2_DIR)$(SEP) + + +T2_COMPILE := $(FT_COMPILE) + + +# T2 driver sources (i.e., C files) +# +T2_DRV_SRC := $(T2_DIR_)t2objs.c \ + $(T2_DIR_)t2load.c \ + $(T2_DIR_)t2gload.c \ + $(T2_DIR_)t2parse.c \ + $(T2_DIR_)t2driver.c + +# T2 driver headers +# +T2_DRV_H := $(T2_DRV_SRC:%.c=%.h) \ + $(T2_DIR_)t2tokens.h + + +# T2 driver object(s) +# +# T2_DRV_OBJ_M is used during `multi' builds +# T2_DRV_OBJ_S is used during `single' builds +# +T2_DRV_OBJ_M := $(T2_DRV_SRC:$(T2_DIR_)%.c=$(OBJ_)%.$O) +T2_DRV_OBJ_S := $(OBJ_)cff.$O + +# T2 driver source file for single build +# +T2_DRV_SRC_S := $(T2_DIR_)cff.c + + +# T2 driver - single object +# +$(T2_DRV_OBJ_S): $(T2_DRV_SRC_S) $(T2_DRV_SRC) $(FREETYPE_H) $(T2_DRV_H) + $(T2_COMPILE) $T$@ $(T2_DRV_SRC_S) + + +# T2 driver - multiple objects +# +$(OBJ_)%.$O: $(T2_DIR_)%.c $(FREETYPE_H) $(T2_DRV_H) + $(T2_COMPILE) $T$@ $< + + +# update main driver object lists +# +DRV_OBJS_S += $(T2_DRV_OBJ_S) +DRV_OBJS_M += $(T2_DRV_OBJ_M) + +# EOF diff --git a/src/freetype/cff/t2driver.c b/src/freetype/cff/t2driver.c new file mode 100644 index 0000000000..d1e1b188d2 --- /dev/null +++ b/src/freetype/cff/t2driver.c @@ -0,0 +1,377 @@ +/***************************************************************************/ +/* */ +/* t2driver.c */ +/* */ +/* OpenType font driver implementation (body). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#include +#include +#include +#include +#include + +#include + + +#ifdef FT_FLAT_COMPILE + +#include "t2driver.h" +#include "t2gload.h" + +#else + +#include +#include + +#endif + + + /*************************************************************************/ + /* */ + /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ + /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ + /* messages during execution. */ + /* */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_t2driver + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** F A C E S ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + +#undef PAIR_TAG +#define PAIR_TAG( left, right ) ( ( (FT_ULong)left << 16 ) | \ + (FT_ULong)right ) + + + /*************************************************************************/ + /* */ + /* */ + /* Get_Kerning */ + /* */ + /* */ + /* A driver method used to return the kerning vector between two */ + /* glyphs of the same face. */ + /* */ + /* */ + /* face :: A handle to the source face object. */ + /* */ + /* left_glyph :: The index of the left glyph in the kern pair. */ + /* */ + /* right_glyph :: The index of the right glyph in the kern pair. */ + /* */ + /* */ + /* kerning :: The kerning vector. This is in font units for */ + /* scalable formats, and in pixels for fixed-sizes */ + /* formats. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* Only horizontal layouts (left-to-right & right-to-left) are */ + /* supported by this function. Other layouts, or more sophisticated */ + /* kernings, are out of scope of this method (the basic driver */ + /* interface is meant to be simple). */ + /* */ + /* They can be implemented by format-specific interfaces. */ + /* */ + static + FT_Error Get_Kerning( TT_Face face, + FT_UInt left_glyph, + FT_UInt right_glyph, + FT_Vector* kerning ) + { + TT_Kern_0_Pair* pair; + + + if ( !face ) + return T2_Err_Invalid_Face_Handle; + + kerning->x = 0; + kerning->y = 0; + + if ( face->kern_pairs ) + { + /* there are some kerning pairs in this font file! */ + FT_ULong search_tag = PAIR_TAG( left_glyph, right_glyph ); + FT_Long left, right; + + + left = 0; + right = face->num_kern_pairs - 1; + + while ( left <= right ) + { + FT_Int middle = left + ( ( right - left ) >> 1 ); + FT_ULong cur_pair; + + + pair = face->kern_pairs + middle; + cur_pair = PAIR_TAG( pair->left, pair->right ); + + if ( cur_pair == search_tag ) + goto Found; + + if ( cur_pair < search_tag ) + left = middle + 1; + else + right = middle - 1; + } + } + + Exit: + return T2_Err_Ok; + + Found: + kerning->x = pair->value; + goto Exit; + } + + +#undef PAIR_TAG + + + /*************************************************************************/ + /* */ + /* */ + /* Load_Glyph */ + /* */ + /* */ + /* A driver method used to load a glyph within a given glyph slot. */ + /* */ + /* */ + /* slot :: A handle to the target slot object where the glyph */ + /* will be loaded. */ + /* */ + /* size :: A handle to the source face size at which the glyph */ + /* must be scaled, loaded, etc. */ + /* */ + /* glyph_index :: The index of the glyph in the font file. */ + /* */ + /* load_flags :: A flag indicating what to load for this glyph. The */ + /* FTLOAD_??? constants can be used to control the */ + /* glyph loading process (e.g., whether the outline */ + /* should be scaled, whether to load bitmaps or not, */ + /* whether to hint the outline, etc). */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + static + FT_Error Load_Glyph( T2_GlyphSlot slot, + T2_Size size, + FT_UShort glyph_index, + FT_UInt load_flags ) + { + FT_Error error; + + + if ( !slot ) + return T2_Err_Invalid_Glyph_Handle; + + /* check whether we want a scaled outline or bitmap */ + if ( !size ) + load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING; + + if ( load_flags & FT_LOAD_NO_SCALE ) + size = NULL; + + /* reset the size object if necessary */ + if ( size ) + { + /* these two object must have the same parent */ + if ( size->face != slot->root.face ) + return T2_Err_Invalid_Face_Handle; + } + + /* now load the glyph outline if necessary */ + error = T2_Load_Glyph( slot, size, glyph_index, load_flags ); + + /* force drop-out mode to 2 - irrelevant now */ + /* slot->outline.dropout_mode = 2; */ + + return error; + } + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** C H A R A C T E R M A P P I N G S ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + /*************************************************************************/ + /* */ + /* */ + /* Get_Char_Index */ + /* */ + /* */ + /* Uses a charmap to return a given character code's glyph index. */ + /* */ + /* */ + /* charmap :: A handle to the source charmap object. */ + /* charcode :: The character code. */ + /* */ + /* */ + /* Glyph index. 0 means `undefined character code'. */ + /* */ + static + FT_UInt t2_get_char_index( TT_CharMap charmap, + FT_Long charcode ) + { + FT_Error error; + T2_Face face; + TT_CMapTable* cmap; + + + cmap = &charmap->cmap; + face = (T2_Face)charmap->root.face; + + /* Load table if needed */ + if ( !cmap->loaded ) + { + SFNT_Interface* sfnt = (SFNT_Interface*)face->sfnt; + + + error = sfnt->load_charmap( face, cmap, face->root.stream ); + if ( error ) + return 0; + + cmap->loaded = TRUE; + } + + return ( cmap->get_index ? cmap->get_index( cmap, charcode ) : 0 ); + } + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** D R I V E R I N T E R F A C E ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + static + FT_Module_Interface t2_get_interface( T2_Driver driver, + const char* interface ) + { + FT_Module sfnt; + + + /* we simply pass our request to the `sfnt' module */ + sfnt = FT_Get_Module( driver->root.root.library, "sfnt" ); + + return sfnt ? sfnt->clazz->get_interface( sfnt, interface ) : 0; + } + + + /* The FT_DriverInterface structure is defined in ftdriver.h. */ + + const FT_Driver_Class cff_driver_class = + { + /* begin with the FT_Module_Class fields */ + { + ft_module_font_driver | ft_module_driver_scalable, + sizeof( T2_DriverRec ), + "cff", + 0x10000L, + 0x20000L, + + 0, /* module-specific interface */ + + (FT_Module_Constructor)T2_Init_Driver, + (FT_Module_Destructor) T2_Done_Driver, + (FT_Module_Requester) t2_get_interface, + }, + + /* now the specific driver fields */ + sizeof( TT_FaceRec ), + sizeof( FT_SizeRec ), + sizeof( T2_GlyphSlotRec ), + + (FTDriver_initFace) T2_Init_Face, + (FTDriver_doneFace) T2_Done_Face, + (FTDriver_initSize) 0, + (FTDriver_doneSize) 0, + (FTDriver_initGlyphSlot)0, + (FTDriver_doneGlyphSlot)0, + + (FTDriver_setCharSizes) 0, + (FTDriver_setPixelSizes)0, + + (FTDriver_loadGlyph) Load_Glyph, + (FTDriver_getCharIndex) t2_get_char_index, + + (FTDriver_getKerning) Get_Kerning, + (FTDriver_attachFile) 0, + (FTDriver_getAdvances) 0 + }; + + +#ifdef FT_CONFIG_OPTION_DYNAMIC_DRIVERS + + + /*************************************************************************/ + /* */ + /* */ + /* getDriverClass */ + /* */ + /* */ + /* This function is used when compiling the TrueType driver as a */ + /* shared library (`.DLL' or `.so'). It will be used by the */ + /* high-level library of FreeType to retrieve the address of the */ + /* driver's generic interface. */ + /* */ + /* It shouldn't be implemented in a static build, as each driver must */ + /* have the same function as an exported entry point. */ + /* */ + /* */ + /* The address of the TrueType's driver generic interface. The */ + /* format-specific interface can then be retrieved through the method */ + /* interface->get_format_interface. */ + /* */ + EXPORT_FUNC( FT_Driver_Class* ) getDriverClass( void ) + { + return &cff_driver_class; + } + + +#endif /* CONFIG_OPTION_DYNAMIC_DRIVERS */ + + +/* END */ diff --git a/src/freetype/cff/t2driver.h b/src/freetype/cff/t2driver.h new file mode 100644 index 0000000000..e0b0afd3ac --- /dev/null +++ b/src/freetype/cff/t2driver.h @@ -0,0 +1,30 @@ +/***************************************************************************/ +/* */ +/* t2driver.h */ +/* */ +/* High-level OpenType driver interface (specification). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef T2DRIVER_H +#define T2DRIVER_H + +#include + + FT_EXPORT_VAR( const FT_Driver_Class ) cff_driver_class; + + +#endif /* T2DRIVER_H */ + + +/* END */ diff --git a/src/freetype/cff/t2gload.c b/src/freetype/cff/t2gload.c new file mode 100644 index 0000000000..1023e3cf48 --- /dev/null +++ b/src/freetype/cff/t2gload.c @@ -0,0 +1,2045 @@ +/***************************************************************************/ +/* */ +/* t2gload.c */ +/* */ +/* OpenType Glyph Loader (body). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#include +#include +#include +#include +#include +#include + + +#ifdef FT_FLAT_COMPILE + +#include "t2load.h" +#include "t2gload.h" + +#else + +#include +#include + +#endif + + +#include + + + /*************************************************************************/ + /* */ + /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ + /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ + /* messages during execution. */ + /* */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_t2gload + + + typedef enum T2_Operator_ + { + t2_op_unknown = 0, + + t2_op_rmoveto, + t2_op_hmoveto, + t2_op_vmoveto, + + t2_op_rlineto, + t2_op_hlineto, + t2_op_vlineto, + + t2_op_rrcurveto, + t2_op_hhcurveto, + t2_op_hvcurveto, + t2_op_rcurveline, + t2_op_rlinecurve, + t2_op_vhcurveto, + t2_op_vvcurveto, + + t2_op_flex, + t2_op_hflex, + t2_op_hflex1, + t2_op_flex1, + + t2_op_endchar, + + t2_op_hstem, + t2_op_vstem, + t2_op_hstemhm, + t2_op_vstemhm, + + t2_op_hintmask, + t2_op_cntrmask, + + t2_op_abs, + t2_op_add, + t2_op_sub, + t2_op_div, + t2_op_neg, + t2_op_random, + t2_op_mul, + t2_op_sqrt, + + t2_op_blend, + + t2_op_drop, + t2_op_exch, + t2_op_index, + t2_op_roll, + t2_op_dup, + + t2_op_put, + t2_op_get, + t2_op_store, + t2_op_load, + + t2_op_and, + t2_op_or, + t2_op_not, + t2_op_eq, + t2_op_ifelse, + + t2_op_callsubr, + t2_op_callgsubr, + t2_op_return, + + /* do not remove */ + t2_op_max + + } T2_Operator; + + +#define T2_COUNT_CHECK_WIDTH 0x80 +#define T2_COUNT_EXACT 0x40 +#define T2_COUNT_CLEAR_STACK 0x20 + + + static const FT_Byte t2_argument_counts[] = + { + 0, /* unknown */ + + 2 | T2_COUNT_CHECK_WIDTH | T2_COUNT_EXACT, /* rmoveto */ + 1 | T2_COUNT_CHECK_WIDTH | T2_COUNT_EXACT, + 1 | T2_COUNT_CHECK_WIDTH | T2_COUNT_EXACT, + + 0 | T2_COUNT_CLEAR_STACK, /* rlineto */ + 0 | T2_COUNT_CLEAR_STACK, + 0 | T2_COUNT_CLEAR_STACK, + + 0 | T2_COUNT_CLEAR_STACK, /* rrcurveto */ + 0 | T2_COUNT_CLEAR_STACK, + 0 | T2_COUNT_CLEAR_STACK, + 0 | T2_COUNT_CLEAR_STACK, + 0 | T2_COUNT_CLEAR_STACK, + 0 | T2_COUNT_CLEAR_STACK, + 0 | T2_COUNT_CLEAR_STACK, + + 13, /* flex */ + 7, + 9, + 11, + + 0, /* endchar */ + + 2 | T2_COUNT_CHECK_WIDTH, /* hstem */ + 2 | T2_COUNT_CHECK_WIDTH, + 2 | T2_COUNT_CHECK_WIDTH, + 2 | T2_COUNT_CHECK_WIDTH, + + 0, /* hintmask */ + 0, /* cntrmask */ + + 1, /* abs */ + 2, + 2, + 2, + 1, + 0, + 2, + 1, + + 1, /* blend */ + + 1, /* drop */ + 2, + 1, + 2, + 1, + + 2, /* put */ + 1, + 4, + 3, + + 2, /* and */ + 2, + 1, + 2, + 4, + + 1, /* callsubr */ + 1, + 0 + }; + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /********** *********/ + /********** *********/ + /********** GENERIC CHARSTRING PARSING *********/ + /********** *********/ + /********** *********/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* */ + /* T2_Init_Builder */ + /* */ + /* */ + /* Initializes a given glyph builder. */ + /* */ + /* */ + /* builder :: A pointer to the glyph builder to initialize. */ + /* */ + /* */ + /* face :: The current face object. */ + /* */ + /* size :: The current size object. */ + /* */ + /* glyph :: The current glyph object. */ + /* */ + static + void T2_Init_Builder( T2_Builder* builder, + TT_Face face, + T2_Size size, + T2_GlyphSlot glyph ) + { + builder->path_begun = 0; + builder->load_points = 1; + + builder->face = face; + builder->glyph = glyph; + builder->memory = face->root.memory; + + if ( glyph ) + { + FT_GlyphLoader* loader = glyph->root.loader; + + + builder->loader = loader; + builder->base = &loader->base.outline; + builder->current = &loader->current.outline; + FT_GlyphLoader_Rewind( loader ); + } + + if ( size ) + { + builder->scale_x = size->metrics.x_scale; + builder->scale_y = size->metrics.y_scale; + } + + builder->pos_x = 0; + builder->pos_y = 0; + + builder->left_bearing.x = 0; + builder->left_bearing.y = 0; + builder->advance.x = 0; + builder->advance.y = 0; + } + + + /*************************************************************************/ + /* */ + /* */ + /* T2_Done_Builder */ + /* */ + /* */ + /* Finalizes a given glyph builder. Its contents can still be used */ + /* after the call, but the function saves important information */ + /* within the corresponding glyph slot. */ + /* */ + /* */ + /* builder :: A pointer to the glyph builder to finalize. */ + /* */ + static + void T2_Done_Builder( T2_Builder* builder ) + { + T2_GlyphSlot glyph = builder->glyph; + + + if ( glyph ) + glyph->root.outline = *builder->base; + } + + + /*************************************************************************/ + /* */ + /* */ + /* t2_compute_bias */ + /* */ + /* */ + /* Computes the bias value in dependence of the number of glyph */ + /* subroutines. */ + /* */ + /* */ + /* num_subrs :: The number of glyph subroutines. */ + /* */ + /* */ + /* The bias value. */ + static + FT_Int t2_compute_bias( FT_UInt num_subrs ) + { + FT_Int result; + + + if ( num_subrs < 1240 ) + result = 107; + else if ( num_subrs < 33900 ) + result = 1131; + else + result = 32768; + + return result; + } + + + /*************************************************************************/ + /* */ + /* */ + /* T2_Init_Decoder */ + /* */ + /* */ + /* Initializes a given glyph decoder. */ + /* */ + /* */ + /* decoder :: A pointer to the glyph builder to initialize. */ + /* */ + /* */ + /* face :: The current face object. */ + /* */ + /* size :: The current size object. */ + /* */ + /* slot :: The current glyph object. */ + /* */ + LOCAL_FUNC + void T2_Init_Decoder( T2_Decoder* decoder, + TT_Face face, + T2_Size size, + T2_GlyphSlot slot ) + { + CFF_Font* cff = (CFF_Font*)face->extra.data; + + + /* clear everything */ + MEM_Set( decoder, 0, sizeof ( *decoder ) ); + + /* initialize builder */ + T2_Init_Builder( &decoder->builder, face, size, slot ); + + /* initialize Type2 decoder */ + decoder->num_globals = cff->num_global_subrs; + decoder->globals = cff->global_subrs; + decoder->globals_bias = t2_compute_bias( decoder->num_globals ); + } + + + /* this function is used to select the locals subrs array */ + LOCAL_DEF + void T2_Prepare_Decoder( T2_Decoder* decoder, + FT_UInt glyph_index ) + { + CFF_Font* cff = (CFF_Font*)decoder->builder.face->extra.data; + CFF_SubFont* sub = &cff->top_font; + + + /* manage CID fonts */ + if ( cff->num_subfonts >= 1 ) + { + FT_Byte fd_index = CFF_Get_FD( &cff->fd_select, glyph_index ); + + + sub = cff->subfonts[fd_index]; + } + + decoder->num_locals = sub->num_local_subrs; + decoder->locals = sub->local_subrs; + decoder->locals_bias = t2_compute_bias( decoder->num_locals ); + + decoder->glyph_width = sub->private_dict.default_width; + decoder->nominal_width = sub->private_dict.nominal_width; + } + + + /* check that there is enough room for `count' more points */ + static + FT_Error check_points( T2_Builder* builder, + FT_Int count ) + { + return FT_GlyphLoader_Check_Points( builder->loader, count, 0 ); + } + + + /* add a new point, do not check space */ + static + void add_point( T2_Builder* builder, + FT_Pos x, + FT_Pos y, + FT_Byte flag ) + { + FT_Outline* outline = builder->current; + + + if ( builder->load_points ) + { + FT_Vector* point = outline->points + outline->n_points; + FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points; + + + point->x = x >> 16; + point->y = y >> 16; + *control = flag ? FT_Curve_Tag_On : FT_Curve_Tag_Cubic; + + builder->last = *point; + } + outline->n_points++; + } + + + /* check space for a new on-curve point, then add it */ + static + FT_Error add_point1( T2_Builder* builder, + FT_Pos x, + FT_Pos y ) + { + FT_Error error; + + + error = check_points( builder, 1 ); + if ( !error ) + add_point( builder, x, y, 1 ); + + return error; + } + + + /* check room for a new contour, then add it */ + static + FT_Error add_contour( T2_Builder* builder ) + { + FT_Outline* outline = builder->current; + FT_Error error; + + + if ( !builder->load_points ) + { + outline->n_contours++; + return T2_Err_Ok; + } + + error = FT_GlyphLoader_Check_Points( builder->loader, 0, 1 ); + if ( !error ) + { + if ( outline->n_contours > 0 ) + outline->contours[outline->n_contours - 1] = outline->n_points - 1; + + outline->n_contours++; + } + + return error; + } + + + /* if a path was begun, add its first on-curve point */ + static + FT_Error start_point( T2_Builder* builder, + FT_Pos x, + FT_Pos y ) + { + FT_Error error = 0; + + + /* test whether we are building a new contour */ + if ( !builder->path_begun ) + { + builder->path_begun = 1; + error = add_contour( builder ); + if ( !error ) + error = add_point1( builder, x, y ); + } + return error; + } + + + /* close the current contour */ + static + void close_contour( T2_Builder* builder ) + { + FT_Outline* outline = builder->current; + + /* XXXX: We must not include the last point in the path if it */ + /* is located on the first point. */ + if ( outline->n_points > 1 ) + { + FT_Int first = 0; + FT_Vector* p1 = outline->points + first; + FT_Vector* p2 = outline->points + outline->n_points - 1; + + if ( outline->n_contours > 1 ) + { + first = outline->contours[outline->n_contours - 2] + 1; + p1 = outline->points + first; + } + + if ( p1->x == p2->x && p1->y == p2->y ) + outline->n_points--; + } + + if ( outline->n_contours > 0 ) + outline->contours[outline->n_contours - 1] = outline->n_points - 1; + } + + +#define USE_ARGS( n ) do \ + { \ + top -= n; \ + if ( top < decoder->stack ) \ + goto Stack_Underflow; \ + } while ( 0 ) + + + /*************************************************************************/ + /* */ + /* */ + /* T2_Parse_CharStrings */ + /* */ + /* */ + /* Parses a given Type 2 charstrings program. */ + /* */ + /* */ + /* decoder :: The current Type 1 decoder. */ + /* */ + /* */ + /* charstring_base :: The base of the charstring stream. */ + /* */ + /* charstring_len :: The length in bytes of the charstring stream. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + LOCAL_FUNC + FT_Error T2_Parse_CharStrings( T2_Decoder* decoder, + FT_Byte* charstring_base, + FT_Int charstring_len ) + { + FT_Error error; + T2_Decoder_Zone* zone; + FT_Byte* ip; + FT_Byte* limit; + T2_Builder* builder = &decoder->builder; + FT_Outline* outline; + FT_Pos x, y; + FT_Fixed seed; + FT_Fixed* stack; + + + /* set default width */ + decoder->num_hints = 0; + decoder->read_width = 1; + + /* compute random seed from stack address of parameter */ + seed = (FT_Fixed)(char*)&seed ^ + (FT_Fixed)(char*)&decoder ^ + (FT_Fixed)(char*)&charstring_base; + seed = ( seed ^ ( seed >> 10 ) ^ ( seed >> 20 ) ) & 0xFFFF; + if ( seed == 0 ) + seed = 0x7384; + + /* initialize the decoder */ + decoder->top = decoder->stack; + decoder->zone = decoder->zones; + zone = decoder->zones; + stack = decoder->top; + + builder->path_begun = 0; + + zone->base = charstring_base; + limit = zone->limit = charstring_base + charstring_len; + ip = zone->cursor = zone->base; + + error = T2_Err_Ok; + outline = builder->current; + + x = builder->pos_x; + y = builder->pos_y; + + /* now, execute loop */ + while ( ip < limit ) + { + T2_Operator op; + FT_Byte v; + FT_Byte count; + + + /********************************************************************/ + /* */ + /* Decode operator or operand */ + /* */ + v = *ip++; + if ( v >= 32 || v == 28 ) + { + FT_Int shift = 16; + FT_Int32 val; + + + /* this is an operand, push it on the stack */ + if ( v == 28 ) + { + if ( ip + 1 >= limit ) + goto Syntax_Error; + val = (FT_Short)( ( (FT_Short)ip[0] << 8 ) | ip[1] ); + ip += 2; + } + else if ( v < 247 ) + val = (FT_Long)v - 139; + else if ( v < 251 ) + { + if ( ip >= limit ) + goto Syntax_Error; + val = ( (FT_Long)v - 247 ) * 256 + *ip++ + 108; + } + else if ( v < 255 ) + { + if ( ip >= limit ) + goto Syntax_Error; + val = -( (FT_Long)v - 251 ) * 256 - *ip++ - 108; + } + else + { + if ( ip + 3 >= limit ) + goto Syntax_Error; + val = ( (FT_Int32)ip[0] << 24 ) | + ( (FT_Int32)ip[1] << 16 ) | + ( (FT_Int32)ip[2] << 8 ) | + ip[3]; + ip += 4; + shift = 0; + } + if ( decoder->top - stack >= T2_MAX_OPERANDS ) + goto Stack_Overflow; + + val <<= shift; + *decoder->top++ = val; + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( !( val & 0xFFFF ) ) + FT_TRACE4(( " %d", (FT_Int32)( val >> 16 ) )); + else + FT_TRACE4(( " %.2f", val/65536.0 )); +#endif + + } + else + { + FT_Fixed* args = decoder->top; + FT_Int num_args = args - decoder->stack; + FT_Int req_args; + + + /* find operator */ + op = t2_op_unknown; + + switch ( v ) + { + case 1: + op = t2_op_hstem; + break; + case 3: + op = t2_op_vstem; + break; + case 4: + op = t2_op_vmoveto; + break; + case 5: + op = t2_op_rlineto; + break; + case 6: + op = t2_op_hlineto; + break; + case 7: + op = t2_op_vlineto; + break; + case 8: + op = t2_op_rrcurveto; + break; + case 10: + op = t2_op_callsubr; + break; + case 11: + op = t2_op_return; + break; + case 12: + { + if ( ip >= limit ) + goto Syntax_Error; + v = *ip++; + + switch ( v ) + { + case 3: + op = t2_op_and; + break; + case 4: + op = t2_op_or; + break; + case 5: + op = t2_op_not; + break; + case 8: + op = t2_op_store; + break; + case 9: + op = t2_op_abs; + break; + case 10: + op = t2_op_add; + break; + case 11: + op = t2_op_sub; + break; + case 12: + op = t2_op_div; + break; + case 13: + op = t2_op_load; + break; + case 14: + op = t2_op_neg; + break; + case 15: + op = t2_op_eq; + break; + case 18: + op = t2_op_drop; + break; + case 20: + op = t2_op_put; + break; + case 21: + op = t2_op_get; + break; + case 22: + op = t2_op_ifelse; + break; + case 23: + op = t2_op_random; + break; + case 24: + op = t2_op_mul; + break; + case 26: + op = t2_op_sqrt; + break; + case 27: + op = t2_op_dup; + break; + case 28: + op = t2_op_exch; + break; + case 29: + op = t2_op_index; + break; + case 30: + op = t2_op_roll; + break; + case 34: + op = t2_op_hflex; + break; + case 35: + op = t2_op_flex; + break; + case 36: + op = t2_op_hflex1; + break; + case 37: + op = t2_op_flex1; + break; + default: + /* decrement ip for syntax error message */ + ip--; + } + } + break; + case 14: + op = t2_op_endchar; + break; + case 16: + op = t2_op_blend; + break; + case 18: + op = t2_op_hstemhm; + break; + case 19: + op = t2_op_hintmask; + break; + case 20: + op = t2_op_cntrmask; + break; + case 21: + op = t2_op_rmoveto; + break; + case 22: + op = t2_op_hmoveto; + break; + case 23: + op = t2_op_vstemhm; + break; + case 24: + op = t2_op_rcurveline; + break; + case 25: + op = t2_op_rlinecurve; + break; + case 26: + op = t2_op_vvcurveto; + break; + case 27: + op = t2_op_hhcurveto; + break; + case 29: + op = t2_op_callgsubr; + break; + case 30: + op = t2_op_vhcurveto; + break; + case 31: + op = t2_op_hvcurveto; + break; + default: + ; + } + if ( op == t2_op_unknown ) + goto Syntax_Error; + + /* check arguments */ + req_args = count = t2_argument_counts[op]; + if ( req_args & T2_COUNT_CHECK_WIDTH ) + { + args = stack; + if ( num_args & 1 && decoder->read_width ) + { + decoder->glyph_width = decoder->nominal_width + + ( stack[0] >> 16 ); + num_args--; + args++; + } + decoder->read_width = 0; + req_args = 0; + } + + req_args &= 15; + if ( num_args < req_args ) + goto Stack_Underflow; + args -= req_args; + num_args -= req_args; + + switch ( op ) + { + case t2_op_hstem: + case t2_op_vstem: + case t2_op_hstemhm: + case t2_op_vstemhm: + /* if the number of arguments is not even, the first one */ + /* is simply the glyph width, encoded as the difference */ + /* to nominalWidthX */ + FT_TRACE4(( op == t2_op_hstem ? " hstem" : + op == t2_op_vstem ? " vstem" : + op == t2_op_hstemhm ? " hstemhm" : + " vstemhm" )); + decoder->num_hints += num_args / 2; + args = stack; + break; + + case t2_op_hintmask: + case t2_op_cntrmask: + FT_TRACE4(( op == t2_op_hintmask ? " hintmask" + : " cntrmask" )); + + decoder->num_hints += num_args / 2; + ip += ( decoder->num_hints + 7 ) >> 3; + if ( ip >= limit ) + goto Syntax_Error; + args = stack; + break; + + case t2_op_rmoveto: + FT_TRACE4(( " rmoveto" )); + + close_contour( builder ); + builder->path_begun = 0; + x += args[0]; + y += args[1]; + args = stack; + break; + + case t2_op_vmoveto: + FT_TRACE4(( " vmoveto" )); + + close_contour( builder ); + builder->path_begun = 0; + y += args[0]; + args = stack; + break; + + case t2_op_hmoveto: + FT_TRACE4(( " hmoveto" )); + + close_contour( builder ); + builder->path_begun = 0; + x += args[0]; + args = stack; + break; + + case t2_op_rlineto: + FT_TRACE4(( " rlineto" )); + + if ( start_point ( builder, x, y ) || + check_points( builder, num_args / 2 ) ) + goto Memory_Error; + + if ( num_args < 2 || num_args & 1 ) + goto Stack_Underflow; + + args = stack; + while ( args < decoder->top ) + { + x += args[0]; + y += args[1]; + add_point( builder, x, y, 1 ); + args += 2; + } + args = stack; + break; + + case t2_op_hlineto: + case t2_op_vlineto: + { + FT_Int phase = ( op == t2_op_hlineto ); + + + FT_TRACE4(( op == t2_op_hlineto ? " hlineto" + : " vlineto" )); + + if ( start_point ( builder, x, y ) || + check_points( builder, num_args ) ) + goto Memory_Error; + + args = stack; + while (args < decoder->top ) + { + if ( phase ) + x += args[0]; + else + y += args[0]; + + if ( add_point1( builder, x, y ) ) + goto Memory_Error; + + args++; + phase ^= 1; + } + args = stack; + } + break; + + case t2_op_rrcurveto: + FT_TRACE4(( " rrcurveto" )); + + /* check number of arguments; must be a multiple of 6 */ + if ( num_args % 6 != 0 ) + goto Stack_Underflow; + + if ( start_point ( builder, x, y ) || + check_points( builder, num_args / 2 ) ) + goto Memory_Error; + + args = stack; + while ( args < decoder->top ) + { + x += args[0]; + y += args[1]; + add_point( builder, x, y, 0 ); + x += args[2]; + y += args[3]; + add_point( builder, x, y, 0 ); + x += args[4]; + y += args[5]; + add_point( builder, x, y, 1 ); + args += 6; + } + args = stack; + break; + + case t2_op_vvcurveto: + FT_TRACE4(( " vvcurveto" )); + + if ( start_point ( builder, x, y ) ) + goto Memory_Error; + + args = stack; + if ( num_args & 1 ) + { + x += args[0]; + args++; + num_args--; + } + + if ( num_args % 4 != 0 ) + goto Stack_Underflow; + + if ( check_points( builder, 3 * ( num_args / 4 ) ) ) + goto Memory_Error; + + while ( args < decoder->top ) + { + y += args[0]; + add_point( builder, x, y, 0 ); + x += args[1]; + y += args[2]; + add_point( builder, x, y, 0 ); + y += args[3]; + add_point( builder, x, y, 1 ); + args += 4; + } + args = stack; + break; + + case t2_op_hhcurveto: + FT_TRACE4(( " hhcurveto" )); + + if ( start_point ( builder, x, y ) ) + goto Memory_Error; + + args = stack; + if ( num_args & 1 ) + { + y += args[0]; + args++; + num_args--; + } + + if ( num_args % 4 != 0 ) + goto Stack_Underflow; + + if ( check_points( builder, 3 * ( num_args / 4 ) ) ) + goto Memory_Error; + + while ( args < decoder->top ) + { + x += args[0]; + add_point( builder, x, y, 0 ); + x += args[1]; + y += args[2]; + add_point( builder, x, y, 0 ); + x += args[3]; + add_point( builder, x, y, 1 ); + args += 4; + } + args = stack; + break; + + case t2_op_vhcurveto: + case t2_op_hvcurveto: + { + FT_Int phase; + + + FT_TRACE4(( op == t2_op_vhcurveto ? " vhcurveto" + : " hvcurveto" )); + + if ( start_point ( builder, x, y ) ) + goto Memory_Error; + + args = stack; + if (num_args < 4 || ( num_args % 4 ) > 1 ) + goto Stack_Underflow; + + if ( check_points( builder, ( num_args / 4 ) * 3 ) ) + goto Stack_Underflow; + + phase = ( op == t2_op_hvcurveto ); + + while ( num_args >= 4 ) + { + num_args -= 4; + if ( phase ) + { + x += args[0]; + add_point( builder, x, y, 0 ); + x += args[1]; + y += args[2]; + add_point( builder, x, y, 0 ); + y += args[3]; + if ( num_args == 1 ) + x += args[4]; + add_point( builder, x, y, 1 ); + } + else + { + y += args[0]; + add_point( builder, x, y, 0 ); + x += args[1]; + y += args[2]; + add_point( builder, x, y, 0 ); + x += args[3]; + if ( num_args == 1 ) + y += args[4]; + add_point( builder, x, y, 1 ); + } + args += 4; + phase ^= 1; + } + args = stack; + } + break; + + case t2_op_rlinecurve: + { + FT_Int num_lines = ( num_args - 6 ) / 2; + + + FT_TRACE4(( " rlinecurve" )); + + if ( num_args < 8 || ( num_args - 6 ) & 1 ) + goto Stack_Underflow; + + if ( start_point( builder, x, y ) || + check_points( builder, num_lines + 3 ) ) + goto Memory_Error; + + args = stack; + + /* first, add the line segments */ + while ( num_lines > 0 ) + { + x += args[0]; + y += args[1]; + add_point( builder, x, y, 1 ); + args += 2; + num_lines--; + } + + /* then the curve */ + x += args[0]; + y += args[1]; + add_point( builder, x, y, 0 ); + x += args[2]; + y += args[3]; + add_point( builder, x, y, 0 ); + x += args[4]; + y += args[5]; + add_point( builder, x, y, 1 ); + args = stack; + } + break; + + case t2_op_rcurveline: + { + FT_Int num_curves = ( num_args - 2 ) / 6; + + + FT_TRACE4(( " rcurveline" )); + + if ( num_args < 8 || ( num_args - 2 ) % 6 ) + goto Stack_Underflow; + + if ( start_point ( builder, x, y ) || + check_points( builder, num_curves*3 + 2 ) ) + goto Memory_Error; + + args = stack; + + /* first, add the curves */ + while ( num_curves > 0 ) + { + x += args[0]; + y += args[1]; + add_point( builder, x, y, 0 ); + x += args[2]; + y += args[3]; + add_point( builder, x, y, 0 ); + x += args[4]; + y += args[5]; + add_point( builder, x, y, 1 ); + args += 6; + num_curves--; + } + + /* then the final line */ + x += args[0]; + y += args[1]; + add_point( builder, x, y, 1 ); + args = stack; + } + break; + + case t2_op_hflex1: + { + FT_Pos start_y; + + + FT_TRACE4(( " hflex1" )); + + args = stack; + + /* adding five more points; 4 control points, 1 on-curve point */ + /* make sure we have enough space for the start point if it */ + /* needs to be added.. */ + if ( start_point( builder, x, y ) || + check_points( builder, 6 ) ) + goto Memory_Error; + + /* Record the starting point's y postion for later use */ + start_y = y; + + /* first control point */ + x += args[0]; + y += args[1]; + add_point( builder, x, y, 0 ); + + /* second control point */ + x += args[2]; + y += args[3]; + add_point( builder, x, y, 0 ); + + /* join point; on curve, with y-value the same as the last */ + /* control point's y-value */ + x += args[4]; + add_point( builder, x, y, 1 ); + + /* third control point, with y-value the same as the join */ + /* point's y-value */ + x += args[5]; + add_point( builder, x, y, 0 ); + + /* fourth control point */ + x += args[6]; + y += args[7]; + add_point( builder, x, y, 0 ); + + /* ending point, with y-value the same as the start */ + x += args[8]; + y = start_y; + add_point( builder, x, y, 1 ); + + args = stack; + break; + } + + case t2_op_hflex: + { + FT_Pos start_y; + + + FT_TRACE4(( " hflex" )); + + args = stack; + + /* adding six more points; 4 control points, 2 on-curve points */ + if ( start_point( builder, x, y ) || + check_points ( builder, 6 ) ) + goto Memory_Error; + + /* record the starting point's y-position for later use */ + start_y = y; + + /* first control point */ + x += args[0]; + add_point( builder, x, y, 0 ); + + /* second control point */ + x += args[1]; + y += args[2]; + add_point( builder, x, y, 0 ); + + /* join point; on curve, with y-value the same as the last */ + /* control point's y-value */ + x += args[3]; + add_point( builder, x, y, 1 ); + + /* third control point, with y-value the same as the join */ + /* point's y-value */ + x += args[4]; + add_point( builder, x, y, 0 ); + + /* fourth control point */ + x += args[5]; + y = start_y; + add_point( builder, x, y, 0 ); + + /* ending point, with y-value the same as the start point's */ + /* y-value -- we don't add this point, though */ + x += args[6]; + add_point( builder, x, y, 1 ); + + args = stack; + break; + } + + case t2_op_flex1: + { + FT_Pos start_x, start_y; /* record start x, y values for alter */ + /* use */ + FT_Int dx = 0, dy = 0; /* used in horizontal/vertical */ + /* algorithm below */ + FT_Int horizontal, count; + + + FT_TRACE4(( " flex1" )); + + /* adding six more points; 4 control points, 2 on-curve points */ + if ( start_point( builder, x, y ) || + check_points( builder, 6 ) ) + goto Memory_Error; + + /* record the starting point's x, y postion for later use */ + start_x = x; + start_y = y; + + /* XXX: figure out whether this is supposed to be a horizontal */ + /* or vertical flex; the Type 2 specification is vague... */ + + args = stack; + + /* grab up to the last argument */ + for ( count = 5; count > 0; count-- ) + { + dx += args[0]; + dy += args[1]; + args += 2; + } + + /* rewind */ + args = stack; + + if ( dx < 0 ) dx = -dx; + if ( dy < 0 ) dy = -dy; + + /* strange test, but here it is... */ + horizontal = ( dx > dy ); + + for ( count = 5; count > 0; count-- ) + { + x += args[0]; + y += args[1]; + add_point( builder, x, y, (FT_Bool)( count == 3 ) ); + args += 2; + } + + /* is last operand an x- or y-delta? */ + if ( horizontal ) + { + x += args[0]; + y = start_y; + } + else + { + x = start_x; + y += args[0]; + } + + add_point( builder, x, y, 1 ); + + args = stack; + break; + } + + case t2_op_flex: + { + FT_UInt count; + + + FT_TRACE4(( " flex" )); + + if ( start_point( builder, x, y ) || + check_points( builder, 6 ) ) + goto Memory_Error; + + args = stack; + for ( count = 6; count > 0; count-- ) + { + x += args[0]; + y += args[1]; + add_point( builder, x, y, + (FT_Bool)( count == 3 || count == 0 ) ); + args += 2; + } + + args = stack; + } + break; + + case t2_op_endchar: + FT_TRACE4(( " endchar" )); + + close_contour( builder ); + + /* add current outline to the glyph slot */ + FT_GlyphLoader_Add( builder->loader ); + + /* return now! */ + FT_TRACE4(( "\n\n" )); + return T2_Err_Ok; + + case t2_op_abs: + FT_TRACE4(( " abs" )); + + if ( args[0] < 0 ) + args[0] = -args[0]; + args++; + break; + + case t2_op_add: + FT_TRACE4(( " add" )); + + args[0] += args[1]; + args++; + break; + + case t2_op_sub: + FT_TRACE4(( " sub" )); + + args[0] -= args[1]; + args++; + break; + + case t2_op_div: + FT_TRACE4(( " div" )); + + args[0] = FT_DivFix( args[0], args[1] ); + args++; + break; + + case t2_op_neg: + FT_TRACE4(( " neg" )); + + args[0] = -args[0]; + args++; + break; + + case t2_op_random: + { + FT_Fixed rand; + + + FT_TRACE4(( " rand" )); + + rand = seed; + if ( rand >= 0x8000 ) + rand++; + + args[0] = rand; + seed = FT_MulFix( seed, 0x10000L - seed ); + if ( seed == 0 ) + seed += 0x2873; + args++; + } + break; + + case t2_op_mul: + FT_TRACE4(( " mul" )); + + args[0] = FT_MulFix( args[0], args[1] ); + args++; + break; + + case t2_op_sqrt: + FT_TRACE4(( " sqrt" )); + + if ( args[0] > 0 ) + { + FT_Int count = 9; + FT_Fixed root = args[0]; + FT_Fixed new_root; + + + for (;;) + { + new_root = ( root + FT_DivFix(args[0],root) + 1 ) >> 1; + if ( new_root == root || count <= 0 ) + break; + root = new_root; + } + args[0] = new_root; + } + else + args[0] = 0; + args++; + break; + + case t2_op_drop: + /* nothing */ + FT_TRACE4(( " drop" )); + + break; + + case t2_op_exch: + { + FT_Fixed tmp; + + + FT_TRACE4(( " exch" )); + + tmp = args[0]; + args[0] = args[1]; + args[1] = tmp; + args += 2; + } + break; + + case t2_op_index: + { + FT_Int index = args[0] >> 16; + + + FT_TRACE4(( " index" )); + + if ( index < 0 ) + index = 0; + else if ( index > num_args - 2 ) + index = num_args - 2; + args[0] = args[-( index + 1 )]; + args++; + } + break; + + case t2_op_roll: + { + FT_Int count = (FT_Int)( args[0] >> 16 ); + FT_Int index = (FT_Int)( args[1] >> 16 ); + + + FT_TRACE4(( " roll" )); + + if ( count <= 0 ) + count = 1; + + args -= count; + if ( args < stack ) + goto Stack_Underflow; + + if ( index >= 0 ) + { + while ( index > 0 ) + { + FT_Fixed tmp = args[count - 1]; + FT_Int i; + + + for ( i = count - 2; i >= 0; i-- ) + args[i + 1] = args[i]; + args[0] = tmp; + index--; + } + } + else + { + while ( index < 0 ) + { + FT_Fixed tmp = args[0]; + FT_Int i; + + + for ( i = 0; i < count - 1; i++ ) + args[i] = args[i + 1]; + args[count - 1] = tmp; + index++; + } + } + args += count; + } + break; + + case t2_op_dup: + FT_TRACE4(( " dup" )); + + args[1] = args[0]; + args++; + break; + + case t2_op_put: + { + FT_Fixed val = args[0]; + FT_Int index = (FT_Int)( args[1] >> 16 ); + + + FT_TRACE4(( " put" )); + + if ( index >= 0 && index < decoder->len_buildchar ) + decoder->buildchar[index] = val; + } + break; + + case t2_op_get: + { + FT_Int index = (FT_Int)( args[0] >> 16 ); + FT_Fixed val = 0; + + + FT_TRACE4(( " get" )); + + if ( index >= 0 && index < decoder->len_buildchar ) + val = decoder->buildchar[index]; + + args[0] = val; + args++; + } + break; + + case t2_op_store: + FT_TRACE4(( " store ")); + + goto Unimplemented; + + case t2_op_load: + FT_TRACE4(( " load" )); + + goto Unimplemented; + + case t2_op_and: + { + FT_Fixed cond = args[0] && args[1]; + + + FT_TRACE4(( " and" )); + + args[0] = cond ? 0x10000L : 0; + args++; + } + break; + + case t2_op_or: + { + FT_Fixed cond = args[0] || args[1]; + + + FT_TRACE4(( " or" )); + + args[0] = cond ? 0x10000L : 0; + args++; + } + break; + + case t2_op_eq: + { + FT_Fixed cond = !args[0]; + + + FT_TRACE4(( " eq" )); + + args[0] = cond ? 0x10000L : 0; + args++; + } + break; + + case t2_op_ifelse: + { + FT_Fixed cond = (args[2] <= args[3]); + + + FT_TRACE4(( " ifelse" )); + + if ( !cond ) + args[0] = args[1]; + args++; + } + break; + + case t2_op_callsubr: + { + FT_UInt index = (FT_UInt)( ( args[0] >> 16 ) + + decoder->locals_bias ); + + + FT_TRACE4(( " callsubr(%d)", index )); + + if ( index >= decoder->num_locals ) + { + FT_ERROR(( "T2_Parse_CharStrings:" )); + FT_ERROR(( " invalid local subr index\n" )); + goto Syntax_Error; + } + + if ( zone - decoder->zones >= T2_MAX_SUBRS_CALLS ) + { + FT_ERROR(( "T2_Parse_CharStrings: too many nested subrs\n" )); + goto Syntax_Error; + } + + zone->cursor = ip; /* save current instruction pointer */ + + zone++; + zone->base = decoder->locals[index]; + zone->limit = decoder->locals[index+1]; + zone->cursor = zone->base; + + if ( !zone->base ) + { + FT_ERROR(( "T2_Parse_CharStrings: invoking empty subrs!\n" )); + goto Syntax_Error; + } + + decoder->zone = zone; + ip = zone->base; + limit = zone->limit; + } + break; + + case t2_op_callgsubr: + { + FT_UInt index = (FT_UInt)( ( args[0] >> 16 ) + + decoder->globals_bias ); + + + FT_TRACE4(( " callgsubr(%d)", index )); + + if ( index >= decoder->num_globals ) + { + FT_ERROR(( "T2_Parse_CharStrings:" )); + FT_ERROR(( " invalid global subr index\n" )); + goto Syntax_Error; + } + + if ( zone - decoder->zones >= T2_MAX_SUBRS_CALLS ) + { + FT_ERROR(( "T2_Parse_CharStrings: too many nested subrs\n" )); + goto Syntax_Error; + } + + zone->cursor = ip; /* save current instruction pointer */ + + zone++; + zone->base = decoder->globals[index]; + zone->limit = decoder->globals[index+1]; + zone->cursor = zone->base; + + if ( !zone->base ) + { + FT_ERROR(( "T2_Parse_CharStrings: invoking empty subrs!\n" )); + goto Syntax_Error; + } + + decoder->zone = zone; + ip = zone->base; + limit = zone->limit; + } + break; + + case t2_op_return: + FT_TRACE4(( " return" )); + + if ( decoder->zone <= decoder->zones ) + { + FT_ERROR(( "T2_Parse_CharStrings: unexpected return\n" )); + goto Syntax_Error; + } + + decoder->zone--; + zone = decoder->zone; + ip = zone->cursor; + limit = zone->limit; + break; + + default: + Unimplemented: + FT_ERROR(( "Unimplemented opcode: %d", ip[-1] )); + + if ( ip[-1] == 12 ) + FT_ERROR(( " %d", ip[0] )); + FT_ERROR(( "\n" )); + + return T2_Err_Unimplemented_Feature; + } + + decoder->top = args; + + } /* general operator processing */ + + } /* while ip < limit */ + + FT_TRACE4(( "..end..\n\n" )); + + return error; + + Syntax_Error: + FT_TRACE4(( "T2_Parse_CharStrings: syntax error!" )); + return T2_Err_Invalid_File_Format; + + Stack_Underflow: + FT_TRACE4(( "T2_Parse_CharStrings: stack underflow!" )); + return T2_Err_Too_Few_Arguments; + + Stack_Overflow: + FT_TRACE4(( "T2_Parse_CharStrings: stack overflow!" )); + return T2_Err_Stack_Overflow; + + Memory_Error: + return builder->error; + } + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /********** *********/ + /********** *********/ + /********** COMPUTE THE MAXIMUM ADVANCE WIDTH *********/ + /********** *********/ + /********** The following code is in charge of computing *********/ + /********** the maximum advance width of the font. It *********/ + /********** quickly processes each glyph charstring to *********/ + /********** extract the value from either a `sbw' or `seac' *********/ + /********** operator. *********/ + /********** *********/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + +#if 0 /* unused until we support pure CFF fonts */ + + + LOCAL_FUNC + FT_Error T2_Compute_Max_Advance( TT_Face face, + FT_Int* max_advance ) + { + FT_Error error = 0; + T2_Decoder decoder; + FT_Int glyph_index; + CFF_Font* cff = (CFF_Font*)face->other; + + + *max_advance = 0; + + /* Initialize load decoder */ + T2_Init_Decoder( &decoder, face, 0, 0 ); + + decoder.builder.metrics_only = 1; + decoder.builder.load_points = 0; + + /* For each glyph, parse the glyph charstring and extract */ + /* the advance width. */ + for ( glyph_index = 0; glyph_index < face->root.num_glyphs; + glyph_index++ ) + { + FT_Byte* charstring; + FT_ULong charstring_len; + + + /* now get load the unscaled outline */ + error = T2_Access_Element( &cff->charstrings_index, glyph_index, + &charstring, &charstring_len ); + if ( !error ) + { + T2_Prepare_Decoder( &decoder, glyph_index ); + error = T2_Parse_CharStrings( &decoder, charstring, charstring_len ); + + T2_Forget_Element( &cff->charstrings_index, &charstring ); + } + + /* ignore the error if one has occurred -- skip to next glyph */ + error = 0; + } + + *max_advance = decoder.builder.advance.x; + + return T2_Err_Ok; + } + + +#endif /* 0 */ + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /********** *********/ + /********** *********/ + /********** UNHINTED GLYPH LOADER *********/ + /********** *********/ + /********** The following code is in charge of loading a *********/ + /********** single outline. It completely ignores hinting *********/ + /********** and is used when FT_LOAD_NO_HINTING is set. *********/ + /********** *********/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + LOCAL_FUNC + FT_Error T2_Load_Glyph( T2_GlyphSlot glyph, + T2_Size size, + FT_Int glyph_index, + FT_Int load_flags ) + { + FT_Error error; + T2_Decoder decoder; + TT_Face face = (TT_Face)glyph->root.face; + FT_Bool hinting; + CFF_Font* cff = (CFF_Font*)face->extra.data; + + + if ( load_flags & FT_LOAD_NO_RECURSE ) + load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING; + + glyph->x_scale = 0x10000L; + glyph->y_scale = 0x10000L; + if ( size ) + { + glyph->x_scale = size->metrics.x_scale; + glyph->y_scale = size->metrics.y_scale; + } + + glyph->root.outline.n_points = 0; + glyph->root.outline.n_contours = 0; + + hinting = ( load_flags & FT_LOAD_NO_SCALE ) == 0 && + ( load_flags & FT_LOAD_NO_HINTING ) == 0; + + glyph->root.format = ft_glyph_format_outline; /* by default */ + + { + FT_Byte* charstring; + FT_ULong charstring_len; + + + T2_Init_Decoder( &decoder, face, size, glyph ); + + decoder.builder.no_recurse = + (FT_Bool)( ( load_flags & FT_LOAD_NO_RECURSE ) != 0 ); + + /* now load the unscaled outline */ + error = T2_Access_Element( &cff->charstrings_index, glyph_index, + &charstring, &charstring_len ); + if ( !error ) + { + T2_Prepare_Decoder( &decoder, glyph_index ); + error = T2_Parse_CharStrings( &decoder, charstring, charstring_len ); + + T2_Forget_Element( &cff->charstrings_index, &charstring ); + } + + /* save new glyph tables */ + T2_Done_Builder( &decoder.builder ); + } + + /* Now, set the metrics -- this is rather simple, as */ + /* the left side bearing is the xMin, and the top side */ + /* bearing the yMax. */ + if ( !error ) + { + /* for composite glyphs, return only left side bearing and */ + /* advance width */ + if ( glyph->root.format == ft_glyph_format_composite ) + { + glyph->root.metrics.horiBearingX = decoder.builder.left_bearing.x; + glyph->root.metrics.horiAdvance = decoder.glyph_width; + } + else + { + FT_BBox cbox; + FT_Glyph_Metrics* metrics = &glyph->root.metrics; + + + /* copy the _unscaled_ advance width */ + metrics->horiAdvance = decoder.glyph_width; + + /* make up vertical metrics */ + metrics->vertBearingX = 0; + metrics->vertBearingY = 0; + metrics->vertAdvance = 0; + + glyph->root.format = ft_glyph_format_outline; + + glyph->root.outline.flags = 0; + if ( size && size->metrics.y_ppem < 24 ) + glyph->root.outline.flags |= ft_outline_high_precision; + + glyph->root.outline.flags |= ft_outline_reverse_fill; + + if ( ( load_flags & FT_LOAD_NO_SCALE ) == 0 ) + { + /* scale the outline and the metrics */ + FT_Int n; + FT_Outline* cur = &glyph->root.outline; + FT_Vector* vec = cur->points; + FT_Fixed x_scale = glyph->x_scale; + FT_Fixed y_scale = glyph->y_scale; + + + /* First of all, scale the points */ + for ( n = cur->n_points; n > 0; n--, vec++ ) + { + vec->x = FT_MulFix( vec->x, x_scale ); + vec->y = FT_MulFix( vec->y, y_scale ); + } + + FT_Outline_Get_CBox( &glyph->root.outline, &cbox ); + + /* Then scale the metrics */ + metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale ); + metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale ); + + metrics->vertBearingX = FT_MulFix( metrics->vertBearingX, x_scale ); + metrics->vertBearingY = FT_MulFix( metrics->vertBearingY, y_scale ); + } + +#if 0 + /* apply the font matrix */ + FT_Outline_Transform( &glyph->root.outline, cff->font_matrix ); +#endif + + /* compute the other metrics */ + FT_Outline_Get_CBox( &glyph->root.outline, &cbox ); + + /* grid fit the bounding box if necessary */ + if ( hinting ) + { + cbox.xMin &= -64; + cbox.yMin &= -64; + cbox.xMax = ( cbox.xMax + 63 ) & -64; + cbox.yMax = ( cbox.yMax + 63 ) & -64; + } + + metrics->width = cbox.xMax - cbox.xMin; + metrics->height = cbox.yMax - cbox.yMin; + + metrics->horiBearingX = cbox.xMin; + metrics->horiBearingY = cbox.yMax; + } + } + + return error; + } + + +/* END */ diff --git a/src/freetype/cff/t2gload.h b/src/freetype/cff/t2gload.h new file mode 100644 index 0000000000..2654d4b563 --- /dev/null +++ b/src/freetype/cff/t2gload.h @@ -0,0 +1,213 @@ +/***************************************************************************/ +/* */ +/* t2gload.h */ +/* */ +/* OpenType Glyph Loader (specification). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef T2GLOAD_H +#define T2GLOAD_H + +#include + + +#ifdef FT_FLAT_COMPILE + +#include "t2objs.h" + +#else + +#include + +#endif + + +#ifdef __cplusplus + extern "C" { +#endif + + +#define T2_MAX_OPERANDS 48 +#define T2_MAX_SUBRS_CALLS 32 + + + /*************************************************************************/ + /* */ + /* */ + /* T2_Builder */ + /* */ + /* */ + /* A structure used during glyph loading to store its outline. */ + /* */ + /* */ + /* memory :: The current memory object. */ + /* */ + /* face :: The current face object. */ + /* */ + /* glyph :: The current glyph slot. */ + /* */ + /* current :: The current glyph outline. */ + /* */ + /* base :: The base glyph outline. */ + /* */ + /* max_points :: maximum points in builder outline */ + /* */ + /* max_contours :: Maximal number of contours in builder outline. */ + /* */ + /* last :: The last point position. */ + /* */ + /* scale_x :: The horizontal scale (FUnits to sub-pixels). */ + /* */ + /* scale_y :: The vertical scale (FUnits to sub-pixels). */ + /* */ + /* pos_x :: The horizontal translation (if composite glyph). */ + /* */ + /* pos_y :: The vertical translation (if composite glyph). */ + /* */ + /* left_bearing :: The left side bearing point. */ + /* */ + /* advance :: The horizontal advance vector. */ + /* */ + /* bbox :: Unused. */ + /* */ + /* path_begun :: A flag which indicates that a new path has begun. */ + /* */ + /* load_points :: If this flag is not set, no points are loaded. */ + /* */ + /* no_recurse :: Set but not used. */ + /* */ + /* error :: An error code that is only used to report memory */ + /* allocation problems. */ + /* */ + /* metrics_only :: A boolean indicating that we only want to compute */ + /* the metrics of a given glyph, not load all of its */ + /* points. */ + /* */ + typedef struct T2_Builder_ + { + FT_Memory memory; + TT_Face face; + T2_GlyphSlot glyph; + FT_GlyphLoader* loader; + FT_Outline* base; + FT_Outline* current; + + FT_Vector last; + + FT_Fixed scale_x; + FT_Fixed scale_y; + + FT_Pos pos_x; + FT_Pos pos_y; + + FT_Vector left_bearing; + FT_Vector advance; + + FT_BBox bbox; /* bounding box */ + FT_Bool path_begun; + FT_Bool load_points; + FT_Bool no_recurse; + + FT_Error error; /* only used for memory errors */ + FT_Bool metrics_only; + + } T2_Builder; + + + /* execution context charstring zone */ + + typedef struct T2_Decoder_Zone_ + { + FT_Byte* base; + FT_Byte* limit; + FT_Byte* cursor; + + } T2_Decoder_Zone; + + + typedef struct T2_Decoder_ + { + T2_Builder builder; + CFF_Font* cff; + + FT_Fixed stack[T2_MAX_OPERANDS + 1]; + FT_Fixed* top; + + T2_Decoder_Zone zones[T2_MAX_SUBRS_CALLS + 1]; + T2_Decoder_Zone* zone; + + FT_Int flex_state; + FT_Int num_flex_vectors; + FT_Vector flex_vectors[7]; + + FT_Pos glyph_width; + FT_Pos nominal_width; + + FT_Bool read_width; + FT_Int num_hints; + FT_Fixed* buildchar; + FT_Int len_buildchar; + + FT_UInt num_locals; + FT_UInt num_globals; + + FT_Int locals_bias; + FT_Int globals_bias; + + FT_Byte** locals; + FT_Byte** globals; + + } T2_Decoder; + + + LOCAL_DEF + void T2_Init_Decoder( T2_Decoder* decoder, + TT_Face face, + T2_Size size, + T2_GlyphSlot slot ); + + LOCAL_DEF + void T2_Prepare_Decoder( T2_Decoder* decoder, + FT_UInt glyph_index ); + +#if 0 /* unused until we support pure CFF fonts */ + + /* Compute the maximum advance width of a font through quick parsing */ + LOCAL_DEF + FT_Error T2_Compute_Max_Advance( TT_Face face, + FT_Int* max_advance ); + +#endif /* 0 */ + + LOCAL_DEF + FT_Error T2_Parse_CharStrings( T2_Decoder* decoder, + FT_Byte* charstring_base, + FT_Int charstring_len ); + + LOCAL_DEF + FT_Error T2_Load_Glyph( T2_GlyphSlot glyph, + T2_Size size, + FT_Int glyph_index, + FT_Int load_flags ); + + +#ifdef __cplusplus + } +#endif + + +#endif /* T2GLOAD_H */ + + +/* END */ diff --git a/src/freetype/cff/t2load.c b/src/freetype/cff/t2load.c new file mode 100644 index 0000000000..4a77693318 --- /dev/null +++ b/src/freetype/cff/t2load.c @@ -0,0 +1,757 @@ +/***************************************************************************/ +/* */ +/* t2load.c */ +/* */ +/* TrueType glyph data/program tables loader (body). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#include +#include +#include +#include + +#include +#include + + +#ifdef FT_FLAT_COMPILE + +#include "t2load.h" +#include "t2parse.h" + +#else + +#include +#include + +#endif + + + /*************************************************************************/ + /* */ + /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ + /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ + /* messages during execution. */ + /* */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_t2load + + + /* read a CFF offset from memory */ + static + FT_ULong t2_get_offset( FT_Byte* p, + FT_Byte off_size ) + { + FT_ULong result; + + + for ( result = 0; off_size > 0; off_size-- ) + { + result <<= 8; + result |= *p++; + } + + return result; + } + + + static + FT_Error t2_new_cff_index( CFF_Index* index, + FT_Stream stream, + FT_Bool load ) + { + FT_Error error; + FT_Memory memory = stream->memory; + FT_UShort count; + + + MEM_Set( index, 0, sizeof ( *index ) ); + + index->stream = stream; + if ( !READ_UShort( count ) && + count > 0 ) + { + FT_Byte* p; + FT_Byte offsize; + FT_ULong data_size; + FT_ULong* poff; + + + /* there is at least one element; read the offset size, */ + /* then access the offset table to compute the index's total size */ + if ( READ_Byte( offsize ) ) + goto Exit; + + index->stream = stream; + index->count = count; + index->off_size = offsize; + data_size = (FT_ULong)( count + 1 ) * offsize; + + if ( ALLOC_ARRAY( index->offsets, count + 1, FT_ULong ) || + ACCESS_Frame( data_size ) ) + goto Exit; + + poff = index->offsets; + p = (FT_Byte*)stream->cursor; + + for ( ; (FT_Short)count >= 0; count-- ) + { + poff[0] = t2_get_offset( p, offsize ); + poff++; + p += offsize; + } + + FORGET_Frame(); + + index->data_offset = FILE_Pos(); + data_size = poff[-1] - 1; + + if ( load ) + { + /* load the data */ + if ( EXTRACT_Frame( data_size, index->bytes ) ) + goto Exit; + } + else + { + /* skip the data */ + (void)FILE_Skip( data_size ); + } + } + + Exit: + if ( error ) + FREE( index->offsets ); + + return error; + } + + + static + void t2_done_cff_index( CFF_Index* index ) + { + if ( index->stream ) + { + FT_Stream stream = index->stream; + FT_Memory memory = stream->memory; + + + if ( index->bytes ) + RELEASE_Frame( index->bytes ); + + FREE( index->offsets ); + MEM_Set( index, 0, sizeof ( *index ) ); + } + } + + + static + FT_Error t2_explicit_cff_index( CFF_Index* index, + FT_Byte*** table ) + { + FT_Error error = 0; + FT_Memory memory = index->stream->memory; + FT_UInt n, offset, old_offset; + FT_Byte** t; + + + *table = 0; + + if ( index->count > 0 && !ALLOC_ARRAY( t, index->count + 1, FT_Byte* ) ) + { + old_offset = 1; + for ( n = 0; n <= index->count; n++ ) + { + offset = index->offsets[n]; + if ( !offset ) + offset = old_offset; + + t[n] = index->bytes + offset - 1; + + old_offset = offset; + } + *table = t; + } + + return error; + } + + + LOCAL_FUNC + FT_Error T2_Access_Element( CFF_Index* index, + FT_UInt element, + FT_Byte** pbytes, + FT_ULong* pbyte_len ) + { + FT_Error error = 0; + + + if ( index && index->count > element ) + { + /* compute start and end offsets */ + FT_ULong off1, off2; + + + off1 = index->offsets[element]; + if ( off1 ) + { + do + { + element++; + off2 = index->offsets[element]; + + } while ( off2 == 0 && element < index->count ); + + if ( !off2 ) + off1 = 0; + } + + /* access element */ + if ( off1 ) + { + *pbyte_len = off2 - off1; + + if ( index->bytes ) + { + /* this index was completely loaded in memory, that's easy */ + *pbytes = index->bytes + off1 - 1; + } + else + { + /* this index is still on disk/file, access it through a frame */ + FT_Stream stream = index->stream; + + + if ( FILE_Seek( index->data_offset + off1 - 1 ) || + EXTRACT_Frame( off2 - off1, *pbytes ) ) + goto Exit; + } + } + else + { + /* empty index element */ + *pbytes = 0; + *pbyte_len = 0; + } + } + else + error = T2_Err_Invalid_Argument; + + Exit: + return error; + } + + + LOCAL_FUNC + void T2_Forget_Element( CFF_Index* index, + FT_Byte** pbytes ) + { + if ( index->bytes == 0 ) + { + FT_Stream stream = index->stream; + + + RELEASE_Frame( *pbytes ); + } + } + + + LOCAL_FUNC + FT_String* T2_Get_Name( CFF_Index* index, + FT_UInt element ) + { + FT_Memory memory = index->stream->memory; + FT_Byte* bytes; + FT_ULong byte_len; + FT_Error error; + FT_String* name = 0; + + + error = T2_Access_Element( index, element, &bytes, &byte_len ); + if ( error ) + goto Exit; + + if ( !ALLOC( name, byte_len + 1 ) ) + { + MEM_Copy( name, bytes, byte_len ); + name[byte_len] = 0; + } + T2_Forget_Element( index, &bytes ); + + Exit: + return name; + } + + + LOCAL_FUNC + FT_String* T2_Get_String( CFF_Index* index, + FT_UInt sid, + PSNames_Interface* interface ) + { + /* if it is not a standard string, return it */ + if ( sid > 390 ) + return T2_Get_Name( index, sid - 390 ); + + /* that's a standard string, fetch a copy from the PSName module */ + { + FT_String* name = 0; + const char* adobe_name = interface->adobe_std_strings( sid ); + FT_UInt len; + + + if ( adobe_name ) + { + FT_Memory memory = index->stream->memory; + FT_Error error; + + + len = (FT_UInt)strlen( adobe_name ); + if ( !ALLOC( name, len + 1 ) ) + { + MEM_Copy( name, adobe_name, len ); + name[len] = 0; + } + } + + return name; + } + } + + + /*************************************************************************/ + /*************************************************************************/ + /*** ***/ + /*** FD Select table support ***/ + /*** ***/ + /*************************************************************************/ + /*************************************************************************/ + + + static + void CFF_Done_FD_Select( CFF_FD_Select* select, + FT_Stream stream ) + { + if ( select->data ) + RELEASE_Frame( select->data ); + + select->data_size = 0; + select->format = 0; + select->range_count = 0; + } + + + static + FT_Error CFF_Load_FD_Select( CFF_FD_Select* select, + FT_UInt num_glyphs, + FT_Stream stream, + FT_ULong offset ) + { + FT_Error error; + FT_Byte format; + FT_UInt num_ranges; + + + /* read format */ + if ( FILE_Seek( offset ) || READ_Byte( format ) ) + goto Exit; + + select->format = format; + select->cache_count = 0; /* clear cache */ + + switch ( format ) + { + case 0: /* format 0, that's simple */ + select->data_size = num_glyphs; + goto Load_Data; + + case 3: /* format 3, a tad more complex */ + if ( READ_UShort( num_ranges ) ) + goto Exit; + + select->data_size = num_ranges * 3 + 2; + + Load_Data: + if ( EXTRACT_Frame( select->data_size, select->data ) ) + goto Exit; + break; + + default: /* hmm... that's wrong */ + error = T2_Err_Invalid_File_Format; + } + + Exit: + return error; + } + + + LOCAL_FUNC + FT_Byte CFF_Get_FD( CFF_FD_Select* select, + FT_UInt glyph_index ) + { + FT_Byte fd = 0; + + + switch ( select->format ) + { + case 0: + fd = select->data[glyph_index]; + break; + + case 3: + /* first, compare to cache */ + if ( (FT_UInt)(glyph_index-select->cache_first) < select->cache_count ) + { + fd = select->cache_fd; + break; + } + + /* then, lookup the ranges array */ + { + FT_Byte* p = select->data; + FT_Byte* p_limit = p + select->data_size; + FT_Byte fd2; + FT_UInt first, limit; + + + first = NEXT_UShort( p ); + do + { + if ( glyph_index < first ) + break; + + fd2 = *p++; + limit = NEXT_UShort( p ); + + if ( glyph_index < limit ) + { + fd = fd2; + + /* update cache */ + select->cache_first = first; + select->cache_count = limit-first; + select->cache_fd = fd2; + break; + } + first = limit; + + } while ( p < p_limit ); + } + break; + + default: + ; + } + + return fd; + } + + + /*************************************************************************/ + /*************************************************************************/ + /*** ***/ + /*** CFF font support ***/ + /*** ***/ + /*************************************************************************/ + /*************************************************************************/ + + + static + FT_Error CFF_Load_SubFont( CFF_SubFont* font, + CFF_Index* index, + FT_UInt font_index, + FT_Stream stream, + FT_ULong base_offset ) + { + FT_Error error; + T2_Parser parser; + FT_Byte* dict; + FT_ULong dict_len; + CFF_Font_Dict* top = &font->font_dict; + CFF_Private* priv = &font->private_dict; + + + T2_Parser_Init( &parser, T2CODE_TOPDICT, &font->font_dict ); + + /* set defaults */ + MEM_Set( top, 0, sizeof ( *top ) ); + + top->underline_position = -100; + top->underline_thickness = 50; + top->charstring_type = 2; + top->font_matrix.xx = 0x10000L; + top->font_matrix.yy = 0x10000L; + top->cid_count = 8720; + + error = T2_Access_Element( index, font_index, &dict, &dict_len ) || + T2_Parser_Run( &parser, dict, dict + dict_len ); + + T2_Forget_Element( index, &dict ); + + if ( error ) + goto Exit; + + /* if it is a CID font, we stop there */ + if ( top->cid_registry ) + goto Exit; + + /* parse the private dictionary, if any */ + if ( top->private_offset && top->private_size ) + { + /* set defaults */ + MEM_Set( priv, 0, sizeof ( *priv ) ); + + priv->blue_shift = 7; + priv->blue_fuzz = 1; + priv->lenIV = -1; + priv->expansion_factor = (FT_Fixed)0.06 * 0x10000L; + priv->blue_scale = (FT_Fixed)0.039625 * 0x10000L; + + T2_Parser_Init( &parser, T2CODE_PRIVATE, priv ); + + if ( FILE_Seek( base_offset + font->font_dict.private_offset ) || + ACCESS_Frame( font->font_dict.private_size ) ) + goto Exit; + + error = T2_Parser_Run( &parser, + (FT_Byte*)stream->cursor, + (FT_Byte*)stream->limit ); + FORGET_Frame(); + if ( error ) + goto Exit; + } + + /* read the local subrs, if any */ + if ( priv->local_subrs_offset ) + { + if ( FILE_Seek( base_offset + top->private_offset + + priv->local_subrs_offset ) ) + goto Exit; + + error = t2_new_cff_index( &font->local_subrs_index, stream, 1 ); + if ( error ) + goto Exit; + + font->num_local_subrs = font->local_subrs_index.count; + error = t2_explicit_cff_index( &font->local_subrs_index, + &font->local_subrs ); + } + + Exit: + return error; + } + + + static + void CFF_Done_SubFont( FT_Memory memory, + CFF_SubFont* subfont ) + { + if ( subfont ) + { + t2_done_cff_index( &subfont->local_subrs_index ); + FREE( subfont->local_subrs ); + } + } + + + LOCAL_FUNC + FT_Error T2_Load_CFF_Font( FT_Stream stream, + FT_Int face_index, + CFF_Font* font ) + { + static const FT_Frame_Field cff_header_fields[] = + { + FT_FRAME_START( 4 ), + FT_FRAME_BYTE( CFF_Font, version_major ), + FT_FRAME_BYTE( CFF_Font, version_minor ), + FT_FRAME_BYTE( CFF_Font, header_size ), + FT_FRAME_BYTE( CFF_Font, absolute_offsize ), + FT_FRAME_END + }; + + FT_Error error; + FT_Memory memory = stream->memory; + FT_ULong base_offset; + CFF_Font_Dict* dict; + + + MEM_Set( font, 0, sizeof ( *font ) ); + font->stream = stream; + font->memory = memory; + dict = &font->top_font.font_dict; + base_offset = FILE_Pos(); + + /* read CFF font header */ + if ( READ_Fields( cff_header_fields, font ) ) + goto Exit; + + /* check format */ + if ( font->version_major != 1 || + font->header_size < 4 || + font->absolute_offsize > 4 ) + { + FT_TRACE2(( "[not a CFF font header!]\n" )); + error = FT_Err_Unknown_File_Format; + goto Exit; + } + + /* skip the rest of the header */ + (void)FILE_Skip( font->header_size - 4 ); + + /* read the name, top dict, string and global subrs index */ + error = t2_new_cff_index( &font->name_index, stream, 0 ) || + t2_new_cff_index( &font->font_dict_index, stream, 0 ) || + t2_new_cff_index( &font->string_index, stream, 0 ) || + t2_new_cff_index( &font->global_subrs_index, stream, 1 ); + if ( error ) + goto Exit; + + /* well, we don't really forget the `disabled' fonts... */ + font->num_faces = font->name_index.count; + if ( face_index >= (FT_Int)font->num_faces ) + { + FT_ERROR(( "T2_Load_CFF_Font: incorrect face index = %d\n", + face_index )); + error = T2_Err_Invalid_Argument; + } + + /* in case of a font format check, simply exit now */ + if ( face_index < 0 ) + goto Exit; + + /* now, parse the top-level font dictionary */ + error = CFF_Load_SubFont( &font->top_font, + &font->font_dict_index, + face_index, + stream, + base_offset ); + if ( error ) + goto Exit; + + /* now, check for a CID font */ + if ( dict->cid_registry ) + { + CFF_Index fd_index; + CFF_SubFont* sub; + FT_UInt index; + + + /* this is a CID-keyed font, we must now allocate a table of */ + /* sub-fonts, then load each of them separately */ + if ( FILE_Seek( base_offset + dict->cid_fd_array_offset ) ) + goto Exit; + + error = t2_new_cff_index( &fd_index, stream, 0 ); + if ( error ) + goto Exit; + + if ( fd_index.count > CFF_MAX_CID_FONTS ) + { + FT_ERROR(( "T2_Load_CFF_Font: FD array too large in CID font\n" )); + goto Fail_CID; + } + + /* allocate & read each font dict independently */ + font->num_subfonts = fd_index.count; + if ( ALLOC_ARRAY( sub, fd_index.count, CFF_SubFont ) ) + goto Fail_CID; + + /* setup pointer table */ + for ( index = 0; index < fd_index.count; index++ ) + font->subfonts[index] = sub + index; + + /* now load each sub font independently */ + for ( index = 0; index < fd_index.count; index++ ) + { + sub = font->subfonts[index]; + error = CFF_Load_SubFont( sub, &fd_index, index, + stream, base_offset ); + if ( error ) + goto Fail_CID; + } + + /* now load the FD Select array */ + error = CFF_Load_FD_Select( &font->fd_select, + dict->cid_count, + stream, + base_offset + dict->cid_fd_select_offset ); + + Fail_CID: + t2_done_cff_index( &fd_index ); + + if ( error ) + goto Exit; + } + else + font->num_subfonts = 0; + + /* read the charstrings index now */ + if ( dict->charstrings_offset == 0 ) + { + FT_ERROR(( "T2_Load_CFF_Font: no charstrings offset!\n" )); + error = FT_Err_Unknown_File_Format; + goto Exit; + } + + if ( FILE_Seek( base_offset + dict->charstrings_offset ) ) + goto Exit; + + error = t2_new_cff_index( &font->charstrings_index, stream, 0 ); + if ( error ) + goto Exit; + + /* explicit the global subrs */ + font->num_global_subrs = font->global_subrs_index.count; + font->num_glyphs = font->charstrings_index.count; + + error = t2_explicit_cff_index( &font->global_subrs_index, + &font->global_subrs ) ; + + if ( error ) + goto Exit; + + /* get the font name */ + font->font_name = T2_Get_Name( &font->name_index, face_index ); + + Exit: + return error; + } + + + LOCAL_FUNC + void T2_Done_CFF_Font( CFF_Font* font ) + { + FT_Memory memory = font->memory; + FT_UInt index; + + + t2_done_cff_index( &font->global_subrs_index ); + t2_done_cff_index( &font->string_index ); + t2_done_cff_index( &font->font_dict_index ); + t2_done_cff_index( &font->name_index ); + t2_done_cff_index( &font->charstrings_index ); + + /* release font dictionaries */ + for ( index = 0; index < font->num_subfonts; index++ ) + CFF_Done_SubFont( memory, font->subfonts[index] ); + + CFF_Done_SubFont( memory, &font->top_font ); + + CFF_Done_FD_Select( &font->fd_select, font->stream ); + + FREE( font->global_subrs ); + FREE( font->font_name ); + } + + +/* END */ diff --git a/src/freetype/cff/t2load.h b/src/freetype/cff/t2load.h new file mode 100644 index 0000000000..7ebc76d27d --- /dev/null +++ b/src/freetype/cff/t2load.h @@ -0,0 +1,69 @@ +/***************************************************************************/ +/* */ +/* t2load.h */ +/* */ +/* OpenType glyph data/program tables loader (specification). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef T2LOAD_H +#define T2LOAD_H + +#include +#include + +#ifdef __cplusplus + extern "C" { +#endif + + LOCAL_DEF + FT_String* T2_Get_Name( CFF_Index* index, + FT_UInt element ); + + LOCAL_DEF + FT_String* T2_Get_String( CFF_Index* index, + FT_UInt sid, + PSNames_Interface* interface ); + + LOCAL_DEF + FT_Error T2_Access_Element( CFF_Index* index, + FT_UInt element, + FT_Byte** pbytes, + FT_ULong* pbyte_len ); + + LOCAL_DEF + void T2_Forget_Element( CFF_Index* index, + FT_Byte** pbytes ); + + LOCAL_DEF + FT_Error T2_Load_CFF_Font( FT_Stream stream, + FT_Int face_index, + CFF_Font* font ); + + LOCAL_DEF + void T2_Done_CFF_Font( CFF_Font* font ); + + LOCAL_DEF + FT_Byte CFF_Get_FD( CFF_FD_Select* select, + FT_UInt glyph_index ); + + +#ifdef __cplusplus + } +#endif + + +#endif /* T2LOAD_H */ + + +/* END */ diff --git a/src/freetype/cff/t2objs.c b/src/freetype/cff/t2objs.c new file mode 100644 index 0000000000..1d59a585f7 --- /dev/null +++ b/src/freetype/cff/t2objs.c @@ -0,0 +1,600 @@ +/***************************************************************************/ +/* */ +/* t2objs.c */ +/* */ +/* OpenType objects manager (body). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#include +#include +#include +#include +#include +#include + +#include +#include + + +#ifdef FT_FLAT_COMPILE + +#include "t2objs.h" +#include "t2load.h" + +#else + +#include +#include + +#endif + + +#include + +#include /* for strlen() */ + + + /*************************************************************************/ + /* */ + /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ + /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ + /* messages during execution. */ + /* */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_t2objs + + + /*************************************************************************/ + /* */ + /* FACE FUNCTIONS */ + /* */ + /*************************************************************************/ + + static + FT_String* T2_StrCopy( FT_Memory memory, + const FT_String* source ) + { + FT_Error error; + FT_String* result = 0; + FT_Int len = (FT_Int)strlen( source ); + + + if ( !ALLOC( result, len + 1 ) ) + { + MEM_Copy( result, source, len ); + result[len] = 0; + } + return result; + } + + +#if 0 + + /* this function is used to build a Unicode charmap from the glyph names */ + /* in a file */ + static + FT_Error CFF_Build_Unicode_Charmap( T2_Face face, + FT_ULong base_offset, + PSNames_Interface* psnames ) + { + CFF_Font* font = (CFF_Font*)face->extra.data; + FT_Memory memory = FT_FACE_MEMORY(face); + FT_UInt n, num_glyphs = face->root.num_glyphs; + const char** glyph_names; + FT_Error error; + CFF_Font_Dict* dict = &font->top_font.font_dict; + FT_ULong charset_offset; + FT_Byte format; + FT_Stream stream = face->root.stream; + + + charset_offset = dict->charset_offset; + if ( !charset_offset ) + { + FT_ERROR(( "CFF.Build_Unicode_Charmap: charset table is missing\n" )); + error = T2_Err_Invalid_File_Format; + goto Exit; + } + + /* allocate the charmap */ + if ( ALLOC( face->charmap, ... + + /* seek to charset table and allocate glyph names table */ + if ( FILE_Seek( base_offset + charset_offset ) || + ALLOC_ARRAY( glyph_names, num_glyphs, const char* ) ) + goto Exit; + + /* now, read each glyph name and store it in the glyph name table */ + if ( READ_Byte( format ) ) + goto Fail; + + switch ( format ) + { + case 0: /* format 0 - one SID per glyph */ + { + const char** gname = glyph_names; + const char** limit = gname + num_glyphs; + + if ( ACCESS_Frame( num_glyphs*2 ) ) + goto Fail; + + for ( ; gname < limit; gname++ ) + gname[0] = T2_Get_String( &font->string_index, + GET_UShort(), + psnames ); + FORGET_Frame(); + break; + } + + case 1: /* format 1 - sequential ranges */ + case 2: /* format 2 - sequential ranges with 16-bit counts */ + { + const char** gname = glyph_names; + const char** limit = gname + num_glyphs; + FT_UInt len = 3; + + if (format == 2) + len++; + + while (gname < limit) + { + FT_UInt first; + FT_UInt count; + + if ( ACCESS_Frame( len ) ) + goto Fail; + + first = GET_UShort(); + if (format == 3) + count = GET_UShort(); + else + count = GET_Byte(); + + FORGET_Frame(); + + for ( ; count > 0; count-- ) + { + gname[0] = T2_Get_String( &font->string_index, + first, + psnames ); + gname++; + first++; + } + } + break; + } + + default: /* unknown charset format! */ + FT_ERROR(( "CFF: unknown charset format!\n" )); + error = T2_Err_Invalid_File_Format; + goto Fail; + } + + /* all right, the glyph names were loaded, we now need to create */ + /* the corresponding unicode charmap.. */ + + Fail: + for ( n = 0; n < num_glyphs; n++ ) + FREE( glyph_names[n] ); + + FREE( glyph_names ); + + Exit: + return error; + } + +#endif /* 0 */ + + + static + FT_Encoding find_encoding( int platform_id, + int encoding_id ) + { + typedef struct TEncoding + { + int platform_id; + int encoding_id; + FT_Encoding encoding; + + } TEncoding; + + static + const TEncoding tt_encodings[] = + { + { TT_PLATFORM_ISO, -1, ft_encoding_unicode }, + + { TT_PLATFORM_APPLE_UNICODE, -1, ft_encoding_unicode }, + + { TT_PLATFORM_MACINTOSH, TT_MAC_ID_ROMAN, ft_encoding_apple_roman }, + + { TT_PLATFORM_MICROSOFT, TT_MS_ID_UNICODE_CS, ft_encoding_unicode }, + { TT_PLATFORM_MICROSOFT, TT_MS_ID_SJIS, ft_encoding_sjis }, + { TT_PLATFORM_MICROSOFT, TT_MS_ID_GB2312, ft_encoding_gb2312 }, + { TT_PLATFORM_MICROSOFT, TT_MS_ID_BIG_5, ft_encoding_big5 }, + { TT_PLATFORM_MICROSOFT, TT_MS_ID_WANSUNG, ft_encoding_wansung }, + { TT_PLATFORM_MICROSOFT, TT_MS_ID_JOHAB, ft_encoding_johab } + }; + + const TEncoding *cur, *limit; + + + cur = tt_encodings; + limit = cur + sizeof ( tt_encodings ) / sizeof ( tt_encodings[0] ); + + for ( ; cur < limit; cur++ ) + { + if ( cur->platform_id == platform_id ) + { + if ( cur->encoding_id == encoding_id || + cur->encoding_id == -1 ) + return cur->encoding; + } + } + + return ft_encoding_none; + } + + + /*************************************************************************/ + /* */ + /* */ + /* T2_Init_Face */ + /* */ + /* */ + /* Initializes a given OpenType face object. */ + /* */ + /* */ + /* stream :: The source font stream. */ + /* */ + /* face_index :: The index of the font face in the resource. */ + /* */ + /* num_params :: Number of additional generic parameters. Ignored. */ + /* */ + /* params :: Additional generic parameters. Ignored. */ + /* */ + /* */ + /* face :: The newly built face object. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + LOCAL_DEF + FT_Error T2_Init_Face( FT_Stream stream, + T2_Face face, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ) + { + FT_Error error; + SFNT_Interface* sfnt; + PSNames_Interface* psnames; + FT_Bool pure_cff = 1; + FT_Bool sfnt_format = 0; + + + sfnt = (SFNT_Interface*)FT_Get_Module_Interface( + face->root.driver->root.library, "sfnt" ); + if ( !sfnt ) + goto Bad_Format; + + psnames = (PSNames_Interface*)FT_Get_Module_Interface( + face->root.driver->root.library, "psnames" ); + + /* create input stream from resource */ + if ( FILE_Seek( 0 ) ) + goto Exit; + + /* check that we have a valid OpenType file */ + error = sfnt->init_face( stream, face, face_index, num_params, params ); + if ( !error ) + { + if ( face->format_tag != 0x4F54544FL ) /* `OTTO'; OpenType/CFF font */ + { + FT_TRACE2(( "[not a valid OpenType/CFF font]\n" )); + goto Bad_Format; + } + + /* If we are performing a simple font format check, exit immediately */ + if ( face_index < 0 ) + return T2_Err_Ok; + + sfnt_format = 1; + + /* now, the font can be either an OpenType/CFF font, or a SVG CEF */ + /* font in the later case; it doesn't have a `head' table */ + error = face->goto_table( face, TTAG_head, stream, 0 ); + if ( !error ) + { + pure_cff = 0; + + /* Load font directory */ + error = sfnt->load_face( stream, face, + face_index, num_params, params ); + if ( error ) + goto Exit; + } + else + { + /* load the `cmap' table by hand */ + error = sfnt->load_charmaps( face, stream ); + if ( error ) + goto Exit; + + /* XXX: for now, we don't load the GPOS table, as OpenType Layout */ + /* support will be added later to FreeType 2 as a separate module */ + } + + /* now, load the CFF part of the file */ + error = face->goto_table( face, TTAG_CFF, stream, 0 ); + if ( error ) + goto Exit; + } + else + { + /* rewind to start of file; we are going to load a pure-CFF font */ + (void)FILE_Seek( 0 ); + error = FT_Err_Ok; + } + + /* now load and parse the CFF table in the file */ + { + CFF_Font* cff; + FT_Memory memory = face->root.memory; + FT_Face root; + FT_UInt flags; + FT_ULong base_offset; + + + if ( ALLOC( cff, sizeof ( *cff ) ) ) + goto Exit; + + base_offset = FILE_Pos(); + + face->extra.data = cff; + error = T2_Load_CFF_Font( stream, face_index, cff ); + if ( error ) + goto Exit; + + /* Complement the root flags with some interesting information. */ + /* Note that this is only necessary for pure CFF and CEF fonts */ + + root = &face->root; + if ( pure_cff ) + { + CFF_Font_Dict* dict = &cff->top_font.font_dict; + + + /* we need the `PSNames' module for pure-CFF and CEF formats */ + if ( !psnames ) + { + FT_ERROR(( "T2_Init_Face:" )); + FT_ERROR(( " cannot open CFF & CEF fonts\n" )); + FT_ERROR(( " " )); + FT_ERROR(( " without the `PSNames' module\n" )); + goto Bad_Format; + } + + /* compute number of glyphs */ + if ( dict->cid_registry ) + root->num_glyphs = dict->cid_count; + else + root->num_glyphs = cff->charstrings_index.count; + + /* set global bbox, as well as EM size */ + root->units_per_EM = (FT_UInt)FT_DivFix( 1000L << 16, + dict->font_matrix.yy ) >> 16; + root->bbox = dict->font_bbox; + root->ascender = (FT_Short)root->bbox.yMax; + root->descender = (FT_Short)root->bbox.yMin; + + /* retrieve font family & style name */ + root->family_name = T2_Get_Name( &cff->name_index, face_index ); + if ( dict->cid_registry ) + { + root->style_name = T2_StrCopy( memory, "Regular" ); /* XXXX */ + } + else + { + root->style_name = T2_Get_String( &cff->string_index, + dict->weight, + psnames ); + } + + /*******************************************************************/ + /* */ + /* Compute face flags. */ + /* */ + flags = FT_FACE_FLAG_SCALABLE | /* scalable outlines */ + FT_FACE_FLAG_HORIZONTAL; /* horizontal data */ + + if ( sfnt_format ) + flags |= FT_FACE_FLAG_SFNT; + + /* fixed width font? */ + if ( dict->is_fixed_pitch ) + flags |= FT_FACE_FLAG_FIXED_WIDTH; + +/* XXXX: WE DO NOT SUPPORT KERNING METRICS IN THE GPOS TABLE FOR NOW */ +#if 0 + /* kerning available? */ + if ( face->kern_pairs ) + flags |= FT_FACE_FLAG_KERNING; +#endif + + root->face_flags = flags; + + /*******************************************************************/ + /* */ + /* Compute style flags. */ + /* */ + flags = 0; + + if ( dict->italic_angle ) + flags |= FT_STYLE_FLAG_ITALIC; + + /* XXX: may not be correct */ + if ( cff->top_font.private_dict.force_bold ) + flags |= FT_STYLE_FLAG_BOLD; + + root->style_flags = flags; + + /* set the charmaps if any */ + if ( sfnt_format ) + { + /*****************************************************************/ + /* */ + /* Polish the charmaps. */ + /* */ + /* Try to set the charmap encoding according to the platform & */ + /* encoding ID of each charmap. */ + /* */ + TT_CharMap charmap; + FT_Int n; + + + charmap = face->charmaps; + root->num_charmaps = face->num_charmaps; + + /* allocate table of pointers */ + if ( ALLOC_ARRAY( root->charmaps, root->num_charmaps, FT_CharMap ) ) + goto Exit; + + for ( n = 0; n < root->num_charmaps; n++, charmap++ ) + { + FT_Int platform = charmap->cmap.platformID; + FT_Int encoding = charmap->cmap.platformEncodingID; + + + charmap->root.face = (FT_Face)face; + charmap->root.platform_id = platform; + charmap->root.encoding_id = encoding; + charmap->root.encoding = find_encoding( platform, encoding ); + + /* now, set root->charmap with a unicode charmap */ + /* wherever available */ + if ( !root->charmap && + charmap->root.encoding == ft_encoding_unicode ) + root->charmap = (FT_CharMap)charmap; + + root->charmaps[n] = (FT_CharMap)charmap; + } + } + } + } + + Exit: + return error; + + Bad_Format: + error = FT_Err_Unknown_File_Format; + goto Exit; + } + + + /*************************************************************************/ + /* */ + /* */ + /* T2_Done_Face */ + /* */ + /* */ + /* Finalizes a given face object. */ + /* */ + /* */ + /* face :: A pointer to the face object to destroy. */ + /* */ + LOCAL_DEF + void T2_Done_Face( T2_Face face ) + { + FT_Memory memory = face->root.memory; + SFNT_Interface* sfnt = (SFNT_Interface*)face->sfnt; + + + if ( sfnt ) + sfnt->done_face( face ); + + { + CFF_Font* cff = (CFF_Font*)face->extra.data; + + + if ( cff ) + { + T2_Done_CFF_Font( cff ); + FREE( face->extra.data ); + } + } + } + + + /*************************************************************************/ + /* */ + /* */ + /* T2_Init_Driver */ + /* */ + /* */ + /* Initializes a given OpenType driver object. */ + /* */ + /* */ + /* driver :: A handle to the target driver object. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + LOCAL_FUNC + FT_Error T2_Init_Driver( T2_Driver driver ) + { + /* init extension registry if needed */ + +#ifdef TT_CONFIG_OPTION_EXTEND_ENGINE + + return TT_Init_Extensions( driver ); + +#else + + FT_UNUSED( driver ); + + return T2_Err_Ok; + +#endif + } + + + /*************************************************************************/ + /* */ + /* */ + /* T2_Done_Driver */ + /* */ + /* */ + /* Finalizes a given OpenType driver. */ + /* */ + /* */ + /* driver :: A handle to the target OpenType driver. */ + /* */ + LOCAL_FUNC + void T2_Done_Driver( T2_Driver driver ) + { + /* destroy extensions registry if needed */ + +#ifdef TT_CONFIG_OPTION_EXTEND_ENGINE + + TT_Done_Extensions( driver ); + +#else + + FT_UNUSED( driver ); + +#endif + } + + +/* END */ diff --git a/src/freetype/cff/t2objs.h b/src/freetype/cff/t2objs.h new file mode 100644 index 0000000000..2602862751 --- /dev/null +++ b/src/freetype/cff/t2objs.h @@ -0,0 +1,148 @@ +/***************************************************************************/ +/* */ +/* t2objs.h */ +/* */ +/* OpenType objects manager (specification). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef T2OBJS_H +#define T2OBJS_H + + +#include +#include +#include +#include + +#ifdef __cplusplus + extern "C" { +#endif + + + /*************************************************************************/ + /* */ + /* */ + /* T2_Driver */ + /* */ + /* */ + /* A handle to an OpenType driver object. */ + /* */ + typedef struct T2_DriverRec_* T2_Driver; + + typedef TT_Face T2_Face; + + + /*************************************************************************/ + /* */ + /* */ + /* T2_Size */ + /* */ + /* */ + /* A handle to an OpenType size object. */ + /* */ + typedef FT_Size T2_Size; + + + /*************************************************************************/ + /* */ + /* */ + /* T2_GlyphSlot */ + /* */ + /* */ + /* A handle to an OpenType glyph slot object. */ + /* */ + typedef struct T2_GlyphSlotRec_ + { + FT_GlyphSlotRec root; + + FT_Bool hint; + FT_Bool scaled; + + FT_Fixed x_scale; + FT_Fixed y_scale; + + } T2_GlyphSlotRec, *T2_GlyphSlot; + + + + /*************************************************************************/ + /* */ + /* Subglyph transformation record. */ + /* */ + typedef struct T2_Transform_ + { + FT_Fixed xx, xy; /* transformation matrix coefficients */ + FT_Fixed yx, yy; + FT_F26Dot6 ox, oy; /* offsets */ + + } T2_Transform; + + + /* this is only used in the case of a pure CFF font with no charmap */ + typedef struct T2_CharMapRec_ + { + TT_CharMapRec root; + PS_Unicodes unicodes; + + } T2_CharMapRec, *T2_CharMap; + + + /***********************************************************************/ + /* */ + /* TrueType driver class. */ + /* */ + typedef struct T2_DriverRec_ + { + FT_DriverRec root; + + void* extension_component; + + } T2_DriverRec; + + + /*************************************************************************/ + /* */ + /* Face functions */ + /* */ + LOCAL_DEF + FT_Error T2_Init_Face( FT_Stream stream, + T2_Face face, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ); + + LOCAL_DEF + void T2_Done_Face( T2_Face face ); + + + /*************************************************************************/ + /* */ + /* Driver functions */ + /* */ + LOCAL_DEF + FT_Error T2_Init_Driver( T2_Driver driver ); + + LOCAL_DEF + void T2_Done_Driver( T2_Driver driver ); + + +#ifdef __cplusplus + } +#endif + + +#endif /* T2OBJS_H */ + + +/* END */ diff --git a/src/freetype/cff/t2parse.c b/src/freetype/cff/t2parse.c new file mode 100644 index 0000000000..7d62fef5b6 --- /dev/null +++ b/src/freetype/cff/t2parse.c @@ -0,0 +1,641 @@ +/***************************************************************************/ +/* */ +/* t2parse.c */ +/* */ +/* OpenType parser (body). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifdef FT_FLAT_COMPILE + +#include "t2parse.h" + +#else + +#include + +#endif + + +#include + + + /*************************************************************************/ + /* */ + /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ + /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ + /* messages during execution. */ + /* */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_t2parse + + +#define T2_Err_Stack_Underflow FT_Err_Invalid_Argument +#define T2_Err_Syntax_Error FT_Err_Invalid_Argument + + + enum + { + t2_kind_none = 0, + t2_kind_num, + t2_kind_fixed, + t2_kind_string, + t2_kind_bool, + t2_kind_delta, + t2_kind_callback, + + t2_kind_max /* do not remove */ + }; + + + /* now generate handlers for the most simple fields */ + typedef FT_Error (*T2_Field_Reader)( T2_Parser* parser ); + + typedef struct T2_Field_Handler_ + { + int kind; + int code; + FT_UInt offset; + FT_Byte size; + T2_Field_Reader reader; + FT_UInt array_max; + FT_UInt count_offset; + + } T2_Field_Handler; + + + LOCAL_FUNC + void T2_Parser_Init( T2_Parser* parser, + FT_UInt code, + void* object ) + { + MEM_Set( parser, 0, sizeof ( *parser ) ); + + parser->top = parser->stack; + parser->object_code = code; + parser->object = object; + } + + + /* reads an integer */ + static + FT_Long parse_t2_integer( FT_Byte* start, + FT_Byte* limit ) + { + FT_Byte* p = start; + FT_Int v = *p++; + FT_Long val = 0; + + + if ( v == 28 ) + { + if ( p + 2 > limit ) + goto Bad; + + val = (FT_Short)( ( (FT_Int)p[0] << 8 ) | p[1] ); + p += 2; + } + else if ( v == 29 ) + { + if ( p + 4 > limit ) + goto Bad; + + val = ( (FT_Long)p[0] << 24 ) | + ( (FT_Long)p[1] << 16 ) | + ( (FT_Long)p[2] << 8 ) | + p[3]; + p += 4; + } + else if ( v < 247 ) + { + val = v - 139; + } + else if ( v < 251 ) + { + if ( p + 1 > limit ) + goto Bad; + + val = ( v - 247 ) * 256 + p[0] + 108; + p++; + } + else + { + if ( p + 1 > limit ) + goto Bad; + + val = -( v - 251 ) * 256 - p[0] - 108; + p++; + } + + Exit: + return val; + + Bad: + val = 0; + goto Exit; + } + + + /* read a real */ + static + FT_Fixed parse_t2_real( FT_Byte* start, + FT_Byte* limit, + FT_Int power_ten ) + { + FT_Byte* p = start; + FT_Long num, divider, result, exp; + FT_Int sign = 0, exp_sign = 0; + FT_Byte nib; + FT_Byte phase; + + + result = 0; + num = 0; + divider = 1; + + /* first of all, read the integer part */ + phase = 4; + p--; + + for (;;) + { + /* read one nibble at a time */ + if ( phase && ++p >= limit ) + goto Bad; + + nib = ( p[0] >> phase ) & 0xF; + phase = 4 - phase; + + if ( nib == 0xE ) + sign = 1; + else if ( nib > 9 ) + break; + else + result = result * 10 + nib; + } + + /* read decimal part, if any */ + if ( nib == 0xa ) + for (;;) + { + /* read one nibble at a time */ + if ( !phase && ++p >= limit ) + goto Bad; + + phase = 4 - phase; + nib = ( p[0] >> phase ) & 0xF; + + if ( nib >= 10 ) + break; + + if (divider < 10000000L) + { + num = num * 10 + nib; + divider *= 10; + } + } + + /* read exponent, if any */ + if ( nib == 12 ) + { + exp_sign = 1; + nib = 11; + } + + if ( nib == 11 ) + { + exp = 0; + + for (;;) + { + /* read one nibble at a time */ + if ( !phase && ++p >= limit ) + goto Bad; + + phase = 4 - phase; + nib = ( p[0] >> phase ) & 0xF; + + if ( nib >= 10 ) + break; + + exp = exp * 10 + nib; + } + + if ( exp_sign ) + exp = -exp; + + power_ten += exp; + } + + /* raise to power of ten if needed */ + while ( power_ten > 0 ) + { + result = result * 10; + num = num * 10; + + power_ten--; + } + + while ( power_ten < 0 ) + { + result = result / 10; + divider = divider * 10; + + power_ten++; + } + + if ( num ) + result += FT_DivFix( num, divider ); + + if ( sign ) + result = -result; + + Exit: + return result; + + Bad: + result = 0; + goto Exit; + } + + + /* read a number, either integer or real */ + static + FT_Long t2_parse_num( FT_Byte** d ) + { + return ( **d == 30 ? ( parse_t2_real( d[0], d[1], 0 ) >> 16 ) + : parse_t2_integer( d[0], d[1] ) ); + } + + + /* reads a floating point number, either integer or real */ + static + FT_Fixed t2_parse_fixed( FT_Byte** d ) + { + return ( **d == 30 ? parse_t2_real( d[0], d[1], 0 ) + : parse_t2_integer( d[0], d[1] ) << 16 ); + } + + + static + FT_Error parse_font_matrix( T2_Parser* parser ) + { + CFF_Font_Dict* dict = (CFF_Font_Dict*)parser->object; + FT_Matrix* matrix = &dict->font_matrix; + FT_Byte** data = parser->stack; + FT_Error error; + + + error = T2_Err_Stack_Underflow; + + if ( parser->top >= parser->stack + 4 ) + { + matrix->xx = t2_parse_fixed( data++ ); + matrix->yx = t2_parse_fixed( data++ ); + matrix->xy = t2_parse_fixed( data++ ); + matrix->yy = t2_parse_fixed( data ); + error = T2_Err_Ok; + } + + return error; + } + + + static + FT_Error parse_font_bbox( T2_Parser* parser ) + { + CFF_Font_Dict* dict = (CFF_Font_Dict*)parser->object; + FT_BBox* bbox = &dict->font_bbox; + FT_Byte** data = parser->stack; + FT_Error error; + + + error = T2_Err_Stack_Underflow; + + if ( parser->top >= parser->stack + 4 ) + { + bbox->xMin = t2_parse_num( data++ ); + bbox->yMin = t2_parse_num( data++ ); + bbox->xMax = t2_parse_num( data++ ); + bbox->yMax = t2_parse_num( data ); + error = T2_Err_Ok; + } + + return error; + } + + + static + FT_Error parse_private_dict( T2_Parser* parser ) + { + CFF_Font_Dict* dict = (CFF_Font_Dict*)parser->object; + FT_Byte** data = parser->stack; + FT_Error error; + + + error = T2_Err_Stack_Underflow; + + if ( parser->top >= parser->stack + 2 ) + { + dict->private_size = t2_parse_num( data++ ); + dict->private_offset = t2_parse_num( data ); + error = T2_Err_Ok; + } + + return error; + } + + + static + FT_Error parse_cid_ros( T2_Parser* parser ) + { + CFF_Font_Dict* dict = (CFF_Font_Dict*)parser->object; + FT_Byte** data = parser->stack; + FT_Error error; + + + error = T2_Err_Stack_Underflow; + + if ( parser->top >= parser->stack + 3 ) + { + dict->cid_registry = (FT_UInt)t2_parse_num( data++ ); + dict->cid_ordering = (FT_UInt)t2_parse_num( data++ ); + dict->cid_supplement = (FT_ULong)t2_parse_num( data ); + error = T2_Err_Ok; + } + + return error; + } + + +#define T2_FIELD_NUM( code, name ) \ + T2_FIELD( code, name, t2_kind_num ) +#define T2_FIELD_FIXED( code, name ) \ + T2_FIELD( code, name, t2_kind_fixed ) +#define T2_FIELD_STRING( code, name ) \ + T2_FIELD( code, name, t2_kind_string ) +#define T2_FIELD_BOOL( code, name ) \ + T2_FIELD( code, name, t2_kind_bool ) +#define T2_FIELD_DELTA( code, name,max ) \ + T2_FIELD( code, name, t2_kind_delta ) + +#define T2_REF( s, f ) ( ((s*)0)->f ) + +#define T2_FIELD_CALLBACK( code, name ) \ + { \ + t2_kind_callback, \ + code | T2CODE, \ + 0, 0, \ + parse_ ## name, \ + 0, 0 \ + }, + +#undef T2_FIELD +#define T2_FIELD( code, name, kind ) \ + { \ + kind, \ + code | T2CODE, \ + (FT_UInt)(char*)&T2_REF( T2TYPE, name ), \ + sizeof( T2_REF( T2TYPE, name ) ), \ + 0, 0, 0 \ + }, + +#undef T2_FIELD_DELTA +#define T2_FIELD_DELTA( code, name, max ) \ + { \ + t2_kind_delta, \ + code | T2CODE, \ + (FT_UInt)(char*)&T2_REF( T2TYPE, name ), \ + sizeof( T2_REF( T2TYPE, name )[0] ), \ + 0, \ + max, \ + (FT_UInt)(char*)&T2_REF( T2TYPE, num_ ## name ) \ + }, + +#define T2CODE_TOPDICT 0x1000 +#define T2CODE_PRIVATE 0x2000 + + static const T2_Field_Handler t2_field_handlers[] = + { + +#ifdef FT_FLAT_COMPILE + +#include "t2tokens.h" + +#else + +#include + +#endif + + { 0, 0, 0, 0, 0, 0, 0 } + }; + + + LOCAL_FUNC + FT_Error T2_Parser_Run( T2_Parser* parser, + FT_Byte* start, + FT_Byte* limit ) + { + FT_Byte* p = start; + FT_Error error = T2_Err_Ok; + + + parser->top = parser->stack; + parser->start = start; + parser->limit = limit; + parser->cursor = start; + + while ( p < limit ) + { + FT_Byte v = *p; + + + if ( v >= 27 && v != 31 ) + { + /* it's a number; we will push its position on the stack */ + if ( parser->top - parser->stack >= T2_MAX_STACK_DEPTH ) + goto Stack_Overflow; + + *parser->top ++ = p; + + /* now, skip it */ + if ( v == 30 ) + { + /* skip real number */ + for (;;) + { + if ( p >= limit ) + goto Syntax_Error; + v = p[0] >> 4; + if ( v == 15 ) + break; + v = p[0] & 0xF; + if ( v == 15 ) + break; + p++; + } + p++; + } + else if ( v == 28 ) + p += 2; + else if ( v == 29 ) + p += 4; + else if ( v > 246 ) + p += 1; + } + else + { + /* This is not a number, hence it's an operator. Compute its code */ + /* and look for it in our current list. */ + + FT_UInt code; + FT_UInt num_args = (FT_UInt) + ( parser->top - parser->stack ); + const T2_Field_Handler* field; + + + /* first of all, a trivial check */ + if ( num_args < 1 ) + goto Stack_Underflow; + + *parser->top = p; + code = v; + if ( v == 12 ) + { + /* two byte operator */ + p++; + code = 0x100 | p[0]; + } + code = code | parser->object_code; + + for ( field = t2_field_handlers; field->kind; field++ ) + { + if ( field->code == (FT_Int)code ) + { + /* we found our field's handler; read it */ + FT_Long val; + FT_Byte* q = (FT_Byte*)parser->object + field->offset; + + + switch ( field->kind ) + { + case t2_kind_bool: + case t2_kind_string: + case t2_kind_num: + val = t2_parse_num( parser->stack ); + goto Store_Number; + + case t2_kind_fixed: + val = t2_parse_fixed( parser->stack ); + + Store_Number: + switch ( field->size ) + { + case 1: + *(FT_Byte*)q = (FT_Byte)val; + break; + + case 2: + *(FT_Short*)q = (FT_Short)val; + break; + + case 4: + *(FT_Int32*)q = (FT_Int)val; + break; + + default: /* for 64-bit systems where long is 8 bytes */ + *(FT_Long*)q = val; + } + break; + + case t2_kind_delta: + { + FT_Byte* qcount = (FT_Byte*)parser->object + + field->count_offset; + + FT_Long val; + FT_Byte** data = parser->stack; + + + if ( num_args > field->array_max ) + num_args = field->array_max; + + /* store count */ + *qcount = (FT_Byte)num_args; + + val = 0; + while ( num_args > 0 ) + { + val += t2_parse_num( data++ ); + switch ( field->size ) + { + case 1: + *(FT_Byte*)q = (FT_Byte)val; + break; + + case 2: + *(FT_Short*)q = (FT_Short)val; + break; + + case 4: + *(FT_Int32*)q = (FT_Int)val; + break; + + default: /* for 64-bit systems */ + *(FT_Long*)q = val; + } + + q += field->size; + num_args--; + } + } + break; + + default: /* callback */ + error = field->reader( parser ); + if ( error ) + goto Exit; + } + goto Found; + } + } + + /* this is an unknown operator, or it is unsupported; */ + /* we will ignore it for now. */ + + Found: + /* clear stack */ + parser->top = parser->stack; + } + p++; + } + + Exit: + return error; + + Stack_Overflow: + error = T2_Err_Invalid_Argument; + goto Exit; + + Stack_Underflow: + error = T2_Err_Invalid_Argument; + goto Exit; + + Syntax_Error: + error = T2_Err_Invalid_Argument; + goto Exit; + } + + +/* END */ diff --git a/src/freetype/cff/t2parse.h b/src/freetype/cff/t2parse.h new file mode 100644 index 0000000000..2238444b7a --- /dev/null +++ b/src/freetype/cff/t2parse.h @@ -0,0 +1,70 @@ +/***************************************************************************/ +/* */ +/* t2parse.h */ +/* */ +/* OpenType parser (specification). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef T2PARSE_H +#define T2PARSE_H + +#include +#include + +#define T2_MAX_STACK_DEPTH 96 + +#define T2CODE_TOPDICT 0x1000 +#define T2CODE_PRIVATE 0x2000 + + +#ifdef __cplusplus + extern "C" { +#endif + + + typedef struct T2_Parser_ + { + FT_Byte* start; + FT_Byte* limit; + FT_Byte* cursor; + + FT_Byte* stack[T2_MAX_STACK_DEPTH + 1]; + FT_Byte** top; + + FT_UInt object_code; + void* object; + + } T2_Parser; + + + LOCAL_DEF + void T2_Parser_Init( T2_Parser* parser, + FT_UInt code, + void* object ); + + LOCAL_DEF + FT_Error T2_Parser_Run( T2_Parser* parser, + FT_Byte* start, + FT_Byte* limit ); + + +#ifdef __cplusplus + } +#endif + + +#endif /* T2PARSE_H */ + + +/* END */ diff --git a/src/freetype/cff/t2tokens.h b/src/freetype/cff/t2tokens.h new file mode 100644 index 0000000000..13a15e43df --- /dev/null +++ b/src/freetype/cff/t2tokens.h @@ -0,0 +1,96 @@ +/***************************************************************************/ +/* */ +/* t2tokens.h */ +/* */ +/* OpenType token definitions (specification only). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#undef T2TYPE +#undef T2CODE +#define T2TYPE CFF_Font_Dict +#define T2CODE T2CODE_TOPDICT + + T2_FIELD_STRING ( 0, version ) + T2_FIELD_STRING ( 1, notice ) + T2_FIELD_STRING ( 0x100, copyright ) + T2_FIELD_STRING ( 2, full_name ) + T2_FIELD_STRING ( 3, family_name ) + T2_FIELD_STRING ( 4, weight ) + T2_FIELD_BOOL ( 0x101, is_fixed_pitch ) + T2_FIELD_FIXED ( 0x102, italic_angle ) + T2_FIELD_NUM ( 0x103, underline_position ) + T2_FIELD_NUM ( 0x104, underline_thickness ) + T2_FIELD_NUM ( 0x105, paint_type ) + T2_FIELD_NUM ( 0x106, charstring_type ) + T2_FIELD_CALLBACK( 0x107, font_matrix ) + T2_FIELD_NUM ( 13, unique_id ) + T2_FIELD_CALLBACK( 5, font_bbox ) + T2_FIELD_NUM ( 0x108, stroke_width ) + T2_FIELD_NUM ( 15, charset_offset ) + T2_FIELD_NUM ( 16, encoding_offset ) + T2_FIELD_NUM ( 17, charstrings_offset ) + T2_FIELD_CALLBACK( 18, private_dict ) + T2_FIELD_NUM ( 0x114, synthetic_base ) + T2_FIELD_STRING ( 0x115, postscript ) + T2_FIELD_STRING ( 0x116, base_font_name ) + +#if 0 + T2_FIELD_DELTA ( 0x117, base_font_blend, 16 ) + T2_FIELD_CALLBACK( 0x118, multiple_master ) + T2_FIELD_CALLBACK( 0x119, blend_axit_types ) +#endif + + T2_FIELD_CALLBACK( 0x11E, cid_ros ) + T2_FIELD_NUM ( 0x11F, cid_font_version ) + T2_FIELD_NUM ( 0x120, cid_font_revision ) + T2_FIELD_NUM ( 0x121, cid_font_type ) + T2_FIELD_NUM ( 0x122, cid_count ) + T2_FIELD_NUM ( 0x123, cid_uid_base ) + T2_FIELD_NUM ( 0x124, cid_fd_array_offset ) + T2_FIELD_NUM ( 0x125, cid_fd_select_offset ) + T2_FIELD_STRING ( 0x126, cid_font_name ) + +#if 0 + T2_FIELD_NUM ( 0x127, chameleon ) +#endif + + +#undef T2TYPE +#undef T2CODE +#define T2TYPE CFF_Private +#define T2CODE T2CODE_PRIVATE + + T2_FIELD_DELTA( 6, blue_values, 14 ) + T2_FIELD_DELTA( 7, other_blues, 10 ) + T2_FIELD_DELTA( 8, family_blues, 14 ) + T2_FIELD_DELTA( 9, family_other_blues, 10 ) + T2_FIELD_FIXED( 0x109, blue_scale ) + T2_FIELD_NUM ( 0x10A, blue_shift ) + T2_FIELD_NUM ( 0x10B, blue_fuzz ) + T2_FIELD_NUM ( 10, standard_width ) + T2_FIELD_NUM ( 11, standard_height ) + T2_FIELD_DELTA( 0x10C, snap_widths, 13 ) + T2_FIELD_DELTA( 0x10D, snap_heights, 13 ) + T2_FIELD_BOOL ( 0x10E, force_bold ) + T2_FIELD_FIXED( 0x10F, force_bold_threshold ) + T2_FIELD_NUM ( 0x110, lenIV ) + T2_FIELD_NUM ( 0x111, language_group ) + T2_FIELD_FIXED( 0x112, expansion_factor ) + T2_FIELD_NUM ( 0x113, initial_random_seed ) + T2_FIELD_NUM ( 19, local_subrs_offset ) + T2_FIELD_NUM ( 20, default_width ) + T2_FIELD_NUM ( 21, nominal_width ) + + +/* END */ diff --git a/src/freetype/cid/cidafm.c b/src/freetype/cid/cidafm.c new file mode 100644 index 0000000000..b5638836ea --- /dev/null +++ b/src/freetype/cid/cidafm.c @@ -0,0 +1,293 @@ +/***************************************************************************/ +/* */ +/* cidafm.c */ +/* */ +/* AFM support for CID-keyed fonts (body). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifdef FT_FLAT_COMPILE + +#include "cidafm.h" + +#else + +#include + +#endif + + +#include +#include +#include + +#include /* for qsort() */ +#include /* for strcmp() */ +#include /* for isalnum() */ + + + /*************************************************************************/ + /* */ + /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ + /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ + /* messages during execution. */ + /* */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_cidafm + + + LOCAL_FUNC + void CID_Done_AFM( FT_Memory memory, + CID_AFM* afm ) + { + FREE( afm->kern_pairs ); + afm->num_pairs = 0; + } + + +#undef IS_KERN_PAIR +#define IS_KERN_PAIR( p ) ( p[0] == 'K' && p[1] == 'P' ) + +#define IS_ALPHANUM( c ) ( isalnum( c ) || \ + c == '_' || \ + c == '.' ) + + + /* read a glyph name and return the equivalent glyph index */ + static + FT_UInt afm_atoindex( FT_Byte** start, + FT_Byte* limit, + T1_Font* type1 ) + { + FT_Byte* p = *start; + FT_Int len; + FT_UInt result = 0; + char temp[64]; + + + /* skip whitespace */ + while ( ( *p == ' ' || *p == '\t' || *p == ':' || *p == ';' ) && + p < limit ) + p++; + *start = p; + + /* now, read glyph name */ + while ( IS_ALPHANUM( *p ) && p < limit ) + p++; + + len = p - *start; + + if ( len > 0 && len < 64 ) + { + FT_Int n; + + + /* copy glyph name to intermediate array */ + MEM_Copy( temp, *start, len ); + temp[len] = 0; + + /* lookup glyph name in face array */ + for ( n = 0; n < type1->num_glyphs; n++ ) + { + char* gname = (char*)type1->glyph_names[n]; + + + if ( gname && gname[0] == temp[0] && strcmp( gname, temp ) == 0 ) + { + result = n; + break; + } + } + } + *start = p; + return result; + } + + + /* read an integer */ + static + int afm_atoi( FT_Byte** start, + FT_Byte* limit ) + { + FT_Byte* p = *start; + int sum = 0; + int sign = 1; + + + /* skip everything that is not a number */ + while ( p < limit && !isdigit( *p ) ) + { + sign = 1; + if ( *p == '-' ) + sign = -1; + + p++; + } + + while ( p < limit && isdigit( *p ) ) + { + sum = sum * 10 + ( *p - '0' ); + p++; + } + *start = p; + + return sum * sign; + } + + +#undef KERN_INDEX +#define KERN_INDEX( g1, g2 ) ( ( (FT_ULong)g1 << 16 ) | g2 ) + + + /* compare two kerning pairs */ + static + int compare_kern_pairs( const void* a, + const void* b ) + { + CID_Kern_Pair* pair1 = (CID_Kern_Pair*)a; + CID_Kern_Pair* pair2 = (CID_Kern_Pair*)b; + + FT_ULong index1 = KERN_INDEX( pair1->glyph1, pair1->glyph2 ); + FT_ULong index2 = KERN_INDEX( pair2->glyph1, pair2->glyph2 ); + + + return ( index1 - index2 ); + } + + + /* parse an AFM file -- for now, only read the kerning pairs */ + LOCAL_FUNC + FT_Error CID_Read_AFM( FT_Face cid_face, + FT_Stream stream ) + { + FT_Error error; + FT_Memory memory = stream->memory; + FT_Byte* start; + FT_Byte* limit; + FT_Byte* p; + FT_Int count = 0; + CID_Kern_Pair* pair; + T1_Font* type1 = &((T1_Face)t1_face)->type1; + CID_AFM* afm = 0; + + + if ( ACCESS_Frame( stream->size ) ) + return error; + + start = (FT_Byte*)stream->cursor; + limit = (FT_Byte*)stream->limit; + p = start; + + /* we are now going to count the occurrences of `KP' or `KPX' in */ + /* the AFM file. */ + count = 0; + for ( p = start; p < limit - 3; p++ ) + { + if ( IS_KERN_PAIR( p ) ) + count++; + } + + /* Actually, kerning pairs are simply optional! */ + if ( count == 0 ) + goto Exit; + + /* allocate the pairs */ + if ( ALLOC( afm, sizeof ( *afm ) ) || + ALLOC_ARRAY( afm->kern_pairs, count, CID_Kern_Pair ) ) + goto Exit; + + /* now, read each kern pair */ + pair = afm->kern_pairs; + afm->num_pairs = count; + + /* save in face object */ + ((T1_Face)t1_face)->afm_data = afm; + + for ( p = start; p < limit - 3; p++ ) + { + if ( IS_KERN_PAIR( p ) ) + { + FT_Byte* q; + + + /* skip keyword (`KP' or `KPX') */ + q = p + 2; + if ( *q == 'X' ) + q++; + + pair->glyph1 = afm_atoindex( &q, limit, type1 ); + pair->glyph2 = afm_atoindex( &q, limit, type1 ); + pair->kerning.x = afm_atoi( &q, limit ); + + pair->kerning.y = 0; + if ( p[2] != 'X' ) + pair->kerning.y = afm_atoi( &q, limit ); + + pair++; + } + } + + /* now, sort the kern pairs according to their glyph indices */ + qsort( afm->kern_pairs, count, sizeof ( CID_Kern_Pair ), + compare_kern_pairs ); + + Exit: + if ( error ) + FREE( afm ); + + FORGET_Frame(); + + return error; + } + + + /* find the kerning for a given glyph pair */ + LOCAL_FUNC + void CID_Get_Kerning( CID_AFM* afm, + FT_UInt glyph1, + FT_UInt glyph2, + FT_Vector* kerning ) + { + CID_Kern_Pair *min, *mid, *max; + FT_ULong index = KERN_INDEX( glyph1, glyph2 ); + + + /* simple binary search */ + min = afm->kern_pairs; + max = min + afm->num_pairs - 1; + + while ( min <= max ) + { + FT_ULong midi; + + + mid = min + ( max - min ) / 2; + midi = KERN_INDEX( mid->glyph1, mid->glyph2 ); + if ( midi == index ) + { + *kerning = mid->kerning; + return; + } + + if ( midi < index ) + min = mid + 1; + else + max = mid - 1; + } + + kerning->x = 0; + kerning->y = 0; + } + + +/* END */ diff --git a/src/freetype/cid/cidafm.h b/src/freetype/cid/cidafm.h new file mode 100644 index 0000000000..542604e0dd --- /dev/null +++ b/src/freetype/cid/cidafm.h @@ -0,0 +1,78 @@ +/***************************************************************************/ +/* */ +/* cidafm.h */ +/* */ +/* AFM support for CID-keyed fonts (specification). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef CIDAFM_H +#define CIDAFM_H + + +#ifdef FT_FLAT_COMPILE + +#include "cidobjs.h" + +#else + +#include + +#endif + + +#ifdef __cplusplus + extern "C" { +#endif + + + typedef struct CID_Kern_Pair_ + { + FT_UInt glyph1; + FT_UInt glyph2; + FT_Vector kerning; + + } CID_Kern_Pair; + + typedef struct CID_AFM_ + { + FT_UInt num_pairs; + CID_Kern_Pair* kern_pairs; + + } CID_AFM; + + + LOCAL_DEF + FT_Error CID_Read_AFM( FT_Face cid_face, + FT_Stream stream ); + + LOCAL_DEF + void CID_Done_AFM( FT_Memory memory, + CID_AFM* afm ); + + LOCAL_DEF + void CID_Get_Kerning( CID_AFM* afm, + FT_UInt glyph1, + FT_UInt glyph2, + FT_Vector* kerning ); + + +#ifdef __cplusplus + } +#endif + + +#endif /* CIDAFM_H */ + + +/* END */ diff --git a/src/freetype/cid/cidgload.c b/src/freetype/cid/cidgload.c new file mode 100644 index 0000000000..97c9252be2 --- /dev/null +++ b/src/freetype/cid/cidgload.c @@ -0,0 +1,1558 @@ +/***************************************************************************/ +/* */ +/* cidgload.c */ +/* */ +/* CID-keyed Type1 Glyph Loader (body). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifdef FT_FLAT_COMPILE + +#include "cidload.h" +#include "cidgload.h" + +#else + +#include +#include + +#endif + + +#include +#include +#include + + + /*************************************************************************/ + /* */ + /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ + /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ + /* messages during execution. */ + /* */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_cidgload + + + /* forward */ + static + FT_Error cid_load_glyph( CID_Decoder* decoder, + FT_UInt glyph_index ); + + + typedef enum CID_Operator_ + { + op_none = 0, + + op_endchar, + op_hsbw, + op_seac, + op_sbw, + op_closepath, + + op_hlineto, + op_hmoveto, + op_hvcurveto, + op_rlineto, + op_rmoveto, + op_rrcurveto, + op_vhcurveto, + op_vlineto, + op_vmoveto, + + op_dotsection, + + op_hstem, + op_hstem3, + op_vstem, + op_vstem3, + + op_div, + op_callothersubr, + op_callsubr, + op_pop, + op_return, + op_setcurrentpoint, + + op_max /* never remove this one */ + + } CID_Operator; + + static + const FT_Int t1_args_count[op_max] = + { + 0, /* none */ + 0, /* endchar */ + 2, /* hsbw */ + 5, /* seac */ + 4, /* sbw */ + 0, /* closepath */ + + 1, /* hlineto */ + 1, /* hmoveto */ + 4, /* hvcurveto */ + 2, /* rlineto */ + 2, /* rmoveto */ + 6, /* rrcurveto */ + 4, /* vhcurveto */ + 1, /* vlineto */ + 1, /* vmoveto */ + + 0, /* dotsection */ + + 2, /* hstem */ + 6, /* hstem3 */ + 2, /* vstem */ + 6, /* vstem3 */ + + 2, /* div */ + -1, /* callothersubr */ + 1, /* callsubr */ + 0, /* pop */ + 0, /* return */ + 2 /* setcurrentpoint */ + }; + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /********** *********/ + /********** *********/ + /********** GENERIC CHARSTRING PARSING *********/ + /********** *********/ + /********** *********/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* */ + /* CID_Init_Builder */ + /* */ + /* */ + /* Initializes a given glyph builder. */ + /* */ + /* */ + /* builder :: A pointer to the glyph builder to initialize. */ + /* */ + /* */ + /* face :: The current face object. */ + /* */ + /* size :: The current size object. */ + /* */ + /* glyph :: The current glyph object. */ + /* */ + LOCAL_FUNC + void CID_Init_Builder( CID_Builder* builder, + CID_Face face, + CID_Size size, + CID_GlyphSlot glyph ) + { + builder->path_begun = 0; + builder->load_points = 1; + + builder->face = face; + builder->glyph = glyph; + builder->memory = face->root.memory; + + if ( glyph ) + { + FT_GlyphLoader* loader = glyph->root.loader; + + + builder->loader = loader; + builder->base = &loader->base.outline; + builder->current = &loader->current.outline; + + FT_GlyphLoader_Rewind( loader ); + } + + if ( size ) + { + builder->scale_x = size->root.metrics.x_scale; + builder->scale_y = size->root.metrics.y_scale; + } + + builder->pos_x = 0; + builder->pos_y = 0; + + builder->left_bearing.x = 0; + builder->left_bearing.y = 0; + builder->advance.x = 0; + builder->advance.y = 0; + + } + + + /*************************************************************************/ + /* */ + /* */ + /* CID_Done_Builder */ + /* */ + /* */ + /* Finalizes a given glyph builder. Its contents can still be used */ + /* after the call, but the function saves important information */ + /* within the corresponding glyph slot. */ + /* */ + /* */ + /* builder :: A pointer to the glyph builder to finalize. */ + /* */ + LOCAL_FUNC + void CID_Done_Builder( CID_Builder* builder ) + { + CID_GlyphSlot glyph = builder->glyph; + + + if ( glyph ) + glyph->root.outline = *builder->base; + } + + + /*************************************************************************/ + /* */ + /* */ + /* CID_Init_Decoder */ + /* */ + /* */ + /* Initializes a given glyph decoder. */ + /* */ + /* */ + /* decoder :: A pointer to the glyph builder to initialize. */ + /* */ + LOCAL_FUNC + void CID_Init_Decoder( CID_Decoder* decoder ) + { + MEM_Set( decoder, 0, sizeof ( *decoder ) ); + + decoder->font_matrix.xx = 0x10000L; + decoder->font_matrix.yy = 0x10000L; + } + + + /* check that there is enough space for `count' more points */ + static + FT_Error check_points( CID_Builder* builder, + FT_Int count ) + { + return FT_GlyphLoader_Check_Points( builder->loader, count, 0 ); + } + + + /* add a new point, but do not check space */ + static + void add_point( CID_Builder* builder, + FT_Pos x, + FT_Pos y, + FT_Byte flag ) + { + FT_Outline* outline = builder->current; + + + if ( builder->load_points ) + { + FT_Vector* point = outline->points + outline->n_points; + FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points; + + + point->x = x; + point->y = y; + *control = flag ? FT_Curve_Tag_On : FT_Curve_Tag_Cubic; + + builder->last = *point; + } + + outline->n_points++; + } + + + /* check space for a new on-curve point, then add it */ + static + FT_Error add_point1( CID_Builder* builder, + FT_Pos x, + FT_Pos y ) + { + FT_Error error; + + + error = check_points( builder, 1 ); + if ( !error ) + add_point( builder, x, y, 1 ); + + return error; + } + + + /* check room for a new contour, then add it */ + static + FT_Error add_contour( CID_Builder* builder ) + { + FT_Outline* outline = builder->current; + FT_Error error; + + + if ( !builder->load_points ) + { + outline->n_contours++; + return T1_Err_Ok; + } + + error = FT_GlyphLoader_Check_Points( builder->loader, 0, 1 ); + if ( !error ) + { + if ( outline->n_contours > 0 ) + outline->contours[outline->n_contours - 1] = outline->n_points - 1; + + outline->n_contours++; + } + return error; + } + + + /* if a path has been started, add its first on-curve point */ + static + FT_Error start_point( CID_Builder* builder, + FT_Pos x, + FT_Pos y ) + { + /* test whether we are building a new contour */ + if ( !builder->path_begun ) + { + FT_Error error; + + + builder->path_begun = 1; + error = add_contour( builder ); + if ( error ) + return error; + } + + return add_point1( builder, x, y ); + } + + + /* close the current contour */ + static + void close_contour( CID_Builder* builder ) + { + FT_Outline* outline = builder->current; + + + /* XXX: We must not include the last point in the path if it */ + /* is located on the first point. */ + if ( outline->n_points > 1 ) + { + FT_Int first = 0; + FT_Vector* p1 = outline->points + first; + FT_Vector* p2 = outline->points + outline->n_points - 1; + + + if ( outline->n_contours > 1 ) + { + first = outline->contours[outline->n_contours - 2] + 1; + p1 = outline->points + first; + } + + if ( p1->x == p2->x && p1->y == p2->y ) + outline->n_points--; + } + + if ( outline->n_contours > 0 ) + outline->contours[outline->n_contours - 1] = outline->n_points - 1; + } + + +#if 0 + + + /*************************************************************************/ + /* */ + /* */ + /* lookup_glyph_by_stdcharcode */ + /* */ + /* */ + /* Looks up a given glyph by its StandardEncoding charcode. Used */ + /* to implement the SEAC Type 1 operator. */ + /* */ + /* */ + /* face :: The current face object. */ + /* */ + /* charcode :: The character code to look for. */ + /* */ + /* */ + /* A glyph index in the font face. Returns -1 if the corresponding */ + /* glyph wasn't found. */ + /* */ + static + FT_Int lookup_glyph_by_stdcharcode( CID_Face face, + FT_Int charcode ) + { + FT_Int n; + const FT_String* glyph_name; + PSNames_Interface* psnames = (PSNames_Interface*)face->psnames; + + + /* check range of standard char code */ + if ( charcode < 0 || charcode > 255 ) + return -1; + + glyph_name = psnames->adobe_std_strings( + psnames->adobe_std_encoding[charcode]); + + for ( n = 0; n < face->cid.cid_count; n++ ) + { + FT_String* name = (FT_String*)face->type1.glyph_names[n]; + + + if ( name && strcmp( name, glyph_name ) == 0 ) + return n; + } + + return -1; + } + + +#endif /* 0 */ + + + /*************************************************************************/ + /* */ + /* */ + /* t1operator_seac */ + /* */ + /* */ + /* Implements the `seac' Type 1 operator for a Type 1 decoder. */ + /* */ + /* */ + /* decoder :: The current CID decoder. */ + /* */ + /* asb :: The accent's side bearing. */ + /* */ + /* adx :: The horizontal offset of the accent. */ + /* */ + /* ady :: The vertical offset of the accent. */ + /* */ + /* bchar :: The base character's StandardEncoding charcode. */ + /* */ + /* achar :: The accent character's StandardEncoding charcode. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + static + FT_Error t1operator_seac( CID_Decoder* decoder, + FT_Pos asb, + FT_Pos adx, + FT_Pos ady, + FT_Int bchar, + FT_Int achar ) + { + FT_Error error; + FT_Int bchar_index, achar_index, n_base_points; + FT_Outline* base = decoder->builder.base; + FT_Vector left_bearing, advance; + + + bchar_index = bchar; + achar_index = achar; + + if ( bchar_index < 0 || achar_index < 0 ) + { + FT_ERROR(( "t1operator_seac:" )); + FT_ERROR(( " invalid seac character code arguments\n" )); + return T1_Err_Syntax_Error; + } + + /* if we are trying to load a composite glyph, do not load the */ + /* accent character and return the array of subglyphs. */ + if ( decoder->builder.no_recurse ) + { + FT_GlyphSlot glyph = (FT_GlyphSlot)decoder->builder.glyph; + FT_GlyphLoader* loader = glyph->loader; + FT_SubGlyph* subg; + + + /* reallocate subglyph array if necessary */ + error = FT_GlyphLoader_Check_Subglyphs( loader, 2 ); + if ( error ) + goto Exit; + + subg = loader->current.subglyphs; + + /* subglyph 0 = base character */ + subg->index = bchar_index; + subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES | + FT_SUBGLYPH_FLAG_USE_MY_METRICS; + subg->arg1 = 0; + subg->arg2 = 0; + subg++; + + /* subglyph 1 = accent character */ + subg->index = achar_index; + subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES; + subg->arg1 = adx - asb; + subg->arg2 = ady; + + /* set up remaining glyph fields */ + glyph->num_subglyphs = 2; + glyph->subglyphs = loader->current.subglyphs; + glyph->format = ft_glyph_format_composite; + + loader->current.num_subglyphs = 2; + } + + /* First load `bchar' in builder */ + /* now load the unscaled outline */ + if ( decoder->builder.loader ) + FT_GlyphLoader_Prepare( decoder->builder.loader ); + + error = cid_load_glyph( decoder, bchar_index ); /* load one glyph */ + if ( error ) + goto Exit; + + n_base_points = base->n_points; + + { + /* save the left bearing and width of the base character */ + /* as they will be erased by the next load. */ + + left_bearing = decoder->builder.left_bearing; + advance = decoder->builder.advance; + + decoder->builder.left_bearing.x = 0; + decoder->builder.left_bearing.y = 0; + + /* Now load `achar' on top of */ + /* the base outline */ + error = cid_load_glyph( decoder, achar_index ); + if ( error ) + return error; + + /* restore the left side bearing and */ + /* advance width of the base character */ + + decoder->builder.left_bearing = left_bearing; + decoder->builder.advance = advance; + + /* Finally, move the accent */ + if ( decoder->builder.load_points ) + { + FT_Outline dummy; + + + dummy.n_points = base->n_points - n_base_points; + dummy.points = base->points + n_base_points; + FT_Outline_Translate( &dummy, adx - asb, ady ); + } + } + + Exit: + return error; + } + + +#define USE_ARGS( n ) do \ + { \ + top -= n; \ + if ( top < decoder->stack ) \ + goto Stack_Underflow; \ + } while ( 0 ) + + + /*************************************************************************/ + /* */ + /* */ + /* CID_Parse_CharStrings */ + /* */ + /* */ + /* Parses a given CID charstrings program. */ + /* */ + /* */ + /* decoder :: The current CID decoder. */ + /* */ + /* */ + /* charstring_base :: The base of the charstring stream. */ + /* */ + /* charstring_len :: The length in bytes of the charstring stream. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + LOCAL_FUNC + FT_Error CID_Parse_CharStrings( CID_Decoder* decoder, + FT_Byte* charstring_base, + FT_Int charstring_len ) + { + FT_Error error; + CID_Decoder_Zone* zone; + FT_Byte* ip; + FT_Byte* limit; + CID_Builder* builder = &decoder->builder; + FT_Outline* outline; + FT_Pos x, y; + + + /* First of all, initialize the decoder */ + decoder->top = decoder->stack; + decoder->zone = decoder->zones; + zone = decoder->zones; + + builder->path_begun = 0; + + zone->base = charstring_base; + limit = zone->limit = charstring_base + charstring_len; + ip = zone->cursor = zone->base; + + error = T1_Err_Ok; + outline = builder->current; + + x = builder->pos_x; + y = builder->pos_y; + + /* now, execute loop */ + while ( ip < limit ) + { + FT_Int* top = decoder->top; + CID_Operator op = op_none; + FT_Long value = 0; + + + /********************************************************************/ + /* */ + /* Decode operator or operand */ + /* */ + + /* First of all, decompress operator or value */ + switch ( *ip++ ) + { + case 1: + op = op_hstem; + break; + + case 3: + op = op_vstem; + break; + case 4: + op = op_vmoveto; + break; + case 5: + op = op_rlineto; + break; + case 6: + op = op_hlineto; + break; + case 7: + op = op_vlineto; + break; + case 8: + op = op_rrcurveto; + break; + case 9: + op = op_closepath; + break; + case 10: + op = op_callsubr; + break; + case 11: + op = op_return; + break; + + case 13: + op = op_hsbw; + break; + case 14: + op = op_endchar; + break; + + case 21: + op = op_rmoveto; + break; + case 22: + op = op_hmoveto; + break; + + case 30: + op = op_vhcurveto; + break; + case 31: + op = op_hvcurveto; + break; + + case 12: + if ( ip > limit ) + { + FT_ERROR(( "CID_Parse_CharStrings: invalid escape (12+EOF)\n" )); + goto Syntax_Error; + } + + switch ( *ip++ ) + { + case 0: + op = op_dotsection; + break; + case 1: + op = op_vstem3; + break; + case 2: + op = op_hstem3; + break; + case 6: + op = op_seac; + break; + case 7: + op = op_sbw; + break; + case 12: + op = op_div; + break; + case 16: + op = op_callothersubr; + break; + case 17: + op = op_pop; + break; + case 33: + op = op_setcurrentpoint; + break; + + default: + FT_ERROR(( "CID_Parse_CharStrings: invalid escape (12+%d)\n", + ip[-1] )); + goto Syntax_Error; + } + break; + + case 255: /* four bytes integer */ + if ( ip + 4 > limit ) + { + FT_ERROR(( "CID_Parse_CharStrings: unexpected EOF in integer\n" )); + goto Syntax_Error; + } + + value = ( (long)ip[0] << 24 ) | + ( (long)ip[1] << 16 ) | + ( (long)ip[2] << 8 ) | + ip[3]; + ip += 4; + break; + + default: + if ( ip[-1] >= 32 ) + { + if ( ip[-1] < 247 ) + value = (long)ip[-1] - 139; + else + { + if ( ++ip > limit ) + { + FT_ERROR(( "CID_Parse_CharStrings:" )); + FT_ERROR(( " unexpected EOF in integer\n" )); + goto Syntax_Error; + } + + if ( ip[-2] < 251 ) + value = ( (long)( ip[-2] - 247 ) << 8 ) + ip[-1] + 108; + else + value = -( ( ( (long)ip[-2] - 251 ) << 8 ) + ip[-1] + 108 ); + } + } + else + { + FT_ERROR(( "CID_Parse_CharStrings: invalid byte (%d)\n", + ip[-1] )); + goto Syntax_Error; + } + } + + /********************************************************************/ + /* */ + /* Push value on stack, or process operator */ + /* */ + if ( op == op_none ) + { + if ( top - decoder->stack >= T1_MAX_CHARSTRINGS_OPERANDS ) + { + FT_ERROR(( "CID_Parse_CharStrings: Stack overflow!\n" )); + goto Syntax_Error; + } + + FT_TRACE4(( " %ld", value )); + *top++ = value; + decoder->top = top; + } + else if ( op == op_callothersubr ) /* callothersubr */ + { + FT_TRACE4(( " callothersubr" )); + + if ( top - decoder->stack < 2 ) + goto Stack_Underflow; + + top -= 2; + switch ( top[1] ) + { + case 1: /* start flex feature ---------------------- */ + if ( top[0] != 0 ) + goto Unexpected_OtherSubr; + + decoder->flex_state = 1; + decoder->num_flex_vectors = 0; + if ( start_point( builder, x, y ) || + check_points( builder, 6 ) ) + goto Memory_Error; + break; + + case 2: /* add flex vectors ------------------------ */ + { + FT_Int index; + + + if ( top[0] != 0 ) + goto Unexpected_OtherSubr; + + /* note that we should not add a point for index 0. */ + /* this will move our current position to the flex */ + /* point without adding any point to the outline */ + index = decoder->num_flex_vectors++; + if ( index > 0 && index < 7 ) + add_point( builder, + x, + y, + (FT_Byte)( index==3 || index==6 ) ); + } + break; + + case 0: /* end flex feature ------------------------- */ + if ( top[0] != 3 ) + goto Unexpected_OtherSubr; + + if ( decoder->flex_state == 0 || + decoder->num_flex_vectors != 7 ) + { + FT_ERROR(( "CID_Parse_CharStrings: unexpected flex end\n" )); + goto Syntax_Error; + } + + /* now consume the remaining `pop pop setcurpoint' */ + if ( ip + 6 > limit || + ip[0] != 12 || ip[1] != 17 || /* pop */ + ip[2] != 12 || ip[3] != 17 || /* pop */ + ip[4] != 12 || ip[5] != 33 ) /* setcurpoint */ + { + FT_ERROR(( "CID_Parse_CharStrings: invalid flex charstring\n" )); + goto Syntax_Error; + } + + ip += 6; + decoder->flex_state = 0; + break; + + case 3: /* change hints ---------------------------- */ + if ( top[0] != 1 ) + goto Unexpected_OtherSubr; + + /* eat the following `pop' */ + if ( ip + 2 > limit ) + { + FT_ERROR(( "CID_Parse_CharStrings: invalid escape (12+%d)\n", + ip[-1] )); + goto Syntax_Error; + } + + if ( ip[0] != 12 || ip[1] != 17 ) + { + FT_ERROR(( "CID_Parse_CharStrings:" )); + FT_ERROR(( " `pop' expected, found (%d %d)\n", + ip[0], ip[1] )); + goto Syntax_Error; + } + ip += 2; + break; + + case 12: + case 13: + /* counter control hints, clear stack */ + top = decoder->stack; + break; + +#if 0 + + case 14: + case 15: + case 16: + case 17: + case 18: /* multiple masters */ + { + T1_Blend* blend = decoder->blend; + FT_UInt num_points, nn, mm; + FT_Int* delta; + FT_Int* values; + + + if ( !blend ) + { + FT_ERROR(( "CID_Parse_CharStrings:" )); + FT_ERROR(( " unexpected multiple masters operator!\n" )); + goto Syntax_Error; + } + + num_points = top[1] - 13 + ( top[1] == 18 ); + if ( top[0] != num_points * blend->num_designs ) + { + FT_ERROR(( "CID_Parse_CharStrings:" )); + FT_ERROR(( " incorrect number of mm arguments\n" )); + goto Syntax_Error; + } + + top -= blend->num_designs * num_points; + if ( top < decoder->stack ) + goto Stack_Underflow; + + /* We want to compute: */ + /* */ + /* a0*w0 + a1*w1 + ... + ak*wk */ + /* */ + /* but we only have the a0, a1-a0, a2-a0, .. ak-a0. */ + /* However, given that w0 + w1 + ... + wk == 1, we can */ + /* rewrite it easily as: */ + /* */ + /* a0 + (a1-a0)*w1 + (a2-a0)*w2 + .. + (ak-a0)*wk */ + /* */ + /* where k == num_designs-1 */ + /* */ + /* I guess that's why it's written in this `compact' */ + /* form... */ + /* */ + delta = top + num_points; + values = top; + for ( nn = 0; nn < num_points; nn++ ) + { + FT_Int x = values[0]; + + + for ( mm = 1; mm < blend->num_designs; mm++ ) + x += FT_MulFix( *delta++, blend->weight_vector[mm] ); + + *values++ = x; + } + /* note that `top' will be incremented later by calls to `pop' */ + } + break; + +#endif + + default: + Unexpected_OtherSubr: + FT_ERROR(( "CID_Parse_CharStrings: invalid othersubr [%d %d]!\n", + top[0], top[1] )); + goto Syntax_Error; + } + decoder->top = top; + } + else /* general operator */ + { + FT_Int num_args = t1_args_count[op]; + + + if ( top - decoder->stack < num_args ) + goto Stack_Underflow; + + top -= num_args; + + switch ( op ) + { + case op_endchar: + FT_TRACE4(( " endchar" )); + + close_contour( builder ); + + /* add current outline to the glyph slot */ + FT_GlyphLoader_Add( builder->loader ); + + /* return now! */ + FT_TRACE4(( "\n\n" )); + return T1_Err_Ok; + + case op_hsbw: + FT_TRACE4(( " hsbw" )); + + builder->left_bearing.x += top[0]; + builder->advance.x = top[1]; + builder->advance.y = 0; + + builder->last.x = x = top[0]; + builder->last.y = y = 0; + + /* The `metrics_only' indicates that we only want to compute */ + /* the glyph's metrics (lsb + advance width), not load the */ + /* rest of it. So exit immediately. */ + if ( builder->metrics_only ) + return T1_Err_Ok; + + break; + + case op_seac: + /* return immediately after processing */ + return t1operator_seac( decoder, top[0], top[1], + top[2], top[3], top[4] ); + + case op_sbw: + FT_TRACE4(( " sbw" )); + + builder->left_bearing.x += top[0]; + builder->left_bearing.y += top[1]; + builder->advance.x = top[2]; + builder->advance.y = top[3]; + + builder->last.x = x = top[0]; + builder->last.y = y = top[1]; + + /* The `metrics_only' indicates that we only want to compute */ + /* the glyph's metrics (lsb + advance width), not load the */ + /* rest of it. So exit immediately. */ + if ( builder->metrics_only ) + return T1_Err_Ok; + + break; + + case op_closepath: + FT_TRACE4(( " closepath" )); + + close_contour( builder ); + builder->path_begun = 0; + break; + + case op_hlineto: + FT_TRACE4(( " hlineto" )); + + if ( start_point( builder, x, y ) ) + goto Memory_Error; + + x += top[0]; + goto Add_Line; + + case op_hmoveto: + FT_TRACE4(( " hmoveto" )); + + x += top[0]; + break; + + case op_hvcurveto: + FT_TRACE4(( " hvcurveto" )); + + if ( start_point( builder, x, y ) || + check_points( builder, 3 ) ) + goto Memory_Error; + + x += top[0]; + add_point( builder, x, y, 0 ); + + x += top[1]; + y += top[2]; + add_point( builder, x, y, 0 ); + + y += top[3]; + add_point( builder, x, y, 1 ); + + break; + + case op_rlineto: + FT_TRACE4(( " rlineto" )); + + if ( start_point( builder, x, y ) ) + goto Memory_Error; + + x += top[0]; + y += top[1]; + + Add_Line: + if ( add_point1( builder, x, y ) ) + goto Memory_Error; + break; + + case op_rmoveto: + FT_TRACE4(( " rmoveto" )); + + x += top[0]; + y += top[1]; + break; + + case op_rrcurveto: + FT_TRACE4(( " rcurveto" )); + + if ( start_point( builder, x, y ) || + check_points( builder, 3 ) ) + goto Memory_Error; + + x += top[0]; + y += top[1]; + add_point( builder, x, y, 0 ); + + x += top[2]; + y += top[3]; + add_point( builder, x, y, 0 ); + + x += top[4]; + y += top[5]; + add_point( builder, x, y, 1 ); + + break; + + case op_vhcurveto: + FT_TRACE4(( " vhcurveto" )); + + if ( start_point( builder, x, y ) || + check_points( builder, 3 ) ) + goto Memory_Error; + + y += top[0]; + add_point( builder, x, y, 0 ); + + x += top[1]; + y += top[2]; + add_point( builder, x, y, 0 ); + + x += top[3]; + add_point( builder, x, y, 1 ); + + break; + + case op_vlineto: + FT_TRACE4(( " vlineto" )); + + if ( start_point( builder, x, y ) ) + goto Memory_Error; + + y += top[0]; + goto Add_Line; + + case op_vmoveto: + FT_TRACE4(( " vmoveto" )); + + y += top[0]; + break; + + case op_div: + FT_TRACE4(( " div" )); + + if ( top[1] ) + { + *top = top[0] / top[1]; + top++; + } + else + { + FT_ERROR(( "CID_Parse_CharStrings: division by 0\n" )); + goto Syntax_Error; + } + break; + + case op_callsubr: + { + FT_Int index; + + + FT_TRACE4(( " callsubr" )); + + index = top[0]; + if ( index < 0 || index >= (FT_Int)decoder->subrs->num_subrs ) + { + FT_ERROR(( "CID_Parse_CharStrings: invalid subrs index\n" )); + goto Syntax_Error; + } + + if ( zone - decoder->zones >= T1_MAX_SUBRS_CALLS ) + { + FT_ERROR(( "CID_Parse_CharStrings: too many nested subrs\n" )); + goto Syntax_Error; + } + + zone->cursor = ip; /* save current instruction pointer */ + + zone++; + zone->base = decoder->subrs->code[index] + decoder->lenIV; + zone->limit = decoder->subrs->code[index + 1]; + zone->cursor = zone->base; + + if ( !zone->base ) + { + FT_ERROR(( "CID_Parse_CharStrings: invoking empty subrs!\n" )); + goto Syntax_Error; + } + + decoder->zone = zone; + ip = zone->base; + limit = zone->limit; + } + break; + + case op_pop: + FT_TRACE4(( " pop" )); + + /* theoretically, the arguments are already on the stack */ + top++; + break; + + case op_return: + FT_TRACE4(( " return" )); + + if ( zone <= decoder->zones ) + { + FT_ERROR(( "CID_Parse_CharStrings: unexpected return\n" )); + goto Syntax_Error; + } + + zone--; + ip = zone->cursor; + limit = zone->limit; + decoder->zone = zone; + + break; + + case op_dotsection: + FT_TRACE4(( " dotsection" )); + + break; + + case op_hstem: + FT_TRACE4(( " hstem" )); + + break; + + case op_hstem3: + FT_TRACE4(( " hstem3" )); + + break; + + case op_vstem: + FT_TRACE4(( " vstem" )); + + break; + + case op_vstem3: + FT_TRACE4(( " vstem3" )); + + break; + + case op_setcurrentpoint: + FT_TRACE4(( " setcurrentpoint" )); + + FT_ERROR(( "CID_Parse_CharStrings:" )); + FT_ERROR(( " unexpected `setcurrentpoint'\n" )); + goto Syntax_Error; + + default: + FT_ERROR(( "CID_Parse_CharStrings: unhandled opcode %d\n", op )); + goto Syntax_Error; + } + + decoder->top = top; + + } /* general operator processing */ + + } /* while ip < limit */ + + FT_TRACE4(( "..end..\n\n" )); + + return error; + + Syntax_Error: + return T1_Err_Syntax_Error; + + Stack_Underflow: + return T1_Err_Stack_Underflow; + + Memory_Error: + return builder->error; + } + + +#if 0 + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /********** *********/ + /********** *********/ + /********** COMPUTE THE MAXIMUM ADVANCE WIDTH *********/ + /********** *********/ + /********** The following code is in charge of computing *********/ + /********** the maximum advance width of the font. It *********/ + /********** quickly processes each glyph charstring to *********/ + /********** extract the value from either a `sbw' or `seac' *********/ + /********** operator. *********/ + /********** *********/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + LOCAL_FUNC + FT_Error CID_Compute_Max_Advance( CID_Face face, + FT_Int* max_advance ) + { + FT_Error error; + CID_Decoder decoder; + FT_Int glyph_index; + + + *max_advance = 0; + + /* Initialize load decoder */ + CID_Init_Decoder( &decoder ); + CID_Init_Builder( &decoder.builder, face, 0, 0 ); + + decoder.builder.metrics_only = 1; + decoder.builder.load_points = 0; + + /* for each glyph, parse the glyph charstring and extract */ + /* the advance width */ + for ( glyph_index = 0; glyph_index < face->root.num_glyphs; + glyph_index++ ) + { + /* now get load the unscaled outline */ + error = cid_load_glyph( &decoder, glyph_index ); + /* ignore the error if one occurred - skip to next glyph */ + } + + *max_advance = decoder.builder.advance.x; + + return T1_Err_Ok; + } + + +#endif /* 0 */ + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /********** *********/ + /********** *********/ + /********** UNHINTED GLYPH LOADER *********/ + /********** *********/ + /********** The following code is in charge of loading a *********/ + /********** single outline. It completely ignores hinting *********/ + /********** and is used when FT_LOAD_NO_HINTING is set. *********/ + /********** *********/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + static + FT_Error cid_load_glyph( CID_Decoder* decoder, + FT_UInt glyph_index ) + { + CID_Face face = decoder->builder.face; + CID_Info* cid = &face->cid; + FT_Byte* p; + FT_UInt entry_len = cid->fd_bytes + cid->gd_bytes; + FT_UInt fd_select; + FT_ULong off1, glyph_len; + FT_Stream stream = face->root.stream; + FT_Error error = 0; + + + /* read the CID font dict index and charstring offset from the CIDMap */ + if ( FILE_Seek( cid->data_offset + cid->cidmap_offset + + glyph_index * entry_len) || + ACCESS_Frame( 2 * entry_len ) ) + goto Exit; + + p = (FT_Byte*)stream->cursor; + fd_select = (FT_UInt) cid_get_offset( &p, (FT_Byte)cid->fd_bytes ); + off1 = (FT_ULong)cid_get_offset( &p, (FT_Byte)cid->gd_bytes ); + p += cid->fd_bytes; + glyph_len = cid_get_offset( &p, (FT_Byte)cid->gd_bytes ) - off1; + + FORGET_Frame(); + + /* now, if the glyph is not empty, set up the subrs array, and parse */ + /* the charstrings */ + if ( glyph_len > 0 ) + { + CID_FontDict* dict; + FT_Byte* charstring; + FT_UInt lenIV; + FT_Memory memory = face->root.memory; + + + /* setup subrs */ + decoder->subrs = face->subrs + fd_select; + + /* setup font matrix */ + dict = cid->font_dicts + fd_select; + decoder->font_matrix = dict->font_matrix; + lenIV = dict->private_dict.lenIV; + decoder->lenIV = lenIV; + + /* the charstrings are encoded (stupid!) */ + /* load the charstrings, then execute it */ + + if ( ALLOC( charstring, glyph_len ) ) + goto Exit; + + if ( !FILE_Read_At( cid->data_offset + off1, charstring, glyph_len ) ) + { + cid_decrypt( charstring, glyph_len, 4330 ); + error = CID_Parse_CharStrings( decoder, + charstring + lenIV, + glyph_len - lenIV ); + } + + FREE( charstring ); + } + + Exit: + return error; + } + + + LOCAL_FUNC + FT_Error CID_Load_Glyph( CID_GlyphSlot glyph, + CID_Size size, + FT_Int glyph_index, + FT_Int load_flags ) + { + FT_Error error; + CID_Decoder decoder; + CID_Face face = (CID_Face)glyph->root.face; + FT_Bool hinting; + + + if ( load_flags & FT_LOAD_NO_RECURSE ) + load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING; + + glyph->x_scale = size->root.metrics.x_scale; + glyph->y_scale = size->root.metrics.y_scale; + + glyph->root.outline.n_points = 0; + glyph->root.outline.n_contours = 0; + + hinting = ( load_flags & FT_LOAD_NO_SCALE ) == 0 && + ( load_flags & FT_LOAD_NO_HINTING ) == 0; + + glyph->root.format = ft_glyph_format_outline; + + { + CID_Init_Decoder( &decoder ); + CID_Init_Builder( &decoder.builder, face, size, glyph ); + + /* set up the decoder */ + decoder.builder.no_recurse = + (FT_Bool)( load_flags & FT_LOAD_NO_RECURSE ); + + error = cid_load_glyph( &decoder, glyph_index ); + + /* save new glyph tables */ + CID_Done_Builder( &decoder.builder ); + } + + /* Now, set the metrics - this is rather simple, as */ + /* the left side bearing is the xMin, and the top side */ + /* bearing the yMax. */ + if ( !error ) + { + /* for composite glyphs, return only the left side bearing and the */ + /* advance width */ + if ( load_flags & FT_LOAD_NO_RECURSE ) + { + glyph->root.metrics.horiBearingX = decoder.builder.left_bearing.x; + glyph->root.metrics.horiAdvance = decoder.builder.advance.x; + } + else + { + FT_BBox cbox; + FT_Glyph_Metrics* metrics = &glyph->root.metrics; + + + /* copy the _unscaled_ advance width */ + metrics->horiAdvance = decoder.builder.advance.x; + + /* make up vertical metrics */ + metrics->vertBearingX = 0; + metrics->vertBearingY = 0; + metrics->vertAdvance = 0; + + glyph->root.format = ft_glyph_format_outline; + + glyph->root.outline.flags &= ft_outline_owner; + if ( size && size->root.metrics.y_ppem < 24 ) + glyph->root.outline.flags |= ft_outline_high_precision; + + glyph->root.outline.flags |= ft_outline_reverse_fill; + +#if 0 + glyph->root.outline.second_pass = TRUE; + glyph->root.outline.high_precision = size->root.metrics.y_ppem < 24; + glyph->root.outline.dropout_mode = 2; +#endif + + if ( ( load_flags & FT_LOAD_NO_SCALE ) == 0 ) + { + /* scale the outline and the metrics */ + FT_Int n; + FT_Outline* cur = &glyph->root.outline; + FT_Vector* vec = cur->points; + FT_Fixed x_scale = glyph->x_scale; + FT_Fixed y_scale = glyph->y_scale; + + + /* First of all, scale the points */ + for ( n = cur->n_points; n > 0; n--, vec++ ) + { + vec->x = FT_MulFix( vec->x, x_scale ); + vec->y = FT_MulFix( vec->y, y_scale ); + } + + FT_Outline_Get_CBox( &glyph->root.outline, &cbox ); + + /* Then scale the metrics */ + metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale ); + metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale ); + + metrics->vertBearingX = FT_MulFix( metrics->vertBearingX, x_scale ); + metrics->vertBearingY = FT_MulFix( metrics->vertBearingY, y_scale ); + } + + /* apply the font matrix */ + FT_Outline_Transform( &glyph->root.outline, &decoder.font_matrix ); + + /* compute the other metrics */ + FT_Outline_Get_CBox( &glyph->root.outline, &cbox ); + + /* grid fit the bounding box if necessary */ + if ( hinting ) + { + cbox.xMin &= -64; + cbox.yMin &= -64; + cbox.xMax = ( cbox.xMax + 63 ) & -64; + cbox.yMax = ( cbox.yMax + 63 ) & -64; + } + + metrics->width = cbox.xMax - cbox.xMin; + metrics->height = cbox.yMax - cbox.yMin; + + metrics->horiBearingX = cbox.xMin; + metrics->horiBearingY = cbox.yMax; + } + } + + return error; + } + + +/* END */ diff --git a/src/freetype/cid/cidgload.h b/src/freetype/cid/cidgload.h new file mode 100644 index 0000000000..5f3913d527 --- /dev/null +++ b/src/freetype/cid/cidgload.h @@ -0,0 +1,198 @@ +/***************************************************************************/ +/* */ +/* cidgload.h */ +/* */ +/* OpenType Glyph Loader (specification). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef CIDGLOAD_H +#define CIDGLOAD_H + + +#ifdef FT_FLAT_COMPILE + +#include "cidobjs.h" + +#else + +#include + +#endif + + +#ifdef __cplusplus + extern "C" { +#endif + + + /*************************************************************************/ + /* */ + /* */ + /* CID_Builder */ + /* */ + /* */ + /* A structure used during glyph loading to store its outline. */ + /* */ + /* */ + /* memory :: The current memory object. */ + /* */ + /* face :: The current face object. */ + /* */ + /* glyph :: The current glyph slot. */ + /* */ + /* current :: The current glyph outline. */ + /* */ + /* base :: The base glyph outline. */ + /* */ + /* max_points :: maximum points in builder outline */ + /* */ + /* max_contours :: Maximal number of contours in builder outline. */ + /* */ + /* last :: The last point position. */ + /* */ + /* scale_x :: The horizontal scale (FUnits to sub-pixels). */ + /* */ + /* scale_y :: The vertical scale (FUnits to sub-pixels). */ + /* */ + /* pos_x :: The horizontal translation (if composite glyph). */ + /* */ + /* pos_y :: The vertical translation (if composite glyph). */ + /* */ + /* left_bearing :: The left side bearing point. */ + /* */ + /* advance :: The horizontal advance vector. */ + /* */ + /* bbox :: Unused. */ + /* */ + /* path_begun :: A flag which indicates that a new path has begun. */ + /* */ + /* load_points :: If this flag is not set, no points are loaded. */ + /* */ + /* no_recurse :: Set but not used. */ + /* */ + /* error :: An error code that is only used to report memory */ + /* allocation problems. */ + /* */ + /* metrics_only :: A boolean indicating that we only want to compute */ + /* the metrics of a given glyph, not load all of its */ + /* points. */ + /* */ + typedef struct CID_Builder_ + { + FT_Memory memory; + CID_Face face; + CID_GlyphSlot glyph; + FT_GlyphLoader* loader; + FT_Outline* base; + FT_Outline* current; + + FT_Vector last; + + FT_Fixed scale_x; + FT_Fixed scale_y; + + FT_Pos pos_x; + FT_Pos pos_y; + + FT_Vector left_bearing; + FT_Vector advance; + + FT_BBox bbox; /* bounding box */ + FT_Bool path_begun; + FT_Bool load_points; + FT_Bool no_recurse; + + FT_Error error; /* only used for memory errors */ + FT_Bool metrics_only; + + } CID_Builder; + + + /* execution context charstring zone */ + + typedef struct CID_Decoder_Zone_ + { + FT_Byte* base; + FT_Byte* limit; + FT_Byte* cursor; + + } CID_Decoder_Zone; + + + typedef struct CID_Decoder_ + { + CID_Builder builder; + + FT_Int stack[T1_MAX_CHARSTRINGS_OPERANDS]; + FT_Int* top; + + CID_Decoder_Zone zones[T1_MAX_SUBRS_CALLS + 1]; + CID_Decoder_Zone* zone; + + FT_Matrix font_matrix; + CID_Subrs* subrs; + FT_UInt lenIV; + + FT_Int flex_state; + FT_Int num_flex_vectors; + FT_Vector flex_vectors[7]; + + } CID_Decoder; + + + LOCAL_DEF + void CID_Init_Builder( CID_Builder* builder, + CID_Face face, + CID_Size size, + CID_GlyphSlot glyph ); + + LOCAL_DEF + void CID_Done_Builder( CID_Builder* builder ); + + + LOCAL_DEF + void CID_Init_Decoder( CID_Decoder* decoder ); + + +#if 0 + + /* Compute the maximum advance width of a font through quick parsing */ + LOCAL_DEF + FT_Error CID_Compute_Max_Advance( CID_Face face, + FT_Int* max_advance ); + +#endif + + /* This function is exported, because it is used by the T1Dump utility */ + LOCAL_DEF + FT_Error CID_Parse_CharStrings( CID_Decoder* decoder, + FT_Byte* charstring_base, + FT_Int charstring_len ); + + LOCAL_DEF + FT_Error CID_Load_Glyph( CID_GlyphSlot glyph, + CID_Size size, + FT_Int glyph_index, + FT_Int load_flags ); + + +#ifdef __cplusplus + } +#endif + + +#endif /* CIDGLOAD_H */ + + +/* END */ diff --git a/src/freetype/cid/cidload.c b/src/freetype/cid/cidload.c new file mode 100644 index 0000000000..1f7c7aea01 --- /dev/null +++ b/src/freetype/cid/cidload.c @@ -0,0 +1,537 @@ +/***************************************************************************/ +/* */ +/* cidload.c */ +/* */ +/* CID-keyed Type1 font loader (body). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#include +#include +#include + +#include +#include + + +#ifdef FT_FLAT_COMPILE + +#include "cidload.h" + +#else + +#include + +#endif + + +#include +#include /* for isspace(), isalnum() */ + + + /*************************************************************************/ + /* */ + /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ + /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ + /* messages during execution. */ + /* */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_cidload + + + /* read a single offset */ + LOCAL_FUNC + FT_Long cid_get_offset( FT_Byte** start, + FT_Byte offsize ) + { + FT_Long result; + FT_Byte* p = *start; + + + for ( result = 0; offsize > 0; offsize-- ) + { + result <<= 8; + result |= *p++; + } + + *start = p; + return result; + } + + + LOCAL_FUNC + void cid_decrypt( FT_Byte* buffer, + FT_Int length, + FT_UShort seed ) + { + while ( length > 0 ) + { + FT_Byte plain; + + + plain = ( *buffer ^ ( seed >> 8 ) ); + seed = ( *buffer + seed ) * 52845 + 22719; + *buffer++ = plain; + length--; + } + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** TYPE 1 SYMBOL PARSING *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + static + FT_Error cid_load_keyword( CID_Face face, + CID_Loader* loader, + const CID_Field_Rec* keyword ) + { + FT_Error error; + CID_Parser* parser = &loader->parser; + FT_Byte* object; + CID_Info* cid = &face->cid; + + + /* if the keyword has a dedicated callback, call it */ + if ( keyword->type == t1_field_callback ) + { + error = keyword->reader( face, parser ); + goto Exit; + } + + /* we must now compute the address of our target object */ + switch ( keyword->location ) + { + case t1_field_cid_info: + object = (FT_Byte*)cid; + break; + + case t1_field_font_info: + object = (FT_Byte*)&cid->font_info; + break; + + default: + { + CID_FontDict* dict; + + + if ( parser->num_dict < 0 ) + { + FT_ERROR(( "cid_load_keyword: invalid use of `%s'!\n", + keyword->ident )); + error = T1_Err_Syntax_Error; + goto Exit; + } + + dict = cid->font_dicts + parser->num_dict; + switch ( keyword->location ) + { + case t1_field_private: + object = (FT_Byte*)&dict->private_dict; + break; + + default: + object = (FT_Byte*)dict; + } + } + } + + /* now, load the keyword data in the object's field(s) */ + if ( keyword->type == t1_field_integer_array || + keyword->type == t1_field_fixed_array ) + error = CID_Load_Field_Table( parser, keyword, object ); + else + error = CID_Load_Field( parser, keyword, object ); + + Exit: + return error; + } + + + static + FT_Error parse_font_bbox( CID_Face face, + CID_Parser* parser ) + { + FT_Short temp[4]; + FT_BBox* bbox = &face->cid.font_bbox; + + + (void)CID_ToCoordArray( parser, 4, temp ); + bbox->xMin = temp[0]; + bbox->yMin = temp[1]; + bbox->xMax = temp[2]; + bbox->yMax = temp[3]; + + return T1_Err_Ok; /* this is a callback function; */ + /* we must return an error code */ + } + + + static + FT_Error parse_font_matrix( CID_Face face, + CID_Parser* parser ) + { + FT_Matrix* matrix; + CID_FontDict* dict; + FT_Fixed temp[4]; + + + if ( parser->num_dict >= 0 ) + { + dict = face->cid.font_dicts + parser->num_dict; + matrix = &dict->font_matrix; + + (void)CID_ToFixedArray( parser, 4, temp, 3 ); + matrix->xx = temp[0]; + matrix->yx = temp[1]; + matrix->xy = temp[2]; + matrix->yy = temp[3]; + } + + return T1_Err_Ok; /* this is a callback function; */ + /* we must return an error code */ + } + + + static + FT_Error parse_fd_array( CID_Face face, + CID_Parser* parser ) + { + CID_Info* cid = &face->cid; + FT_Memory memory = face->root.memory; + FT_Error error = T1_Err_Ok; + FT_Long num_dicts; + + + num_dicts = CID_ToInt( parser ); + + if ( !cid->font_dicts ) + { + FT_Int n; + + + if ( ALLOC_ARRAY( cid->font_dicts, num_dicts, CID_FontDict ) ) + goto Exit; + + cid->num_dicts = (FT_UInt)num_dicts; + + /* don't forget to set a few defaults */ + for ( n = 0; n < cid->num_dicts; n++ ) + { + CID_FontDict* dict = cid->font_dicts + n; + + + /* default value for lenIV */ + dict->private_dict.lenIV = 4; + } + } + + Exit: + return error; + } + + + static + const CID_Field_Rec t1_field_records[] = + { + +#ifdef FT_FLAT_COMPILE + +#include "cidtokens.h" + +#else + +#include + +#endif + + { 0, t1_field_cid_info, t1_field_none, 0, 0, 0, 0, 0 } + }; + + + static + int is_alpha( char c ) + { + return ( isalnum( c ) || + c == '.' || + c == '_' ); + } + + + static + void skip_whitespace( CID_Parser* parser ) + { + FT_Byte* cur = parser->cursor; + + + while ( cur < parser->limit && isspace( *cur ) ) + cur++; + + parser->cursor = cur; + } + + + static + FT_Error parse_dict( CID_Face face, + CID_Loader* loader, + FT_Byte* base, + FT_Long size ) + { + CID_Parser* parser = &loader->parser; + + + parser->cursor = base; + parser->limit = base + size; + parser->error = 0; + + { + FT_Byte* cur = base; + FT_Byte* limit = cur + size; + + + for ( ;cur < limit; cur++ ) + { + /* look for `%ADOBeginFontDict' */ + if ( *cur == '%' && cur + 20 < limit && + strncmp( (char*)cur, "%ADOBeginFontDict", 17 ) == 0 ) + { + cur += 17; + + /* if /FDArray was found, then cid->num_dicts is > 0, and */ + /* we can start increasing parser->num_dict */ + if ( face->cid.num_dicts > 0 ) + parser->num_dict++; + } + /* look for immediates */ + else if ( *cur == '/' && cur + 2 < limit ) + { + FT_Byte* cur2; + FT_Int len; + + + cur++; + + cur2 = cur; + while ( cur2 < limit && is_alpha( *cur2 ) ) + cur2++; + + len = cur2 - cur; + if ( len > 0 && len < 22 ) + { + /* now compare the immediate name to the keyword table */ + const CID_Field_Rec* keyword = t1_field_records; + + + for (;;) + { + FT_Byte* name; + + + name = (FT_Byte*)keyword->ident; + if ( !name ) + break; + + if ( cur[0] == name[0] && + len == (FT_Int)strlen( (const char*)name ) ) + { + FT_Int n; + + + for ( n = 1; n < len; n++ ) + if ( cur[n] != name[n] ) + break; + + if ( n >= len ) + { + /* we found it - run the parsing callback */ + parser->cursor = cur2; + skip_whitespace( parser ); + parser->error = cid_load_keyword( face, loader, keyword ); + if ( parser->error ) + return parser->error; + + cur = parser->cursor; + break; + } + } + keyword++; + } + } + } + } + } + return parser->error; + } + + + /* read the subrmap and the subrs of each font dict */ + static + FT_Error cid_read_subrs( CID_Face face ) + { + CID_Info* cid = &face->cid; + FT_Memory memory = face->root.memory; + FT_Stream stream = face->root.stream; + FT_Error error; + FT_Int n; + CID_Subrs* subr; + FT_UInt max_offsets = 0; + FT_ULong* offsets = 0; + + + if ( ALLOC_ARRAY( face->subrs, cid->num_dicts, CID_Subrs ) ) + goto Exit; + + subr = face->subrs; + for ( n = 0; n < cid->num_dicts; n++, subr++ ) + { + CID_FontDict* dict = cid->font_dicts + n; + FT_UInt count, num_subrs = dict->num_subrs; + FT_ULong data_len; + FT_Byte* p; + + + /* reallocate offsets array if needed */ + if ( num_subrs + 1 > max_offsets ) + { + FT_UInt new_max = ( num_subrs + 1 + 3 ) & -4; + + + if ( REALLOC_ARRAY( offsets, max_offsets, new_max, FT_ULong ) ) + goto Fail; + + max_offsets = new_max; + } + + /* read the subrmap's offsets */ + if ( FILE_Seek( cid->data_offset + dict->subrmap_offset ) || + ACCESS_Frame( ( num_subrs + 1 ) * dict->sd_bytes ) ) + goto Fail; + + p = (FT_Byte*)stream->cursor; + for ( count = 0; count <= num_subrs; count++ ) + offsets[count] = cid_get_offset( &p, (FT_Byte)dict->sd_bytes ); + + FORGET_Frame(); + + /* now, compute the size of subrs charstrings, */ + /* allocate, and read them */ + data_len = offsets[num_subrs] - offsets[0]; + + if ( ALLOC_ARRAY( subr->code, num_subrs + 1, FT_Byte* ) || + ALLOC( subr->code[0], data_len ) ) + goto Fail; + + if ( FILE_Seek( cid->data_offset + offsets[0] ) || + FILE_Read( subr->code[0], data_len ) ) + goto Exit; + + /* set up pointers */ + for ( count = 1; count <= num_subrs; count++ ) + { + FT_UInt len; + + + len = offsets[count] - offsets[count - 1]; + subr->code[count] = subr->code[count - 1] + len; + } + + /* decrypt subroutines */ + for ( count = 0; count < num_subrs; count++ ) + { + FT_UInt len; + + + len = offsets[count + 1] - offsets[count]; + cid_decrypt( subr->code[count], len, 4330 ); + } + + subr->num_subrs = num_subrs; + } + + Exit: + FREE( offsets ); + return error; + + Fail: + if ( face->subrs ) + { + for ( n = 0; n < cid->num_dicts; n++ ) + { + if ( face->subrs[n].code ) + FREE( face->subrs[n].code[0] ); + + FREE( face->subrs[n].code ); + } + FREE( face->subrs ); + } + goto Exit; + } + + + static + void t1_init_loader( CID_Loader* loader, + CID_Face face ) + { + FT_UNUSED( face ); + + MEM_Set( loader, 0, sizeof ( *loader ) ); + } + + + static + void t1_done_loader( CID_Loader* loader ) + { + CID_Parser* parser = &loader->parser; + + + /* finalize parser */ + CID_Done_Parser( parser ); + } + + + LOCAL_FUNC + FT_Error CID_Open_Face( CID_Face face ) + { + CID_Loader loader; + CID_Parser* parser; + FT_Error error; + + + t1_init_loader( &loader, face ); + + parser = &loader.parser; + error = CID_New_Parser( parser, face->root.stream, face->root.memory ); + if ( error ) + goto Exit; + + error = parse_dict( face, &loader, + parser->postscript, + parser->postscript_len ); + if ( error ) + goto Exit; + + face->cid.data_offset = loader.parser.data_offset; + error = cid_read_subrs( face ); + + Exit: + t1_done_loader( &loader ); + return error; + } + + +/* END */ diff --git a/src/freetype/cid/cidload.h b/src/freetype/cid/cidload.h new file mode 100644 index 0000000000..7495da0dc1 --- /dev/null +++ b/src/freetype/cid/cidload.h @@ -0,0 +1,70 @@ +/***************************************************************************/ +/* */ +/* cidload.h */ +/* */ +/* CID-keyed Type1 font loader (specification). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef CIDLOAD_H +#define CIDLOAD_H + +#include + + +#ifdef FT_FLAT_COMPILE + +#include "cidparse.h" + +#else + +#include + +#endif + + +#ifdef __cplusplus + extern "C" { +#endif + + + typedef struct CID_Loader_ + { + CID_Parser parser; /* parser used to read the stream */ + FT_Int num_chars; /* number of characters in encoding */ + + } CID_Loader; + + + LOCAL_DEF + FT_Long cid_get_offset( FT_Byte** start, + FT_Byte offsize ); + + LOCAL_DEF + void cid_decrypt( FT_Byte* buffer, + FT_Int length, + FT_UShort seed ); + + LOCAL_DEF + FT_Error CID_Open_Face( CID_Face face ); + + +#ifdef __cplusplus + } +#endif + + +#endif /* CIDLOAD_H */ + + +/* END */ diff --git a/src/freetype/cid/cidobjs.c b/src/freetype/cid/cidobjs.c new file mode 100644 index 0000000000..a75567b6bf --- /dev/null +++ b/src/freetype/cid/cidobjs.c @@ -0,0 +1,380 @@ +/***************************************************************************/ +/* */ +/* cidobjs.c */ +/* */ +/* CID objects manager (body). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#include +#include + + +#ifdef FT_FLAT_COMPILE + +#include "cidgload.h" +#include "cidload.h" + +#else + +#include +#include + +#endif + + +#include + + + /*************************************************************************/ + /* */ + /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ + /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ + /* messages during execution. */ + /* */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_cidobjs + + + /*************************************************************************/ + /* */ + /* FACE FUNCTIONS */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* */ + /* CID_Done_Face */ + /* */ + /* */ + /* Finalizes a given face object. */ + /* */ + /* */ + /* face :: A pointer to the face object to destroy. */ + /* */ + LOCAL_FUNC + void CID_Done_Face( CID_Face face ) + { + FT_Memory memory; + + + if ( face ) + { + CID_Info* cid = &face->cid; + T1_FontInfo* info = &cid->font_info; + + + memory = face->root.memory; + + /* release FontInfo strings */ + FREE( info->version ); + FREE( info->notice ); + FREE( info->full_name ); + FREE( info->family_name ); + FREE( info->weight ); + + /* release font dictionaries */ + FREE( cid->font_dicts ); + cid->num_dicts = 0; + + /* release other strings */ + FREE( cid->cid_font_name ); + FREE( cid->registry ); + FREE( cid->ordering ); + + face->root.family_name = 0; + face->root.style_name = 0; + } + } + + + /*************************************************************************/ + /* */ + /* */ + /* CID_Init_Face */ + /* */ + /* */ + /* Initializes a given CID face object. */ + /* */ + /* */ + /* stream :: The source font stream. */ + /* */ + /* face_index :: The index of the font face in the resource. */ + /* */ + /* num_params :: Number of additional generic parameters. Ignored. */ + /* */ + /* params :: Additional generic parameters. Ignored. */ + /* */ + /* */ + /* face :: The newly built face object. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + LOCAL_FUNC + FT_Error CID_Init_Face( FT_Stream stream, + CID_Face face, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ) + { + FT_Error error; + PSNames_Interface* psnames; + + FT_UNUSED( num_params ); + FT_UNUSED( params ); + FT_UNUSED( face_index ); + FT_UNUSED( stream ); + + + face->root.num_faces = 1; + + psnames = (PSNames_Interface*)face->psnames; + if ( !psnames ) + { + psnames = (PSNames_Interface*)FT_Get_Module_Interface( + FT_FACE_LIBRARY( face ), "psnames" ); + + face->psnames = psnames; + } + + /* open the tokenizer; this will also check the font format */ + if ( FILE_Seek( 0 ) ) + goto Exit; + + error = CID_Open_Face( face ); + if ( error ) + goto Exit; + + /* if we just wanted to check the format, leave successfully now */ + if ( face_index < 0 ) + goto Exit; + + /* check the face index */ + if ( face_index != 0 ) + { + FT_ERROR(( "CID_Init_Face: invalid face index\n" )); + error = T1_Err_Invalid_Argument; + goto Exit; + } + + /* Now, load the font program into the face object */ + { + /* Init the face object fields */ + /* Now set up root face fields */ + { + FT_Face root = (FT_Face)&face->root; + + + root->num_glyphs = face->cid.cid_count; + root->num_charmaps = 0; + + root->face_index = face_index; + root->face_flags = FT_FACE_FLAG_SCALABLE; + + root->face_flags |= FT_FACE_FLAG_HORIZONTAL; + + if ( face->cid.font_info.is_fixed_pitch ) + root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH; + + /* XXX: TODO: add kerning with .afm support */ + + /* get style name -- be careful, some broken fonts only */ + /* have a /FontName dictionary entry! */ + root->family_name = face->cid.font_info.family_name; + if ( root->family_name ) + { + char* full = face->cid.font_info.full_name; + char* family = root->family_name; + + while ( *family && *full == *family ) + { + family++; + full++; + } + + root->style_name = ( *full == ' ' ) ? full + 1 + : (char *)"Regular"; + } + else + { + /* do we have a `/FontName'? */ + if ( face->cid.cid_font_name ) + { + root->family_name = face->cid.cid_font_name; + root->style_name = "Regular"; + } + } + + /* no embedded bitmap support */ + root->num_fixed_sizes = 0; + root->available_sizes = 0; + + root->bbox = face->cid.font_bbox; + root->units_per_EM = 1000; + root->ascender = (FT_Short)face->cid.font_bbox.yMax; + root->descender = -(FT_Short)face->cid.font_bbox.yMin; + root->height = ( ( root->ascender + root->descender ) * 12 ) + / 10; + + +#if 0 + + /* now compute the maximum advance width */ + + root->max_advance_width = face->type1.private_dict.standard_width[0]; + + /* compute max advance width for proportional fonts */ + if ( !face->type1.font_info.is_fixed_pitch ) + { + FT_Int max_advance; + + + error = CID_Compute_Max_Advance( face, &max_advance ); + + /* in case of error, keep the standard width */ + if ( !error ) + root->max_advance_width = max_advance; + else + error = 0; /* clear error */ + } + + root->max_advance_height = root->height; + +#endif /* 0 */ + + root->underline_position = face->cid.font_info.underline_position; + root->underline_thickness = face->cid.font_info.underline_thickness; + + root->max_points = 0; + root->max_contours = 0; + } + } + +#if 0 + + /* charmap support - synthetize unicode charmap when possible */ + { + FT_Face root = &face->root; + FT_CharMap charmap = face->charmaprecs; + + + /* synthesize a Unicode charmap if there is support in the `psnames' */ + /* module */ + if ( face->psnames ) + { + PSNames_Interface* psnames = (PSNames_Interface*)face->psnames; + + + if ( psnames->unicode_value ) + { + error = psnames->build_unicodes( + root->memory, + face->type1.num_glyphs, + (const char**)face->type1.glyph_names, + &face->unicode_map ); + if ( !error ) + { + root->charmap = charmap; + charmap->face = (FT_Face)face; + charmap->encoding = ft_encoding_unicode; + charmap->platform_id = 3; + charmap->encoding_id = 1; + charmap++; + } + + /* simply clear the error in case of failure (which really */ + /* means that out of memory or no unicode glyph names) */ + error = 0; + } + } + + /* now, support either the standard, expert, or custom encodings */ + charmap->face = (FT_Face)face; + charmap->platform_id = 7; /* a new platform id for Adobe fonts? */ + + switch ( face->type1.encoding_type ) + { + case t1_encoding_standard: + charmap->encoding = ft_encoding_adobe_standard; + charmap->encoding_id = 0; + break; + + case t1_encoding_expert: + charmap->encoding = ft_encoding_adobe_expert; + charmap->encoding_id = 1; + break; + + default: + charmap->encoding = ft_encoding_adobe_custom; + charmap->encoding_id = 2; + break; + } + + root->charmaps = face->charmaps; + root->num_charmaps = charmap - face->charmaprecs + 1; + face->charmaps[0] = &face->charmaprecs[0]; + face->charmaps[1] = &face->charmaprecs[1]; + } + +#endif /* 0 */ + + Exit: + return error; + } + + + /*************************************************************************/ + /* */ + /* */ + /* CID_Init_Driver */ + /* */ + /* */ + /* Initializes a given CID driver object. */ + /* */ + /* */ + /* driver :: A handle to the target driver object. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + LOCAL_FUNC + FT_Error CID_Init_Driver( CID_Driver driver ) + { + FT_UNUSED( driver ); + + return T1_Err_Ok; + } + + + /*************************************************************************/ + /* */ + /* */ + /* CID_Done_Driver */ + /* */ + /* */ + /* Finalizes a given CID driver. */ + /* */ + /* */ + /* driver :: A handle to the target CID driver. */ + /* */ + LOCAL_DEF + void CID_Done_Driver( CID_Driver driver ) + { + FT_UNUSED( driver ); + } + + +/* END */ diff --git a/src/freetype/cid/cidobjs.h b/src/freetype/cid/cidobjs.h new file mode 100644 index 0000000000..c28c59be25 --- /dev/null +++ b/src/freetype/cid/cidobjs.h @@ -0,0 +1,141 @@ +/***************************************************************************/ +/* */ +/* cidobjs.h */ +/* */ +/* CID objects manager (specification). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef CIDOBJS_H +#define CIDOBJS_H + +#include +#include +#include +#include + + +#ifdef __cplusplus + extern "C" { +#endif + + + /* The following structures must be defined by the hinter */ + typedef struct CID_Size_Hints_ CID_Size_Hints; + typedef struct CID_Glyph_Hints_ CID_Glyph_Hints; + + + /*************************************************************************/ + /* */ + /* */ + /* CID_Driver */ + /* */ + /* */ + /* A handle to a Type 1 driver object. */ + /* */ + typedef struct CID_DriverRec_* CID_Driver; + + + /*************************************************************************/ + /* */ + /* */ + /* CID_Size */ + /* */ + /* */ + /* A handle to a Type 1 size object. */ + /* */ + typedef struct CID_SizeRec_* CID_Size; + + + /*************************************************************************/ + /* */ + /* */ + /* CID_GlyphSlot */ + /* */ + /* */ + /* A handle to a Type 1 glyph slot object. */ + /* */ + typedef struct CID_GlyphSlotRec_* CID_GlyphSlot; + + + /*************************************************************************/ + /* */ + /* */ + /* CID_CharMap */ + /* */ + /* */ + /* A handle to a Type 1 character mapping object. */ + /* */ + /* */ + /* The Type 1 format doesn't use a charmap but an encoding table. */ + /* The driver is responsible for making up charmap objects */ + /* corresponding to these tables. */ + /* */ + typedef struct CID_CharMapRec_* CID_CharMap; + + + /*************************************************************************/ + /* */ + /* HERE BEGINS THE TYPE 1 SPECIFIC STUFF */ + /* */ + /*************************************************************************/ + + + typedef struct CID_SizeRec_ + { + FT_SizeRec root; + FT_Bool valid; + + } CID_SizeRec; + + + typedef struct CID_GlyphSlotRec_ + { + FT_GlyphSlotRec root; + + FT_Bool hint; + FT_Bool scaled; + + FT_Fixed x_scale; + FT_Fixed y_scale; + + } CID_GlyphSlotRec; + + + LOCAL_DEF + FT_Error CID_Init_Face( FT_Stream stream, + CID_Face face, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ); + + LOCAL_DEF + void CID_Done_Face( CID_Face face ); + + + LOCAL_DEF + FT_Error CID_Init_Driver( CID_Driver driver ); + + LOCAL_DEF + void CID_Done_Driver( CID_Driver driver ); + + +#ifdef __cplusplus + } +#endif + + +#endif /* CIDOBJS_H */ + + +/* END */ diff --git a/src/freetype/cid/cidparse.c b/src/freetype/cid/cidparse.c new file mode 100644 index 0000000000..33d3d8af3c --- /dev/null +++ b/src/freetype/cid/cidparse.c @@ -0,0 +1,1024 @@ +/***************************************************************************/ +/* */ +/* cidparse.c */ +/* */ +/* CID-keyed Type1 parser (body). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#include +#include +#include +#include +#include + + +#ifdef FT_FLAT_COMPILE + +#include "cidparse.h" + +#else + +#include + +#endif + + +#include /* for strncmp() */ + + + /*************************************************************************/ + /* */ + /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ + /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ + /* messages during execution. */ + /* */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_cidparse + + +#if 0 + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** IMPLEMENTATION OF CID_TABLE OBJECT *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* */ + /* CID_New_Table */ + /* */ + /* */ + /* Initializes a CID_Table. */ + /* */ + /* */ + /* table :: The address of the target table. */ + /* */ + /* */ + /* count :: The table size, i.e., the maximal number of elements. */ + /* */ + /* memory :: The memory object to be used for all subsequent */ + /* reallocations. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + LOCAL_FUNC + FT_Error CID_New_Table( CID_Table* table, + FT_Int count, + FT_Memory memory ) + { + FT_Error error; + + + table->memory = memory; + if ( ALLOC_ARRAY( table->elements, count, FT_Byte* ) || + ALLOC_ARRAY( table->lengths, count, FT_Byte* ) ) + goto Exit; + + table->max_elems = count; + table->init = 0xDEADBEEFL; + table->num_elems = 0; + table->block = 0; + table->capacity = 0; + table->cursor = 0; + + Exit: + if ( error ) + FREE( table->elements ); + + return error; + } + + + static + void shift_elements( CID_Table* table, + FT_Byte* old_base ) + { + FT_Long delta = table->block - old_base; + FT_Byte** offset = table->elements; + FT_Byte** limit = offset + table->max_elems; + + + if ( delta ) + for ( ; offset < limit; offset++ ) + { + if ( offset[0] ) + offset[0] += delta; + } + } + + + static + FT_Error reallocate_t1_table( CID_Table* table, + FT_Int new_size ) + { + FT_Memory memory = table->memory; + FT_Byte* old_base = table->block; + FT_Error error; + + + /* realloc the base block */ + if ( REALLOC( table->block, table->capacity, new_size ) ) + return error; + + table->capacity = new_size; + + /* shift all offsets when needed */ + if ( old_base ) + shift_elements( table, old_base ); + + return T1_Err_Ok; + } + + + /*************************************************************************/ + /* */ + /* */ + /* CID_Add_Table */ + /* */ + /* */ + /* Adds an object to a CID_Table, possibly growing its memory block. */ + /* */ + /* */ + /* table :: The target table. */ + /* */ + /* */ + /* index :: The index of the object in the table. */ + /* */ + /* object :: The address of the object to copy in the memory. */ + /* */ + /* length :: The length in bytes of the source object. */ + /* */ + /* */ + /* FreeType error code. 0 means success. An error is returned if */ + /* reallocation fails. */ + /* */ + LOCAL_FUNC + FT_Error CID_Add_Table( CID_Table* table, + FT_Int index, + void* object, + FT_Int length ) + { + if ( index < 0 || index > table->max_elems ) + { + FT_ERROR(( "CID_Add_Table: invalid index\n" )); + return T1_Err_Syntax_Error; + } + + /* grow the base block if needed */ + if ( table->cursor + length > table->capacity ) + { + FT_Error error; + FT_Int new_size = table->capacity; + + + while ( new_size < table->cursor + length ) + new_size += 1024; + + error = reallocate_t1_table( table, new_size ); + if ( error ) + return error; + } + + /* add the object to the base block and adjust offset */ + table->elements[index] = table->block + table->cursor; + table->lengths [index] = length; + + MEM_Copy( table->block + table->cursor, object, length ); + + table->cursor += length; + + return T1_Err_Ok; + } + + + /*************************************************************************/ + /* */ + /* */ + /* CID_Done_Table */ + /* */ + /* */ + /* Finalizes a CID_Table (reallocate it to its current cursor). */ + /* */ + /* */ + /* table :: The target table. */ + /* */ + /* */ + /* This function does NOT release the heap's memory block. It is up */ + /* to the caller to clean it, or reference it in its own structures. */ + /* */ + LOCAL_FUNC + void CID_Done_Table( CID_Table* table ) + { + FT_Memory memory = table->memory; + FT_Error error; + FT_Byte* old_base; + + + /* should never fail, as rec.cursor <= rec.size */ + old_base = table->block; + if ( !old_base ) + return; + + (void)REALLOC( table->block, table->capacity, table->cursor ); + table->capacity = table->cursor; + + if ( old_base != table->block ) + shift_elements( table, old_base ); + } + + + LOCAL_FUNC + void CID_Release_Table( CID_Table* table ) + { + FT_Memory memory = table->memory; + + + if ( table->init == 0xDEADBEEFL ) + { + FREE( table->block ); + FREE( table->elements ); + FREE( table->lengths ); + table->init = 0; + } + } + +#endif /* 0 */ + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** INPUT STREAM PARSER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + +#define IS_CID_WHITESPACE( c ) ( (c) == ' ' || (c) == '\t' ) +#define IS_CID_LINESPACE( c ) ( (c) == '\r' || (c) == '\n' ) + +#define IS_CID_SPACE( c ) ( IS_CID_WHITESPACE( c ) || IS_CID_LINESPACE( c ) ) + + + LOCAL_FUNC + void CID_Skip_Spaces( CID_Parser* parser ) + { + FT_Byte* cur = parser->cursor; + FT_Byte* limit = parser->limit; + + + while ( cur < limit ) + { + FT_Byte c = *cur; + + + if ( !IS_CID_SPACE( c ) ) + break; + cur++; + } + + parser->cursor = cur; + } + + + LOCAL_FUNC + void CID_ToToken( CID_Parser* parser, + CID_Token_Rec* token ) + { + FT_Byte* cur; + FT_Byte* limit; + FT_Byte starter, ender; + FT_Int embed; + + + token->type = t1_token_none; + token->start = 0; + token->limit = 0; + + /* first of all, skip space */ + CID_Skip_Spaces( parser ); + + cur = parser->cursor; + limit = parser->limit; + + if ( cur < limit ) + { + switch ( *cur ) + { + /************* check for strings ***********************/ + case '(': + token->type = t1_token_string; + ender = ')'; + goto Lookup_Ender; + + /************* check for programs/array ****************/ + case '{': + token->type = t1_token_array; + ender = '}'; + goto Lookup_Ender; + + /************* check for table/array ******************/ + case '[': + token->type = t1_token_array; + ender = ']'; + + Lookup_Ender: + embed = 1; + starter = *cur++; + token->start = cur; + + while ( cur < limit ) + { + if ( *cur == starter ) + embed++; + else if ( *cur == ender ) + { + embed--; + if ( embed <= 0 ) + { + token->limit = cur++; + break; + } + } + cur++; + } + break; + + /* **************** otherwise, it is any token **********/ + default: + token->start = cur++; + token->type = t1_token_any; + while ( cur < limit && !IS_CID_SPACE( *cur ) ) + cur++; + + token->limit = cur; + } + + if ( !token->limit ) + { + token->start = 0; + token->type = t1_token_none; + } + + parser->cursor = cur; + } + } + + + LOCAL_FUNC + void CID_ToTokenArray( CID_Parser* parser, + CID_Token_Rec* tokens, + FT_UInt max_tokens, + FT_Int* pnum_tokens ) + { + CID_Token_Rec master; + + + *pnum_tokens = -1; + + CID_ToToken( parser, &master ); + + if ( master.type == t1_token_array ) + { + FT_Byte* old_cursor = parser->cursor; + FT_Byte* old_limit = parser->limit; + CID_Token_Rec* cur = tokens; + CID_Token_Rec* limit = cur + max_tokens; + + + parser->cursor = master.start; + parser->limit = master.limit; + + while ( parser->cursor < parser->limit ) + { + CID_Token_Rec token; + + + CID_ToToken( parser, &token ); + if ( !token.type ) + break; + + if ( cur < limit ) + *cur = token; + + cur++; + } + + *pnum_tokens = cur - tokens; + + parser->cursor = old_cursor; + parser->limit = old_limit; + } + } + + + static + FT_Long t1_toint( FT_Byte** cursor, + FT_Byte* limit ) + { + FT_Long result = 0; + FT_Byte* cur = *cursor; + FT_Byte c, d; + + + for ( ; cur < limit; cur++ ) + { + c = *cur; + d = (FT_Byte)( c - '0' ); + if ( d < 10 ) + break; + + if ( c == '-' ) + { + cur++; + break; + } + } + + if ( cur < limit ) + { + do + { + d = (FT_Byte)( cur[0] - '0' ); + if ( d >= 10 ) + break; + + result = result * 10 + d; + cur++; + + } while ( cur < limit ); + + if ( c == '-' ) + result = -result; + } + + *cursor = cur; + + return result; + } + + + static + FT_Long t1_tofixed( FT_Byte** cursor, + FT_Byte* limit, + FT_Long power_ten ) + { + FT_Byte* cur = *cursor; + FT_Long num, divider, result; + FT_Int sign = 0; + FT_Byte d; + + + if ( cur >= limit ) + return 0; + + /* first of all, read the integer part */ + result = t1_toint( &cur, limit ) << 16; + num = 0; + divider = 1; + + if ( result < 0 ) + { + sign = 1; + result = -result; + } + + if ( cur >= limit ) + goto Exit; + + /* read decimal part, if any */ + if ( *cur == '.' && cur + 1 < limit ) + { + cur++; + + for (;;) + { + d = (FT_Byte)( *cur - '0' ); + if ( d >= 10 ) + break; + + if ( divider < 10000000L ) + { + num = num * 10 + d; + divider *= 10; + } + + cur++; + if ( cur >= limit ) + break; + } + } + + /* read exponent, if any */ + if ( cur + 1 < limit && ( *cur == 'e' || *cur == 'E' ) ) + { + cur++; + power_ten += t1_toint( &cur, limit ); + } + + Exit: + /* raise to power of ten if needed */ + while ( power_ten > 0 ) + { + result = result * 10; + num = num * 10; + power_ten--; + } + + while ( power_ten < 0 ) + { + result = result / 10; + divider = divider * 10; + power_ten++; + } + + if ( num ) + result += FT_DivFix( num, divider ); + + if ( sign ) + result = -result; + + *cursor = cur; + + return result; + } + + + static + int t1_tobool( FT_Byte** cursor, + FT_Byte* limit ) + { + FT_Byte* cur = *cursor; + FT_Bool result = 0; + + + /* return 1 if we find a "true", 0 otherwise */ + if ( cur + 3 < limit && + cur[0] == 't' && + cur[1] == 'r' && + cur[2] == 'u' && + cur[3] == 'e' ) + { + result = 1; + cur += 5; + } + else if ( cur + 4 < limit && + cur[0] == 'f' && + cur[1] == 'a' && + cur[2] == 'l' && + cur[3] == 's' && + cur[4] == 'e' ) + { + result = 0; + cur += 6; + } + *cursor = cur; + return result; + } + + + static + FT_Int t1_tocoordarray( FT_Byte** cursor, + FT_Byte* limit, + FT_Int max_coords, + FT_Short* coords ) + { + FT_Byte* cur = *cursor; + FT_Int count = 0; + FT_Byte c, ender; + + + if ( cur >= limit ) + goto Exit; + + /* check for the beginning of an array. */ + /* If not, only one number will be read */ + c = *cur; + ender = 0; + + if ( c == '[' ) + ender = ']'; + + if ( c == '{' ) + ender = '}'; + + if ( ender ) + cur++; + + /* now, read the coordinates */ + for ( ; cur < limit; ) + { + /* skip whitespace in front of data */ + for (;;) + { + c = *cur; + if ( c != ' ' && c != '\t' ) + break; + + cur++; + if ( cur >= limit ) + goto Exit; + } + + if ( count >= max_coords || c == ender ) + break; + + coords[count] = (FT_Short)( t1_tofixed( &cur, limit, 0 ) >> 16 ); + count++; + + if ( !ender ) + break; + } + + Exit: + *cursor = cur; + return count; + } + + + static + FT_Int t1_tofixedarray( FT_Byte** cursor, + FT_Byte* limit, + FT_Int max_values, + FT_Fixed* values, + FT_Int power_ten ) + { + FT_Byte* cur = *cursor; + FT_Int count = 0; + FT_Byte c, ender; + + + if ( cur >= limit ) + goto Exit; + + /* check for the beginning of an array. */ + /* If not, only one number will be read */ + c = *cur; + ender = 0; + + if ( c == '[' ) + ender = ']'; + + if ( c == '{' ) + ender = '}'; + + if ( ender ) + cur++; + + /* now, read the values */ + for ( ; cur < limit; ) + { + /* skip whitespace in front of data */ + for (;;) + { + c = *cur; + if ( c != ' ' && c != '\t' ) + break; + + cur++; + if ( cur >= limit ) + goto Exit; + } + + if ( count >= max_values || c == ender ) + break; + + values[count] = t1_tofixed( &cur, limit, power_ten ); + count++; + + if ( !ender ) + break; + } + + Exit: + *cursor = cur; + + return count; + } + + + /* Loads a simple field (i.e. non-table) into the current */ + /* list of objects */ + LOCAL_FUNC + FT_Error CID_Load_Field( CID_Parser* parser, + const CID_Field_Rec* field, + void* object ) + { + CID_Token_Rec token; + FT_Byte* cur; + FT_Byte* limit; + FT_UInt count; + FT_UInt index; + FT_Error error; + + + CID_ToToken( parser, &token ); + if ( !token.type ) + goto Fail; + + count = 1; + index = 0; + cur = token.start; + limit = token.limit; + + { + FT_Byte* q = (FT_Byte*)object + field->offset; + FT_Long val; + FT_String* string; + + + switch ( field->type ) + { + case t1_field_bool: + val = t1_tobool( &cur, limit ); + goto Store_Integer; + + case t1_field_fixed: + val = t1_tofixed( &cur, limit, 0 ); + goto Store_Integer; + + case t1_field_integer: + val = t1_toint( &cur, limit ); + + Store_Integer: + switch ( field->size ) + { + case 1: + *(FT_Byte*)q = (FT_Byte)val; + break; + + case 2: + *(FT_UShort*)q = (FT_UShort)val; + break; + + case 4: + *(FT_Int32*)q = (FT_Int)val; + break; + + default: /* for 64-bit systems */ + *(FT_Long*)q = val; + } + break; + + case t1_field_string: + { + FT_Memory memory = parser->memory; + FT_UInt len = limit-cur; + + + if ( ALLOC( string, len + 1 ) ) + goto Exit; + + MEM_Copy( string, cur, len ); + string[len] = 0; + + *(FT_String**)q = string; + } + break; + + default: + /* an error occurred */ + goto Fail; + } + } + + error = 0; + + Exit: + return error; + + Fail: + error = T1_Err_Invalid_File_Format; + goto Exit; + } + + +#define T1_MAX_TABLE_ELEMENTS 32 + + + LOCAL_FUNC + FT_Error CID_Load_Field_Table( CID_Parser* parser, + const CID_Field_Rec* field, + void* object ) + { + CID_Token_Rec elements[T1_MAX_TABLE_ELEMENTS]; + CID_Token_Rec* token; + FT_Int num_elements; + FT_Error error = 0; + FT_Byte* old_cursor; + FT_Byte* old_limit; + CID_Field_Rec fieldrec = *(CID_Field_Rec*)field; + + + fieldrec.type = t1_field_integer; + if ( field->type == t1_field_fixed_array ) + fieldrec.type = t1_field_fixed; + + CID_ToTokenArray( parser, elements, 32, &num_elements ); + if ( num_elements < 0 ) + goto Fail; + + if ( num_elements > T1_MAX_TABLE_ELEMENTS ) + num_elements = T1_MAX_TABLE_ELEMENTS; + + old_cursor = parser->cursor; + old_limit = parser->limit; + + /* we store the elements count */ + if ( field->count_offset ) + *(FT_Byte*)( (FT_Byte*)object + field->count_offset ) = num_elements; + + /* we now load each element, adjusting the field.offset on each one */ + token = elements; + for ( ; num_elements > 0; num_elements--, token++ ) + { + parser->cursor = token->start; + parser->limit = token->limit; + CID_Load_Field( parser, &fieldrec, object ); + fieldrec.offset += fieldrec.size; + } + + parser->cursor = old_cursor; + parser->limit = old_limit; + + Exit: + return error; + + Fail: + error = T1_Err_Invalid_File_Format; + goto Exit; + } + + + LOCAL_FUNC + FT_Long CID_ToInt( CID_Parser* parser ) + { + return t1_toint( &parser->cursor, parser->limit ); + } + + + LOCAL_FUNC + FT_Int CID_ToCoordArray( CID_Parser* parser, + FT_Int max_coords, + FT_Short* coords ) + { + return t1_tocoordarray( &parser->cursor, parser->limit, + max_coords, coords ); + } + + + LOCAL_FUNC + FT_Int CID_ToFixedArray( CID_Parser* parser, + FT_Int max_values, + FT_Fixed* values, + FT_Int power_ten ) + { + return t1_tofixedarray( &parser->cursor, parser->limit, + max_values, values, power_ten ); + } + + +#if 0 + + /* return the value of an hexadecimal digit */ + static + int hexa_value( char c ) + { + unsigned int d; + + + d = (unsigned int)( c - '0' ); + if ( d <= 9 ) + return (int)d; + + d = (unsigned int)( c - 'a' ); + if ( d <= 5 ) + return (int)( d + 10 ); + + d = (unsigned int)( c - 'A' ); + if ( d <= 5 ) + return (int)( d + 10 ); + + return -1; + } + +#endif /* 0 */ + + + LOCAL_FUNC + FT_Error CID_New_Parser( CID_Parser* parser, + FT_Stream stream, + FT_Memory memory ) + { + FT_Error error; + FT_ULong base_offset, offset, ps_len; + FT_Byte buffer[256 + 10]; + FT_Int buff_len; + + + MEM_Set( parser, 0, sizeof ( *parser ) ); + parser->stream = stream; + parser->memory = memory; + + base_offset = FILE_Pos(); + + /* first of all, check the font format in the header */ + if ( ACCESS_Frame( 31 ) ) + goto Exit; + + if ( strncmp( (char *)stream->cursor, + "%!PS-Adobe-3.0 Resource-CIDFont", 31 ) ) + { + FT_TRACE2(( "[not a valid CID-keyed font]\n" )); + error = FT_Err_Unknown_File_Format; + } + + FORGET_Frame(); + if ( error ) + goto Exit; + + /* now, read the rest of the file, until we find a `StartData' */ + buff_len = 256; + for (;;) + { + FT_Byte *p, *limit = buffer + 256; + + /* fill input buffer */ + buff_len -= 256; + if ( buff_len > 0 ) + MEM_Move( buffer, limit, buff_len ); + + if ( FILE_Read( buffer, 256 + 10 - buff_len ) ) + goto Exit; + + buff_len = 256 + 10; + + /* look for `StartData' */ + for ( p = buffer; p < limit; p++ ) + { + if ( p[0] == 'S' && strncmp( (char*)p, "StartData", 9 ) == 0 ) + { + /* save offset of binary data after `StartData' */ + offset = FILE_Pos() - ( limit - p ) + 10; + goto Found; + } + } + } + + Found: + /* we have found the start of the binary data. We will now */ + /* rewind and extract the frame of corresponding to the Postscript */ + /* section */ + + ps_len = offset - base_offset; + if ( FILE_Seek( base_offset ) || + EXTRACT_Frame( ps_len, parser->postscript ) ) + goto Exit; + + parser->data_offset = offset; + parser->postscript_len = ps_len; + parser->cursor = parser->postscript; + parser->limit = parser->cursor + ps_len; + parser->num_dict = -1; + + Exit: + return error; + } + + + LOCAL_FUNC + void CID_Done_Parser( CID_Parser* parser ) + { + /* always free the private dictionary */ + if ( parser->postscript ) + { + FT_Stream stream = parser->stream; + + + RELEASE_Frame( parser->postscript ); + } + } + + +/* END */ diff --git a/src/freetype/cid/cidparse.h b/src/freetype/cid/cidparse.h new file mode 100644 index 0000000000..7a8211ad30 --- /dev/null +++ b/src/freetype/cid/cidparse.h @@ -0,0 +1,353 @@ +/***************************************************************************/ +/* */ +/* cidparse.h */ +/* */ +/* CID-keyed Type1 parser (specification). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef CIDPARSE_H +#define CIDPARSE_H + +#include + + +#ifdef __cplusplus + extern "C" { +#endif + + +#if 0 + + /*************************************************************************/ + /* */ + /* */ + /* CID_Table */ + /* */ + /* */ + /* A CID_Table is a simple object used to store an array of objects */ + /* in a single memory block. */ + /* */ + /* */ + /* block :: The address in memory of the growheap's block. This */ + /* can change between two object adds, due to the use */ + /* of `realloc()'. */ + /* */ + /* cursor :: The current top of the growheap within its block. */ + /* */ + /* capacity :: The current size of the heap block. Increments by */ + /* blocks of 1 kByte. */ + /* */ + /* init :: A boolean. Set when the table has been initialized */ + /* (the table user should set this field). */ + /* */ + /* max_elems :: The maximal number of elements in the table. */ + /* */ + /* num_elems :: The current number of elements (in use) in the table. */ + /* */ + /* elements :: A table of element addresses within the block. */ + /* */ + /* lengths :: A table of element sizes within the block. */ + /* */ + /* memory :: The memory object used for memory operations */ + /* (allocation resp. reallocation). */ + /* */ + typedef struct CID_Table_ + { + FT_Byte* block; /* current memory block */ + FT_Int cursor; /* current cursor in memory block */ + FT_Int capacity; /* current size of memory block */ + FT_Long init; + + FT_Int max_elems; + FT_Int num_elems; + FT_Byte** elements; /* addresses of table elements */ + FT_Int* lengths; /* lengths of table elements */ + + FT_Memory memory; + + } CID_Table; + + + LOCAL_DEF + FT_Error CID_New_Table( CID_Table* table, + FT_Int count, + CID_Memory memory ); + + LOCAL_DEF + FT_Error CID_Add_Table( CID_Table* table, + FT_Int index, + void* object, + FT_Int length ); + + LOCAL_DEF + void CID_Release_Table( CID_Table* table ); + +#endif /* 0 */ + + + /*************************************************************************/ + /* */ + /* */ + /* CID_Parser */ + /* */ + /* */ + /* A CID_Parser is an object used to parse a Type 1 fonts very */ + /* quickly. */ + /* */ + /* */ + /* stream :: The current input stream. */ + /* */ + /* memory :: The current memory object. */ + /* */ + /* postscript :: A pointer to the data to be parsed. */ + /* */ + /* postscript_len :: The length of the data to be parsed. */ + /* */ + /* data_offset :: The start position of the binary data (i.e., the */ + /* end of the data to be parsed. */ + /* */ + /* cursor :: The current parser cursor. */ + /* */ + /* limit :: The current parser limit (i.e., the first byte */ + /* after the current dictionary). */ + /* */ + /* error :: The current parsing error. */ + /* */ + /* cid :: A structure which holds the information about */ + /* the current font. */ + /* */ + /* num_dict :: The number of font dictionaries. */ + /* */ + typedef struct CID_Parser_ + { + FT_Stream stream; + FT_Memory memory; + + FT_Byte* postscript; + FT_Int postscript_len; + + FT_ULong data_offset; + + FT_Byte* cursor; + FT_Byte* limit; + FT_Error error; + + CID_Info* cid; + FT_Int num_dict; + + } CID_Parser; + + + LOCAL_DEF + FT_Error CID_New_Parser( CID_Parser* parser, + FT_Stream stream, + FT_Memory memory ); + + LOCAL_DEF + void CID_Done_Parser( CID_Parser* parser ); + + + /*************************************************************************/ + /* */ + /* PARSING ROUTINES */ + /* */ + /*************************************************************************/ + + LOCAL_DEF + FT_Long CID_ToInt( CID_Parser* parser ); + + LOCAL_DEF + FT_Int CID_ToCoordArray( CID_Parser* parser, + FT_Int max_coords, + FT_Short* coords ); + + LOCAL_DEF + FT_Int CID_ToFixedArray( CID_Parser* parser, + FT_Int max_values, + FT_Fixed* values, + FT_Int power_ten ); + + LOCAL_DEF + void CID_Skip_Spaces( CID_Parser* parser ); + + + /* simple enumeration type used to identify token types */ + typedef enum CID_Token_Type_ + { + t1_token_none = 0, + t1_token_any, + t1_token_string, + t1_token_array, + + /* do not remove */ + t1_token_max + + } CID_Token_Type; + + + /* a simple structure used to identify tokens */ + typedef struct CID_Token_Rec_ + { + FT_Byte* start; /* first character of token in input stream */ + FT_Byte* limit; /* first character after the token */ + CID_Token_Type type; /* type of token */ + + } CID_Token_Rec; + + + LOCAL_DEF + void CID_ToToken( CID_Parser* parser, + CID_Token_Rec* token ); + + + /* enumeration type used to identify object fields */ + typedef enum CID_Field_Type_ + { + t1_field_none = 0, + t1_field_bool, + t1_field_integer, + t1_field_fixed, + t1_field_string, + t1_field_integer_array, + t1_field_fixed_array, + t1_field_callback, + + /* do not remove */ + t1_field_max + + } CID_Field_Type; + + typedef enum CID_Field_Location_ + { + t1_field_cid_info, + t1_field_font_dict, + t1_field_font_info, + t1_field_private, + + /* do not remove */ + t1_field_location_max + + } CID_Field_Location; + + + typedef FT_Error (*CID_Field_Parser)( CID_Face face, + CID_Parser* parser ); + + /* structure type used to model object fields */ + typedef struct CID_Field_Rec_ + { + const char* ident; /* field identifier */ + CID_Field_Location location; + CID_Field_Type type; /* type of field */ + CID_Field_Parser reader; + FT_UInt offset; /* offset of field in object */ + FT_UInt size; /* size of field in bytes */ + FT_UInt array_max; /* maximal number of elements for */ + /* array */ + FT_UInt count_offset; /* offset of element count for */ + /* arrays */ + } CID_Field_Rec; + + +#define CID_FIELD_REF( s, f ) ( ((s*)0)->f ) + +#define CID_NEW_SIMPLE_FIELD( _ident, _type, _fname ) \ + { \ + _ident, T1CODE, _type, \ + 0, \ + (FT_UInt)(char*)&CID_FIELD_REF( T1TYPE, _fname ), \ + sizeof ( CID_FIELD_REF( T1TYPE, _fname ) ), \ + 0, 0 \ + }, + +#define CID_NEW_CALLBACK_FIELD( _ident, _reader ) \ + { \ + _ident, T1CODE, t1_field_callback, \ + _reader, \ + 0, 0, \ + 0, 0 \ + }, + +#define CID_NEW_TABLE_FIELD( _ident, _type, _fname, _max ) \ + { \ + _ident, T1CODE, _type, \ + 0, \ + (FT_UInt)(char*)&CID_FIELD_REF( T1TYPE, _fname ), \ + sizeof ( CID_FIELD_REF( T1TYPE, _fname )[0] ), \ + _max, \ + (FT_UInt)(char*)&CID_FIELD_REF( T1TYPE, num_ ## _fname ) \ + }, + +#define CID_NEW_TABLE_FIELD2( _ident, _type, _fname, _max ) \ + { \ + _ident, T1CODE, _type, \ + 0, \ + (FT_UInt)(char*)&CID_FIELD_REF( T1TYPE, _fname ), \ + sizeof ( CID_FIELD_REF( T1TYPE, _fname )[0] ), \ + _max, 0 \ + }, + + +#define CID_FIELD_BOOL( _ident, _fname ) \ + CID_NEW_SIMPLE_FIELD( _ident, t1_field_bool, _fname ) + +#define CID_FIELD_NUM( _ident, _fname ) \ + CID_NEW_SIMPLE_FIELD( _ident, t1_field_integer, _fname ) + +#define CID_FIELD_FIXED( _ident, _fname ) \ + CID_NEW_SIMPLE_FIELD( _ident, t1_field_fixed, _fname ) + +#define CID_FIELD_STRING( _ident, _fname ) \ + CID_NEW_SIMPLE_FIELD( _ident, t1_field_string, _fname ) + +#define CID_FIELD_NUM_TABLE( _ident, _fname, _fmax ) \ + CID_NEW_TABLE_FIELD( _ident, t1_field_integer_array, \ + _fname, _fmax ) + +#define CID_FIELD_FIXED_TABLE( _ident, _fname, _fmax ) \ + CID_NEW_TABLE_FIELD( _ident, t1_field_fixed_array, \ + _fname, _fmax ) + +#define CID_FIELD_NUM_TABLE2( _ident, _fname, _fmax ) \ + CID_NEW_TABLE_FIELD2( _ident, t1_field_integer_array, \ + _fname, _fmax ) + +#define CID_FIELD_FIXED_TABLE2( _ident, _fname, _fmax ) \ + CID_NEW_TABLE_FIELD2( _ident, t1_field_fixed_array, \ + _fname, _fmax ) + +#define CID_FIELD_CALLBACK( _ident, _name ) \ + CID_NEW_CALLBACK_FIELD( _ident, parse_ ## _name ) + + + LOCAL_DEF + FT_Error CID_Load_Field( CID_Parser* parser, + const CID_Field_Rec* field, + void* object ); + + LOCAL_DEF + FT_Error CID_Load_Field_Table( CID_Parser* parser, + const CID_Field_Rec* field, + void* object ); + + +#ifdef __cplusplus + } +#endif + + +#endif /* CIDPARSE_H */ + + +/* END */ diff --git a/src/freetype/cid/cidriver.c b/src/freetype/cid/cidriver.c new file mode 100644 index 0000000000..f1c6b6a012 --- /dev/null +++ b/src/freetype/cid/cidriver.c @@ -0,0 +1,259 @@ +/***************************************************************************/ +/* */ +/* cidriver.c */ +/* */ +/* CID driver interface (body). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifdef FT_FLAT_COMPILE + +#include "cidriver.h" +#include "cidgload.h" + +#else + +#include +#include + +#endif + + +#include +#include +#include + +#include /* for strcmp() */ + + + /*************************************************************************/ + /* */ + /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ + /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ + /* messages during execution. */ + /* */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_ciddriver + + + static + FT_Module_Interface CID_Get_Interface( FT_Driver driver, + const FT_String* interface ) + { + FT_UNUSED( driver ); + FT_UNUSED( interface ); + + return 0; + } + + +#if 0 /* unimplemented yet */ + + static + FT_Error cid_Get_Kerning( T1_Face face, + FT_UInt left_glyph, + FT_UInt right_glyph, + FT_Vector* kerning ) + { + CID_AFM* afm; + + + kerning->x = 0; + kerning->y = 0; + + afm = (CID_AFM*)face->afm_data; + if ( afm ) + CID_Get_Kerning( afm, left_glyph, right_glyph, kerning ); + + return T1_Err_Ok; + } + + +#endif /* 0 */ + + + /*************************************************************************/ + /* */ + /* */ + /* Cid_Get_Char_Index */ + /* */ + /* */ + /* Uses a charmap to return a given character code's glyph index. */ + /* */ + /* */ + /* charmap :: A handle to the source charmap object. */ + /* */ + /* charcode :: The character code. */ + /* */ + /* */ + /* Glyph index. 0 means `undefined character code'. */ + /* */ + static + FT_UInt CID_Get_Char_Index( FT_CharMap charmap, + FT_Long charcode ) + { + T1_Face face; + FT_UInt result = 0; + PSNames_Interface* psnames; + + + face = (T1_Face)charmap->face; + psnames = (PSNames_Interface*)face->psnames; + if ( psnames ) + switch ( charmap->encoding ) + { + /*******************************************************************/ + /* */ + /* Unicode encoding support */ + /* */ + case ft_encoding_unicode: + /* use the `PSNames' module to synthetize the Unicode charmap */ + result = psnames->lookup_unicode( &face->unicode_map, + (FT_ULong)charcode ); + + /* the function returns 0xFFFF if the Unicode charcode has */ + /* no corresponding glyph. */ + if ( result == 0xFFFF ) + result = 0; + goto Exit; + + /*******************************************************************/ + /* */ + /* Custom Type 1 encoding */ + /* */ + case ft_encoding_adobe_custom: + { + T1_Encoding* encoding = &face->type1.encoding; + + + if ( charcode >= encoding->code_first && + charcode <= encoding->code_last ) + result = encoding->char_index[charcode]; + goto Exit; + } + + /*******************************************************************/ + /* */ + /* Adobe Standard & Expert encoding support */ + /* */ + default: + if ( charcode < 256 ) + { + FT_UInt code; + FT_Int n; + const char* glyph_name; + + + code = psnames->adobe_std_encoding[charcode]; + if ( charmap->encoding == ft_encoding_adobe_expert ) + code = psnames->adobe_expert_encoding[charcode]; + + glyph_name = psnames->adobe_std_strings( code ); + if ( !glyph_name ) + break; + + for ( n = 0; n < face->type1.num_glyphs; n++ ) + { + const char* gname = face->type1.glyph_names[n]; + + + if ( gname && gname[0] == glyph_name[0] && + strcmp( gname, glyph_name ) == 0 ) + { + result = n; + break; + } + } + } + } + + Exit: + return result; + } + + + const FT_Driver_Class t1cid_driver_class = + { + /* first of all, the FT_Module_Class fields */ + { + ft_module_font_driver | ft_module_driver_scalable, + sizeof( FT_DriverRec ), + "t1cid", /* module name */ + 0x10000L, /* version 1.0 of driver */ + 0x20000L, /* requires FreeType 2.0 */ + + 0, + + (FT_Module_Constructor)CID_Init_Driver, + (FT_Module_Destructor) CID_Done_Driver, + (FT_Module_Requester) CID_Get_Interface + }, + + /* then the other font drivers fields */ + sizeof( CID_FaceRec ), + sizeof( CID_SizeRec ), + sizeof( CID_GlyphSlotRec ), + + (FTDriver_initFace) CID_Init_Face, + (FTDriver_doneFace) CID_Done_Face, + + (FTDriver_initSize) 0, + (FTDriver_doneSize) 0, + (FTDriver_initGlyphSlot)0, + (FTDriver_doneGlyphSlot)0, + + (FTDriver_setCharSizes) 0, + (FTDriver_setPixelSizes)0, + + (FTDriver_loadGlyph) CID_Load_Glyph, + (FTDriver_getCharIndex) CID_Get_Char_Index, + + (FTDriver_getKerning) 0, + (FTDriver_attachFile) 0, + + (FTDriver_getAdvances) 0 + }; + + +#ifdef FT_CONFIG_OPTION_DYNAMIC_DRIVERS + + + /*************************************************************************/ + /* */ + /* */ + /* getDriverClass */ + /* */ + /* */ + /* This function is used when compiling the TrueType driver as a */ + /* shared library (`.DLL' or `.so'). It will be used by the */ + /* high-level library of FreeType to retrieve the address of the */ + /* driver's generic interface. */ + /* */ + /* It shouldn't be implemented in a static build, as each driver must */ + /* have the same function as an exported entry point. */ + /* */ + /* */ + /* The address of the TrueType's driver generic interface. The */ + /* format-specific interface can then be retrieved through the method */ + /* interface->get_format_interface. */ + /* */ + EXPORT_FUNC( FT_Driver_Class* ) getDriverClass( void ) + { + return &t1cid_driver_class; + } + + +#endif /* CONFIG_OPTION_DYNAMIC_DRIVERS */ + + +/* END */ diff --git a/src/freetype/cid/cidriver.h b/src/freetype/cid/cidriver.h new file mode 100644 index 0000000000..a9674eed44 --- /dev/null +++ b/src/freetype/cid/cidriver.h @@ -0,0 +1,29 @@ +/***************************************************************************/ +/* */ +/* cidriver.h */ +/* */ +/* High-level CID driver interface (specification). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef CIDRIVER_H +#define CIDRIVER_H + +#include + + FT_EXPORT_VAR( const FT_Driver_Class ) t1cid_driver_class; + +#endif /* CIDRIVER_H */ + + +/* END */ diff --git a/src/freetype/cid/cidtokens.h b/src/freetype/cid/cidtokens.h new file mode 100644 index 0000000000..a916cea322 --- /dev/null +++ b/src/freetype/cid/cidtokens.h @@ -0,0 +1,99 @@ +/***************************************************************************/ +/* */ +/* cidtokens.h */ +/* */ +/* CID token definitions (specification only). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#undef T1TYPE +#undef T1CODE +#define T1TYPE CID_Info +#define T1CODE t1_field_cid_info + + CID_FIELD_STRING ( "CIDFontName", cid_font_name ) + CID_FIELD_NUM ( "CIDFontVersion", cid_version ) + CID_FIELD_NUM ( "CIDFontType", cid_font_type ) + CID_FIELD_STRING ( "Registry", registry ) + CID_FIELD_STRING ( "Ordering", ordering ) + CID_FIELD_NUM ( "Supplement", supplement ) + CID_FIELD_CALLBACK( "FontBBox", font_bbox ) + CID_FIELD_NUM ( "UIDBase", uid_base ) + CID_FIELD_CALLBACK( "FDArray", fd_array ) + CID_FIELD_NUM ( "CIDMapOffset", cidmap_offset ) + CID_FIELD_NUM ( "FDBytes", fd_bytes ) + CID_FIELD_NUM ( "GDBytes", gd_bytes ) + CID_FIELD_NUM ( "CIDCount", cid_count ) + + +#undef T1TYPE +#undef T1CODE +#define T1TYPE T1_FontInfo +#define T1CODE t1_field_font_info + + CID_FIELD_STRING( "version", version ) + CID_FIELD_STRING( "Notice", notice ) + CID_FIELD_STRING( "FullName", full_name ) + CID_FIELD_STRING( "FamilyName", family_name ) + CID_FIELD_STRING( "Weight", weight ) + CID_FIELD_FIXED ( "ItalicAngle", italic_angle ) + CID_FIELD_BOOL ( "isFixedPitch", is_fixed_pitch ) + CID_FIELD_NUM ( "UnderlinePosition", underline_position ) + CID_FIELD_NUM ( "UnderlineThickness", underline_thickness ) + + +#undef T1TYPE +#undef T1CODE +#define T1TYPE CID_FontDict +#define T1CODE t1_field_font_dict + + CID_FIELD_CALLBACK( "FontMatrix", font_matrix ) + CID_FIELD_NUM ( "PaintType", paint_type ) + CID_FIELD_NUM ( "FontType", font_type ) + CID_FIELD_NUM ( "SubrMapOffset", subrmap_offset ) + CID_FIELD_NUM ( "SDBytes", sd_bytes ) + CID_FIELD_NUM ( "SubrCount", num_subrs ) + CID_FIELD_NUM ( "lenBuildCharArray", len_buildchar ) + CID_FIELD_FIXED ( "ForceBoldThreshold", forcebold_threshold ) + CID_FIELD_FIXED ( "ExpansionFactor", expansion_factor ) + CID_FIELD_NUM ( "StrokeWidth", stroke_width ) + + +#undef T1TYPE +#undef T1CODE +#define T1TYPE T1_Private +#define T1CODE t1_field_private + + CID_FIELD_NUM ( "UniqueID", unique_id ) + CID_FIELD_NUM ( "lenIV", lenIV ) + CID_FIELD_NUM ( "LanguageGroup", language_group ) + CID_FIELD_NUM ( "password", password ) + + CID_FIELD_FIXED ( "BlueScale", blue_scale ) + CID_FIELD_NUM ( "BlueShift", blue_shift ) + CID_FIELD_NUM ( "BlueFuzz", blue_fuzz ) + + CID_FIELD_NUM_TABLE ( "BlueValues", blue_values, 14 ) + CID_FIELD_NUM_TABLE ( "OtherBlues", other_blues, 10 ) + CID_FIELD_NUM_TABLE ( "FamilyBlues", family_blues, 14 ) + CID_FIELD_NUM_TABLE ( "FamilyOtherBlues", family_other_blues, 10 ) + + CID_FIELD_NUM_TABLE2( "StdHW", standard_width, 1 ) + CID_FIELD_NUM_TABLE2( "StdVW", standard_height, 1 ) + CID_FIELD_NUM_TABLE2( "MinFeature", min_feature, 2 ) + + CID_FIELD_NUM_TABLE ( "StemSnapH", snap_widths, 12 ) + CID_FIELD_NUM_TABLE ( "StemSnapV", snap_heights, 12 ) + + +/* END */ diff --git a/src/freetype/cid/module.mk b/src/freetype/cid/module.mk new file mode 100644 index 0000000000..3d13c9ca1d --- /dev/null +++ b/src/freetype/cid/module.mk @@ -0,0 +1,6 @@ +make_module_list: add_type1cid_driver + +add_type1cid_driver: + $(OPEN_DRIVER)t1cid_driver_class$(CLOSE_DRIVER) + $(ECHO_DRIVER)cid $(ECHO_DRIVER_DESC)Postscript CID-keyed fonts, no known extension$(ECHO_DRIVER_DONE) +# EOF diff --git a/src/freetype/cid/rules.mk b/src/freetype/cid/rules.mk new file mode 100644 index 0000000000..cbaaec7685 --- /dev/null +++ b/src/freetype/cid/rules.mk @@ -0,0 +1,69 @@ +# +# FreeType 2 CID driver configuration rules +# + + +# Copyright 1996-2000 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +# CID driver directory +# +CID_DIR := $(SRC_)cid +CID_DIR_ := $(CID_DIR)$(SEP) + + +CID_COMPILE := $(FT_COMPILE) + + +# CID driver sources (i.e., C files) +# +CID_DRV_SRC := $(CID_DIR_)cidparse.c \ + $(CID_DIR_)cidload.c \ + $(CID_DIR_)cidriver.c \ + $(CID_DIR_)cidgload.c \ + $(CID_DIR_)cidobjs.c + +# CID driver headers +# +CID_DRV_H := $(CID_DRV_SRC:%.c=%.h) \ + $(CID_DIR_)cidtokens.h + + +# CID driver object(s) +# +# CID_DRV_OBJ_M is used during `multi' builds +# CID_DRV_OBJ_S is used during `single' builds +# +CID_DRV_OBJ_M := $(CID_DRV_SRC:$(CID_DIR_)%.c=$(OBJ_)%.$O) +CID_DRV_OBJ_S := $(OBJ_)type1cid.$O + +# CID driver source file for single build +# +CID_DRV_SRC_S := $(CID_DIR_)type1cid.c + + +# CID driver - single object +# +$(CID_DRV_OBJ_S): $(CID_DRV_SRC_S) $(CID_DRV_SRC) $(FREETYPE_H) $(CID_DRV_H) + $(CID_COMPILE) $T$@ $(CID_DRV_SRC_S) + + +# CID driver - multiple objects +# +$(OBJ_)%.$O: $(CID_DIR_)%.c $(FREETYPE_H) $(CID_DRV_H) + $(CID_COMPILE) $T$@ $< + + +# update main driver object lists +# +DRV_OBJS_S += $(CID_DRV_OBJ_S) +DRV_OBJS_M += $(CID_DRV_OBJ_M) + +# EOF diff --git a/src/freetype/cid/type1cid.c b/src/freetype/cid/type1cid.c new file mode 100644 index 0000000000..d26aee26f4 --- /dev/null +++ b/src/freetype/cid/type1cid.c @@ -0,0 +1,40 @@ +/***************************************************************************/ +/* */ +/* cff.c */ +/* */ +/* FreeType OpenType driver component (body only). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#define FT_MAKE_OPTION_SINGLE_OBJECT + +#ifdef FT_FLAT_COMPILE + +#include "cidparse.c" +#include "cidload.c" +#include "cidobjs.c" +#include "cidriver.c" +#include "cidgload.c" + +#else + +#include +#include +#include +#include +#include + +#endif + + +/* END */ diff --git a/src/freetype/freetype/config/ftconfig.h b/src/freetype/freetype/config/ftconfig.h new file mode 100644 index 0000000000..338e22cb2a --- /dev/null +++ b/src/freetype/freetype/config/ftconfig.h @@ -0,0 +1,187 @@ +/***************************************************************************/ +/* */ +/* ftconfig.h */ +/* */ +/* ANSI-specific configuration file (specification only). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + + /*************************************************************************/ + /* */ + /* This header file contains a number of macro definitions that are used */ + /* by the rest of the engine. Most of the macros here are automatically */ + /* determined at compile time, and you should not need to change it to */ + /* port FreeType, except to compile the library with a non-ANSI */ + /* compiler. */ + /* */ + /* Note however that if some specific modifications are needed, we */ + /* advise you to place a modified copy in your build directory. */ + /* */ + /* The build directory is usually `freetype/builds/', and */ + /* contains system-specific files that are always included first when */ + /* building the library. */ + /* */ + /* This ANSI version should stay in `include/freetype/config'. */ + /* */ + /*************************************************************************/ + + +#ifndef FTCONFIG_H +#define FTCONFIG_H + + + /* Include the header file containing all developer build options */ +#include + + + /*************************************************************************/ + /* */ + /* PLATFORM-SPECIFIC CONFIGURATION MACROS */ + /* */ + /* These macros can be toggled to suit a specific system. The current */ + /* ones are defaults used to compile FreeType in an ANSI C environment */ + /* (16bit compilers are also supported). Copy this file to your own */ + /* `freetype/builds/' directory, and edit it to port the engine. */ + /* */ + /*************************************************************************/ + + + /* We use values to know the sizes of the types. */ +#include + + /* The number of bytes in an `int' type. */ +#if UINT_MAX == 0xFFFFFFFF +#define FT_SIZEOF_INT 4 +#elif UINT_MAX == 0xFFFF +#define FT_SIZEOF_INT 2 +#elif UINT_MAX > 0xFFFFFFFF && UINT_MAX == 0xFFFFFFFFFFFFFFFF +#define FT_SIZEOF_INT 8 +#else +#error "Unsupported number of bytes in `int' type!" +#endif + + /* The number of bytes in a `long' type. */ +#if ULONG_MAX == 0xFFFFFFFF +#define FT_SIZEOF_LONG 4 +#elif ULONG_MAX > 0xFFFFFFFF && ULONG_MAX == 0xFFFFFFFFFFFFFFFF +#define FT_SIZEOF_LONG 8 +#else +#error "Unsupported number of bytes in `long' type!" +#endif + + + /* Preferred alignment of data */ +#define FT_ALIGNMENT 8 + + + /* UNUSED is a macro used to indicate that a given parameter is not used */ + /* -- this is only used to get rid of unpleasant compiler warnings */ +#ifndef FT_UNUSED +#define FT_UNUSED( arg ) ( (arg) = (arg) ) +#endif + + + /*************************************************************************/ + /* */ + /* AUTOMATIC CONFIGURATION MACROS */ + /* */ + /* These macros are computed from the ones defined above. Don't touch */ + /* their definition, unless you know precisely what you are doing. No */ + /* porter should need to mess with them. */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* IntN types */ + /* */ + /* Used to guarantee the size of some specific integers. */ + /* */ + typedef signed short FT_Int16; + typedef unsigned short FT_UInt16; + +#if FT_SIZEOF_INT == 4 + + typedef signed int FT_Int32; + typedef unsigned int FT_UInt32; + +#elif FT_SIZEOF_LONG == 4 + + typedef signed long FT_Int32; + typedef unsigned long FT_UInt32; + +#else +#error "no 32bit type found -- please check your configuration files" +#endif + +#if FT_SIZEOF_LONG == 8 + + /* FT_LONG64 must be defined if a 64-bit type is available */ +#define FT_LONG64 +#define FT_INT64 long + +#else + + + /*************************************************************************/ + /* */ + /* Many compilers provide the non-ANSI `long long' 64-bit type. You can */ + /* activate it by defining the FTCALC_USE_LONG_LONG macro in */ + /* `ftoption.h'. */ + /* */ + /* Note that this will produce many -ansi warnings during library */ + /* compilation, and that in many cases, the generated code will be */ + /* neither smaller nor faster! */ + /* */ +#ifdef FTCALC_USE_LONG_LONG + +#define FT_LONG64 +#define FT_INT64 long long + +#endif /* FTCALC_USE_LONG_LONG */ +#endif /* FT_SIZEOF_LONG == 8 */ + + +#ifdef FT_MAKE_OPTION_SINGLE_OBJECT +#define LOCAL_DEF static +#define LOCAL_FUNC static +#else +#define LOCAL_DEF extern +#define LOCAL_FUNC /* nothing */ +#endif + +#ifdef FT_MAKE_OPTION_SINGLE_LIBRARY_OBJECT +#define BASE_DEF( x ) static x +#define BASE_FUNC( x ) static x +#else +#define BASE_DEF( x ) extern x +#define BASE_FUNC( x ) extern x +#endif + +#ifndef FT_EXPORT_DEF +#define FT_EXPORT_DEF( x ) extern x +#endif + +#ifndef FT_EXPORT_FUNC +#define FT_EXPORT_FUNC( x ) extern x +#endif + +#ifndef FT_EXPORT_VAR +#define FT_EXPORT_VAR( x ) extern x +#endif + +#endif /* FTCONFIG_H */ + + +/* END */ diff --git a/src/freetype/freetype/config/ftmodule.h b/src/freetype/freetype/config/ftmodule.h new file mode 100644 index 0000000000..50cc46b5c6 --- /dev/null +++ b/src/freetype/freetype/config/ftmodule.h @@ -0,0 +1,10 @@ +FT_USE_MODULE(autohint_module_class) +FT_USE_MODULE(cff_driver_class) +FT_USE_MODULE(t1cid_driver_class) +FT_USE_MODULE(psnames_module_class) +FT_USE_MODULE(ft_raster1_renderer_class) +FT_USE_MODULE(sfnt_module_class) +FT_USE_MODULE(ft_smooth_renderer_class) +FT_USE_MODULE(tt_driver_class) +FT_USE_MODULE(t1_driver_class) +FT_USE_MODULE(winfnt_driver_class) diff --git a/src/freetype/freetype/config/ftoption.h b/src/freetype/freetype/config/ftoption.h new file mode 100644 index 0000000000..a7e1f406a2 --- /dev/null +++ b/src/freetype/freetype/config/ftoption.h @@ -0,0 +1,395 @@ +/***************************************************************************/ +/* */ +/* ftoption.h */ +/* */ +/* User-selectable configuration macros (specification only). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef FTOPTION_H +#define FTOPTION_H + + + /*************************************************************************/ + /* */ + /* USER-SELECTABLE CONFIGURATION MACROS */ + /* */ + /* These macros can be toggled by developers to enable or disable */ + /* certain aspects of FreeType. This is a default file, where all major */ + /* options are enabled. */ + /* */ + /* Note that if some modifications are required for your build, we */ + /* advise you to put a modified copy of this file in your build */ + /* directory, rather than modifying it in-place. */ + /* */ + /* The build directory is normally `freetype/builds/' and */ + /* contains build or system-specific files that are included in */ + /* priority when building the library. */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** G E N E R A L F R E E T Y P E 2 C O N F I G U R A T I O N ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* Convenience functions support */ + /* */ + /* Some functions of the FreeType 2 API are provided as a convenience */ + /* for client applications and developers. However, they are not */ + /* required to build and run the library itself. */ + /* */ + /* By defining this configuration macro, you'll disable the */ + /* compilation of these functions at build time. This can be useful */ + /* to reduce the library's code size when you don't need any of */ + /* these functions. */ + /* */ + /* All convenience functions are declared as such in their */ + /* documentation. */ + /* */ +#undef FT_CONFIG_OPTION_NO_CONVENIENCE_FUNCS + + + /*************************************************************************/ + /* */ + /* Alternate Glyph Image Format support */ + /* */ + /* By default, the glyph images returned by the FreeType glyph loader */ + /* can either be a pixmap or a vectorial outline defined through */ + /* Bezier control points. When defining the following configuration */ + /* macro, some font drivers will be able to register alternate */ + /* glyph image formats. */ + /* */ + /* Unset this macro if you are sure that you will never use a font */ + /* driver with an alternate glyph format; this will reduce the size of */ + /* the base layer code. */ + /* */ + /* Note that a few Type 1 fonts, as well as Windows `vector' fonts */ + /* use a vector `plotter' format that isn't supported when this */ + /* macro is undefined. */ + /* */ +#define FT_CONFIG_OPTION_ALTERNATE_GLYPH_FORMATS + + + /*************************************************************************/ + /* */ + /* Glyph Postscript Names handling */ + /* */ + /* By default, FreeType 2 is compiled with the `PSNames' module. This */ + /* This module is in charge of converting a glyph name string into a */ + /* Unicode value, or return a Macintosh standard glyph name for the */ + /* use with the TrueType `post' table. */ + /* */ + /* Undefine this macro if you do not want `PSNames' compiled in your */ + /* build of FreeType. This has the following effects: */ + /* */ + /* - The TrueType driver will provide its own set of glyph names, */ + /* if you build it to support postscript names in the TrueType */ + /* `post' table. */ + /* */ + /* - The Type 1 driver will not be able to synthetize a Unicode */ + /* charmap out of the glyphs found in the fonts. */ + /* */ + /* You would normally undefine this configuration macro when building */ + /* a version of FreeType that doesn't contain a Type 1 or CFF driver. */ + /* */ +#define FT_CONFIG_OPTION_POSTSCRIPT_NAMES + + + /*************************************************************************/ + /* */ + /* Postscript Names to Unicode Values support */ + /* */ + /* By default, FreeType 2 is built with the `PSNames' module compiled */ + /* in. Among other things, the module is used to convert a glyph name */ + /* into a Unicode value. This is especially useful in order to */ + /* synthetize on the fly a Unicode charmap from the CFF/Type 1 driver */ + /* through a big table named the `Adobe Glyph List' (AGL). */ + /* */ + /* Undefine this macro if you do not want the Adobe Glyph List */ + /* compiled in your `PSNames' module. The Type 1 driver will not be */ + /* able to synthetize a Unicode charmap out of the glyphs found in the */ + /* fonts. */ + /* */ +#define FT_CONFIG_OPTION_ADOBE_GLYPH_LIST + + + /*************************************************************************/ + /* */ + /* Many compilers provide the non-ANSI `long long' 64-bit type. You can */ + /* activate it by defining the FTCALC_USE_LONG_LONG macro. Note that */ + /* this will produce many -ansi warnings during library compilation, and */ + /* that in many cases the generated code will not be smaller or faster! */ + /* */ +#undef FTCALC_USE_LONG_LONG + + + /*************************************************************************/ + /* */ + /* DLL export compilation */ + /* */ + /* When compiling FreeType as a DLL, some systems/compilers need a */ + /* special keyword in front OR after the return type of function */ + /* declarations. */ + /* */ + /* Two macros are used within the FreeType source code to define */ + /* exported library functions: FT_EXPORT_DEF and FT_EXPORT_FUNC. */ + /* */ + /* FT_EXPORT_DEF( return_type ) */ + /* */ + /* is used in a function declaration, as in */ + /* */ + /* FT_EXPORT_DEF( FT_Error ) */ + /* FT_Init_FreeType( FT_Library* alibrary ); */ + /* */ + /* */ + /* FT_EXPORT_FUNC( return_type ) */ + /* */ + /* is used in a function definition, as in */ + /* */ + /* FT_EXPORT_FUNC( FT_Error ) */ + /* FT_Init_FreeType( FT_Library* alibrary ) */ + /* { */ + /* ... some code ... */ + /* return FT_Err_Ok; */ + /* } */ + /* */ + /* You can provide your own implementation of FT_EXPORT_DEF and */ + /* FT_EXPORT_FUNC here if you want. If you leave them undefined, they */ + /* will be later automatically defined as `extern return_type' to */ + /* allow normal compilation. */ + /* */ +#undef FT_EXPORT_DEF +#undef FT_EXPORT_FUNC + + + /*************************************************************************/ + /* */ + /* Debug level */ + /* */ + /* FreeType can be compiled in debug or trace mode. In debug mode, */ + /* errors are reported through the `ftdebug' component. In trace */ + /* mode, additional messages are sent to the standard output during */ + /* execution. */ + /* */ + /* Define FT_DEBUG_LEVEL_ERROR to build the library in debug mode. */ + /* Define FT_DEBUG_LEVEL_TRACE to build it in trace mode. */ + /* */ + /* Don't define any of these macros to compile in `release' mode! */ + /* */ +#define FT_DEBUG_LEVEL_ERROR +#define FT_DEBUG_LEVEL_TRACE + + + /*************************************************************************/ + /* */ + /* Computation Algorithms */ + /* */ + /* Used for debugging, this configuration macro should disappear */ + /* soon. */ + /* */ +#define FT_CONFIG_OPTION_OLD_CALCS + + + /*************************************************************************/ + /* */ + /* The size in bytes of the render pool used by the scan-line converter */ + /* to do all of its work. */ + /* */ + /* This must be greater than 4kByte. */ + /* */ +#define FT_RENDER_POOL_SIZE 16384 + + + /*************************************************************************/ + /* */ + /* FT_MAX_MODULES */ + /* */ + /* The maximum number of modules that can be registered in a single */ + /* FreeType library object. 16 is the default. */ + /* */ +#define FT_MAX_MODULES 16 + + + /*************************************************************************/ + /* */ + /* FT_MAX_EXTENSIONS */ + /* */ + /* The maximum number of extensions that can be registered in a single */ + /* font driver. 8 is the default. */ + /* */ + /* If you don't know what this means, you certainly do not need to */ + /* change this value. */ + /* */ +#define FT_MAX_EXTENSIONS 8 + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** S F N T D R I V E R C O N F I G U R A T I O N ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* Define TT_CONFIG_OPTION_EMBEDDED_BITMAPS if you want to support */ + /* embedded bitmaps in all formats using the SFNT module (namely */ + /* TrueType & OpenType). */ + /* */ +#define TT_CONFIG_OPTION_EMBEDDED_BITMAPS + + + /*************************************************************************/ + /* */ + /* Define TT_CONFIG_OPTION_POSTSCRIPT_NAMES if you want to be able to */ + /* load and enumerate the glyph Postscript names in a TrueType or */ + /* OpenType file. */ + /* */ + /* Note that when you do not compile the `PSNames' module by undefining */ + /* the above FT_CONFIG_OPTION_POSTSCRIPT_NAMES, the `sfnt' module will */ + /* contain additional code used to read the PS Names table from a font. */ + /* */ + /* (By default, the module uses `PSNames' to extract glyph names.) */ + /* */ +#define TT_CONFIG_OPTION_POSTSCRIPT_NAMES + + + /*************************************************************************/ + /* */ + /* Define TT_CONFIG_OPTION_SFNT_NAMES if your applications need to */ + /* access the internal name table in a SFNT-based format like TrueType */ + /* or OpenType. The name table contains various strings used to */ + /* describe the font, like family name, copyright, version, etc. It */ + /* does not contain any glyph name though. */ + /* */ + /* Accessing SFNT names is done through the functions declared in */ + /* `freetype/ftnames.h'. */ + /* */ +#define TT_CONFIG_OPTION_SFNT_NAMES + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** T R U E T Y P E D R I V E R C O N F I G U R A T I O N ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + /*************************************************************************/ + /* */ + /* Define TT_CONFIG_OPTION_BYTECODE_INTERPRETER if you want to compile */ + /* a bytecode interpreter in the TrueType driver. Note that there are */ + /* important patent issues related to the use of the interpreter. */ + /* */ + /* By undefining this, you will only compile the code necessary to load */ + /* TrueType glyphs without hinting. */ + /* */ +#undef TT_CONFIG_OPTION_BYTECODE_INTERPRETER + + + /*************************************************************************/ + /* */ + /* Define TT_CONFIG_OPTION_INTERPRETER_SWITCH to compile the TrueType */ + /* bytecode interpreter with a huge switch statement, rather than a call */ + /* table. This results in smaller and faster code for a number of */ + /* architectures. */ + /* */ + /* Note however that on some compiler/processor combinations, undefining */ + /* this macro will generate faster, though larger, code. */ + /* */ +#define TT_CONFIG_OPTION_INTERPRETER_SWITCH + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** T Y P E 1 D R I V E R C O N F I G U R A T I O N ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* T1_MAX_STACK_DEPTH is the maximal depth of the token stack used by */ + /* the Type 1 parser (see t1load.c). A minimum of 16 is required. */ + /* */ +#define T1_MAX_STACK_DEPTH 16 + + + /*************************************************************************/ + /* */ + /* T1_MAX_DICT_DEPTH is the maximal depth of nest dictionaries and */ + /* arrays in the Type 1 stream (see t1load.c). A minimum of 4 is */ + /* required. */ + /* */ +#define T1_MAX_DICT_DEPTH 5 + + + /*************************************************************************/ + /* */ + /* T1_MAX_SUBRS_CALLS details the maximum number of nested sub-routine */ + /* calls during glyph loading. */ + /* */ +#define T1_MAX_SUBRS_CALLS 8 + + + /*************************************************************************/ + /* */ + /* T1_MAX_CHARSTRING_OPERANDS is the charstring stack's capacity. */ + /* */ +#define T1_MAX_CHARSTRINGS_OPERANDS 32 + + + /*************************************************************************/ + /* */ + /* Define T1_CONFIG_OPTION_DISABLE_HINTER if you want to generate a */ + /* driver with no hinter. This can be useful to debug the parser. */ + /* */ +#undef T1_CONFIG_OPTION_DISABLE_HINTER + + + /*************************************************************************/ + /* */ + /* Define this configuration macro if you want to prevent the */ + /* compilation of `t1afm', which is in charge of reading Type 1 AFM */ + /* files into an existing face. Note that if set, the T1 driver will be */ + /* unable to produce kerning distances. */ + /* */ +#undef T1_CONFIG_OPTION_NO_AFM + + + /*************************************************************************/ + /* */ + /* Define this configuration macro if you want to prevent the */ + /* compilation of the Multiple Masters font support in the Type 1 */ + /* driver. */ + /* */ +#undef T1_CONFIG_OPTION_NO_MM_SUPPORT + + +#endif /* FTOPTION_H */ + + +/* END */ diff --git a/src/freetype/freetype/freetype.h b/src/freetype/freetype/freetype.h new file mode 100644 index 0000000000..29316c67ba --- /dev/null +++ b/src/freetype/freetype/freetype.h @@ -0,0 +1,2286 @@ +/***************************************************************************/ +/* */ +/* freetype.h */ +/* */ +/* FreeType high-level API and common types (specification only). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef FREETYPE_H +#define FREETYPE_H + + + /*************************************************************************/ + /* */ + /* The `raster' component duplicates some of the declarations in */ + /* freetype.h for stand-alone use if _FREETYPE_ isn't defined. */ + /* */ +#define _FREETYPE_ + + + /*************************************************************************/ + /* */ + /* The FREETYPE_MAJOR and FREETYPE_MINOR macros are used to version the */ + /* new FreeType design, which is able to host several kinds of font */ + /* drivers. It starts at 2.0. */ + /* */ +#define FREETYPE_MAJOR 2 +#define FREETYPE_MINOR 0 + + +#include /* read configuration information */ +#include +#include + + +#ifdef __cplusplus + extern "C" { +#endif + + + /*************************************************************************/ + /*************************************************************************/ + /* */ + /* B A S I C T Y P E S */ + /* */ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Glyph_Metrics */ + /* */ + /* */ + /* A structure used to model the metrics of a single glyph. Note */ + /* that values are expressed in 26.6 fractional pixel format or in */ + /* font units, depending on context. */ + /* */ + /* */ + /* width :: The glyph's width. */ + /* */ + /* height :: The glyph's height. */ + /* */ + /* horiBearingX :: Horizontal left side bearing. */ + /* */ + /* horiBearingY :: Horizontal top side bearing. */ + /* */ + /* horiAdvance :: Horizontal advance width. */ + /* */ + /* vertBearingX :: Vertical left side bearing. */ + /* */ + /* vertBearingY :: Vertical top side bearing. */ + /* */ + /* vertAdvance :: Vertical advance height. */ + /* */ + typedef struct FT_Glyph_Metrics_ + { + FT_Pos width; /* glyph width */ + FT_Pos height; /* glyph height */ + + FT_Pos horiBearingX; /* left side bearing in horizontal layouts */ + FT_Pos horiBearingY; /* top side bearing in horizontal layouts */ + FT_Pos horiAdvance; /* advance width for horizontal layout */ + + FT_Pos vertBearingX; /* left side bearing in vertical layouts */ + FT_Pos vertBearingY; /* top side bearing in vertical layouts */ + FT_Pos vertAdvance; /* advance height for vertical layout */ + + } FT_Glyph_Metrics; + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Generic_Finalizer */ + /* */ + /* */ + /* Describes a function used to destroy the `client' data of any */ + /* FreeType object. See the description of the FT_Generic type for */ + /* details of usage. */ + /* */ + /* */ + /* The address of the FreeType object which is under finalization. */ + /* Its client data is accessed through its `generic' field. */ + /* */ + typedef void (*FT_Generic_Finalizer)(void* object); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Generic */ + /* */ + /* */ + /* Client applications often need to associate their own data to a */ + /* variety of FreeType core objects. For example, a text layout API */ + /* might want to associate a glyph cache to a given size object. */ + /* */ + /* Most FreeType object contains a `generic' field, of type */ + /* FT_Generic, which usage is left to client applications and font */ + /* servers. */ + /* */ + /* It can be used to store a pointer to client-specific data, as well */ + /* as the address of a `finalizer' function, which will be called by */ + /* FreeType when the object is destroyed (for example, the previous */ + /* client example would put the address of the glyph cache destructor */ + /* in the `finalizer' field). */ + /* */ + /* */ + /* data :: A typeless pointer to any client-specified data. This */ + /* field is completely ignored by the FreeType library. */ + /* */ + /* finalizer :: A pointer to a `generic finalizer' function, which */ + /* will be called when the object is destroyed. If this */ + /* field is set to NULL, no code will be called. */ + /* */ + typedef struct FT_Generic_ + { + void* data; + FT_Generic_Finalizer finalizer; + + } FT_Generic; + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Bitmap_Size */ + /* */ + /* */ + /* An extremely simple structure used to model the size of a bitmap */ + /* strike (i.e., a bitmap instance of the font for a given */ + /* resolution) in a fixed-size font face. This is used for the */ + /* `available_sizes' field of the FT_Face_Properties structure. */ + /* */ + /* */ + /* height :: The character height in pixels. */ + /* */ + /* width :: The character width in pixels. */ + /* */ + typedef struct FT_Bitmap_Size_ + { + FT_Short height; + FT_Short width; + + } FT_Bitmap_Size; + + + /*************************************************************************/ + /*************************************************************************/ + /* */ + /* O B J E C T C L A S S E S */ + /* */ + /*************************************************************************/ + /*************************************************************************/ + + /*************************************************************************/ + /* */ + /* */ + /* FT_Library */ + /* */ + /* */ + /* A handle to a FreeType library instance. Each `library' is */ + /* completely independent from the others; it is the `root' of a set */ + /* of objects like fonts, faces, sizes, etc. */ + /* */ + /* It also embeds a system object (see FT_System), as well as a */ + /* scan-line converter object (see FT_Raster). */ + /* */ + /* */ + /* Library objects are created through FT_Init_FreeType(). */ + /* */ + typedef struct FT_LibraryRec_ *FT_Library; + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Module */ + /* */ + /* */ + /* A handle to a given FreeType module object. Each module can be a */ + /* font driver, a renderer, or anything else that provides services */ + /* to the formers. */ + /* */ + typedef struct FT_ModuleRec_* FT_Module; + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Driver */ + /* */ + /* */ + /* A handle to a given FreeType font driver object. Each font driver */ + /* is able to create faces, sizes, glyph slots, and charmaps from the */ + /* resources whose format it supports. */ + /* */ + /* A driver can support either bitmap, graymap, or scalable font */ + /* formats. */ + /* */ + typedef struct FT_DriverRec_* FT_Driver; + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Renderer */ + /* */ + /* */ + /* A handle to a given FreeType renderer. A renderer is in charge of */ + /* converting a glyph image to a bitmap, when necessary. Each */ + /* supports a given glyph image format, and one or more target */ + /* surface depths. */ + /* */ + typedef struct FT_RendererRec_* FT_Renderer; + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Face */ + /* */ + /* */ + /* A handle to a given driver face object. A face object contains */ + /* all the instance and glyph independent data of a font file */ + /* typeface. */ + /* */ + /* A face object is created from a resource object through the */ + /* new_face() method of a given driver. */ + /* */ + typedef struct FT_FaceRec_* FT_Face; + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Size */ + /* */ + /* */ + /* A handle to a given driver size object. Such an object models the */ + /* _resolution_ AND _size_ dependent state of a given driver face */ + /* size. */ + /* */ + /* A size object is always created from a given face object. It is */ + /* discarded automatically by its parent face. */ + /* */ + typedef struct FT_SizeRec_* FT_Size; + + + /*************************************************************************/ + /* */ + /* */ + /* FT_GlyphSlot */ + /* */ + /* */ + /* A handle to a given `glyph slot'. A slot is a container where it */ + /* is possible to load any of the glyphs contained within its parent */ + /* face. */ + /* */ + /* A glyph slot is created from a given face object. It is discarded */ + /* automatically by its parent face. */ + /* */ + typedef struct FT_GlyphSlotRec_* FT_GlyphSlot; + + + /*************************************************************************/ + /* */ + /* */ + /* FT_CharMap */ + /* */ + /* */ + /* A handle to a given character map. A charmap is used to translate */ + /* character codes in a given encoding into glyph indexes for its */ + /* parent's face. Some font formats may provide several charmaps per */ + /* font. */ + /* */ + /* A charmap is created from a given face object. It is discarded */ + /* automatically by its parent face. */ + /* */ + typedef struct FT_CharMapRec_* FT_CharMap; + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Encoding */ + /* */ + /* */ + /* An enumeration used to specify encodings supported by charmaps. */ + /* Used in the FT_Select_CharMap() API function. */ + /* */ + /* */ + /* Because of 32-bit charcodes defined in Unicode (i.e., surrogates), */ + /* all character codes must be expressed as FT_Longs. */ + /* */ + typedef enum FT_Encoding_ + { + ft_encoding_none = 0, + ft_encoding_symbol = FT_MAKE_TAG( 's', 'y', 'm', 'b' ), + ft_encoding_unicode = FT_MAKE_TAG( 'u', 'n', 'i', 'c' ), + ft_encoding_latin_2 = FT_MAKE_TAG( 'l', 'a', 't', '2' ), + ft_encoding_sjis = FT_MAKE_TAG( 's', 'j', 'i', 's' ), + ft_encoding_gb2312 = FT_MAKE_TAG( 'g', 'b', ' ', ' ' ), + ft_encoding_big5 = FT_MAKE_TAG( 'b', 'i', 'g', '5' ), + ft_encoding_wansung = FT_MAKE_TAG( 'w', 'a', 'n', 's' ), + ft_encoding_johab = FT_MAKE_TAG( 'j', 'o', 'h', 'a' ), + + ft_encoding_adobe_standard = FT_MAKE_TAG( 'A', 'D', 'O', 'B' ), + ft_encoding_adobe_expert = FT_MAKE_TAG( 'A', 'D', 'B', 'E' ), + ft_encoding_adobe_custom = FT_MAKE_TAG( 'A', 'D', 'B', 'C' ), + + ft_encoding_apple_roman = FT_MAKE_TAG( 'a', 'r', 'm', 'n' ) + + /* other encodings might be defined in the future */ + + } FT_Encoding; + + + /*************************************************************************/ + /* */ + /* */ + /* FT_CharMapRec */ + /* */ + /* */ + /* The base charmap class. */ + /* */ + /* */ + /* face :: A handle to the parent face object. */ + /* */ + /* flags :: A set of bit flags used to describe the charmap. */ + /* Each bit indicates that a given encoding is */ + /* supported. */ + /* */ + /* platform_id :: An ID number describing the platform for the */ + /* following encoding ID. This comes directly from */ + /* the TrueType specification and should be emulated */ + /* for other formats. */ + /* */ + /* encoding_id :: A platform specific encoding number. This also */ + /* comes from the TrueType specification and should be */ + /* emulated similarly. */ + /* */ + /* */ + /* We STRONGLY recommmend emulating a Unicode charmap for drivers */ + /* that do not support TrueType or OpenType. */ + /* */ + typedef struct FT_CharMapRec_ + { + FT_Face face; + FT_Encoding encoding; + FT_UShort platform_id; + FT_UShort encoding_id; + + } FT_CharMapRec; + + + /*************************************************************************/ + /*************************************************************************/ + /* */ + /* B A S E O B J E C T C L A S S E S */ + /* */ + /*************************************************************************/ + /*************************************************************************/ + + /*************************************************************************/ + /* */ + /* FreeType base face class */ + /* */ + /* */ + /* FT_FaceRec */ + /* */ + /* */ + /* FreeType root face class structure. A face object models the */ + /* resolution and point-size independent data found in a font file. */ + /* */ + /* */ + /* num_faces :: In the case where the face is located in a */ + /* collection (i.e., a resource which embeds */ + /* several faces), this is the total number of */ + /* faces found in the resource. 1 by default. */ + /* */ + /* face_index :: The index of the face in its resource. */ + /* Usually, this is 0 for all normal font */ + /* formats. It can be more in the case of */ + /* collections (which embed several fonts in a */ + /* single resource/file). */ + /* */ + /* face_flags :: A set of bit flags that give important */ + /* information about the face; see the */ + /* FT_FACE_FLAG_XXX macros for details. */ + /* */ + /* style_flags :: A set of bit flags indicating the style of */ + /* the face (i.e., italic, bold, underline, */ + /* etc). */ + /* */ + /* num_glyphs :: The total number of glyphs in the face. */ + /* */ + /* family_name :: The face's family name. This is an ASCII */ + /* string, usually in English, which describes */ + /* the typeface's family (like `Times New */ + /* Roman', `Bodoni', `Garamond', etc). This */ + /* is a least common denominator used to list */ + /* fonts. Some formats (TrueType & OpenType) */ + /* provide localized and Unicode versions of */ + /* this string. Applications should use the */ + /* format specific interface to access them. */ + /* */ + /* style_name :: The face's style name. This is an ASCII */ + /* string, usually in English, which describes */ + /* the typeface's style (like `Italic', */ + /* `Bold', `Condensed', etc). Not all font */ + /* formats provide a style name, so this field */ + /* is optional, and can be set to NULL. As */ + /* for `family_name', some formats provide */ + /* localized/Unicode versions of this string. */ + /* Applications should use the format specific */ + /* interface to access them. */ + /* */ + /* num_fixed_sizes :: The number of fixed sizes available in this */ + /* face. This should be set to 0 for scalable */ + /* fonts, unless its resource includes a */ + /* complete set of glyphs (called a `strike') */ + /* for the specified size. */ + /* */ + /* available_sizes :: An array of sizes specifying the available */ + /* bitmap/graymap sizes that are contained in */ + /* in the font resource. Should be set to */ + /* NULL if the field `num_fixed_sizes' is set */ + /* to 0. */ + /* */ + /* num_charmaps :: The total number of character maps in the */ + /* face. */ + /* */ + /* charmaps :: A table of pointers to the face's charmaps */ + /* Used to scan the list of available charmaps */ + /* this table might change after a call to */ + /* FT_Attach_File/Stream (e.g. when it used */ + /* to hook and additional encoding/CMap to */ + /* the face object). */ + /* */ + /* generic :: A field reserved for client uses. See the */ + /* FT_Generic type description. */ + /* */ + /* bbox :: The font bounding box. Coordinates are */ + /* expressed in font units (see units_per_EM). */ + /* The box is large enough to contain any */ + /* glyph from the font. Thus, bbox.yMax can */ + /* be seen as the `maximal ascender', */ + /* bbox.yMin as the `minimal descender', and */ + /* the maximal glyph width is given by */ + /* `bbox.xMax-bbox.xMin' (not to be confused */ + /* with the maximal _advance_width_). Only */ + /* relevant for scalable formats. */ + /* */ + /* units_per_EM :: The number of font units per EM square for */ + /* this face. This is typically 2048 for */ + /* TrueType fonts, 1000 for Type1 fonts, and */ + /* should be set to the (unrealistic) value 1 */ + /* for fixed-sizes fonts. Only relevant for */ + /* scalable formats. */ + /* */ + /* ascender :: The face's ascender is the vertical */ + /* distance from the baseline to the topmost */ + /* point of any glyph in the face. This */ + /* field's value is positive, expressed in */ + /* font units. Some font designs use a value */ + /* different from `bbox.yMax'. Only relevant */ + /* for scalable formats. */ + /* */ + /* descender :: The face's descender is the vertical */ + /* distance from the baseline to the */ + /* bottommost point of any glyph in the face. */ + /* This field's value is positive, expressed */ + /* in font units. Some font designs use a */ + /* value different from `-bbox.yMin'. Only */ + /* relevant for scalable formats. */ + /* */ + /* height :: The face's height is the vertical distance */ + /* from one baseline to the next when writing */ + /* several lines of text. Its value is always */ + /* positive, expressed in font units. The */ + /* value can be computed as */ + /* `ascender+descender+line_gap' where the */ + /* value of `line_gap' is also called */ + /* `external leading'. Only relevant for */ + /* scalable formats. */ + /* */ + /* max_advance_width :: The maximal advance width, in font units, */ + /* for all glyphs in this face. This can be */ + /* used to make word wrapping computations */ + /* faster. Only relevant for scalable */ + /* formats. */ + /* */ + /* max_advance_height :: The maximal advance height, in font units, */ + /* for all glyphs in this face. This is only */ + /* relevant for vertical layouts, and should */ + /* be set to the `height' for fonts that do */ + /* not provide vertical metrics. Only */ + /* relevant for scalable formats. */ + /* */ + /* underline_position :: The position, in font units, of the */ + /* underline line for this face. It's the */ + /* center of the underlining stem. Only */ + /* relevant for scalable formats. */ + /* */ + /* underline_thickness :: The thickness, in font units, of the */ + /* underline for this face. Only relevant for */ + /* scalable formats. */ + /* */ + /* driver :: A handle to the face's parent driver */ + /* object. */ + /* */ + /* memory :: A handle to the face's parent memory */ + /* object. Used for the allocation of */ + /* subsequent objects. */ + /* */ + /* stream :: A handle to the face's stream. */ + /* */ + /* glyph :: The face's associated glyph slot(s). This */ + /* object is created automatically with a new */ + /* face object. However, certain kinds of */ + /* applications (mainly tools like converters) */ + /* can need more than one slot to ease their */ + /* task. */ + /* */ + /* sizes_list :: The list of child sizes for this face. */ + /* */ + /* max_points :: The maximal number of points used to store */ + /* the vectorial outline of any glyph in this */ + /* face. If this value cannot be known in */ + /* advance, or if the face isn't scalable, */ + /* this should be set to 0. Only relevant for */ + /* scalable formats. */ + /* */ + /* max_contours :: The maximal number of contours used to */ + /* store the vectorial outline of any glyph in */ + /* this face. If this value cannot be known */ + /* in advance, or if the face isn't scalable, */ + /* this should be set to 0. Only relevant for */ + /* scalable formats. */ + /* */ + /* transform_matrix :: A 2x2 matrix of 16.16 coefficients used */ + /* to transform glyph outlines after they are */ + /* loaded from the font. Only used by the */ + /* convenience functions. */ + /* */ + /* transform_delta :: A translation vector used to transform */ + /* glyph outlines after they are loaded from */ + /* the font. Only used by the convenience */ + /* functions. */ + /* */ + /* transform_flags :: Some flags used to classify the transform. */ + /* Only used by the convenience functions. */ + /* */ + typedef struct FT_FaceRec_ + { + FT_Long num_faces; + FT_Long face_index; + + FT_Long face_flags; + FT_Long style_flags; + + FT_Long num_glyphs; + + FT_String* family_name; + FT_String* style_name; + + FT_Int num_fixed_sizes; + FT_Bitmap_Size* available_sizes; + + /* the face's table of available charmaps */ + FT_Int num_charmaps; + FT_CharMap* charmaps; + + FT_Generic generic; + + /* the following are only relevant for scalable outlines */ + FT_BBox bbox; + + FT_UShort units_per_EM; + FT_Short ascender; + FT_Short descender; + FT_Short height; + + FT_Short max_advance_width; + FT_Short max_advance_height; + + FT_Short underline_position; + FT_Short underline_thickness; + + FT_GlyphSlot glyph; + FT_Size size; + + /************************************************************/ + /* The following fields should be considered private and */ + /* rarely, if ever, used directly by client applications. */ + + FT_Driver driver; + FT_Memory memory; + FT_Stream stream; + + FT_CharMap charmap; + FT_ListRec sizes_list; + + FT_Generic autohint; + void* extensions; + + FT_UShort max_points; + FT_Short max_contours; + + FT_Matrix transform_matrix; + FT_Vector transform_delta; + FT_Int transform_flags; + + } FT_FaceRec; + + + /*************************************************************************/ + /* */ + /* */ + /* FT_FACE_FLAG_SCALABLE */ + /* */ + /* */ + /* A bit-field constant, used to indicate that a given face provides */ + /* vectorial outlines (i.e., TrueType or Type1). This doesn't */ + /* prevent embedding of bitmap strikes though, i.e., a given face can */ + /* have both this bit set, and a `num_fixed_sizes' property > 0. */ + /* */ +#define FT_FACE_FLAG_SCALABLE 1 + + + /*************************************************************************/ + /* */ + /* */ + /* FT_FACE_FLAG_FIXED_SIZES */ + /* */ + /* */ + /* A bit-field constant, used to indicate that a given face contains */ + /* `fixed sizes', i.e., bitmap strikes for some given pixel sizes. */ + /* See the `num_fixed_sizes' and `available_sizes' face properties */ + /* for more information. */ + /* */ +#define FT_FACE_FLAG_FIXED_SIZES 2 + + + /*************************************************************************/ + /* */ + /* */ + /* FT_FACE_FLAG_FIXED_WIDTH */ + /* */ + /* */ + /* A bit-field constant, used to indicate that a given face contains */ + /* fixed-width characters (like Courier, Lucida, MonoType, etc.). */ + /* */ +#define FT_FACE_FLAG_FIXED_WIDTH 4 + + + /*************************************************************************/ + /* */ + /* */ + /* FT_FACE_FLAG_SFNT */ + /* */ + /* */ + /* A bit-field constant, used to indicate that a given face uses the */ + /* `sfnt' storage fomat. For now, this means TrueType or OpenType. */ + /* */ +#define FT_FACE_FLAG_SFNT 8 + + + /*************************************************************************/ + /* */ + /* */ + /* FT_FACE_FLAG_HORIZONTAL */ + /* */ + /* */ + /* A bit-field constant, used to indicate that a given face contains */ + /* horizontal glyph metrics. This should be set for all common */ + /* formats, but who knows. */ + /* */ +#define FT_FACE_FLAG_HORIZONTAL 0x10 + + + /*************************************************************************/ + /* */ + /* */ + /* FT_FACE_FLAG_VERTICAL */ + /* */ + /* */ + /* A bit-field constant, used to indicate that a given face contains */ + /* vertical glyph metrics. If not set, the glyph loader will */ + /* synthetize vertical metrics itself to help display vertical text */ + /* correctly. */ + /* */ +#define FT_FACE_FLAG_VERTICAL 0x20 + + + /*************************************************************************/ + /* */ + /* */ + /* FT_FACE_FLAG_KERNING */ + /* */ + /* */ + /* A bit-field constant, used to indicate that a given face contains */ + /* kerning information. When set, this information can be retrieved */ + /* through the function FT_Get_Kerning(). Note that when unset, this */ + /* function will always return the kerning vector (0,0). */ + /* */ +#define FT_FACE_FLAG_KERNING 0x40 + + + /*************************************************************************/ + /* */ + /* */ + /* FT_FACE_FLAG_FAST_GLYPHS */ + /* */ + /* */ + /* A bit-field constant, used to indicate that the glyphs in a given */ + /* font can be retrieved very quickly, and that a glyph cache is thus */ + /* not necessary for any of its child size objects. */ + /* */ + /* This flag should really be set for fixed-size formats like FNT, */ + /* where each glyph bitmap is available directly in binary form */ + /* without any kind of compression. */ + /* */ +#define FT_FACE_FLAG_FAST_GLYPHS 0x80 + + + /*************************************************************************/ + /* */ + /* */ + /* FT_FACE_FLAG_MULTIPLE_MASTERS */ + /* */ + /* */ + /* A bit-field constant, used to indicate that the font contains */ + /* multiple masters and is capable of interpolating between them. */ + /* */ +#define FT_FACE_FLAG_MULTIPLE_MASTERS 0x100 + + + /*************************************************************************/ + /* */ + /* */ + /* FT_FACE_FLAG_GLYPH_NAMES */ + /* */ + /* */ + /* A bit-field constant, used to indicate that the font contains */ + /* glyph names that can be retrieved through FT_Get_Glyph_Name(). */ + /* */ +#define FT_FACE_FLAG_GLYPH_NAMES 0x200 + + + /*************************************************************************/ + /* */ + /* */ + /* FT_FACE_FLAG_EXTERNAL_STREAM */ + /* */ + /* */ + /* This bit field is used internally by FreeType to indicate that */ + /* a face's stream was provided by the client application and should */ + /* not be destroyed by FT_Done_Face(). */ + /* */ +#define FT_FACE_FLAG_EXTERNAL_STREAM 0x4000 + + +#define FT_HAS_HORIZONTAL( face ) \ + ( face->face_flags & FT_FACE_FLAG_HORIZONTAL ) +#define FT_HAS_VERTICAL( face ) \ + ( face->face_flags & FT_FACE_FLAG_VERTICAL ) +#define FT_HAS_KERNING( face ) \ + ( face->face_flags & FT_FACE_FLAG_KERNING ) +#define FT_IS_SCALABLE( face ) \ + ( face->face_flags & FT_FACE_FLAG_SCALABLE ) +#define FT_IS_SFNT( face ) \ + ( face->face_flags & FT_FACE_FLAG_SFNT ) +#define FT_IS_FIXED_WIDTH( face ) \ + ( face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ) +#define FT_HAS_FIXED_SIZES( face ) \ + ( face->face_flags & FT_FACE_FLAG_FIXED_SIZES ) +#define FT_HAS_FAST_GLYPHS( face ) \ + ( face->face_flags & FT_FACE_FLAG_FAST_GLYPHS ) +#define FT_HAS_GLYPH_NAMES( face ) \ + ( face->face_flags & FT_FACE_FLAG_GLYPH_NAMES ) + +#define FT_HAS_MULTIPLE_MASTERS( face ) \ + ( face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS ) + + + /*************************************************************************/ + /* */ + /* */ + /* FT_STYLE_FLAG_ITALIC */ + /* */ + /* */ + /* A bit-field constant, used to indicate that a given face is */ + /* italicized. */ + /* */ +#define FT_STYLE_FLAG_ITALIC 1 + + + /*************************************************************************/ + /* */ + /* */ + /* FT_STYLE_FLAG_BOLD */ + /* */ + /* */ + /* A bit-field constant, used to indicate that a given face is */ + /* emboldened. */ + /* */ +#define FT_STYLE_FLAG_BOLD 2 + + + /*************************************************************************/ + /* */ + /* FreeType base size metrics */ + /* */ + /* */ + /* FT_Size_Metrics */ + /* */ + /* */ + /* The size metrics structure returned scaled important distances for */ + /* a given size object. */ + /* */ + /* */ + /* x_ppem :: The character width, expressed in integer pixels. */ + /* This is the width of the EM square expressed in */ + /* pixels, hence the term `ppem' (pixels per EM). */ + /* */ + /* y_ppem :: The character height, expressed in integer pixels. */ + /* This is the height of the EM square expressed in */ + /* pixels, hence the term `ppem' (pixels per EM). */ + /* */ + /* x_scale :: A simple 16.16 fixed point format coefficient used */ + /* to scale horizontal distances expressed in font */ + /* units to fractional (26.6) pixel coordinates. */ + /* */ + /* y_scale :: A simple 16.16 fixed point format coefficient used */ + /* to scale vertical distances expressed in font */ + /* units to fractional (26.6) pixel coordinates. */ + /* */ + /* x_resolution :: The horizontal device resolution for this size */ + /* object, expressed in integer dots per inches */ + /* (dpi). As a convention, fixed font formats set */ + /* this value to 72. */ + /* */ + /* y_resolution :: The vertical device resolution for this size */ + /* object, expressed in integer dots per inches */ + /* (dpi). As a convention, fixed font formats set */ + /* this value to 72. */ + /* */ + /* ascender :: The ascender, expressed in 26.6 fixed point */ + /* pixels. Always positive. */ + /* */ + /* descender :: The descender, expressed in 26.6 fixed point */ + /* pixels. Always positive. */ + /* */ + /* height :: The text height, expressed in 26.6 fixed point */ + /* pixels. Always positive. */ + /* */ + /* max_advance :: Maximum horizontal advance, expressed in 26.6 */ + /* fixed point pixels. Always positive. */ + /* */ + /* */ + /* The values of `ascender', `descender', and `height' are only the */ + /* scaled versions of `face->ascender', `face->descender', and */ + /* `face->height'. */ + /* */ + /* Unfortunately, due to glyph hinting, these values might not be */ + /* exact for certain fonts, they thus must be treated as unreliable */ + /* with an error margin of at least one pixel! */ + /* */ + /* Indeed, the only way to get the exact pixel ascender and descender */ + /* is to render _all_ glyphs. As this would be a definite */ + /* performance hit, it is up to client applications to perform such */ + /* computations. */ + /* */ + typedef struct FT_Size_Metrics_ + { + FT_UShort x_ppem; /* horizontal pixels per EM */ + FT_UShort y_ppem; /* vertical pixels per EM */ + + FT_Fixed x_scale; /* two scales used to convert font units */ + FT_Fixed y_scale; /* to 26.6 frac. pixel coordinates.. */ + + FT_Pos ascender; /* ascender in 26.6 frac. pixels */ + FT_Pos descender; /* descender in 26.6 frac. pixels */ + FT_Pos height; /* text height in 26.6 frac. pixels */ + FT_Pos max_advance; /* max horizontal advance, in 26.6 pixels */ + + } FT_Size_Metrics; + + + /*************************************************************************/ + /* */ + /* FreeType base size class */ + /* */ + /* */ + /* FT_SizeRec */ + /* */ + /* */ + /* FreeType root size class structure. A size object models the */ + /* resolution and pointsize dependent data of a given face. */ + /* */ + /* */ + /* face :: Handle to the parent face object. */ + /* */ + /* generic :: A typeless pointer, which is unused by the FreeType */ + /* library or any of its drivers. It can be used by */ + /* client applications to link their own data to each size */ + /* object. */ + /* */ + /* metrics :: Metrics for this size object. This field is read-only. */ + /* */ + typedef struct FT_SizeRec_ + { + FT_Face face; /* parent face object */ + FT_Generic generic; /* generic pointer for client uses */ + FT_Size_Metrics metrics; /* size metrics */ + + } FT_SizeRec; + + + /*************************************************************************/ + /* */ + /* */ + /* FT_SubGlyph */ + /* */ + /* */ + /* The subglyph structure is an internal object used to describe */ + /* subglyphs (for example, in the case of composites). */ + /* */ + /* */ + /* The subglyph implementation is not part of the high-level API, */ + /* hence the forward structure declaration. */ + /* */ + typedef struct FT_SubGlyph_ FT_SubGlyph; + + + /*************************************************************************/ + /* */ + /* */ + /* FT_GlyphLoader */ + /* */ + /* */ + /* The glyph loader is an internal object used to load several glyphs */ + /* together (for example, in the case of composites). */ + /* */ + /* */ + /* The glyph loader implementation is not part of the high-level API, */ + /* hence the forward structure declaration. */ + /* */ + typedef struct FT_GlyphLoader_ FT_GlyphLoader; + + + /*************************************************************************/ + /* */ + /* FreeType Glyph Slot base class */ + /* */ + /* */ + /* FT_GlyphSlotRec */ + /* */ + /* */ + /* FreeType root glyph slot class structure. A glyph slot is a */ + /* container where individual glyphs can be loaded, be they */ + /* vectorial or bitmap/graymaps. */ + /* */ + /* */ + /* library :: A handle to the FreeType library instance */ + /* this slot belongs to. */ + /* */ + /* face :: A handle to the parent face object. */ + /* */ + /* next :: In some cases (like some font tools), several */ + /* glyph slots per face object can be a good */ + /* thing. As this is rare, the glyph slots are */ + /* listed through a direct, single-linked list */ + /* using its `next' field. */ + /* */ + /* generic :: A typeless pointer which is unused by the */ + /* FreeType library or any of its drivers. It */ + /* can be used by client applications to link */ + /* their own data to each size object. */ + /* */ + /* metrics :: The metrics of the last loaded glyph in the */ + /* slot. The returned values depend on the last */ + /* load flags (see the FT_Load_Glyph() API */ + /* function) and can be expressed either in 26.6 */ + /* fractional pixels or font units. */ + /* */ + /* Note that even when the glyph image is */ + /* transformed, the metrics are not. */ + /* */ + /* linearHoriAdvance :: For scalable formats only, this field holds */ + /* the linearly scaled horizontal advance width */ + /* for the glyph (i.e. the scaled and unhinted */ + /* value of the hori advance). This can be */ + /* important to perform correct WYSIWYG layout */ + /* */ + /* Note that this value is expressed by default */ + /* in 16.16 pixels. However, when the glyph is */ + /* loaded with the FT_LOAD_UNSCALED_LINEAR flag, */ + /* this field contains simply the value of the */ + /* advance in original font units. */ + /* */ + /* linearVertAdvance :: For scalable formats only, this field holds */ + /* the linearly scaled vertical advance height */ + /* for the glyph. See linearHoriAdvance for */ + /* comments. */ + /* */ + /* advance :: This is the transformed advance width for the */ + /* glyph. */ + /* */ + /* format :: This field indicates the format of the image */ + /* contained in the glyph slot. Typically */ + /* ft_glyph_format_bitmap, */ + /* ft_glyph_format_outline, and */ + /* ft_glyph_format_composite, but others are */ + /* possible. */ + /* */ + /* bitmap :: This field is used as a bitmap descriptor */ + /* when the slot format is */ + /* ft_glyph_format_bitmap. Note that the */ + /* address and content of the bitmap buffer can */ + /* change between calls of FT_Load_Glyph() and a */ + /* few other functions. */ + /* */ + /* bitmap_left :: This is the bitmap's left bearing expressed */ + /* in integer pixels. Of course, this is only */ + /* valid if the format is */ + /* ft_glyph_format_bitmap. */ + /* */ + /* bitmap_top :: This is the bitmap's top bearing expressed in */ + /* integer pixels. Remember that this is the */ + /* distance from the baseline to the top-most */ + /* glyph scanline, upwards y-coordinates being */ + /* *positive*. */ + /* */ + /* outline :: The outline descriptor for the current glyph */ + /* image if its format is */ + /* ft_glyph_bitmap_outline. */ + /* */ + /* num_subglyphs :: The number of subglyphs in a composite glyph. */ + /* This format is only valid for the composite */ + /* glyph format, that should normally only be */ + /* loaded with the FT_LOAD_NO_RECURSE flag. */ + /* */ + /* subglyphs :: An array of subglyph descriptors for */ + /* composite glyphs. There are `num_subglyphs' */ + /* elements in there. */ + /* */ + /* control_data :: Certain font drivers can also return the */ + /* control data for a given glyph image (e.g. */ + /* TrueType bytecode, Type 1 charstrings, etc.). */ + /* This field is a pointer to such data. */ + /* */ + /* control_len :: This is the length in bytes of the control */ + /* data. */ + /* */ + /* other :: Really wicked formats can use this pointer to */ + /* present their own glyph image to client apps. */ + /* Note that the app will need to know about the */ + /* image format. */ + /* */ + /* loader :: This is a private object for the glyph slot. */ + /* Do not touch this. */ + /* */ + /* */ + /* If FT_Load_Glyph() is called with default flags (FT_LOAD_DEFAULT), */ + /* the glyph image is loaded in the glyph slot in its native format */ + /* (e.g. a vectorial outline for TrueType and Type 1 formats). */ + /* */ + /* This image can later be converted into a bitmap by calling */ + /* FT_Render_Glyph(). This function finds the current renderer for */ + /* the native image's format then invokes it. */ + /* */ + /* The renderer is in charge of transforming the native image through */ + /* the slot's face transformation fields, then convert it into a */ + /* bitmap that is returned in `slot->bitmap'. */ + /* */ + /* Note that `slot->bitmap_left' and `slot->bitmap_top' are also used */ + /* to specify the position of the bitmap relative to the current pen */ + /* position (e.g. coordinates [0,0] on the baseline). Of course, */ + /* `slot->format' is also changed to `ft_glyph_format_bitmap' . */ + /* */ + typedef struct FT_GlyphSlotRec_ + { + FT_Library library; + FT_Face face; + FT_GlyphSlot next; + FT_UInt flags; + FT_Generic generic; + + FT_Glyph_Metrics metrics; + FT_Fixed linearHoriAdvance; + FT_Fixed linearVertAdvance; + FT_Vector advance; + + FT_Glyph_Format format; + + FT_Bitmap bitmap; + FT_Int bitmap_left; + FT_Int bitmap_top; + + FT_Outline outline; + + FT_UInt num_subglyphs; + FT_SubGlyph* subglyphs; + + void* control_data; + long control_len; + + void* other; + + /* private fields */ + FT_GlyphLoader* loader; + + } FT_GlyphSlotRec; + + + /*************************************************************************/ + /*************************************************************************/ + /* */ + /* F U N C T I O N S */ + /* */ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Init_FreeType */ + /* */ + /* */ + /* Initializes a new FreeType library object. The set of drivers */ + /* that are registered by this function is determined at build time. */ + /* */ + /* */ + /* library :: A handle to a new library object. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT_DEF( FT_Error ) FT_Init_FreeType( FT_Library* library ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Done_FreeType */ + /* */ + /* */ + /* Destroys a given FreeType library object and all of its childs, */ + /* including resources, drivers, faces, sizes, etc. */ + /* */ + /* */ + /* library :: A handle to the target library object. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT_DEF( FT_Error ) FT_Done_FreeType( FT_Library library ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Open_Flags */ + /* */ + /* */ + /* An enumeration used to list the bit flags used within */ + /* FT_Open_Args(). */ + /* */ + /* */ + /* ft_open_memory :: This is a memory-based stream. */ + /* */ + /* ft_open_stream :: Copy the stream from the `stream' field. */ + /* */ + /* ft_open_pathname :: Create a new input stream from a C pathname. */ + /* */ + /* ft_open_driver :: Use the `driver' field. */ + /* */ + /* ft_open_params :: Use the `num_params' & `params' field. */ + /* */ + typedef enum + { + ft_open_memory = 1, + ft_open_stream = 2, + ft_open_pathname = 4, + ft_open_driver = 8, + ft_open_params = 16 + + } FT_Open_Flags; + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Parameter */ + /* */ + /* */ + /* A simple structure used to pass more or less generic parameters */ + /* to FT_Open_Face(). */ + /* */ + /* */ + /* tag :: A 4-byte identification tag. */ + /* */ + /* data :: A pointer to the parameter data. */ + /* */ + /* */ + /* The id and function of parameters are driver-specific. */ + /* */ + typedef struct FT_Parameter_ + { + FT_ULong tag; + FT_Pointer data; + + } FT_Parameter; + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Open_Args */ + /* */ + /* */ + /* A structure used to indicate how to open a new font file/stream. */ + /* A pointer to such a structure can be used as a parameter for the */ + /* functions FT_Open_Face() & FT_Attach_Stream(). */ + /* */ + /* */ + /* flags :: A set of bit flags indicating how to use the */ + /* structure. */ + /* */ + /* memory_base :: The first byte of the file in memory. */ + /* */ + /* memory_size :: The size in bytes of the file in memory. */ + /* */ + /* pathname :: A pointer to an 8-bit file pathname. */ + /* */ + /* stream :: A handle to a source stream object. */ + /* */ + /* driver :: This field is exclusively used by FT_Open_Face(); */ + /* it simply specifies the font driver to use to open */ + /* the face. If set to 0, FreeType will try to load */ + /* the face with each one of the drivers in its list. */ + /* */ + /* num_params :: The number of extra parameters. */ + /* */ + /* params :: Extra parameters passed to the font driver when */ + /* opening a new face. */ + /* */ + /* */ + /* `stream_type' determines which fields are used to create a new */ + /* input stream. */ + /* */ + /* If it is `ft_stream_memory', a new memory-based stream will be */ + /* created using the memory block specified by `memory_base' and */ + /* `memory_size'. */ + /* */ + /* If it is `ft_stream_pathname', a new stream will be created with */ + /* the `pathname' field, calling the system-specific FT_New_Stream() */ + /* function. */ + /* */ + /* If is is `ft_stream_copy', then the content of `stream' will be */ + /* copied to a new input stream object. The object will be closed */ + /* and destroyed when the face is destroyed itself. Note that this */ + /* means that you should not close the stream before the library */ + /* does! */ + /* */ + typedef struct FT_Open_Args_ + { + FT_Open_Flags flags; + FT_Byte* memory_base; + FT_Long memory_size; + FT_String* pathname; + FT_Stream stream; + FT_Module driver; + FT_Int num_params; + FT_Parameter* params; + + } FT_Open_Args; + + + /*************************************************************************/ + /* */ + /* */ + /* FT_New_Face */ + /* */ + /* */ + /* Creates a new face object from a given resource and typeface index */ + /* using a pathname to the font file. */ + /* */ + /* */ + /* library :: A handle to the library resource. */ + /* */ + /* */ + /* pathname :: A path to the font file. */ + /* */ + /* face_index :: The index of the face within the resource. The */ + /* first face has index 0. */ + /* */ + /* aface :: A handle to a new face object. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* Unlike FreeType 1.x, this function automatically creates a glyph */ + /* slot for the face object which can be accessed directly through */ + /* `face->glyph'. */ + /* */ + /* Note that additional slots can be added to each face with the */ + /* FT_New_GlyphSlot() API function. Slots are linked in a single */ + /* list through their `next' field. */ + /* */ + /* FT_New_Face() can be used to determine and/or check the font */ + /* format of a given font resource. If the `face_index' field is */ + /* negative, the function will _not_ return any face handle in */ + /* `*face'. Its return value should be 0 if the resource is */ + /* recognized, or non-zero if not. */ + /* */ + FT_EXPORT_DEF( FT_Error ) FT_New_Face( FT_Library library, + const char* filepathname, + FT_Long face_index, + FT_Face* face ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_New_Memory_Face */ + /* */ + /* */ + /* Creates a new face object from a given resource and typeface index */ + /* using a font file already loaded into memory. */ + /* */ + /* */ + /* library :: A handle to the library resource. */ + /* */ + /* */ + /* file_base :: A pointer to the beginning of the font data. */ + /* */ + /* file_size :: The size of the memory chunk used by the font data. */ + /* */ + /* face_index :: The index of the face within the resource. The */ + /* first face has index 0. */ + /* */ + /* face :: A handle to a new face object. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* Unlike FreeType 1.x, this function automatically creates a glyph */ + /* slot for the face object which can be accessed directly through */ + /* `face->glyph'. */ + /* */ + /* Note that additional slots can be added to each face with the */ + /* FT_New_GlyphSlot() API function. Slots are linked in a single */ + /* list through their `next' field. */ + /* */ + /* FT_New_Memory_Face() can be used to determine and/or check the */ + /* font format of a given font resource. If the `face_index' field */ + /* is negative, the function will _not_ return any face handle in */ + /* `*face'. Its return value should be 0 if the resource is */ + /* recognized, or non-zero if not. */ + /* */ + FT_EXPORT_DEF( FT_Error ) FT_New_Memory_Face( FT_Library library, + FT_Byte* file_base, + FT_Long file_size, + FT_Long face_index, + FT_Face* face ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Open_Face */ + /* */ + /* */ + /* Opens a face object from a given resource and typeface index using */ + /* an `FT_Open_Args' structure. If the face object doesn't exist, it */ + /* will be created. */ + /* */ + /* */ + /* library :: A handle to the library resource. */ + /* */ + /* */ + /* args :: A pointer to an `FT_Open_Args' structure which must */ + /* be filled by the caller. */ + /* */ + /* face_index :: The index of the face within the resource. The */ + /* first face has index 0. */ + /* */ + /* aface :: A handle to a new face object. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* Unlike FreeType 1.x, this function automatically creates a glyph */ + /* slot for the face object which can be accessed directly through */ + /* `face->glyph'. */ + /* */ + /* Note that additional slots can be added to each face with the */ + /* FT_New_GlyphSlot() API function. Slots are linked in a single */ + /* list through their `next' field. */ + /* */ + /* FT_Open_Face() can be used to determine and/or check the font */ + /* format of a given font resource. If the `face_index' field is */ + /* negative, the function will _not_ return any face handle in */ + /* `*face'. Its return value should be 0 if the resource is */ + /* recognized, or non-zero if not. */ + /* */ + FT_EXPORT_DEF( FT_Error ) FT_Open_Face( FT_Library library, + FT_Open_Args* args, + FT_Long face_index, + FT_Face* face ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Attach_File */ + /* */ + /* */ + /* `Attaches' a given font file to an existing face. This is usually */ + /* to read additional information for a single face object. For */ + /* example, it is used to read the AFM files that come with Type 1 */ + /* fonts in order to add kerning data and other metrics. */ + /* */ + /* */ + /* face :: The target face object. */ + /* */ + /* */ + /* filepathname :: An 8-bit pathname naming the `metrics' file. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* If your font file is in memory, or if you want to provide your */ + /* own input stream object, use FT_Attach_Stream(). */ + /* */ + /* The meaning of the `attach' action (i.e., what really happens when */ + /* the new file is read) is not fixed by FreeType itself. It really */ + /* depends on the font format (and thus the font driver). */ + /* */ + /* Client applications are expected to know what they are doing */ + /* when invoking this function. Most drivers simply do not implement */ + /* file attachments. */ + /* */ + FT_EXPORT_DEF( FT_Error ) FT_Attach_File( FT_Face face, + const char* filepathname ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Attach_Stream */ + /* */ + /* */ + /* This function is similar to FT_Attach_File() with the exception */ + /* that it reads the attachment from an arbitrary stream. */ + /* */ + /* */ + /* face :: The target face object. */ + /* */ + /* parameters :: A pointer to an FT_Open_Args structure used to */ + /* describe the input stream to FreeType. */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* The meaning of the `attach' (i.e. what really happens when the */ + /* new file is read) is not fixed by FreeType itself. It really */ + /* depends on the font format (and thus the font driver). */ + /* */ + /* Client applications are expected to know what they are doing */ + /* when invoking this function. Most drivers simply do not implement */ + /* file attachments. */ + /* */ + FT_EXPORT_DEF( FT_Error ) FT_Attach_Stream( FT_Face face, + FT_Open_Args* parameters ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Done_Face */ + /* */ + /* */ + /* Discards a given face object, as well as all of its child slots */ + /* and sizes. */ + /* */ + /* */ + /* face :: A handle to a target face object. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT_DEF( FT_Error ) FT_Done_Face( FT_Face face ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Set_Char_Size */ + /* */ + /* */ + /* Sets the character dimensions of a given face object. The */ + /* `char_width' and `char_height' values are used for the width and */ + /* height, respectively, expressed in 26.6 fractional points. */ + /* */ + /* If the horizontal or vertical resolution values are zero, a */ + /* default value of 72dpi is used. Similarly, if one of the */ + /* character dimensions is zero, its value is set equal to the other. */ + /* */ + /* */ + /* size :: A handle to a target size object. */ + /* */ + /* */ + /* char_width :: The character width, in 26.6 fractional points. */ + /* */ + /* char_height :: The character height, in 26.6 fractional */ + /* points. */ + /* */ + /* horz_resolution :: The horizontal resolution. */ + /* */ + /* vert_resolution :: The vertical resolution. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* When dealing with fixed-size faces (i.e., non-scalable formats), */ + /* use the function FT_Set_Pixel_Sizes(). */ + /* */ + FT_EXPORT_DEF( FT_Error ) FT_Set_Char_Size( FT_Face face, + FT_F26Dot6 char_width, + FT_F26Dot6 char_height, + FT_UInt horz_resolution, + FT_UInt vert_resolution ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Set_Pixel_Sizes */ + /* */ + /* */ + /* Sets the character dimensions of a given face object. The width */ + /* and height are expressed in integer pixels. */ + /* */ + /* If one of the character dimensions is zero, its value is set equal */ + /* to the other. */ + /* */ + /* */ + /* face :: A handle to the target face object. */ + /* */ + /* */ + /* pixel_width :: The character width, in integer pixels. */ + /* */ + /* pixel_height :: The character height, in integer pixels. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT_DEF( FT_Error ) FT_Set_Pixel_Sizes( FT_Face face, + FT_UInt pixel_width, + FT_UInt pixel_height ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Load_Glyph */ + /* */ + /* */ + /* A function used to load a single glyph within a given glyph slot, */ + /* for a given size. */ + /* */ + /* */ + /* face :: A handle to the target face object where the glyph */ + /* will be loaded. */ + /* */ + /* glyph_index :: The index of the glyph in the font file. */ + /* */ + /* load_flags :: A flag indicating what to load for this glyph. The */ + /* FT_LOAD_XXX constants can be used to control the */ + /* glyph loading process (e.g., whether the outline */ + /* should be scaled, whether to load bitmaps or not, */ + /* whether to hint the outline, etc). */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* If the glyph image is not a bitmap, and if the bit flag */ + /* FT_LOAD_IGNORE_TRANSFORM is unset, the glyph image will be */ + /* transformed with the information passed to a previous call to */ + /* FT_Set_Transform. */ + /* */ + /* Note that this also transforms the `face.glyph.advance' field, but */ + /* *not* the values in `face.glyph.metrics'. */ + /* */ + FT_EXPORT_DEF( FT_Error ) FT_Load_Glyph( FT_Face face, + FT_UInt glyph_index, + FT_Int load_flags ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Load_Char */ + /* */ + /* */ + /* A function used to load a single glyph within a given glyph slot, */ + /* for a given size, according to its character code. */ + /* */ + /* */ + /* face :: A handle to a target face object where the glyph */ + /* will be loaded. */ + /* */ + /* char_code :: The glyph's character code, according to the */ + /* current charmap used in the face. */ + /* */ + /* load_flags :: A flag indicating what to load for this glyph. The */ + /* FT_LOAD_XXX constants can be used to control the */ + /* glyph loading process (e.g., whether the outline */ + /* should be scaled, whether to load bitmaps or not, */ + /* whether to hint the outline, etc). */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* If the face has no current charmap, or if the character code */ + /* is not defined in the charmap, this function will return an */ + /* error. */ + /* */ + /* If the glyph image is not a bitmap, and if the bit flag */ + /* FT_LOAD_IGNORE_TRANSFORM is unset, the glyph image will be */ + /* transformed with the information passed to a previous call to */ + /* FT_Set_Transform(). */ + /* */ + /* Note that this also transforms the `face.glyph.advance' field, but */ + /* *not* the values in `face.glyph.metrics'. */ + /* */ + FT_EXPORT_DEF( FT_Error ) FT_Load_Char( FT_Face face, + FT_ULong char_code, + FT_Int load_flags ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_LOAD_NO_SCALE */ + /* */ + /* */ + /* A bit field constant, used with FT_Load_Glyph() to indicate that */ + /* the vector outline being loaded should not be scaled to 26.6 */ + /* fractional pixels, but kept in notional units. */ + /* */ +#define FT_LOAD_NO_SCALE 1 + + + /*************************************************************************/ + /* */ + /* */ + /* FT_LOAD_NO_HINTING */ + /* */ + /* */ + /* A bit-field constant, used with FT_Load_Glyph() to indicate that */ + /* the vector outline being loaded should not be fitted to the pixel */ + /* grid but simply scaled to 26.6 fractional pixels. */ + /* */ + /* This flag is ignored if FT_LOAD_NO_SCALE is set. */ + /* */ +#define FT_LOAD_NO_HINTING 2 + + + /*************************************************************************/ + /* */ + /* */ + /* FT_LOAD_RENDER */ + /* */ + /* */ + /* A bit-field constant, used with FT_Load_Glyph() to indicate that */ + /* the function should load the glyph and immediately convert it into */ + /* a bitmap, if necessary, by calling FT_Render_Glyph(). */ + /* */ + /* Note that by default, FT_Load_Glyph() loads the glyph image in its */ + /* native format. */ + /* */ +#define FT_LOAD_RENDER 4 + + + /*************************************************************************/ + /* */ + /* */ + /* FT_LOAD_NO_BITMAP */ + /* */ + /* */ + /* A bit-field constant, used with FT_Load_Glyph() to indicate that */ + /* the function should not load the bitmap or pixmap of a given */ + /* glyph. This is useful when you do not want to load the embedded */ + /* bitmaps of scalable formats, as the native glyph image will be */ + /* loaded, and can then be rendered through FT_Render_Glyph(). */ + /* */ +#define FT_LOAD_NO_BITMAP 8 + + + /*************************************************************************/ + /* */ + /* */ + /* FT_LOAD_VERTICAL_LAYOUT */ + /* */ + /* */ + /* A bit-field constant, used with FT_Load_Glyph() to indicate that */ + /* the glyph image should be prepared for vertical layout. This */ + /* basically means that `face.glyph.advance' will correspond to the */ + /* vertical advance height (instead of the default horizontal */ + /* advance width), and that the glyph image will translated to match */ + /* the vertical bearings positions. */ + /* */ +#define FT_LOAD_VERTICAL_LAYOUT 16 + + + /*************************************************************************/ + /* */ + /* */ + /* FT_LOAD_FORCE_AUTOHINT */ + /* */ + /* */ + /* A bit-field constant, used with FT_Load_Glyph() to indicate that */ + /* the function should try to auto-hint the glyphs, even if a driver */ + /* specific hinter is available. */ + /* */ +#define FT_LOAD_FORCE_AUTOHINT 32 + + + /*************************************************************************/ + /* */ + /* */ + /* FT_LOAD_CROP_BITMAP */ + /* */ + /* */ + /* A bit-field constant, used with FT_Load_Glyph() to indicate that */ + /* the font driver should try to crop the bitmap (i.e. remove all */ + /* space around its black bits) when loading it. For now, this */ + /* really only works with embedded bitmaps in TrueType fonts. */ + /* */ +#define FT_LOAD_CROP_BITMAP 64 + + + /*************************************************************************/ + /* */ + /* */ + /* FT_LOAD_PEDANTIC */ + /* */ + /* */ + /* A bit-field constant, used with FT_Load_Glyph() to indicate that */ + /* the glyph loader should perform a pedantic bytecode */ + /* interpretation. Many popular fonts come with broken glyph */ + /* programs. When this flag is set, loading them will return an */ + /* error. Otherwise, errors are ignored by the loader, sometimes */ + /* resulting in ugly glyphs. */ + /* */ +#define FT_LOAD_PEDANTIC 128 + + + /*************************************************************************/ + /* */ + /* */ + /* FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH */ + /* */ + /* */ + /* A bit-field constant, used with FT_Load_Glyph() to indicate that */ + /* the glyph loader should ignore the global advance width defined */ + /* in the font. As far as we know, this is only used by the */ + /* X-TrueType font server, in order to deal correctly with the */ + /* incorrect metrics contained in DynaLab's TrueType CJK fonts. */ + /* */ +#define FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH 512 + + + /*************************************************************************/ + /* */ + /* */ + /* FT_LOAD_NO_RECURSE */ + /* */ + /* */ + /* A bit-field constant, used with FT_Load_Glyph() to indicate that */ + /* the glyph loader should not load composite glyph recursively. */ + /* Rather, when a composite glyph is encountered, it should set */ + /* the values of `num_subglyphs' and `subglyphs', as well as set */ + /* `face->glyph.format' to ft_glyph_format_composite. */ + /* */ + /* This is for use by the auto-hinter and possibly other tools. */ + /* For nearly all applications, this flags should be left unset */ + /* when invoking FT_Load_Glyph(). */ + /* */ + /* Note that the flag forces the load of unscaled glyphs. */ + /* */ +#define FT_LOAD_NO_RECURSE 1024 + + + /*************************************************************************/ + /* */ + /* */ + /* FT_LOAD_IGNORE_TRANSFORM */ + /* */ + /* */ + /* A bit-field constant, used with FT_Load_Glyph() to indicate that */ + /* the glyph loader should not try to transform the loaded glyph */ + /* image. */ + /* */ +#define FT_LOAD_IGNORE_TRANSFORM 2048 + + + /*************************************************************************/ + /* */ + /* */ + /* FT_LOAD_MONOCHROME */ + /* */ + /* */ + /* Only used with FT_LOAD_RENDER set, it indicates that the returned */ + /* glyph image should be 1-bit monochrome. This really tells the */ + /* glyph loader to use `ft_render_mode_mono' when calling */ + /* FT_Render_Glyph(). */ + /* */ +#define FT_LOAD_MONOCHROME 4096 + + + /*************************************************************************/ + /* */ + /* */ + /* FT_LOAD_LINEAR_DESIGN */ + /* */ + /* */ + /* A bit-field constant, used with FT_Load_Glyph() to indicate that */ + /* the function should return the linearly scaled metrics expressed */ + /* in original font units, instead of the default 16.16 pixel values. */ + /* */ +#define FT_LOAD_LINEAR_DESIGN 8192 + + + /*************************************************************************/ + /* */ + /* */ + /* FT_LOAD_DEFAULT */ + /* */ + /* */ + /* A bit-field constant, used with FT_Load_Glyph() to indicate that */ + /* the function should try to load the glyph normally, i.e., */ + /* embedded bitmaps are favored over outlines, vectors are always */ + /* scaled and grid-fitted. */ + /* */ +#define FT_LOAD_DEFAULT 0 + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Set_Transform */ + /* */ + /* */ + /* A function used to set the transformation that is applied to glyph */ + /* images just before they are converted to bitmaps in a glyph slot */ + /* when FT_Render_Glyph() is called. */ + /* */ + /* */ + /* face :: A handle to the source face object. */ + /* */ + /* */ + /* matrix :: A pointer to the transformation's 2x2 matrix. Use 0 for */ + /* the identity matrix. */ + /* delta :: A pointer to the translation vector. Use 0 for the null */ + /* vector. */ + /* */ + /* */ + /* The transformation is only applied to scalable image formats after */ + /* the glyph has been loaded. It means that hinting is unaltered by */ + /* the transformation and is performed on the character size given in */ + /* the last call to FT_Set_Char_Sizes() or FT_Set_Pixel_Sizes(). */ + /* */ + FT_EXPORT_DEF( void ) FT_Set_Transform( FT_Face face, + FT_Matrix* matrix, + FT_Vector* delta ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Render_Mode */ + /* */ + /* */ + /* An enumeration type that lists the render modes supported by the */ + /* FreeType 2 renderer(s). A renderer is in charge of converting a */ + /* glyph image into a bitmap. */ + /* */ + /* */ + /* ft_render_mode_normal :: This is the default render mode; it */ + /* corresponds to 8-bit anti-aliased */ + /* bitmaps, using 256 levels of gray. */ + /* */ + /* ft_render_mode_mono :: This render mode is used to produce 1-bit */ + /* monochrome bitmaps. */ + /* */ + /* */ + /* There is no render mode to produce 8-bit `monochrome' bitmaps -- */ + /* you have to make the conversion yourself if you need such things */ + /* (besides, FreeType is not a graphics library). */ + /* */ + /* More modes might appear later for specific display modes (e.g. TV, */ + /* LCDs, etc.). They will be supported through the simple addition */ + /* of a renderer module, with no changes to the rest of the engine. */ + /* */ + typedef enum FT_Render_Mode_ + { + ft_render_mode_normal = 0, + ft_render_mode_mono = 1 + + } FT_Render_Mode; + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Render_Glyph */ + /* */ + /* */ + /* Converts a given glyph image to a bitmap. It does so by */ + /* inspecting the glyph image format, find the relevant renderer, and */ + /* invoke it. */ + /* */ + /* */ + /* slot :: A handle to the glyph slot containing the image to */ + /* convert. */ + /* */ + /* render_mode :: This is the render mode used to render the glyph */ + /* image into a bitmap. See FT_Render_Mode for a list */ + /* of possible values. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT_DEF( FT_Error ) FT_Render_Glyph( FT_GlyphSlot slot, + FT_UInt render_mode ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Kerning_Mode */ + /* */ + /* */ + /* An enumeration used to specify which kerning values to return in */ + /* FT_Get_Kerning(). */ + /* */ + /* */ + /* ft_kerning_default :: Return scaled and grid-fitted kerning */ + /* distances (value is 0). */ + /* */ + /* ft_kerning_unfitted :: Return scaled but un-grid-fitted kerning */ + /* distances. */ + /* */ + /* ft_kerning_unscaled :: Return the kerning vector in original font */ + /* units. */ + /* */ + typedef enum FT_Kerning_Mode_ + { + ft_kerning_default = 0, + ft_kerning_unfitted, + ft_kerning_unscaled + + } FT_Kerning_Mode; + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Get_Kerning */ + /* */ + /* */ + /* Returns the kerning vector between two glyphs of a same face. */ + /* */ + /* */ + /* face :: A handle to a source face object. */ + /* */ + /* left_glyph :: The index of the left glyph in the kern pair. */ + /* */ + /* right_glyph :: The index of the right glyph in the kern pair. */ + /* */ + /* kern_mode :: See FT_Kerning_Mode() for more information. */ + /* Determines the scale/dimension of the returned */ + /* kerning vector. */ + /* */ + /* */ + /* kerning :: The kerning vector. This is in font units for */ + /* scalable formats, and in pixels for fixed-sizes */ + /* formats. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* Only horizontal layouts (left-to-right & right-to-left) are */ + /* supported by this method. Other layouts, or more sophisticated */ + /* kernings, are out of the scope of this API function -- they can be */ + /* implemented through format-specific interfaces. */ + /* */ + FT_EXPORT_DEF( FT_Error ) FT_Get_Kerning( FT_Face face, + FT_UInt left_glyph, + FT_UInt right_glyph, + FT_UInt kern_mode, + FT_Vector* kerning ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Get_Glyph_Name */ + /* */ + /* */ + /* Retrieves the ASCII name of a given glyph in a face. This only */ + /* works for those faces where FT_HAS_GLYPH_NAME(face) returns true. */ + /* */ + /* */ + /* face :: A handle to a source face object. */ + /* */ + /* glyph_index :: The glyph index. */ + /* */ + /* buffer :: A pointer to a target buffer where the name will be */ + /* copied to. */ + /* */ + /* buffer_max :: The maximal number of bytes available in the */ + /* buffer. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* An error is returned if the face doesn't provide glyph names or if */ + /* the glyph index is invalid. In all cases of failure, the first */ + /* byte of `buffer' will be set to 0 to indicate an empty name. */ + /* */ + /* The glyph name is truncated to fit within the buffer if it is too */ + /* long. The returned string is always zero-terminated. */ + /* */ + /* This function is not compiled within the library if the config */ + /* macro FT_CONFIG_OPTION_NO_GLYPH_NAMES is defined in */ + /* `include/freetype/config/ftoptions.h' */ + /* */ + FT_EXPORT_DEF( FT_Error ) FT_Get_Glyph_Name( FT_Face face, + FT_UInt glyph_index, + FT_Pointer buffer, + FT_UInt buffer_max ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Select_Charmap */ + /* */ + /* */ + /* Selects a given charmap by its encoding tag (as listed in */ + /* `freetype.h'). */ + /* */ + /* */ + /* face :: A handle to the source face object. */ + /* */ + /* encoding :: A handle to the selected charmap. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* This function will return an error if no charmap in the face */ + /* corresponds to the encoding queried here. */ + /* */ + FT_EXPORT_DEF( FT_Error ) FT_Select_Charmap( FT_Face face, + FT_Encoding encoding ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Set_Charmap */ + /* */ + /* */ + /* Selects a given charmap for character code to glyph index */ + /* decoding. */ + /* */ + /* */ + /* face :: A handle to the source face object. */ + /* charmap :: A handle to the selected charmap. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* This function will return an error if the charmap is not part of */ + /* the face (i.e., if it is not listed in the face->charmaps[] */ + /* table). */ + /* */ + FT_EXPORT_DEF( FT_Error ) FT_Set_Charmap( FT_Face face, + FT_CharMap charmap ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Get_Char_Index */ + /* */ + /* */ + /* Returns the glyph index of a given character code. This function */ + /* uses a charmap object to do the translation. */ + /* */ + /* */ + /* face :: A handle to the source face object. */ + /* */ + /* charcode :: The character code. */ + /* */ + /* */ + /* The glyph index. 0 means `undefined character code'. */ + /* */ + FT_EXPORT_DEF( FT_UInt ) FT_Get_Char_Index( FT_Face face, + FT_ULong charcode ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_MulDiv */ + /* */ + /* */ + /* A very simple function used to perform the computation `(a*b)/c' */ + /* with maximal accuracy (it uses a 64-bit intermediate integer */ + /* whenever necessary). */ + /* */ + /* This function isn't necessarily as fast as some processor specific */ + /* operations, but is at least completely portable. */ + /* */ + /* */ + /* a :: The first multiplier. */ + /* b :: The second multiplier. */ + /* c :: The divisor. */ + /* */ + /* */ + /* The result of `(a*b)/c'. This function never traps when trying to */ + /* divide by zero; it simply returns `MaxInt' or `MinInt' depending */ + /* on the signs of `a' and `b'. */ + /* */ + FT_EXPORT_DEF( FT_Long ) FT_MulDiv( FT_Long a, + FT_Long b, + FT_Long c ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_MulFix */ + /* */ + /* */ + /* A very simple function used to perform the computation */ + /* `(a*b)/0x10000' with maximal accuracy. Most of the time this is */ + /* used to multiply a given value by a 16.16 fixed float factor. */ + /* */ + /* */ + /* a :: The first multiplier. */ + /* b :: The second multiplier. Use a 16.16 factor here whenever */ + /* possible (see note below). */ + /* */ + /* */ + /* The result of `(a*b)/0x10000'. */ + /* */ + /* */ + /* This function has been optimized for the case where the absolute */ + /* value of `a' is less than 2048, and `b' is a 16.16 scaling factor. */ + /* As this happens mainly when scaling from notional units to */ + /* fractional pixels in FreeType, it resulted in noticeable speed */ + /* improvements between versions 2.x and 1.x. */ + /* */ + /* As a conclusion, always try to place a 16.16 factor as the */ + /* _second_ argument of this function; this can make a great */ + /* difference. */ + /* */ + FT_EXPORT_DEF( FT_Long ) FT_MulFix( FT_Long a, + FT_Long b ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_DivFix */ + /* */ + /* */ + /* A very simple function used to perform the computation */ + /* `(a*0x10000)/b' with maximal accuracy. Most of the time, this is */ + /* used to divide a given value by a 16.16 fixed float factor. */ + /* */ + /* */ + /* a :: The first multiplier. */ + /* b :: The second multiplier. Use a 16.16 factor here whenever */ + /* possible (see note below). */ + /* */ + /* */ + /* The result of `(a*0x10000)/b'. */ + /* */ + /* */ + /* The optimization for FT_DivFix() is simple: If (a << 16) fits in */ + /* 32 bits, then the division is computed directly. Otherwise, we */ + /* use a specialized version of the old FT_MulDiv64(). */ + /* */ + FT_EXPORT_DEF( FT_Long ) FT_DivFix( FT_Long a, + FT_Long b ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Vector_Transform */ + /* */ + /* */ + /* Transforms a single vector through a 2x2 matrix. */ + /* */ + /* */ + /* vector :: The target vector to transform. */ + /* */ + /* */ + /* matrix :: A pointer to the source 2x2 matrix. */ + /* */ + /* */ + /* Yes. */ + /* */ + /* */ + /* The result is undefined if either `vector' or `matrix' is invalid. */ + /* */ + FT_EXPORT_DEF( void ) FT_Vector_Transform( FT_Vector* vec, + FT_Matrix* matrix ); + + + +#ifdef __cplusplus + } +#endif + + +#endif /* FREETYPE_H */ + + +/* END */ diff --git a/src/freetype/freetype/ftbbox.h b/src/freetype/freetype/ftbbox.h new file mode 100644 index 0000000000..e1446647df --- /dev/null +++ b/src/freetype/freetype/ftbbox.h @@ -0,0 +1,72 @@ +/***************************************************************************/ +/* */ +/* ftbbox.h */ +/* */ +/* FreeType bbox computation (specification). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + + /*************************************************************************/ + /* */ + /* This component has a _single_ role: to compute exact outline bounding */ + /* boxes. */ + /* */ + /* It is separated from the rest of the engine for various technical */ + /* reasons. It may well be integrated in `ftoutln' later. */ + /* */ + /*************************************************************************/ + + +#ifndef FTBBOX_H +#define FTBBOX_H + +#include + +#ifdef __cplusplus + extern "C" { +#endif + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Raster_GetBBox */ + /* */ + /* */ + /* Computes the exact bounding box of an outline. This is slower */ + /* than computing the control box. However, it uses an advanced */ + /* algorithm which returns _very_ quickly when the two boxes */ + /* coincide. Otherwise, the outline Bezier arcs are walked over to */ + /* extract their extrema. */ + /* */ + /* */ + /* outline :: A pointer to the source outline. */ + /* */ + /* */ + /* bbox :: The outline's exact bounding box. */ + /* */ + /* */ + /* Error code. 0 means success. */ + /* */ + FT_EXPORT_DEF(FT_Error) FT_Raster_GetBBox( FT_Outline* outline, + FT_BBox* abbox ); + + +#ifdef __cplusplus + } +#endif + +#endif /* FTBBOX_H */ + + +/* END */ diff --git a/src/freetype/freetype/fterrors.h b/src/freetype/freetype/fterrors.h new file mode 100644 index 0000000000..9fb8099b89 --- /dev/null +++ b/src/freetype/freetype/fterrors.h @@ -0,0 +1,166 @@ +/***************************************************************************/ +/* */ +/* fterrors.h */ +/* */ +/* FreeType error codes (specification). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + + /*************************************************************************/ + /* */ + /* This file is used to define the FreeType error enumeration constants */ + /* It can also be used to create an error message table easily with */ + /* something like: */ + /* */ + /* { */ + /* #undef FTERRORS_H */ + /* #define FT_ERRORDEF( e, v, s ) { e, s }, */ + /* #define FT_ERROR_START_LIST { */ + /* #define FT_ERROR_END_LIST { 0, 0 } }; */ + /* */ + /* const struct */ + /* { */ + /* int err_code; */ + /* const char* err_msg */ + /* } ft_errors[] = */ + /* */ + /* #include */ + /* } */ + /* */ + /*************************************************************************/ + + +#ifndef FTERRORS_H +#define FTERRORS_H + + +#ifndef FT_ERRORDEF + +#define FT_ERRORDEF( e, v, s ) e = v, +#define FT_ERROR_START_LIST enum { +#define FT_ERROR_END_LIST FT_Err_Max }; + +#endif /* !FT_ERRORDEF */ + + +#ifdef FT_ERROR_START_LIST + FT_ERROR_START_LIST +#endif + + FT_ERRORDEF( FT_Err_Ok, 0x0000, \ + "no error" ) + FT_ERRORDEF( FT_Err_Cannot_Open_Resource, 0x0001, \ + "can't open stream" ) + FT_ERRORDEF( FT_Err_Unknown_File_Format, 0x0002, \ + "unknown file format" ) + FT_ERRORDEF( FT_Err_Invalid_File_Format, 0x0003, \ + "broken file" ) + + FT_ERRORDEF( FT_Err_Invalid_Argument, 0x0010, \ + "invalid argument" ) + FT_ERRORDEF( FT_Err_Invalid_Handle, 0x0011, \ + "invalid object handle" ) + FT_ERRORDEF( FT_Err_Invalid_Glyph_Index, 0x0012, \ + "invalid glyph index" ) + FT_ERRORDEF( FT_Err_Invalid_Character_Code, 0x0013, \ + "invalid character code" ) + + FT_ERRORDEF( FT_Err_Unimplemented_Feature, 0x0020, \ + "unimplemented feature" ) + FT_ERRORDEF( FT_Err_Invalid_Glyph_Format, 0x0021, \ + "unsupported glyph image format" ) + FT_ERRORDEF( FT_Err_Cannot_Render_Glyph, 0x0022, \ + "cannot render this glyph format" ) + + FT_ERRORDEF( FT_Err_Invalid_Library_Handle, 0x0030, \ + "invalid library handle" ) + FT_ERRORDEF( FT_Err_Invalid_Driver_Handle, 0x0031, \ + "invalid module handle" ) + FT_ERRORDEF( FT_Err_Invalid_Face_Handle, 0x0032, \ + "invalid face handle" ) + FT_ERRORDEF( FT_Err_Invalid_Size_Handle, 0x0033, \ + "invalid size handle" ) + FT_ERRORDEF( FT_Err_Invalid_Slot_Handle, 0x0034, \ + "invalid glyph slot handle" ) + FT_ERRORDEF( FT_Err_Invalid_CharMap_Handle, 0x0035, \ + "invalid charmap handle" ) + FT_ERRORDEF( FT_Err_Invalid_Outline, 0x0036, \ + "invalid outline" ) + FT_ERRORDEF( FT_Err_Invalid_Version, 0x0037, \ + "invalid FreeType version" ) + FT_ERRORDEF( FT_Err_Lower_Module_Version, 0x0038, \ + "module version is too low" ) + + FT_ERRORDEF( FT_Err_Too_Many_Drivers, 0x0040, \ + "too many modules" ) + FT_ERRORDEF( FT_Err_Too_Many_Extensions, 0x0041, \ + "too many extensions" ) + + FT_ERRORDEF( FT_Err_Out_Of_Memory, 0x0050, \ + "out of memory" ) + FT_ERRORDEF( FT_Err_Unlisted_Object, 0x0051, \ + "unlisted object" ) + + FT_ERRORDEF( FT_Err_Invalid_Stream_Handle, 0x0060, \ + "invalid stream handle" ) + FT_ERRORDEF( FT_Err_Cannot_Open_Stream, 0x0061, \ + "cannot open stream" ) + FT_ERRORDEF( FT_Err_Invalid_Stream_Seek, 0x0062, \ + "invalid stream seek" ) + FT_ERRORDEF( FT_Err_Invalid_Stream_Skip, 0x0063, \ + "invalid stream skip" ) + FT_ERRORDEF( FT_Err_Invalid_Stream_Read, 0x0064, \ + "invalid stream read" ) + FT_ERRORDEF( FT_Err_Invalid_Stream_Operation, 0x0065, \ + "invalid stream operation" ) + FT_ERRORDEF( FT_Err_Invalid_Frame_Operation, 0x0066, \ + "invalid frame operation" ) + FT_ERRORDEF( FT_Err_Nested_Frame_Access, 0x0067, \ + "nested frame access" ) + FT_ERRORDEF( FT_Err_Invalid_Frame_Read, 0x0068, \ + "invalid frame read" ) + + FT_ERRORDEF( FT_Err_Invalid_Composite, 0x0070, \ + "invalid composite glyph" ) + FT_ERRORDEF( FT_Err_Too_Many_Hints, 0x0071, \ + "too many hints" ) + + FT_ERRORDEF( FT_Err_Raster_Uninitialized, 0x0080, \ + "raster uninitialized" ) + FT_ERRORDEF( FT_Err_Raster_Corrupted, 0x0081, \ + "raster corrupted" ) + FT_ERRORDEF( FT_Err_Raster_Overflow, 0x0082, \ + "raster overflow" ) + FT_ERRORDEF( FT_Err_Raster_Negative_Height, 0x0083, \ + "negative height while rastering" ) + + /* range 0x400 - 0x4FF is reserved for TrueType specific stuff */ + + /* range 0x500 - 0x5FF is reserved for CFF specific stuff */ + + /* range 0x600 - 0x6FF is reserved for Type1 specific stuff */ + +#ifdef FT_ERROR_END_LIST + FT_ERROR_END_LIST +#endif + + +#undef FT_ERROR_START_LIST +#undef FT_ERROR_END_LIST +#undef FT_ERRORDEF + + +#endif /* FTERRORS_H */ + + +/* END */ diff --git a/src/freetype/freetype/ftglyph.h b/src/freetype/freetype/ftglyph.h new file mode 100644 index 0000000000..0647c883eb --- /dev/null +++ b/src/freetype/freetype/ftglyph.h @@ -0,0 +1,422 @@ +/***************************************************************************/ +/* */ +/* ftglyph.h */ +/* */ +/* FreeType convenience functions to handle glyphs (specification). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + + /*************************************************************************/ + /* */ + /* This file contains the definition of several convenience functions */ + /* that can be used by client applications to easily retrieve glyph */ + /* bitmaps and outlines from a given face. */ + /* */ + /* These functions should be optional if you are writing a font server */ + /* or text layout engine on top of FreeType. However, they are pretty */ + /* handy for many other simple uses of the library. */ + /* */ + /*************************************************************************/ + + +#ifndef FTGLYPH_H +#define FTGLYPH_H + +#include + +#ifdef __cplusplus + extern "C" { +#endif + + /* forward declaration to a private type */ + typedef struct FT_Glyph_Class_ FT_Glyph_Class; + + + /*************************************************************************/ + /* */ + /* */ + /* FT_GlyphRec */ + /* */ + /* */ + /* The root glyph structure contains a given glyph image plus its */ + /* advance width in 16.16 fixed float format. */ + /* */ + /* */ + /* library :: A handle to the FreeType library object. */ + /* */ + /* clazz :: A pointer to the glyph's class. Private. */ + /* */ + /* format :: The format of the glyph's image. */ + /* */ + /* advance :: A 16.16 vector that gives the glyph's advance width. */ + /* */ + typedef struct FT_GlyphRec_ + { + FT_Library library; + const FT_Glyph_Class* clazz; + FT_Glyph_Format format; + FT_Vector advance; + + } FT_GlyphRec, *FT_Glyph; + + + /*************************************************************************/ + /* */ + /* */ + /* FT_BitmapGlyphRec */ + /* */ + /* */ + /* A structure used for bitmap glyph images. This really is a */ + /* `sub-class' of `FT_GlyphRec'. */ + /* */ + /* */ + /* root :: The root FT_Glyph fields. */ + /* */ + /* left :: The left-side bearing, i.e., the horizontal distance */ + /* from the current pen position to the left border of the */ + /* glyph bitmap. */ + /* */ + /* top :: The top-side bearing, i.e., the vertical distance from */ + /* the current pen position to the top border of the glyph */ + /* bitmap. This distance is positive for upwards-y! */ + /* */ + /* bitmap :: A descriptor for the bitmap. */ + /* */ + /* */ + /* You can typecast FT_Glyph to FT_BitmapGlyph if you have */ + /* glyph->format == ft_glyph_format_bitmap. This lets you access */ + /* the bitmap's contents easily. */ + /* */ + /* The corresponding pixel buffer is always owned by the BitmapGlyph */ + /* and is thus created and destroyed with it. */ + /* */ + typedef struct FT_BitmapGlyphRec_ + { + FT_GlyphRec root; + FT_Int left; + FT_Int top; + FT_Bitmap bitmap; + + } FT_BitmapGlyphRec, *FT_BitmapGlyph; + + + /*************************************************************************/ + /* */ + /* */ + /* FT_OutlineGlyphRec */ + /* */ + /* */ + /* A structure used for outline (vectorial) glyph images. This */ + /* really is a `sub-class' of `FT_GlyphRec'. */ + /* */ + /* */ + /* root :: The root FT_Glyph fields. */ + /* */ + /* outline :: A descriptor for the outline. */ + /* */ + /* */ + /* You can typecast FT_Glyph to FT_OutlineGlyph if you have */ + /* glyph->format == ft_glyph_format_outline. This lets you access */ + /* the outline's content easily. */ + /* */ + /* As the outline is extracted from a glyph slot, its coordinates are */ + /* expressed normally in 26.6 pixels, unless the flag */ + /* FT_LOAD_NO_SCALE was used in FT_Load_Glyph() or FT_Load_Char(). */ + /* */ + /* The outline's tables are always owned by the object and are */ + /* destroyed with it. */ + /* */ + typedef struct FT_OutlineGlyphRec_ + { + FT_GlyphRec root; + FT_Outline outline; + + } FT_OutlineGlyphRec, *FT_OutlineGlyph; + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Get_Glyph */ + /* */ + /* */ + /* A function used to extract a glyph image from a slot. */ + /* */ + /* */ + /* slot :: A handle to the source glyph slot. */ + /* */ + /* */ + /* aglyph :: A handle to the glyph object. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT_DEF( FT_Error ) FT_Get_Glyph( FT_GlyphSlot slot, + FT_Glyph* aglyph ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Glyph_Copy */ + /* */ + /* */ + /* A function used to copy a glyph image. */ + /* */ + /* */ + /* source :: A handle to the source glyph object. */ + /* */ + /* */ + /* target :: A handle to the target glyph object. 0 in case of */ + /* error. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT_DEF( FT_Error ) FT_Glyph_Copy( FT_Glyph source, + FT_Glyph* target ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Glyph_Transform */ + /* */ + /* */ + /* Transforms a glyph image if its format is scalable. */ + /* */ + /* */ + /* glyph :: A handle to the target glyph object. */ + /* */ + /* matrix :: A pointer to a 2x2 matrix to apply. */ + /* */ + /* delta :: A pointer to a 2d vector to apply. Coordinates are */ + /* expressed in 1/64th of a pixel. */ + /* */ + /* */ + /* FreeType error code (the glyph format is not scalable if it is */ + /* not zero). */ + /* */ + /* */ + /* The 2x2 transformation matrix is also applied to the glyph's */ + /* advance vector. */ + /* */ + FT_EXPORT_DEF( FT_Error ) FT_Glyph_Transform( FT_Glyph glyph, + FT_Matrix* matrix, + FT_Vector* delta ); + + + enum + { + ft_glyph_bbox_pixels = 0, + ft_glyph_bbox_subpixels = 1, + ft_glyph_bbox_gridfit = 2 + }; + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Glyph_Get_CBox */ + /* */ + /* */ + /* Returns the glyph image's bounding box. */ + /* */ + /* */ + /* glyph :: A handle to the source glyph object. */ + /* */ + /* mode :: A set of bit flags that indicate how to interpret the */ + /* returned bounding box values. */ + /* */ + /* */ + /* box :: The glyph bounding box. Coordinates are expressed in */ + /* 1/64th of pixels if it is grid-fitted. */ + /* */ + /* */ + /* Coordinates are relative to the glyph origin, using the Y-upwards */ + /* convention. */ + /* */ + /* If `ft_glyph_bbox_subpixels' is set in `mode', the bbox */ + /* coordinates are returned in 26.6 pixels (i.e. 1/64th of pixels). */ + /* Otherwise, coordinates are expressed in integer pixels. */ + /* */ + /* Note that the maximum coordinates are exclusive, which means that */ + /* one can compute the width and height of the glyph image (be it in */ + /* integer or 26.6 pixels) as: */ + /* */ + /* width = bbox.xMax - bbox.xMin; */ + /* height = bbox.yMax - bbox.yMin; */ + /* */ + /* Note also that for 26.6 coordinates, if the */ + /* `ft_glyph_bbox_gridfit' flag is set in `mode;, the coordinates */ + /* will also be grid-fitted, which corresponds to: */ + /* */ + /* bbox.xMin = FLOOR(bbox.xMin); */ + /* bbox.yMin = FLOOR(bbox.yMin); */ + /* bbox.xMax = CEILING(bbox.xMax); */ + /* bbox.yMax = CEILING(bbox.yMax); */ + /* */ + /* The default value (0) for `bbox_mode' is `ft_glyph_bbox_pixels'. */ + /* */ + FT_EXPORT_DEF( void ) FT_Glyph_Get_CBox( FT_Glyph glyph, + FT_UInt bbox_mode, + FT_BBox* cbox ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Glyph_To_Bitmap */ + /* */ + /* */ + /* Converts a given glyph object to a bitmap glyph object. */ + /* */ + /* */ + /* glyph :: A pointer to a handle to the target glyph. */ + /* */ + /* */ + /* render_mode :: A set of bit flags that describe how the data is */ + /* */ + /* */ + /* origin :: A pointer to a vector used to translate the glyph */ + /* image before rendering. Can be 0 (if no */ + /* translation). The origin is expressed in */ + /* 26.6 pixels. */ + /* */ + /* destroy :: A boolean that indicates that the original glyph */ + /* image should be destroyed by this function. It is */ + /* never destroyed in case of error. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* The glyph image is translated with the `origin' vector before */ + /* rendering. In case of error, it it translated back to its */ + /* original position and the glyph is left untouched. */ + /* */ + /* The first parameter is a pointer to a FT_Glyph handle, that will */ + /* be replaced by this function. Typically, you would use (omitting */ + /* error handling): */ + /* */ + /* */ + /* { */ + /* FT_Glyph glyph; */ + /* FT_BitmapGlyph glyph_bitmap; */ + /* */ + /* */ + /* // load glyph */ + /* error = FT_Load_Char( face, glyph_index, FT_LOAD_DEFAUT ); */ + /* */ + /* // extract glyph image */ + /* error = FT_Get_Glyph( face->glyph, &glyph ); */ + /* */ + /* // convert to a bitmap (default render mode + destroy old) */ + /* if ( glyph->format != ft_glyph_format_bitmap ) */ + /* { */ + /* error = FT_Glyph_To_Bitmap( &glyph, ft_render_mode_default, */ + /* 0, 1 ); */ + /* if ( error ) // glyph unchanged */ + /* ... */ + /* } */ + /* */ + /* // access bitmap content by typecasting */ + /* glyph_bitmap = (FT_BitmapGlyph)glyph; */ + /* */ + /* // do funny stuff with it, like blitting/drawing */ + /* ... */ + /* */ + /* // discard glyph image (bitmap or not) */ + /* FT_Done_Glyph( glyph ); */ + /* } */ + /* */ + /* */ + /* This function will always fail if the glyph's format isn't */ + /* scalable. */ + /* */ + FT_EXPORT_DEF( FT_Error ) FT_Glyph_To_Bitmap( FT_Glyph* the_glyph, + FT_ULong render_mode, + FT_Vector* origin, + FT_Bool destroy ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Done_Glyph */ + /* */ + /* */ + /* Destroys a given glyph. */ + /* */ + /* */ + /* glyph :: A handle to the target glyph object. */ + /* */ + FT_EXPORT_DEF( void ) FT_Done_Glyph( FT_Glyph glyph ); + + + /* other helpful functions */ + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Matrix_Multiply */ + /* */ + /* */ + /* Performs the matrix operation `b = a*b'. */ + /* */ + /* */ + /* a :: A pointer to matrix `a'. */ + /* */ + /* */ + /* b :: A pointer to matrix `b'. */ + /* */ + /* */ + /* Yes. */ + /* */ + /* */ + /* The result is undefined if either `a' or `b' is zero. */ + /* */ + FT_EXPORT_DEF( void ) FT_Matrix_Multiply( FT_Matrix* a, + FT_Matrix* b ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Matrix_Invert */ + /* */ + /* */ + /* Inverts a 2x2 matrix. Returns an error if it can't be inverted. */ + /* */ + /* */ + /* matrix :: A pointer to the target matrix. Remains untouched in */ + /* case of error. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* Yes. */ + /* */ + FT_EXPORT_DEF( FT_Error ) FT_Matrix_Invert( FT_Matrix* matrix ); + + +#ifdef __cplusplus + } +#endif + +#endif /* FTGLYPH_H */ + + +/* END */ diff --git a/src/freetype/freetype/ftimage.h b/src/freetype/freetype/ftimage.h new file mode 100644 index 0000000000..4dd1c3d213 --- /dev/null +++ b/src/freetype/freetype/ftimage.h @@ -0,0 +1,1003 @@ +/***************************************************************************/ +/* */ +/* ftimage.h */ +/* */ +/* FreeType glyph image formats and default raster interface */ +/* (specification). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + /*************************************************************************/ + /* */ + /* Note: A `raster' is simply a scan-line converter, used to render */ + /* FT_Outlines into FT_Bitmaps. */ + /* */ + /*************************************************************************/ + + +#ifndef FTIMAGE_H +#define FTIMAGE_H + + +#ifdef __cplusplus + extern "C" { +#endif + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Pos */ + /* */ + /* */ + /* The type FT_Pos is a 32-bit integer used to store vectorial */ + /* coordinates. Depending on the context, these can represent */ + /* distances in integer font units, or 26.6 fixed float pixel */ + /* coordinates. */ + /* */ + typedef signed long FT_Pos; + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Vector */ + /* */ + /* */ + /* A simple structure used to store a 2D vector; coordinates are of */ + /* the FT_Pos type. */ + /* */ + /* */ + /* x :: The horizontal coordinate. */ + /* y :: The vertical coordinate. */ + /* */ + typedef struct FT_Vector_ + { + FT_Pos x; + FT_Pos y; + + } FT_Vector; + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Pixel_Mode */ + /* */ + /* */ + /* An enumeration type used to describe the format of pixels in a */ + /* given bitmap. Note that additional formats may be added in the */ + /* future. */ + /* */ + /* */ + /* ft_pixel_mode_mono :: A monochrome bitmap (1 bit/pixel). */ + /* */ + /* ft_pixel_mode_grays :: An 8-bit gray-levels bitmap. Note that the */ + /* total number of gray levels is given in the */ + /* `num_grays' field of the FT_Bitmap */ + /* structure. */ + /* */ + /* ft_pixel_mode_pal2 :: A 2-bit paletted bitmap. */ + /* Currently unused by FreeType. */ + /* */ + /* ft_pixel_mode_pal4 :: A 4-bit paletted bitmap. */ + /* Currently unused by FreeType. */ + /* */ + /* ft_pixel_mode_pal8 :: An 8-bit paletted bitmap. */ + /* Currently unused by FreeType. */ + /* */ + /* ft_pixel_mode_rgb15 :: A 15-bit RGB bitmap. Uses 5:5:5 encoding. */ + /* Currently unused by FreeType. */ + /* */ + /* ft_pixel_mode_rgb16 :: A 16-bit RGB bitmap. Uses 5:6:5 encoding. */ + /* Currently unused by FreeType. */ + /* */ + /* ft_pixel_mode_rgb24 :: A 24-bit RGB bitmap. */ + /* Currently unused by FreeType. */ + /* */ + /* ft_pixel_mode_rgb32 :: A 32-bit RGB bitmap. */ + /* Currently unused by FreeType. */ + /* */ + /* */ + /* Some anti-aliased bitmaps might be embedded in TrueType fonts */ + /* using formats pal2 or pal4, though no fonts presenting those have */ + /* been found to date. */ + /* */ + typedef enum FT_Pixel_Mode_ + { + ft_pixel_mode_none = 0, + ft_pixel_mode_mono, + ft_pixel_mode_grays, + ft_pixel_mode_pal2, + ft_pixel_mode_pal4, + ft_pixel_mode_pal8, + ft_pixel_mode_rgb15, + ft_pixel_mode_rgb16, + ft_pixel_mode_rgb24, + ft_pixel_mode_rgb32, + + ft_pixel_mode_max /* do not remove */ + + } FT_Pixel_Mode; + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Palette_Mode */ + /* */ + /* */ + /* An enumeration type used to describe the format of a bitmap */ + /* palette, used with ft_pixel_mode_pal4 and ft_pixel_mode_pal8. */ + /* */ + /* */ + /* ft_palette_mode_rgb :: The palette is an array of 3-bytes RGB */ + /* records. */ + /* */ + /* ft_palette_mode_rgba :: The palette is an array of 4-bytes RGBA */ + /* records. */ + /* */ + /* */ + /* As ft_pixel_mode_pal2, pal4 and pal8 are currently unused by */ + /* FreeType, these types are not handled by the library itself. */ + /* */ + typedef enum FT_Palette_Mode_ + { + ft_palette_mode_rgb = 0, + ft_palette_mode_rgba, + + ft_palettte_mode_max /* do not remove */ + + } FT_Palette_Mode; + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Bitmap */ + /* */ + /* */ + /* A structure used to describe a bitmap or pixmap to the raster. */ + /* Note that we now manage pixmaps of various depths through the */ + /* `pixel_mode' field. */ + /* */ + /* */ + /* rows :: The number of bitmap rows. */ + /* */ + /* width :: The number of pixels in bitmap row. */ + /* */ + /* pitch :: The pitch's absolute value is the number of bytes */ + /* taken by one bitmap row, including padding. */ + /* However, the pitch is positive when the bitmap has */ + /* a `down' flow, and negative when it has an `up' */ + /* flow. In all cases, the pitch is an offset to add */ + /* to a bitmap pointer in order to go down one row. */ + /* */ + /* buffer :: A typeless pointer to the bitmap buffer. This */ + /* value should be aligned on 32-bit boundaries in */ + /* most cases. */ + /* */ + /* num_grays :: This field is only used with */ + /* `ft_pixel_mode_grays'; it gives the number of gray */ + /* levels used in the bitmap. */ + /* */ + /* pixel_mode :: The pixel_mode, i.e., how pixel bits are stored. */ + /* */ + /* palette_mode :: This field is only used with paletted pixel modes; */ + /* it indicates how the palette is stored. */ + /* */ + /* palette :: A typeless pointer to the bitmap palette; only */ + /* used for paletted pixel modes. */ + /* */ + /* */ + /* For now, the only pixel mode supported by FreeType are mono and */ + /* grays. However, drivers might be added in the future to support */ + /* more `colorful' options. */ + /* */ + /* When using pixel modes pal2, pal4 and pal8 with a void `palette' */ + /* field, a gray pixmap with respectively 4, 16, and 256 levels of */ + /* gray is assumed. This, in order to be compatible with some */ + /* embedded bitmap formats defined in the TrueType specification. */ + /* */ + /* Note that no font was found presenting such embedded bitmaps, so */ + /* this is currently completely unhandled by the library. */ + /* */ + typedef struct FT_Bitmap_ + { + int rows; + int width; + int pitch; + unsigned char* buffer; + short num_grays; + char pixel_mode; + char palette_mode; + void* palette; + + } FT_Bitmap; + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Outline */ + /* */ + /* */ + /* This structure is used to describe an outline to the scan-line */ + /* converter. */ + /* */ + /* */ + /* n_contours :: The number of contours in the outline. */ + /* */ + /* n_points :: The number of points in the outline. */ + /* */ + /* points :: A pointer to an array of `n_points' FT_Vector */ + /* elements, giving the outline's point coordinates. */ + /* */ + /* tags :: A pointer to an array of `n_points' chars, giving */ + /* giving each outline point's type. If bit 0 is */ + /* unset, the point is 'off' the curve, i.e. a Bezier */ + /* control point, while it is `on' when unset. */ + /* */ + /* Bit 1 is meaningful for `off' points only. If set, */ + /* it indicates a third-order Bezier arc control point; */ + /* and a second-order control point if unset. */ + /* */ + /* contours :: An array of `n_contours' shorts, giving the end */ + /* point of each contour within the outline. For */ + /* example, the first contour is defined by the points */ + /* `0' to `contours[0]', the second one is defined by */ + /* the points `contours[0]+1' to `contours[1]', etc. */ + /* */ + /* flags :: A set of bit flags used to characterize the outline */ + /* and give hints to the scan-converter and hinter on */ + /* how to convert/grid-fit it. See FT_Outline_Flags. */ + /* */ + typedef struct FT_Outline_ + { + short n_contours; /* number of contours in glyph */ + short n_points; /* number of points in the glyph */ + + FT_Vector* points; /* the outline's points */ + char* tags; /* the points flags */ + short* contours; /* the contour end points */ + + int flags; /* outline masks */ + + } FT_Outline; + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Outline_Flags */ + /* */ + /* */ + /* A simple type used to enumerates the flags in an outline's */ + /* `outline_flags' field. */ + /* */ + /* */ + /* ft_outline_owner :: If set, this flag indicates that the */ + /* outline's field arrays (i.e. */ + /* `points', `flags' & `contours') are */ + /* `owned' by the outline object, and */ + /* should thus be freed when it is */ + /* destroyed. */ + /* */ + /* ft_outline_even_odd_fill :: By default, outlines are filled using */ + /* the non-zero winding rule. If set to */ + /* 1, the outline will be filled using */ + /* the even-odd fill rule (only works */ + /* with the smooth raster). */ + /* */ + /* ft_outline_reverse_fill :: By default, outside contours of an */ + /* outline are oriented in clock-wise */ + /* direction, as defined in the TrueType */ + /* specification. This flag is set if */ + /* the outline uses the opposite */ + /* direction (typically for Type 1 */ + /* fonts). This flag is ignored by the */ + /* scan-converter. However, it is very */ + /* important for the auto-hinter. */ + /* */ + /* ft_outline_ignore_dropouts :: By default, the scan converter will */ + /* try to detect drop-outs in an outline */ + /* and correct the glyph bitmap to */ + /* ensure consistent shape continuity. */ + /* If set, this flag hints the scan-line */ + /* converter to ignore such cases. */ + /* */ + /* ft_outline_high_precision :: This flag indicates that the */ + /* scan-line converter should try to */ + /* convert this outline to bitmaps with */ + /* the highest possible quality. It is */ + /* typically set for small character */ + /* sizes. Note that this is only a */ + /* hint, that might be completely */ + /* ignored by a given scan-converter. */ + /* */ + /* ft_outline_single_pass :: This flag is set to force a given */ + /* scan-converter to only use a single */ + /* pass over the outline to render a */ + /* bitmap glyph image. Normally, it is */ + /* set for very large character sizes. */ + /* It is only a hint, that might be */ + /* completely ignored by a given */ + /* scan-converter. */ + /* */ + typedef enum FT_Outline_Flags_ + { + ft_outline_none = 0, + ft_outline_owner = 1, + ft_outline_even_odd_fill = 2, + ft_outline_reverse_fill = 4, + ft_outline_ignore_dropouts = 8, + ft_outline_high_precision = 256, + ft_outline_single_pass = 512 + + } FT_Outline_Flags; + + +#define FT_CURVE_TAG( flag ) ( flag & 3 ) + +#define FT_Curve_Tag_On 1 +#define FT_Curve_Tag_Conic 0 +#define FT_Curve_Tag_Cubic 2 + +#define FT_Curve_Tag_Touch_X 8 /* reserved for the TrueType hinter */ +#define FT_Curve_Tag_Touch_Y 16 /* reserved for the TrueType hinter */ + +#define FT_Curve_Tag_Touch_Both ( FT_Curve_Tag_Touch_X | \ + FT_Curve_Tag_Touch_Y ) + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Outline_MoveTo_Func */ + /* */ + /* */ + /* A function pointer type used to describe the signature of a `move */ + /* to' function during outline walking/decomposition. */ + /* */ + /* A `move to' is emitted to start a new contour in an outline. */ + /* */ + /* */ + /* to :: A pointer to the target point of the `move to'. */ + /* */ + /* user :: A typeless pointer which is passed from the caller of the */ + /* decomposition function. */ + /* */ + /* */ + /* Error code. 0 means success. */ + /* */ + typedef int (*FT_Outline_MoveTo_Func)( FT_Vector* to, + void* user ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Outline_LineTo_Func */ + /* */ + /* */ + /* A function pointer type used to describe the signature of a `line */ + /* to' function during outline walking/decomposition. */ + /* */ + /* A `line to' is emitted to indicate a segment in the outline. */ + /* */ + /* */ + /* to :: A pointer to the target point of the `line to'. */ + /* */ + /* user :: A typeless pointer which is passed from the caller of the */ + /* decomposition function. */ + /* */ + /* */ + /* Error code. 0 means success. */ + /* */ + typedef int (*FT_Outline_LineTo_Func)( FT_Vector* to, + void* user ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Outline_ConicTo_Func */ + /* */ + /* */ + /* A function pointer type use to describe the signature of a `conic */ + /* to' function during outline walking/decomposition. */ + /* */ + /* A `conic to' is emitted to indicate a second-order Bezier arc in */ + /* the outline. */ + /* */ + /* */ + /* control :: An intermediate control point between the last position */ + /* and the new target in `to'. */ + /* */ + /* to :: A pointer to the target end point of the conic arc. */ + /* */ + /* user :: A typeless pointer which is passed from the caller of */ + /* the decomposition function. */ + /* */ + /* */ + /* Error code. 0 means success. */ + /* */ + typedef int (*FT_Outline_ConicTo_Func)( FT_Vector* control, + FT_Vector* to, + void* user ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Outline_CubicTo_Func */ + /* */ + /* */ + /* A function pointer type used to describe the signature of a `cubic */ + /* to' function during outline walking/decomposition. */ + /* */ + /* A `cubic to' is emitted to indicate a third-order Bezier arc. */ + /* */ + /* */ + /* control1 :: A pointer to the first Bezier control point. */ + /* */ + /* control2 :: A pointer to the second Bezier control point. */ + /* */ + /* to :: A pointer to the target end point. */ + /* */ + /* user :: A typeless pointer which is passed from the caller of */ + /* the decomposition function. */ + /* */ + /* */ + /* Error code. 0 means success. */ + /* */ + typedef int (*FT_Outline_CubicTo_Func)( FT_Vector* control1, + FT_Vector* control2, + FT_Vector* to, + void* user ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Outline_Funcs */ + /* */ + /* */ + /* A structure to hold various function pointers used during outline */ + /* decomposition in order to emit segments, conic, and cubic Beziers, */ + /* as well as `move to' and `close to' operations. */ + /* */ + /* */ + /* move_to :: The `move to' emitter. */ + /* */ + /* line_to :: The segment emitter. */ + /* */ + /* conic_to :: The second-order Bezier arc emitter. */ + /* */ + /* cubic_to :: The third-order Bezier arc emitter. */ + /* */ + /* shift :: The shift that is applied to coordinates before they */ + /* are sent to the emitter. */ + /* */ + /* delta :: The delta that is applied to coordinates before they */ + /* are sent to the emitter, but after the shift. */ + /* */ + /* */ + /* The point coordinates sent to the emitters are the transformed */ + /* version of the original coordinates (this is important for high */ + /* accuracy during scan-conversion). The transformation is simple: */ + /* */ + /* x' = (x << shift) - delta */ + /* y' = (x << shift) - delta */ + /* */ + /* Set the value of `shift' and `delta' to 0 to get the original */ + /* point coordinates. */ + /* */ + typedef struct FT_Outline_Funcs_ + { + FT_Outline_MoveTo_Func move_to; + FT_Outline_LineTo_Func line_to; + FT_Outline_ConicTo_Func conic_to; + FT_Outline_CubicTo_Func cubic_to; + + int shift; + FT_Pos delta; + + } FT_Outline_Funcs; + + + /*************************************************************************/ + /* */ + /* */ + /* FT_IMAGE_TAG */ + /* */ + /* */ + /* This macro converts four letter tags into an unsigned long. */ + /* */ +#define FT_IMAGE_TAG( _x1, _x2, _x3, _x4 ) \ + ( ( (unsigned long)_x1 << 24 ) | \ + ( (unsigned long)_x2 << 16 ) | \ + ( (unsigned long)_x3 << 8 ) | \ + (unsigned long)_x4 ) + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Glyph_Format */ + /* */ + /* */ + /* An enumeration type used to describe the format of a given glyph */ + /* image. Note that this version of FreeType only supports two image */ + /* formats, even though future font drivers will be able to register */ + /* their own format. */ + /* */ + /* */ + /* ft_glyph_format_composite :: The glyph image is a composite of */ + /* several other images. This glyph */ + /* format is _only_ used with the */ + /* FT_LOAD_FLAG_NO_RECURSE flag (XXX: */ + /* Which is currently unimplemented). */ + /* */ + /* ft_glyph_format_bitmap :: The glyph image is a bitmap, and can */ + /* be described as a FT_Bitmap. */ + /* */ + /* ft_glyph_format_outline :: The glyph image is a vectorial image */ + /* made of bezier control points, and */ + /* can be described as a FT_Outline. */ + /* */ + /* ft_glyph_format_plotter :: The glyph image is a vectorial image */ + /* made of plotter lines (some T1 fonts */ + /* like Hershey contain glyph in this */ + /* format). */ + /* */ + typedef enum FT_Glyph_Format_ + { + ft_glyph_format_none = 0, + ft_glyph_format_composite = FT_IMAGE_TAG( 'c', 'o', 'm', 'p' ), + ft_glyph_format_bitmap = FT_IMAGE_TAG( 'b', 'i', 't', 's' ), + ft_glyph_format_outline = FT_IMAGE_TAG( 'o', 'u', 't', 'l' ), + ft_glyph_format_plotter = FT_IMAGE_TAG( 'p', 'l', 'o', 't' ) + + } FT_Glyph_Format; + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** R A S T E R D E F I N I T I O N S *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* A raster is a scan converter, in charge of rendering an outline into */ + /* a a bitmap. This section contains the public API for rasters. */ + /* */ + /* Note that in FreeType 2, all rasters are now encapsulated within */ + /* specific modules called `renderers'. See `freetype/ftrender.h' for */ + /* more details on renderers. */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Raster */ + /* */ + /* */ + /* A handle (pointer) to a raster object. Each object can be used */ + /* independently to convert an outline into a bitmap or pixmap. */ + /* */ + typedef struct FT_RasterRec_* FT_Raster; + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Span */ + /* */ + /* */ + /* A structure used to model a single span of gray (or black) pixels */ + /* when rendering a monochrome or anti-aliased bitmap. */ + /* */ + /* */ + /* x :: The span's horizontal start position. */ + /* */ + /* len :: The span's length in pixels. */ + /* */ + /* coverage :: The span color/coverage, ranging from 0 (background) */ + /* to 255 (foreground). Only used for anti-aliased */ + /* rendering. */ + /* */ + /* */ + /* This structure is used by the span drawing callback type named */ + /* FT_Raster_Span_Func(), which takes the y-coordinate of the span as */ + /* a parameter. */ + /* */ + /* The coverage value is always between 0 and 255, even if the number */ + /* of gray levels have been set through FT_Set_Gray_Levels(). */ + /* */ + typedef struct FT_Span_ + { + short x; + unsigned short len; + unsigned char coverage; + + } FT_Span; + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Raster_Span_Func */ + /* */ + /* */ + /* A function used as a call-back by the anti-aliased renderer in */ + /* order to let client applications draw themselves the gray pixel */ + /* spans on each scan line. */ + /* */ + /* */ + /* y :: The scanline's y-coordinate. */ + /* */ + /* count :: The number of spans to draw on this scanline. */ + /* */ + /* spans :: A table of `count' spans to draw on the scanline. */ + /* */ + /* user :: User-supplied data that is passed to the callback. */ + /* */ + /* */ + /* This callback allows client applications to directly render the */ + /* gray spans of the anti-aliased bitmap to any kind of surfaces. */ + /* */ + /* This can be used to write anti-aliased outlines directly to a */ + /* given background bitmap, and even perform translucency. */ + /* */ + /* Note that the `count' field cannot be greater than a fixed value */ + /* defined by the FT_MAX_GRAY_SPANS configuration macro in */ + /* ftoption.h. By default, this value is set to 32, which means that */ + /* if there are more than 32 spans on a given scanline, the callback */ + /* will be called several times with the same `y' parameter in order */ + /* to draw all callbacks. */ + /* */ + /* Otherwise, the callback is only called once per scan-line, and */ + /* only for those scanlines that do have `gray' pixels on them. */ + /* */ + typedef void (*FT_Raster_Span_Func)( int y, + int count, + FT_Span* spans, + void* user ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Raster_BitTest_Func */ + /* */ + /* */ + /* A function used as a call-back by the monochrome scan-converter */ + /* to test whether a given target pixel is already set to the drawing */ + /* `color'. These tests are crucial to implement drop-out control */ + /* per-se the TrueType spec. */ + /* */ + /* */ + /* y :: The pixel's y-coordinate. */ + /* */ + /* x :: The pixel's x-coordinate. */ + /* */ + /* user :: User-supplied data that is passed to the callback. */ + /* */ + /* */ + /* 1 if the pixel is `set', 0 otherwise. */ + /* */ + typedef int (*FT_Raster_BitTest_Func)( int y, + int x, + void* user ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Raster_BitSet_Func */ + /* */ + /* */ + /* A function used as a call-back by the monochrome scan-converter */ + /* to set an individual target pixel. This is crucial to implement */ + /* drop-out control according to the TrueType specification. */ + /* */ + /* */ + /* y :: The pixel's y-coordinate. */ + /* */ + /* x :: The pixel's x-coordinate. */ + /* */ + /* user :: User-supplied data that is passed to the callback. */ + /* */ + /* */ + /* 1 if the pixel is `set', 0 otherwise. */ + /* */ + typedef void (*FT_Raster_BitSet_Func)( int y, + int x, + void* user ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Raster_Flag */ + /* */ + /* */ + /* An enumeration to list the bit flags as used in the `flags' field */ + /* of a FT_Raster_Params structure. */ + /* */ + /* */ + /* ft_raster_flag_default :: This value is 0. */ + /* */ + /* ft_raster_flag_aa :: Requests the rendering of an */ + /* anti-aliased glyph bitmap. If unset, a */ + /* monchrome bitmap will be rendered. */ + /* */ + /* ft_raster_flag_direct :: Requests direct rendering over the */ + /* target bitmap. Direct rendering uses */ + /* user-provided callbacks in order to */ + /* perform direct drawing or composition */ + /* over an existing bitmap. If this bit is */ + /* unset, the content of the target bitmap */ + /* *must be zeroed*! */ + /* */ + typedef enum + { + ft_raster_flag_default = 0, + ft_raster_flag_aa = 1, + ft_raster_flag_direct = 2 + + } FT_Raster_Flag; + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Raster_Params */ + /* */ + /* */ + /* A structure to hold the arguments used by a raster's render */ + /* function. */ + /* */ + /* */ + /* target :: The target bitmap. */ + /* */ + /* source :: A pointer to the source glyph image (e.g. an */ + /* FT_Outline). */ + /* */ + /* flags :: The rendering flags. */ + /* */ + /* gray_spans :: The gray span drawing callback. */ + /* */ + /* black_spans :: The black span drawing callback. */ + /* */ + /* bit_test :: The bit test callback. */ + /* */ + /* bit_set :: The bit set callback. */ + /* */ + /* user :: User-supplied data that is passed to each drawing */ + /* callback. */ + /* */ + /* */ + /* An anti-aliased glyph bitmap is drawn if the ft_raster_flag_aa bit */ + /* flag is set in the `flags' field, otherwise a monochrome bitmap */ + /* will be generated. */ + /* */ + /* If the ft_raster_flag_direct bit flag is set in `flags', the */ + /* raster will call the `gray_spans' callback to draw gray pixel */ + /* spans, in the case of an aa glyph bitmap, it will call */ + /* `black_spans', and `bit_test' and `bit_set' in the case of a */ + /* monochrome bitmap. This allows direct composition over a */ + /* pre-existing bitmap through user-provided callbacks to perform the */ + /* span drawing/composition. */ + /* */ + /* Note that the `bit_test' and `bit_set' callbacks are required when */ + /* rendering a monochrome bitmap, as they are crucial to implement */ + /* correct drop-out control as defined in the TrueType specification. */ + /* */ + typedef struct FT_Raster_Params_ + { + FT_Bitmap* target; + void* source; + int flags; + FT_Raster_Span_Func gray_spans; + FT_Raster_Span_Func black_spans; + FT_Raster_BitTest_Func bit_test; + FT_Raster_BitSet_Func bit_set; + void* user; + + } FT_Raster_Params; + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Raster_New_Func */ + /* */ + /* */ + /* A function used to create a new raster object. */ + /* */ + /* */ + /* memory :: A handle to the memory allocator. */ + /* */ + /* */ + /* raster :: A handle to the new raster object. */ + /* */ + /* */ + /* Error code. 0 means success. */ + /* */ + /* */ + /* The `memory' parameter is a typeless pointer in order to avoid */ + /* un-wanted dependencies on the rest of the FreeType code. In */ + /* practice, it is a FT_Memory, i.e., a handle to the standard */ + /* FreeType memory allocator. However, this field can be completely */ + /* ignored by a given raster implementation. */ + /* */ + typedef int (*FT_Raster_New_Func)( void* memory, + FT_Raster* raster ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Raster_Done_Func */ + /* */ + /* */ + /* A function used to destroy a given raster object. */ + /* */ + /* */ + /* raster :: A handle to the raster object. */ + /* */ + typedef void (*FT_Raster_Done_Func)( FT_Raster raster ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Raster_Reset_Func */ + /* */ + /* */ + /* FreeType provides an area of memory called the `render pool', */ + /* available to all registered rasters. This pool can be freely used */ + /* during a given scan-conversion but is shared by all rasters. Its */ + /* content is thus transient. */ + /* */ + /* This function is called each time the render pool changes, or just */ + /* after a new raster object is created. */ + /* */ + /* */ + /* raster :: A handle to the new raster object. */ + /* */ + /* pool_base :: The address in memory of the render pool. */ + /* */ + /* pool_size :: The size in bytes of the render pool. */ + /* */ + /* */ + /* Rasters can ignore the render pool and rely on dynamic memory */ + /* allocation if they want to (a handle to the memory allocator is */ + /* passed to the raster constructor). However, this is not */ + /* recommended for efficiency purposes. */ + /* */ + typedef void (*FT_Raster_Reset_Func)( FT_Raster raster, + unsigned char* pool_base, + unsigned long pool_size ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Raster_Set_Mode_Func */ + /* */ + /* */ + /* This function is a generic facility to change modes or attributes */ + /* in a given raster. This can be used for debugging purposes, or */ + /* simply to allow implementation-specific `features' in a given */ + /* raster module. */ + /* */ + /* */ + /* raster :: A handle to the new raster object. */ + /* */ + /* mode :: A 4-byte tag used to name the mode or property. */ + /* */ + /* args :: A pointer to the new mode/property to use. */ + /* */ + typedef int (*FT_Raster_Set_Mode_Func)( FT_Raster raster, + unsigned long mode, + void* args ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Raster_Render_Func */ + /* */ + /* */ + /* Invokes a given raster to scan-convert a given glyph image into a */ + /* target bitmap. */ + /* */ + /* */ + /* raster :: A handle to the raster object. */ + /* */ + /* params :: A pointer to a FT_Raster_Params structure used to store */ + /* the rendering parameters. */ + /* */ + /* */ + /* Error code. 0 means success. */ + /* */ + /* */ + /* The exact format of the source image depends on the raster's glyph */ + /* format defined in its FT_Raster_Funcs structure. It can be an */ + /* FT_Outline or anything else in order to support a large array of */ + /* glyph formats. */ + /* */ + /* Note also that the render function can fail and return a */ + /* FT_Err_Unimplemented_Feature error code if the raster used does */ + /* not support direct composition. */ + /* */ + /* XXX: For now, the standard raster doesn't support direct */ + /* composition but this should change for the final release (see */ + /* the files demos/src/ftgrays.c and demos/src/ftgrays2.c for */ + /* examples of distinct implementations which support direct */ + /* composition). */ + /* */ + typedef int (*FT_Raster_Render_Func)( FT_Raster raster, + FT_Raster_Params* params ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Raster_Funcs */ + /* */ + /* */ + /* A structure used to describe a given raster class to the library. */ + /* */ + /* */ + /* glyph_format :: The supported glyph format for this raster. */ + /* */ + /* raster_new :: The raster constructor. */ + /* */ + /* raster_reset :: Used to reset the render pool within the raster. */ + /* */ + /* raster_render :: A function to render a glyph into a given bitmap. */ + /* */ + /* raster_done :: The raster destructor. */ + /* */ + typedef struct FT_Raster_Funcs_ + { + FT_Glyph_Format glyph_format; + FT_Raster_New_Func raster_new; + FT_Raster_Reset_Func raster_reset; + FT_Raster_Set_Mode_Func raster_set_mode; + FT_Raster_Render_Func raster_render; + FT_Raster_Done_Func raster_done; + + } FT_Raster_Funcs; + + +#ifdef __cplusplus + } +#endif + + +#endif /* FTIMAGE_H */ + + +/* END */ diff --git a/src/freetype/freetype/ftmm.h b/src/freetype/freetype/ftmm.h new file mode 100644 index 0000000000..db5db0464c --- /dev/null +++ b/src/freetype/freetype/ftmm.h @@ -0,0 +1,175 @@ +/***************************************************************************/ +/* */ +/* ftmm.h */ +/* */ +/* FreeType Multiple Master font interface (specification). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef FTMM_H +#define FTMM_H + +#include + +#ifdef __cplusplus + extern "C" { +#endif + + + /*************************************************************************/ + /* */ + /* */ + /* FT_MM_Axis */ + /* */ + /* */ + /* A simple structure used to model a given axis in design space for */ + /* Multiple Masters fonts. */ + /* */ + /* */ + /* name :: The axis's name. */ + /* */ + /* minimum :: The axis's minimum design coordinate. */ + /* */ + /* maximum :: The axis's maximum design coordinate. */ + /* */ + typedef struct FT_MM_Axis_ + { + FT_String* name; + FT_Long minimum; + FT_Long maximum; + + } FT_MM_Axis; + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Multi_Master */ + /* */ + /* */ + /* A structure used to model the axes and space of a Multiple Masters */ + /* font. */ + /* */ + /* */ + /* num_axis :: Number of axes. Cannot exceed 4. */ + /* */ + /* num_designs :: Number of designs; should ne normally 2^num_axis */ + /* even though the Type 1 specification strangely */ + /* allows for intermediate designs to be present. This */ + /* number cannot exceed 16. */ + /* */ + /* axis :: A table of axis descriptors. */ + /* */ + typedef struct FT_Multi_Master_ + { + FT_UInt num_axis; + FT_UInt num_designs; + FT_MM_Axis axis[T1_MAX_MM_AXIS]; + + } FT_Multi_Master; + + + typedef FT_Error (*FT_Get_MM_Func)( FT_Face face, + FT_Multi_Master* master ); + + typedef FT_Error (*FT_Set_MM_Design_Func)( FT_Face face, + FT_UInt num_coords, + FT_Long* coords ); + + typedef FT_Error (*FT_Set_MM_Blend_Func)( FT_Face face, + FT_UInt num_coords, + FT_Long* coords ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Get_Multi_Master */ + /* */ + /* */ + /* Retrieves the Multiple Master descriptor of a given font. */ + /* */ + /* */ + /* face :: A handle to the source face. */ + /* */ + /* */ + /* master :: The Multiple Masters descriptor. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT_DEF( FT_Error ) FT_Get_Multi_Master( FT_Face face, + FT_Multi_Master* master ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Set_MM_Design_Coordinates */ + /* */ + /* */ + /* For Multiple Masters fonts, choose an interpolated font design */ + /* through design coordinates. */ + /* */ + /* */ + /* face :: A handle to the source face. */ + /* */ + /* num_coords :: The number of design coordinates (must be equal to */ + /* the number of axes in the font). */ + /* */ + /* coords :: The design coordinates. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT_DEF( FT_Error ) FT_Set_MM_Design_Coordinates( + FT_Face face, + FT_UInt num_coords, + FT_Long* coords ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Set_MM_Blend_Coordinates */ + /* */ + /* */ + /* For Multiple Masters fonts, choose an interpolated font design */ + /* through normalized blend coordinates. */ + /* */ + /* */ + /* face :: A handle to the source face. */ + /* */ + /* num_coords :: The number of design coordinates (must be equal to */ + /* the number of axes in the font). */ + /* */ + /* coords :: The design coordinates (each one must be between 0 */ + /* and 1.0). */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT_DEF( FT_Error ) FT_Set_MM_Blend_Coordinates( + FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ); + + +#ifdef __cplusplus + } +#endif + +#endif /* FTMM_H */ + + +/* END */ diff --git a/src/freetype/freetype/ftmodule.h b/src/freetype/freetype/ftmodule.h new file mode 100644 index 0000000000..3c09aa2afd --- /dev/null +++ b/src/freetype/freetype/ftmodule.h @@ -0,0 +1,274 @@ +/***************************************************************************/ +/* */ +/* ftmodule.h */ +/* */ +/* FreeType modules public interface (specification). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef FTMODULE_H +#define FTMODULE_H + +#include + + +#ifdef __cplusplus + extern "C" { +#endif + + + /* module bit flags */ + typedef enum FT_Module_Flags_ + { + ft_module_font_driver = 1, /* this module is a font driver */ + ft_module_renderer = 2, /* this module is a renderer */ + ft_module_hinter = 4, /* this module is a glyph hinter */ + ft_module_styler = 8, /* this module is a styler */ + + ft_module_driver_scalable = 0x100, /* the driver supports scalable */ + /* fonts */ + ft_module_driver_no_outlines = 0x200, /* the driver does not support */ + /* vector outlines */ + ft_module_driver_has_hinter = 0x400 /* the driver provides its own */ + /* hinter */ + + } FT_Module_Flags; + + + typedef void (*FT_Module_Interface)( void ); + + typedef FT_Error (*FT_Module_Constructor)( FT_Module module ); + + typedef void (*FT_Module_Destructor)( FT_Module module ); + + typedef FT_Module_Interface (*FT_Module_Requester)( FT_Module module, + const char* name ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Module_Class */ + /* */ + /* */ + /* The module class descriptor. */ + /* */ + /* */ + /* module_flags :: Bit flags describing the module. */ + /* */ + /* module_size :: The size of one module object/instance in */ + /* bytes. */ + /* */ + /* module_name :: The name of the module. */ + /* */ + /* module_version :: The version, as a 16.16 fixed number */ + /* (major.minor). */ + /* */ + /* module_requires :: The version of FreeType this module requires */ + /* (starts at version 2.0, i.e 0x20000) */ + /* */ + /* module_init :: A function used to initialize (not create) a */ + /* new module object. */ + /* */ + /* module_done :: A function used to finalize (not destroy) a */ + /* given module object */ + /* */ + /* get_interface :: Queries a given module for a specific */ + /* interface by name. */ + /* */ + typedef struct FT_Module_Class_ + { + FT_ULong module_flags; + FT_Int module_size; + const FT_String* module_name; + FT_Fixed module_version; + FT_Fixed module_requires; + + const void* module_interface; + + FT_Module_Constructor module_init; + FT_Module_Destructor module_done; + FT_Module_Requester get_interface; + + } FT_Module_Class; + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Add_Module */ + /* */ + /* */ + /* Adds a new module to a given library instance. */ + /* */ + /* */ + /* library :: A handle to the library object. */ + /* */ + /* clazz :: A pointer to class descriptor for the module. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* An error will be returned if a module already exists by that name, */ + /* or if the module requires a version of FreeType that is too great. */ + /* */ + FT_EXPORT_DEF( FT_Error ) FT_Add_Module( FT_Library library, + const FT_Module_Class* clazz ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Get_Module */ + /* */ + /* */ + /* Finds a module by its name. */ + /* */ + /* */ + /* library :: A handle to the library object. */ + /* */ + /* module_name :: The module's name (as an ASCII string). */ + /* */ + /* */ + /* A module handle. 0 if none was found. */ + /* */ + /* */ + /* You should better be familiar with FreeType internals to know */ + /* which module to look for :-) */ + /* */ + FT_EXPORT_DEF( FT_Module ) FT_Get_Module( FT_Library library, + const char* module_name ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Remove_Module */ + /* */ + /* */ + /* Removes a given module from a library instance. */ + /* */ + /* */ + /* library :: A handle to a library object. */ + /* */ + /* module :: A handle to a module object. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* The module object is destroyed by the function in case of success. */ + /* */ + FT_EXPORT_DEF( FT_Error ) FT_Remove_Module( FT_Library library, + FT_Module module ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_New_Library */ + /* */ + /* */ + /* This function is used to create a new FreeType library instance */ + /* from a given memory object. It is thus possible to use libraries */ + /* with distinct memory allocators within the same program. */ + /* */ + /* */ + /* memory :: A handle to the original memory object. */ + /* */ + /* */ + /* alibrary :: A pointer to handle of a new library object. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT_DEF( FT_Error ) FT_New_Library( FT_Memory memory, + FT_Library* library ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Done_Library */ + /* */ + /* */ + /* Discards a given library object. This closes all drivers and */ + /* discards all resource objects. */ + /* */ + /* */ + /* library :: A handle to the target library. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT_DEF( FT_Error ) FT_Done_Library( FT_Library library ); + + + + typedef void (*FT_DebugHook_Func)( void* arg ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Set_Debug_Hook */ + /* */ + /* */ + /* Sets a debug hook function for debugging the interpreter of a font */ + /* format. */ + /* */ + /* */ + /* library :: A handle to the library object. */ + /* */ + /* hook_index :: The index of the debug hook. You should use the */ + /* values defined in ftobjs.h, e.g. */ + /* FT_DEBUG_HOOK_TRUETYPE */ + /* */ + /* debug_hook :: The function used to debug the interpreter. */ + /* */ + /* */ + /* Currently, four debug hook slots are available, but only two (for */ + /* the TrueType and the Type 1 interpreter) are defined. */ + /* */ + FT_EXPORT_DEF( void ) FT_Set_Debug_Hook( FT_Library library, + FT_UInt hook_index, + FT_DebugHook_Func debug_hook ); + + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Add_Default_Modules */ + /* */ + /* */ + /* Adds the set of default drivers to a given library object. */ + /* This is only useful when you create a library object with */ + /* FT_New_Library() (usually to plug a custom memory manager). */ + /* */ + /* */ + /* library :: A handle to a new library object. */ + /* */ + FT_EXPORT_DEF( void ) FT_Add_Default_Modules( FT_Library library ); + + +#ifdef __cplusplus + } +#endif + + +#endif /* FTMODULE_H */ + + +/* END */ diff --git a/src/freetype/freetype/ftnames.h b/src/freetype/freetype/ftnames.h new file mode 100644 index 0000000000..2969214b9b --- /dev/null +++ b/src/freetype/freetype/ftnames.h @@ -0,0 +1,52 @@ +/***************************************************************************/ +/* */ +/* ftnames.h */ +/* */ +/* Simple interface to access SFNT name tables (which are used */ +/* to hold font names, copyright info, notices, etc.). */ +/* */ +/* This is _not_ used to retrieve glyph names! */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef FTNAMES_H +#define FTNAMES_H + + +#include + + + typedef struct FT_SfntName_ + { + FT_UShort platform_id; + FT_UShort encoding_id; + FT_UShort language_id; + FT_UShort name_id; + + FT_Byte* string; + FT_UInt string_len; /* in bytes */ + + } FT_SfntName; + + + FT_EXPORT_DEF( FT_UInt ) FT_Get_Sfnt_Name_Count( FT_Face face ); + + FT_EXPORT_DEF( FT_Error ) FT_Get_Sfnt_Name( FT_Face face, + FT_UInt index, + FT_SfntName* aname ); + + +#endif /* FTNAMES_H */ + + +/* END */ diff --git a/src/freetype/freetype/ftoutln.h b/src/freetype/freetype/ftoutln.h new file mode 100644 index 0000000000..1e448bd0ec --- /dev/null +++ b/src/freetype/freetype/ftoutln.h @@ -0,0 +1,344 @@ +/***************************************************************************/ +/* */ +/* ftoutln.h */ +/* */ +/* Support for the FT_Outline type used to store glyph shapes of */ +/* most scalable font formats (specification). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef FTOUTLN_H +#define FTOUTLN_H + + +#include + +#ifdef __cplusplus + extern "C" { +#endif + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Outline_Decompose */ + /* */ + /* */ + /* Walks over an outline's structure to decompose it into individual */ + /* segments and Bezier arcs. This function is also able to emit */ + /* `move to' and `close to' operations to indicate the start and end */ + /* of new contours in the outline. */ + /* */ + /* */ + /* outline :: A pointer to the source target. */ + /* */ + /* interface :: A table of `emitters', i.e,. function pointers called */ + /* during decomposition to indicate path operations. */ + /* */ + /* user :: A typeless pointer which is passed to each emitter */ + /* during the decomposition. It can be used to store */ + /* the state during the decomposition. */ + /* */ + /* */ + /* FreeType error code. 0 means sucess. */ + /* */ + FT_EXPORT_DEF( FT_Error ) FT_Outline_Decompose( + FT_Outline* outline, + FT_Outline_Funcs* interface, + void* user ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Outline_New */ + /* */ + /* */ + /* Creates a new outline of a given size. */ + /* */ + /* */ + /* library :: A handle to the library object from where the */ + /* outline is allocated. Note however that the new */ + /* outline will NOT necessarily be FREED, when */ + /* destroying the library, by FT_Done_FreeType(). */ + /* */ + /* numPoints :: The maximal number of points within the outline. */ + /* */ + /* numContours :: The maximal number of contours within the outline. */ + /* */ + /* */ + /* outline :: A handle to the new outline. NULL in case of */ + /* error. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* No. */ + /* */ + /* */ + /* The reason why this function takes a `library' parameter is simply */ + /* to use the library's memory allocator. */ + /* */ + FT_EXPORT_DEF( FT_Error ) FT_Outline_New( FT_Library library, + FT_UInt numPoints, + FT_Int numContours, + FT_Outline* outline ); + + + FT_EXPORT_DEF( FT_Error ) FT_Outline_New_Internal( + FT_Memory memory, + FT_UInt numPoints, + FT_Int numContours, + FT_Outline* outline ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Outline_Done */ + /* */ + /* */ + /* Destroys an outline created with FT_Outline_New(). */ + /* */ + /* */ + /* library :: A handle of the library object used to allocate the */ + /* outline. */ + /* */ + /* outline :: A pointer to the outline object to be discarded. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* No. */ + /* */ + /* */ + /* If the outline's `owner' field is not set, only the outline */ + /* descriptor will be released. */ + /* */ + /* The reason why this function takes an `outline' parameter is */ + /* simply to use FT_Free(). */ + /* */ + FT_EXPORT_DEF( FT_Error ) FT_Outline_Done( FT_Library library, + FT_Outline* outline ); + + + FT_EXPORT_DEF( FT_Error ) FT_Outline_Done_Internal( FT_Memory memory, + FT_Outline* outline ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Outline_Get_CBox */ + /* */ + /* */ + /* Returns an outline's `control box'. The control box encloses all */ + /* the outline's points, including Bezier control points. Though it */ + /* coincides with the exact bounding box for most glyphs, it can be */ + /* slightly larger in some situations (like when rotating an outline */ + /* which contains Bezier outside arcs). */ + /* */ + /* Computing the control box is very fast, while getting the bounding */ + /* box can take much more time as it needs to walk over all segments */ + /* and arcs in the outline. To get the latter, you can use the */ + /* `ftbbox' component which is dedicated to this single task. */ + /* */ + /* */ + /* outline :: A pointer to the source outline descriptor. */ + /* */ + /* */ + /* cbox :: The outline's control box. */ + /* */ + /* */ + /* Yes. */ + /* */ + FT_EXPORT_DEF( void ) FT_Outline_Get_CBox( FT_Outline* outline, + FT_BBox* cbox ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Outline_Translate */ + /* */ + /* */ + /* Applies a simple translation to the points of an outline. */ + /* */ + /* */ + /* outline :: A pointer to the target outline descriptor. */ + /* */ + /* xOffset :: The horizontal offset. */ + /* */ + /* yOffset :: The vertical offset. */ + /* */ + /* */ + /* Yes. */ + /* */ + FT_EXPORT_DEF( void ) FT_Outline_Translate( FT_Outline* outline, + FT_Pos xOffset, + FT_Pos yOffset ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Outline_Copy */ + /* */ + /* */ + /* Copies an outline into another one. Both objects must have the */ + /* same sizes (number of points & number of contours) when this */ + /* function is called. */ + /* */ + /* */ + /* source :: A handle to the source outline. */ + /* */ + /* */ + /* target :: A handle to the target outline. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT_DEF( FT_Error ) FT_Outline_Copy( FT_Outline* source, + FT_Outline* target ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Vector_Transform */ + /* */ + /* */ + /* Transforms a single vector through a 2x2 matrix. */ + /* */ + /* */ + /* vector :: The target vector to transform. */ + /* */ + /* */ + /* matrix :: A pointer to the source 2x2 matrix. */ + /* */ + /* */ + /* Yes. */ + /* */ + /* */ + /* The result is undefined if either `vector' or `matrix' is invalid. */ + /* */ + FT_EXPORT_DEF( void ) FT_Outline_Transform( FT_Outline* outline, + FT_Matrix* matrix ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Outline_Reverse */ + /* */ + /* */ + /* Reverses the drawing direction of an outline. This is used to */ + /* ensure consistent fill conventions for mirrored glyphs. */ + /* */ + /* */ + /* outline :: A pointer to the target outline descriptor. */ + /* */ + /* */ + /* This functions toggles the bit flag `ft_outline_reverse_fill' in */ + /* the outline's `flags' field. */ + /* */ + /* It shouldn't be used by a normal client application, unless it */ + /* knows what it is doing. */ + /* */ + FT_EXPORT_DEF( void ) FT_Outline_Reverse( FT_Outline* outline ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Outline_Get_Bitmap */ + /* */ + /* */ + /* Renders an outline within a bitmap. The outline's image is simply */ + /* OR-ed to the target bitmap. */ + /* */ + /* */ + /* library :: A handle to a FreeType library object. */ + /* */ + /* outline :: A pointer to the source outline descriptor. */ + /* */ + /* map :: A pointer to the target bitmap descriptor. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* YES. Rendering is synchronized, so that concurrent calls to the */ + /* scan-line converter will be serialized. */ + /* */ + /* */ + /* This function does NOT CREATE the bitmap, it only renders an */ + /* outline image within the one you pass to it! */ + /* */ + /* It will use the raster correponding to the default glyph format. */ + /* */ + FT_EXPORT_DEF( FT_Error ) FT_Outline_Get_Bitmap( FT_Library library, + FT_Outline* outline, + FT_Bitmap* bitmap ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Outline_Render */ + /* */ + /* */ + /* Renders an outline within a bitmap using the current scan-convert. */ + /* This functions uses an FT_Raster_Params structure as an argument, */ + /* allowing advanced features like direct composition, translucency, */ + /* etc. */ + /* */ + /* */ + /* library :: A handle to a FreeType library object. */ + /* */ + /* outline :: A pointer to the source outline descriptor. */ + /* */ + /* params :: A pointer to a FT_Raster_Params structure used to */ + /* describe the rendering operation. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* YES. Rendering is synchronized, so that concurrent calls to the */ + /* scan-line converter will be serialized. */ + /* */ + /* */ + /* You should know what you are doing and how FT_Raster_Params works */ + /* to use this function. */ + /* */ + /* The field `params.source' will be set to `outline' before the scan */ + /* converter is called, which means that the value you give to it is */ + /* actually ignored. */ + /* */ + FT_EXPORT_DEF( FT_Error ) FT_Outline_Render( FT_Library library, + FT_Outline* outline, + FT_Raster_Params* params ); + + +#ifdef __cplusplus + } +#endif + + +#endif /* FTOUTLN_H */ + + +/* END */ diff --git a/src/freetype/freetype/ftrender.h b/src/freetype/freetype/ftrender.h new file mode 100644 index 0000000000..fe5acd2ce6 --- /dev/null +++ b/src/freetype/freetype/ftrender.h @@ -0,0 +1,191 @@ +/***************************************************************************/ +/* */ +/* ftrender.h */ +/* */ +/* FreeType renderer modules public interface (specification). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef FTRENDER_H +#define FTRENDER_H + +#include +#include + + +#ifdef __cplusplus + extern "C" { +#endif + + + /* create a new glyph object */ + typedef FT_Error (*FT_Glyph_Init_Func)( FT_Glyph glyph, + FT_GlyphSlot slot ); + + /* destroys a given glyph object */ + typedef void (*FT_Glyph_Done_Func)( FT_Glyph glyph ); + + typedef void (*FT_Glyph_Transform_Func)( FT_Glyph glyph, + FT_Matrix* matrix, + FT_Vector* delta ); + + typedef void (*FT_Glyph_BBox_Func)( FT_Glyph glyph, + FT_BBox* abbox ); + + typedef FT_Error (*FT_Glyph_Copy_Func)( FT_Glyph source, + FT_Glyph target ); + + typedef FT_Error (*FT_Glyph_Prepare_Func)( FT_Glyph glyph, + FT_GlyphSlot slot ); + + struct FT_Glyph_Class_ + { + FT_UInt glyph_size; + FT_Glyph_Format glyph_format; + FT_Glyph_Init_Func glyph_init; + FT_Glyph_Done_Func glyph_done; + FT_Glyph_Copy_Func glyph_copy; + FT_Glyph_Transform_Func glyph_transform; + FT_Glyph_BBox_Func glyph_bbox; + FT_Glyph_Prepare_Func glyph_prepare; + }; + + + typedef FT_Error (*FTRenderer_render)( FT_Renderer renderer, + FT_GlyphSlot slot, + FT_UInt mode, + FT_Vector* origin ); + + typedef FT_Error (*FTRenderer_transform)( FT_Renderer renderer, + FT_GlyphSlot slot, + FT_Matrix* matrix, + FT_Vector* delta ); + + typedef void (*FTRenderer_getCBox)( FT_Renderer renderer, + FT_GlyphSlot slot, + FT_BBox* cbox ); + + typedef FT_Error (*FTRenderer_setMode)( FT_Renderer renderer, + FT_ULong mode_tag, + FT_Pointer mode_ptr ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Renderer_Class */ + /* */ + /* */ + /* The renderer module class descriptor. */ + /* */ + /* */ + /* root :: The root FT_Module_Class fields. */ + /* */ + /* glyph_format :: The glyph image format this renderer handles. */ + /* */ + /* render_glyph :: A method used to render the image that is in a */ + /* given glyph slot into a bitmap. */ + /* */ + /* set_mode :: A method used to pass additional parameters. */ + /* */ + /* raster_class :: For `ft_glyph_format_outline' renderers only, this */ + /* is a pointer to its raster's class. */ + /* */ + /* raster :: For `ft_glyph_format_outline' renderers only. this */ + /* is a pointer to the corresponding raster object, */ + /* if any. */ + /* */ + typedef struct FT_Renderer_Class_ + { + FT_Module_Class root; + + FT_Glyph_Format glyph_format; + + FTRenderer_render render_glyph; + FTRenderer_transform transform_glyph; + FTRenderer_getCBox get_glyph_cbox; + FTRenderer_setMode set_mode; + + FT_Raster_Funcs* raster_class; + + } FT_Renderer_Class; + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Get_Renderer */ + /* */ + /* */ + /* Retrieves the current renderer for a given glyph format. */ + /* */ + /* */ + /* library :: A handle to the library object. */ + /* */ + /* format :: The glyph format. */ + /* */ + /* */ + /* A renderer handle. 0 if none found. */ + /* */ + /* */ + /* An error will be returned if a module already exists by that name, */ + /* or if the module requires a version of FreeType that is too great. */ + /* */ + /* To add a new renderer, simply use FT_Add_Module(). To retrieve a */ + /* renderer by its name, use FT_Get_Module(). */ + /* */ + FT_EXPORT_DEF( FT_Renderer ) FT_Get_Renderer( FT_Library library, + FT_Glyph_Format format ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Set_Renderer */ + /* */ + /* */ + /* Sets the current renderer to use, and set additional mode. */ + /* */ + /* */ + /* library :: A handle to the library object. */ + /* */ + /* renderer :: A handle to the renderer object. */ + /* */ + /* num_params :: The number of additional parameters. */ + /* */ + /* parameters :: Additional parameters. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* In case of success, the renderer will be used to convert glyph */ + /* images in the renderer's known format into bitmaps. */ + /* */ + /* This doesn't change the current renderer for other formats. */ + /* */ + FT_EXPORT_DEF(FT_Error) FT_Set_Renderer( FT_Library library, + FT_Renderer renderer, + FT_UInt num_params, + FT_Parameter* parameters ); + + +#ifdef __cplusplus + } +#endif + + +#endif /* FTRENDER_H */ + + +/* END */ diff --git a/src/freetype/freetype/ftsystem.h b/src/freetype/freetype/ftsystem.h new file mode 100644 index 0000000000..bc74bced22 --- /dev/null +++ b/src/freetype/freetype/ftsystem.h @@ -0,0 +1,101 @@ +/***************************************************************************/ +/* */ +/* ftsystem.h */ +/* */ +/* FreeType low-level system interface definition (specification). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef FTSYSTEM_H +#define FTSYSTEM_H + + + /*************************************************************************/ + /* */ + /* M E M O R Y M A N A G E M E N T */ + /* */ + /*************************************************************************/ + + + typedef struct FT_MemoryRec_* FT_Memory; + + + typedef void* (*FT_Alloc_Func)( FT_Memory memory, + long size ); + + typedef void (*FT_Free_Func)( FT_Memory memory, + void* block ); + + typedef void* (*FT_Realloc_Func)( FT_Memory memory, + long cur_size, + long new_size, + void* block ); + + + struct FT_MemoryRec_ + { + void* user; + FT_Alloc_Func alloc; + FT_Free_Func free; + FT_Realloc_Func realloc; + }; + + + /*************************************************************************/ + /* */ + /* I / O M A N A G E M E N T */ + /* */ + /*************************************************************************/ + + + typedef union FT_StreamDesc_ + { + long value; + void* pointer; + + } FT_StreamDesc; + + + typedef struct FT_StreamRec_* FT_Stream; + + + typedef unsigned long (*FT_Stream_IO)( FT_Stream stream, + unsigned long offset, + unsigned char* buffer, + unsigned long count ); + + typedef void (*FT_Stream_Close)( FT_Stream stream ); + + + struct FT_StreamRec_ + { + unsigned char* base; + unsigned long size; + unsigned long pos; + + FT_StreamDesc descriptor; + FT_StreamDesc pathname; /* ignored by FreeType -- */ + /* useful for debugging */ + FT_Stream_IO read; + FT_Stream_Close close; + + FT_Memory memory; + unsigned char* cursor; + unsigned char* limit; + }; + + +#endif /* FTSYSTEM_H */ + + +/* END */ diff --git a/src/freetype/freetype/fttypes.h b/src/freetype/freetype/fttypes.h new file mode 100644 index 0000000000..ec909061de --- /dev/null +++ b/src/freetype/freetype/fttypes.h @@ -0,0 +1,400 @@ +/***************************************************************************/ +/* */ +/* fttypes.h */ +/* */ +/* FreeType simple types definitions (specification only). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef FTTYPES_H +#define FTTYPES_H + + +#include +#include + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Bool */ + /* */ + /* */ + /* A typedef of unsigned char, used for simple booleans. */ + /* */ + typedef unsigned char FT_Bool; + + + /*************************************************************************/ + /* */ + /* */ + /* FT_FWord */ + /* */ + /* */ + /* A signed 16-bit integer used to store a distance in original font */ + /* units. */ + /* */ + typedef signed short FT_FWord; /* distance in FUnits */ + + + /*************************************************************************/ + /* */ + /* */ + /* FT_UFWord */ + /* */ + /* */ + /* An unsigned 16-bit integer used to store a distance in original */ + /* font units. */ + /* */ + typedef unsigned short FT_UFWord; /* unsigned distance */ + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Char */ + /* */ + /* */ + /* A simple typedef for the _signed_ char type. */ + /* */ + typedef signed char FT_Char; + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Byte */ + /* */ + /* */ + /* A simple typedef for the _unsigned_ char type. */ + /* */ + typedef unsigned char FT_Byte; + + + /*************************************************************************/ + /* */ + /* */ + /* FT_String */ + /* */ + /* */ + /* A simple typedef for the char type, usually used for strings. */ + /* */ + typedef char FT_String; + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Short */ + /* */ + /* */ + /* A typedef for signed short. */ + /* */ + typedef signed short FT_Short; + + + /*************************************************************************/ + /* */ + /* */ + /* FT_UShort */ + /* */ + /* */ + /* A typedef for unsigned short. */ + /* */ + typedef unsigned short FT_UShort; + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Int */ + /* */ + /* */ + /* A typedef for the int type. */ + /* */ + typedef int FT_Int; + + + /*************************************************************************/ + /* */ + /* */ + /* FT_UInt */ + /* */ + /* */ + /* A typedef for the unsigned int type. */ + /* */ + typedef unsigned int FT_UInt; + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Long */ + /* */ + /* */ + /* A typedef for signed long. */ + /* */ + typedef signed long FT_Long; + + + /*************************************************************************/ + /* */ + /* */ + /* FT_ULong */ + /* */ + /* */ + /* A typedef for unsigned long. */ + /* */ + typedef unsigned long FT_ULong; + + + /*************************************************************************/ + /* */ + /* */ + /* FT_F2Dot14 */ + /* */ + /* */ + /* A signed 2.14 fixed float type used for unit vectors. */ + /* */ + typedef signed short FT_F2Dot14; + + + /*************************************************************************/ + /* */ + /* */ + /* FT_F26Dot6 */ + /* */ + /* */ + /* A signed 26.6 fixed float type used for vectorial pixel */ + /* coordinates. */ + /* */ + typedef signed long FT_F26Dot6; + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Fixed */ + /* */ + /* */ + /* This type is used to store 16.16 fixed float values, like scales */ + /* or matrix coefficients. */ + /* */ + typedef signed long FT_Fixed; + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Error */ + /* */ + /* */ + /* The FreeType error code type. A value of 0 is always interpreted */ + /* as a successful operation. */ + /* */ + typedef int FT_Error; + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Pointer */ + /* */ + /* */ + /* A simple typedef for a typeless pointer. */ + /* */ + typedef void* FT_Pointer; + + + /*************************************************************************/ + /* */ + /* */ + /* FT_UnitVector */ + /* */ + /* */ + /* A simple structure used to store a 2D vector unit vector. Uses */ + /* FT_F2Dot14 types. */ + /* */ + /* */ + /* x :: Horizontal coordinate. */ + /* */ + /* y :: Vertical coordinate. */ + /* */ + typedef struct FT_UnitVector_ + { + FT_F2Dot14 x; + FT_F2Dot14 y; + + } FT_UnitVector; + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Matrix */ + /* */ + /* */ + /* A simple structure used to store a 2x2 matrix. Coefficients are */ + /* in 16.16 fixed float format. The computation performed is: */ + /* */ + /* { */ + /* x' = x*xx + y*xy */ + /* y' = x*yx + y*yy */ + /* } */ + /* */ + /* */ + /* xx :: Matrix coefficient. */ + /* */ + /* xy :: Matrix coefficient. */ + /* */ + /* yx :: Matrix coefficient. */ + /* */ + /* yy :: Matrix coefficient. */ + /* */ + typedef struct FT_Matrix_ + { + FT_Fixed xx, xy; + FT_Fixed yx, yy; + + } FT_Matrix; + + + /*************************************************************************/ + /* */ + /* */ + /* FT_BBox */ + /* */ + /* */ + /* A structure used to hold an outline's bounding box, i.e., the */ + /* coordinates of its extrema in the horizontal and vertical */ + /* directions. */ + /* */ + /* */ + /* xMin :: The horizontal minimum (left-most). */ + /* */ + /* yMin :: The vertical minimum (bottom-most). */ + /* */ + /* xMax :: The horizontal maximum (right-most). */ + /* */ + /* yMax :: The vertical maximum (top-most). */ + /* */ + typedef struct FT_BBox_ + { + FT_Pos xMin, yMin; + FT_Pos xMax, yMax; + + } FT_BBox; + + + /*************************************************************************/ + /* */ + /* */ + /* FT_MAKE_TAG */ + /* */ + /* */ + /* This macro converts four letter tags which are used to label */ + /* TrueType tables into an unsigned long to be used within FreeType. */ + /* */ +#define FT_MAKE_TAG( _x1, _x2, _x3, _x4 ) \ + ( ( (FT_ULong)_x1 << 24 ) | \ + ( (FT_ULong)_x2 << 16 ) | \ + ( (FT_ULong)_x3 << 8 ) | \ + (FT_ULong)_x4 ) + + + /*************************************************************************/ + /*************************************************************************/ + /* */ + /* L I S T M A N A G E M E N T */ + /* */ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* */ + /* FT_ListNode */ + /* */ + /* */ + /* Many elements and objects in FreeType are listed through a */ + /* FT_List record (see FT_ListRec). As its name suggests, a */ + /* FT_ListNode is a handle to a single list element. */ + /* */ + typedef struct FT_ListNodeRec_* FT_ListNode; + + + /*************************************************************************/ + /* */ + /* */ + /* FT_List */ + /* */ + /* */ + /* A handle to a list record (see FT_ListRec). */ + /* */ + typedef struct FT_ListRec_* FT_List; + + + /*************************************************************************/ + /* */ + /* */ + /* FT_ListNodeRec */ + /* */ + /* */ + /* A structure used to hold a single list element. */ + /* */ + /* */ + /* prev :: The previous element in the list. NULL if first. */ + /* */ + /* next :: The next element in the list. NULL if last. */ + /* */ + /* data :: A typeless pointer to the listed object. */ + /* */ + typedef struct FT_ListNodeRec_ + { + FT_ListNode prev; + FT_ListNode next; + void* data; + + } FT_ListNodeRec; + + + /*************************************************************************/ + /* */ + /* */ + /* FT_ListRec */ + /* */ + /* */ + /* A structure used to hold a simple doubly-linked list. These are */ + /* used in many parts of FreeType. */ + /* */ + /* */ + /* head :: The head (first element) of doubly-linked list. */ + /* */ + /* tail :: The tail (last element) of doubly-linked list. */ + /* */ + typedef struct FT_ListRec_ + { + FT_ListNode head; + FT_ListNode tail; + + } FT_ListRec; + + +#define FT_IS_EMPTY( list ) ( (list).head == 0 ) + + +#endif /* FTTYPES_H */ + + +/* END */ diff --git a/src/freetype/freetype/internal/autohint.h b/src/freetype/freetype/internal/autohint.h new file mode 100644 index 0000000000..5d35a5dcd4 --- /dev/null +++ b/src/freetype/freetype/internal/autohint.h @@ -0,0 +1,195 @@ +/***************************************************************************/ +/* */ +/* autohint.h */ +/* */ +/* High-level `autohint' module-specific interface (specification). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + + /*************************************************************************/ + /* */ + /* The auto-hinter is used to load and automatically hint glyphs if a */ + /* format-specific hinter isn't available. */ + /* */ + /*************************************************************************/ + + +#ifndef AUTOHINT_H +#define AUTOHINT_H + + + /*************************************************************************/ + /* */ + /* A small technical note regarding automatic hinting in order to */ + /* clarify this module interface. */ + /* */ + /* An automatic hinter might compute two kinds of data for a given face: */ + /* */ + /* - global hints: Usually some metrics that describe global properties */ + /* of the face. It is computed by scanning more or less */ + /* agressively the glyphs in the face, and thus can be */ + /* very slow to compute (even if the size of global */ + /* hints is really small). */ + /* */ + /* - glyph hints: These describe some important features of the glyph */ + /* outline, as well as how to align them. They are */ + /* generally much faster to compute than global hints. */ + /* */ + /* The current FreeType auto-hinter does a pretty good job while */ + /* performing fast computations for both global and glyph hints. */ + /* However, we might be interested in introducing more complex and */ + /* powerful algorithms in the future, like the one described in the John */ + /* D. Hobby paper, which unfortunately requires a lot more horsepower. */ + /* */ + /* Because a sufficiently sophisticated font management system would */ + /* typically implement an LRU cache of opened face objects to reduce */ + /* memory usage, it is a good idea to be able to avoid recomputing */ + /* global hints every time the same face is re-opened. */ + /* */ + /* We thus provide the ability to cache global hints outside of the face */ + /* object, in order to speed up font re-opening time. Of course, this */ + /* feature is purely optional, so most client programs won't even notice */ + /* it. */ + /* */ + /* I initially thought that it would be a good idea to cache the glyph */ + /* hints too. However, my general idea now is that if you really need */ + /* to cache these too, you are simply in need of a new font format, */ + /* where all this information could be stored within the font file and */ + /* decoded on the fly. */ + /* */ + /*************************************************************************/ + + +#include + + + typedef struct FT_AutoHinterRec_ *FT_AutoHinter; + + + /*************************************************************************/ + /* */ + /* */ + /* FT_AutoHinter_Get_Global_Func */ + /* */ + /* */ + /* Retrieves the global hints computed for a given face object the */ + /* resulting data is dissociated from the face and will survive a */ + /* call to FT_Done_Face(). It must be discarded through the API */ + /* FT_AutoHinter_Done_Global_Func(). */ + /* */ + /* */ + /* hinter :: A handle to the source auto-hinter. */ + /* */ + /* face :: A handle to the source face object. */ + /* */ + /* */ + /* global_hints :: A typeless pointer to the global hints. */ + /* */ + /* global_len :: The size in bytes of the global hints. */ + /* */ + typedef void (*FT_AutoHinter_Get_Global_Func)( + FT_AutoHinter hinter, + FT_Face face, + void** global_hints, + long* global_len ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_AutoHinter_Done_Global_Func */ + /* */ + /* */ + /* Discards the global hints retrieved through */ + /* FT_AutoHinter_Get_Global_Func(). This is the only way these hints */ + /* are freed from memory. */ + /* */ + /* */ + /* hinter :: A handle to the auto-hinter module. */ + /* */ + /* global :: A pointer to retrieved global hints to discard. */ + /* */ + typedef void (*FT_AutoHinter_Done_Global_Func)( FT_AutoHinter hinter, + void* global ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_AutoHinter_Reset_Func */ + /* */ + /* */ + /* This function is used to recompute the global metrics in a given */ + /* font. This is useful when global font data changes (e.g. Multiple */ + /* Masters fonts where blend coordinates change). */ + /* */ + /* */ + /* hinter :: A handle to the source auto-hinter. */ + /* */ + /* face :: A handle to the face. */ + /* */ + typedef void (*FT_AutoHinter_Reset_Func)( FT_AutoHinter hinter, + FT_Face face ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_AutoHinter_Load_Func */ + /* */ + /* */ + /* This function is used to load, scale, and automatically hint a */ + /* glyph from a given face. */ + /* */ + /* */ + /* face :: A handle to the face. */ + /* glyph_index :: The glyph index. */ + /* load_flags :: The load flags. */ + /* */ + /* */ + /* This function is capable of loading composite glyphs by hinting */ + /* each sub-glyph independently (which improves quality). */ + /* */ + /* It will call the font driver with FT_Load_Glyph(), with */ + /* FT_LOAD_NO_SCALE set. */ + /* */ + typedef FT_Error (*FT_AutoHinter_Load_Func)( FT_AutoHinter hinter, + FT_GlyphSlot slot, + FT_Size size, + FT_UInt glyph_index, + FT_ULong load_flags ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_AutoHinter_Interface */ + /* */ + /* */ + /* The auto-hinter module's interface. */ + /* */ + typedef struct FT_AutoHinter_Interface + { + FT_AutoHinter_Reset_Func reset_face; + FT_AutoHinter_Load_Func load_glyph; + + FT_AutoHinter_Get_Global_Func get_global_hints; + FT_AutoHinter_Done_Global_Func done_global_hints; + + } FT_AutoHinter_Interface; + + +#endif /* AUTOHINT_H */ + + +/* END */ diff --git a/src/freetype/freetype/internal/ftcalc.h b/src/freetype/freetype/internal/ftcalc.h new file mode 100644 index 0000000000..99b6cfaf64 --- /dev/null +++ b/src/freetype/freetype/internal/ftcalc.h @@ -0,0 +1,123 @@ +/***************************************************************************/ +/* */ +/* ftcalc.h */ +/* */ +/* Arithmetic computations (specification). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef FTCALC_H +#define FTCALC_H + +#include +#include /* for LONG64 */ + +#ifdef __cplusplus + extern "C" { +#endif + + +#ifdef LONG64 + + + typedef INT64 FT_Int64; + +#define ADD_64( x, y, z ) z = (x) + (y) +#define MUL_64( x, y, z ) z = (FT_Int64)(x) * (y) + +#define DIV_64( x, y ) ( (x) / (y) ) + + +#ifdef FT_CONFIG_OPTION_OLD_CALCS + +#define SQRT_64( z ) FT_Sqrt64( z ) + + FT_EXPORT_DEF( FT_Int32 ) FT_Sqrt64( FT_Int64 l ); + +#endif /* FT_CONFIG_OPTION_OLD_CALCS */ + + +#else /* LONG64 */ + + + typedef struct FT_Int64_ + { + FT_UInt32 lo; + FT_UInt32 hi; + + } FT_Int64; + + +#define ADD_64( x, y, z ) FT_Add64( &x, &y, &z ) +#define MUL_64( x, y, z ) FT_MulTo64( x, y, &z ) +#define DIV_64( x, y ) FT_Div64by32( &x, y ) + + + FT_EXPORT_DEF( void ) FT_Add64( FT_Int64* x, + FT_Int64* y, + FT_Int64* z ); + + FT_EXPORT_DEF( void ) FT_MulTo64( FT_Int32 x, + FT_Int32 y, + FT_Int64* z ); + + FT_EXPORT_DEF( FT_Int32 ) FT_Div64by32( FT_Int64* x, + FT_Int32 y ); + + +#ifdef FT_CONFIG_OPTION_OLD_CALCS + +#define SQRT_64( z ) FT_Sqrt64( &z ) + + FT_EXPORT_DEF( FT_Int32 ) FT_Sqrt64( FT_Int64* x ); + +#endif /* FT_CONFIG_OPTION_OLD_CALCS */ + + +#endif /* LONG64 */ + + +#ifndef FT_CONFIG_OPTION_OLD_CALCS + +#define SQRT_32( x ) FT_Sqrt32( x ) + + BASE_DEF( FT_Int32 ) FT_Sqrt32( FT_Int32 x ); + +#endif /* !FT_CONFIG_OPTION_OLD_CALCS */ + + + /*************************************************************************/ + /* */ + /* FT_MulDiv() and FT_MulFix() are declared in freetype.h. */ + /* */ + /*************************************************************************/ + + +#define INT_TO_F26DOT6( x ) ( (FT_Long)(x) << 6 ) +#define INT_TO_F2DOT14( x ) ( (FT_Long)(x) << 14 ) +#define INT_TO_FIXED( x ) ( (FT_Long)(x) << 16 ) +#define F2DOT14_TO_FIXED( x ) ( (FT_Long)(x) << 2 ) +#define FLOAT_TO_FIXED( x ) ( (FT_Long)( x * 65536.0 ) ) + +#define ROUND_F26DOT6( x ) ( x >= 0 ? ( ( (x) + 32 ) & -64 ) \ + : ( -( ( 32 - (x) ) & -64 ) ) ) + + +#ifdef __cplusplus + } +#endif + +#endif /* FTCALC_H */ + + +/* END */ diff --git a/src/freetype/freetype/internal/ftdebug.h b/src/freetype/freetype/internal/ftdebug.h new file mode 100644 index 0000000000..8b1e4dd5a5 --- /dev/null +++ b/src/freetype/freetype/internal/ftdebug.h @@ -0,0 +1,225 @@ +/***************************************************************************/ +/* */ +/* ftdebug.h */ +/* */ +/* Debugging and logging component (specification). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef FTDEBUG_H +#define FTDEBUG_H + +#include /* for FT_DEBUG_LEVEL_TRACE, */ + /* FT_DEBUG_LEVEL_ERROR */ + +#ifdef __cplusplus + extern "C" { +#endif + + + /* A very stupid pre-processor trick. See K&R version 2 */ + /* section A12.3 for details... */ + /* */ + /* It is also described in the section `Separate */ + /* Expansion of Macro Arguments' in the info file */ + /* `cpp.info', describing GNU cpp. */ + /* */ +#define FT_CAT( x, y ) x ## y +#define FT_XCAT( x, y ) FT_CAT( x, y ) + + +#ifdef FT_DEBUG_LEVEL_TRACE + + + /* note that not all levels are used currently */ + + typedef enum FT_Trace_ + { + /* the first level must always be `trace_any' */ + trace_any = 0, + + /* base components */ + trace_aaraster, /* anti-aliasing raster (ftgrays.c) */ + trace_calc, /* calculations (ftcalc.c) */ + trace_extend, /* extension manager (ftextend.c) */ + trace_glyph, /* glyph manager (ftglyph.c) */ + trace_io, /* i/o monitoring (ftsystem.c) */ + trace_init, /* initialization (ftinit.c) */ + trace_list, /* list manager (ftlist.c) */ + trace_memory, /* memory manager (ftobjs.c) */ + trace_mm, /* MM interface (ftmm.c) */ + trace_objs, /* base objects (ftobjs.c) */ + trace_outline, /* outline management (ftoutln.c) */ + trace_raster, /* rasterizer (ftraster.c) */ + trace_stream, /* stream manager (ftstream.c) */ + + /* SFNT driver components */ + trace_sfobjs, /* SFNT object handler (sfobjs.c) */ + trace_ttcmap, /* charmap handler (ttcmap.c) */ + trace_ttload, /* basic TrueType tables (ttload.c) */ + trace_ttpost, /* PS table processing (ttpost.c) */ + trace_ttsbit, /* TrueType sbit handling (ttsbit.c) */ + + /* TrueType driver components */ + trace_ttdriver, /* TT font driver (ttdriver.c) */ + trace_ttgload, /* TT glyph loader (ttgload.c) */ + trace_ttinterp, /* bytecode interpreter (ttinterp.c) */ + trace_ttobjs, /* TT objects manager (ttobjs.c) */ + trace_ttpload, /* TT data/program loader (ttpload.c) */ + + /* Type 1 driver components */ + trace_t1driver, + trace_t1gload, + trace_t1hint, + trace_t1load, + trace_t1objs, + + /* experimental Type 1 driver components */ + trace_z1driver, + trace_z1gload, + trace_z1hint, + trace_z1load, + trace_z1objs, + trace_z1parse, + + /* Type 2 driver components */ + trace_t2driver, + trace_t2gload, + trace_t2load, + trace_t2objs, + trace_t2parse, + + /* CID driver components */ + trace_cidafm, + trace_ciddriver, + trace_cidgload, + trace_cidload, + trace_cidobjs, + trace_cidparse, + + /* Windows fonts component */ + trace_winfnt, + + /* the last level must always be `trace_max' */ + trace_max + + } FT_Trace; + + + /* declared in ftdebug.c */ + extern char ft_trace_levels[trace_max]; + + + /*************************************************************************/ + /* */ + /* IMPORTANT! */ + /* */ + /* Each component must define the macro FT_COMPONENT to a valid FT_Trace */ + /* value before using any TRACE macro. */ + /* */ + /*************************************************************************/ + + +#define FT_TRACE( level, varformat ) \ + do \ + { \ + if ( ft_trace_levels[FT_COMPONENT] >= level ) \ + FT_XCAT( FT_Message, varformat ); \ + } while ( 0 ) + + + FT_EXPORT_DEF( void ) FT_SetTraceLevel( FT_Trace component, + char level ); + + +#elif defined( FT_DEBUG_LEVEL_ERROR ) + + +#define FT_TRACE( level, varformat ) do ; while ( 0 ) /* nothing */ + + +#else /* release mode */ + + +#define FT_Assert( condition ) do ; while ( 0 ) /* nothing */ + +#define FT_TRACE( level, varformat ) do ; while ( 0 ) /* nothing */ +#define FT_ERROR( varformat ) do ; while ( 0 ) /* nothing */ + + +#endif /* FT_DEBUG_LEVEL_TRACE, FT_DEBUG_LEVEL_ERROR */ + + + /*************************************************************************/ + /* */ + /* Define macros and functions that are common to the debug and trace */ + /* modes. */ + /* */ + /* You need vprintf() to be able to compile ftdebug.c. */ + /* */ + /*************************************************************************/ + + +#if defined( FT_DEBUG_LEVEL_TRACE ) || defined( FT_DEBUG_LEVEL_ERROR ) + + +#include "stdio.h" /* for vprintf() */ + + +#define FT_Assert( condition ) \ + do \ + { \ + if ( !( condition ) ) \ + FT_Panic( "assertion failed on line %d of file %s\n", \ + __LINE__, __FILE__ ); \ + } while ( 0 ) + + /* print a message */ + FT_EXPORT_DEF( void ) FT_Message( const char* fmt, ... ); + + /* print a message and exit */ + FT_EXPORT_DEF( void ) FT_Panic( const char* fmt, ... ); + +#define FT_ERROR( varformat ) FT_XCAT( FT_Message, varformat ) + + +#endif /* FT_DEBUG_LEVEL_TRACE || FT_DEBUG_LEVEL_ERROR */ + + + /*************************************************************************/ + /* */ + /* You need two opening resp. closing parentheses! */ + /* */ + /* Example: FT_TRACE0(( "Value is %i", foo )) */ + /* */ + /*************************************************************************/ + +#define FT_TRACE0( varformat ) FT_TRACE( 0, varformat ) +#define FT_TRACE1( varformat ) FT_TRACE( 1, varformat ) +#define FT_TRACE2( varformat ) FT_TRACE( 2, varformat ) +#define FT_TRACE3( varformat ) FT_TRACE( 3, varformat ) +#define FT_TRACE4( varformat ) FT_TRACE( 4, varformat ) +#define FT_TRACE5( varformat ) FT_TRACE( 5, varformat ) +#define FT_TRACE6( varformat ) FT_TRACE( 6, varformat ) +#define FT_TRACE7( varformat ) FT_TRACE( 7, varformat ) + + +#ifdef __cplusplus + } +#endif + + +#endif /* FTDEBUG_H */ + + +/* END */ diff --git a/src/freetype/freetype/internal/ftdriver.h b/src/freetype/freetype/internal/ftdriver.h new file mode 100644 index 0000000000..592de498c1 --- /dev/null +++ b/src/freetype/freetype/internal/ftdriver.h @@ -0,0 +1,182 @@ +/***************************************************************************/ +/* */ +/* ftdriver.h */ +/* */ +/* FreeType font driver interface (specification). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef FTDRIVER_H +#define FTDRIVER_H + + +#include +#include + + + typedef FT_Error (*FTDriver_initFace)( FT_Stream stream, + FT_Face face, + FT_Int typeface_index, + FT_Int num_params, + FT_Parameter* parameters ); + + typedef void (*FTDriver_doneFace)( FT_Face face ); + + + typedef FT_Error (*FTDriver_initSize)( FT_Size size ); + + typedef void (*FTDriver_doneSize)( FT_Size size ); + + + typedef FT_Error (*FTDriver_initGlyphSlot)( FT_GlyphSlot slot ); + + typedef void (*FTDriver_doneGlyphSlot)( FT_GlyphSlot slot ); + + + typedef FT_Error (*FTDriver_setCharSizes)( FT_Size size, + FT_F26Dot6 char_width, + FT_F26Dot6 char_height, + FT_UInt horz_resolution, + FT_UInt vert_resolution ); + + typedef FT_Error (*FTDriver_setPixelSizes)( FT_Size size, + FT_UInt pixel_width, + FT_UInt pixel_height ); + + typedef FT_Error (*FTDriver_loadGlyph)( FT_GlyphSlot slot, + FT_Size size, + FT_UInt glyph_index, + FT_Int load_flags ); + + + typedef FT_UInt (*FTDriver_getCharIndex)( FT_CharMap charmap, + FT_Long charcode ); + + typedef FT_Error (*FTDriver_getKerning)( FT_Face face, + FT_UInt left_glyph, + FT_UInt right_glyph, + FT_Vector* kerning ); + + + typedef FT_Error (*FTDriver_attachFile)( FT_Face face, + FT_Stream stream ); + + + typedef FT_Error (*FTDriver_getAdvances)( FT_Face face, + FT_UInt first, + FT_UInt count, + FT_Bool vertical, + FT_UShort* advances ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Driver_Class */ + /* */ + /* */ + /* The font driver class. This structure mostly contains pointers to */ + /* driver methods. */ + /* */ + /* */ + /* root :: The parent module. */ + /* */ + /* face_object_size :: The size of a face object in bytes. */ + /* */ + /* size_object_size :: The size of a size object in bytes. */ + /* */ + /* slot_object_size :: The size of a glyph object in bytes. */ + /* */ + /* init_face :: The format-specific face constructor. */ + /* */ + /* done_face :: The format-specific face destructor. */ + /* */ + /* init_size :: The format-specific size constructor. */ + /* */ + /* done_size :: The format-specific size destructor. */ + /* */ + /* init_slot :: The format-specific slot constructor. */ + /* */ + /* done_slot :: The format-specific slot destructor. */ + /* */ + /* set_char_sizes :: A handle to a function used to set the new */ + /* character size in points + resolution. Can be */ + /* set to 0 to indicate default behaviour. */ + /* */ + /* set_pixel_sizes :: A handle to a function used to set the new */ + /* character size in pixels. Can be set to 0 to */ + /* indicate default behaviour. */ + /* */ + /* load_glyph :: A function handle to load a given glyph image */ + /* in a slot. This field is mandatory! */ + /* */ + /* get_char_index :: A function handle to return the glyph index of */ + /* a given character for a given charmap. This */ + /* field is mandatory! */ + /* */ + /* get_kerning :: A function handle to return the unscaled */ + /* kerning for a given pair of glyphs. Can be */ + /* set to 0 if the format doesn't support */ + /* kerning. */ + /* */ + /* attach_file :: This function handle is used to read */ + /* additional data for a face from another */ + /* file/stream. For example, this can be used to */ + /* add data from AFM or PFM files on a Type 1 */ + /* face, or a CIDMap on a CID-keyed face. */ + /* */ + /* get_advances :: A function handle used to return the advances */ + /* of 'count' glyphs, starting at `index'. the */ + /* `vertical' flags must be set when vertical */ + /* advances are queried. The advances buffer is */ + /* caller-allocated. */ + /* */ + /* */ + /* Most function pointers, with the exception of `load_glyph' and */ + /* `get_char_index' can be set to 0 to indicate a default behaviour. */ + /* */ + typedef struct FT_Driver_Class_ + { + FT_Module_Class root; + + FT_Int face_object_size; + FT_Int size_object_size; + FT_Int slot_object_size; + + FTDriver_initFace init_face; + FTDriver_doneFace done_face; + + FTDriver_initSize init_size; + FTDriver_doneSize done_size; + + FTDriver_initGlyphSlot init_slot; + FTDriver_doneGlyphSlot done_slot; + + FTDriver_setCharSizes set_char_sizes; + FTDriver_setPixelSizes set_pixel_sizes; + + FTDriver_loadGlyph load_glyph; + FTDriver_getCharIndex get_char_index; + + FTDriver_getKerning get_kerning; + FTDriver_attachFile attach_file; + + FTDriver_getAdvances get_advances; + + } FT_Driver_Class; + + +#endif /* FTDRIVER_H */ + + +/* END */ diff --git a/src/freetype/freetype/internal/ftextend.h b/src/freetype/freetype/internal/ftextend.h new file mode 100644 index 0000000000..fdd2c6ef24 --- /dev/null +++ b/src/freetype/freetype/internal/ftextend.h @@ -0,0 +1,178 @@ +/***************************************************************************/ +/* */ +/* ftextend.h */ +/* */ +/* FreeType extensions implementation (specification). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef FTEXTEND_H +#define FTEXTEND_H + + +#include + + +#ifdef __cplusplus + extern "C" { +#endif + + + /*************************************************************************/ + /* */ + /* The extensions don't need to be integrated at compile time into the */ + /* engine, only at link time. */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Extension_Initializer */ + /* */ + /* */ + /* Each new face object can have several extensions associated with */ + /* it at creation time. This function is used to initialize given */ + /* extension data for a given face. */ + /* */ + /* */ + /* ext :: A typeless pointer to the extension data. */ + /* */ + /* face :: A handle to the source face object the extension is */ + /* associated with. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* In case of error, the initializer should not destroy the extension */ + /* data, as the finalizer will get called later by the function's */ + /* caller. */ + /* */ + typedef FT_Error (*FT_Extension_Initializer)( void* ext, + FT_Face face ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Extension_Finalizer */ + /* */ + /* */ + /* Each new face object can have several extensions associated with */ + /* it at creation time. This function is used to finalize given */ + /* extension data for a given face; it occurs before the face object */ + /* itself is finalized. */ + /* */ + /* */ + /* ext :: A typeless pointer to the extension data. */ + /* */ + /* face :: A handle to the source face object the extension is */ + /* associated with. */ + /* */ + typedef void (*FT_Extension_Finalizer)( void* ext, + FT_Face face ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Extension_Class */ + /* */ + /* */ + /* A simple structure used to describe a given extension to the */ + /* FreeType base layer. An FT_Extension_Class is used as a parameter */ + /* for FT_Register_Extension(). */ + /* */ + /* */ + /* id :: The extension's ID. This is a normal C string that */ + /* is used to uniquely reference the extension's */ + /* interface. */ + /* */ + /* size :: The size in bytes of the extension data that must be */ + /* associated with each face object. */ + /* */ + /* init :: A pointer to the extension data's initializer. */ + /* */ + /* finalize :: A pointer to the extension data's finalizer. */ + /* */ + /* interface :: This pointer can be anything, but should usually */ + /* point to a table of function pointers which implement */ + /* the extension's interface. */ + /* */ + /* offset :: This field is set and used within the base layer and */ + /* should be set to 0 when registering an extension */ + /* through FT_Register_Extension(). It contains an */ + /* offset within the face's extension block for the */ + /* current extension's data. */ + /* */ + typedef struct FT_Extension_Class_ + { + const char* id; + FT_ULong size; + FT_Extension_Initializer init; + FT_Extension_Finalizer finalize; + void* interface; + + FT_ULong offset; + + } FT_Extension_Class; + + + FT_EXPORT_DEF( FT_Error ) FT_Register_Extension( + FT_Driver driver, + FT_Extension_Class* clazz ); + + +#ifdef FT_CONFIG_OPTION_EXTEND_ENGINE + + + /* Initialize the extension component */ + LOCAL_DEF + FT_Error FT_Init_Extensions( FT_Library library ); + + /* Finalize the extension component */ + LOCAL_DEF + FT_Error FT_Done_Extensions( FT_Library library ); + + /* Create an extension within a face object. Called by the */ + /* face object constructor. */ + LOCAL_DEF + FT_Error FT_Create_Extensions( FT_Face face ); + + /* Destroy all extensions within a face object. Called by the */ + /* face object destructor. */ + LOCAL_DEF + FT_Error FT_Destroy_Extensions( FT_Face face ); + + +#endif + + + /* return an extension's data & interface according to its ID */ + FT_EXPORT_DEF( void* ) FT_Get_Extension( + FT_Face face, + const char* extension_id, + void** extension_interface ); + + +#ifdef __cplusplus + } +#endif + + +#endif /* FTEXTEND_H */ + + +/* END */ diff --git a/src/freetype/freetype/internal/ftlist.h b/src/freetype/freetype/internal/ftlist.h new file mode 100644 index 0000000000..7c6d8ed3b3 --- /dev/null +++ b/src/freetype/freetype/internal/ftlist.h @@ -0,0 +1,113 @@ +/***************************************************************************/ +/* */ +/* ftlist.c */ +/* */ +/* Generic list support for FreeType (specification). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + + /*************************************************************************/ + /* */ + /* This file implements functions relative to list processing. Its */ + /* data structures are defined in `freetype.h'. */ + /* */ + /*************************************************************************/ + + +#ifndef FTLIST_H +#define FTLIST_H + +#include + +#ifdef __cplusplus + extern "C" { +#endif + + + FT_EXPORT_DEF( FT_ListNode ) FT_List_Find( FT_List list, + void* data ); + + FT_EXPORT_DEF( void ) FT_List_Add( FT_List list, + FT_ListNode node ); + + FT_EXPORT_DEF( void ) FT_List_Insert( FT_List list, + FT_ListNode node ); + + FT_EXPORT_DEF( void ) FT_List_Remove( FT_List list, + FT_ListNode node ); + + FT_EXPORT_DEF( void ) FT_List_Up( FT_List list, + FT_ListNode node ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_List_Iterator */ + /* */ + /* */ + /* An FT_List iterator function which is called during a list parse */ + /* by FT_List_Iterate(). */ + /* */ + /* */ + /* node :: The current iteration list node. */ + /* */ + /* user :: A typeless pointer passed to FT_List_Iterate(). */ + /* Can be used to point to the iteration's state. */ + /* */ + typedef FT_Error (*FT_List_Iterator)( FT_ListNode node, + void* user ); + + + FT_EXPORT_DEF( FT_Error ) FT_List_Iterate( FT_List list, + FT_List_Iterator iterator, + void* user ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_List_Destructor */ + /* */ + /* */ + /* An FT_List iterator function which is called during a list */ + /* finalization by FT_List_Finalize() to destroy all elements in a */ + /* given list. */ + /* */ + /* */ + /* system :: The current system object. */ + /* */ + /* data :: The current object to destroy. */ + /* */ + /* user :: A typeless pointer passed to FT_List_Iterate(). It can */ + /* be used to point to the iteration's state. */ + /* */ + typedef void (*FT_List_Destructor)( FT_Memory memory, + void* data, + void* user ); + + + FT_EXPORT_DEF( void ) FT_List_Finalize( FT_List list, + FT_List_Destructor destroy, + FT_Memory memory, + void* user ); + + +#ifdef __cplusplus + } +#endif + +#endif /* FTLIST_H */ + + +/* END */ diff --git a/src/freetype/freetype/internal/ftmemory.h b/src/freetype/freetype/internal/ftmemory.h new file mode 100644 index 0000000000..da8d3a4126 --- /dev/null +++ b/src/freetype/freetype/internal/ftmemory.h @@ -0,0 +1,127 @@ +/***************************************************************************/ +/* */ +/* ftmemory.h */ +/* */ +/* The FreeType memory management macros (specification). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef FTMEMORY_H +#define FTMEMORY_H + + +#include +#include + + + /*************************************************************************/ + /* */ + /* */ + /* FT_SET_ERROR */ + /* */ + /* */ + /* This macro is used to set an implicit `error' variable to a given */ + /* expression's value (usually a function call), and convert it to a */ + /* boolean which is set whenever the value is != 0. */ + /* */ +#undef FT_SET_ERROR +#define FT_SET_ERROR( expression ) \ + ( ( error = (expression) ) != 0 ) + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** M E M O R Y ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + BASE_DEF( FT_Error ) FT_Alloc( FT_Memory memory, + FT_Long size, + void** P ); + + BASE_DEF( FT_Error ) FT_Realloc( FT_Memory memory, + FT_Long current, + FT_Long size, + void** P ); + + BASE_DEF( void ) FT_Free( FT_Memory memory, + void** P ); + + + + /* This `#include' is needed by the MEM_xxx() macros; it should be */ + /* available on all platforms we know of. */ +#include + +#define MEM_Set( dest, byte, count ) memset( dest, byte, count ) + +#define MEM_Copy( dest, source, count ) memcpy( dest, source, count ) + +#define MEM_Move( dest, source, count ) memmove( dest, source, count ) + + + /*************************************************************************/ + /* */ + /* We now support closures to produce completely reentrant code. This */ + /* means the allocation functions now takes an additional argument */ + /* (`memory'). It is a handle to a given memory object, responsible for */ + /* all low-level operations, including memory management and */ + /* synchronisation. */ + /* */ + /* In order to keep our code readable and use the same macros in the */ + /* font drivers and the rest of the library, MEM_Alloc(), ALLOC(), and */ + /* ALLOC_ARRAY() now use an implicit variable, `memory'. It must be */ + /* defined at all locations where a memory operation is queried. */ + /* */ +#define MEM_Alloc( _pointer_, _size_ ) \ + FT_Alloc( memory, _size_, (void**)&(_pointer_) ) + +#define MEM_Alloc_Array( _pointer_, _count_, _type_ ) \ + FT_Alloc( memory, (_count_)*sizeof ( _type_ ), \ + (void**)&(_pointer_) ) + +#define MEM_Realloc( _pointer_, _current_, _size_ ) \ + FT_Realloc( memory, _current_, _size_, (void**)&(_pointer_) ) + +#define MEM_Realloc_Array( _pointer_, _current_, _new_, _type_ ) \ + FT_Realloc( memory, (_current_)*sizeof ( _type_ ), \ + (_new_)*sizeof ( _type_ ), (void**)&(_pointer_) ) + +#define ALLOC( _pointer_, _size_ ) \ + FT_SET_ERROR( MEM_Alloc( _pointer_, _size_ ) ) + +#define REALLOC( _pointer_, _current_, _size_ ) \ + FT_SET_ERROR( MEM_Realloc( _pointer_, _current_, _size_ ) ) + +#define ALLOC_ARRAY( _pointer_, _count_, _type_ ) \ + FT_SET_ERROR( MEM_Alloc( _pointer_, \ + (_count_)*sizeof ( _type_ ) ) ) + +#define REALLOC_ARRAY( _pointer_, _current_, _count_, _type_ ) \ + FT_SET_ERROR( MEM_Realloc( _pointer_, \ + (_current_)*sizeof ( _type_ ), \ + (_count_)*sizeof ( _type_ ) ) ) + +#define FREE( _pointer_ ) FT_Free( memory, (void**)&(_pointer_) ) + + +#endif /* FTMEMORY_H */ + + +/* END */ diff --git a/src/freetype/freetype/internal/ftobjs.h b/src/freetype/freetype/internal/ftobjs.h new file mode 100644 index 0000000000..0d0f5d80ac --- /dev/null +++ b/src/freetype/freetype/internal/ftobjs.h @@ -0,0 +1,532 @@ +/***************************************************************************/ +/* */ +/* ftobjs.h */ +/* */ +/* The FreeType private base classes (specification). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + + /*************************************************************************/ + /* */ + /* This file contains the definition of all internal FreeType classes. */ + /* */ + /*************************************************************************/ + + +#ifndef FTOBJS_H +#define FTOBJS_H + +#include +#include +#include +#include + + +#ifdef __cplusplus + extern "C" { +#endif + + + /*************************************************************************/ + /* */ + /* Some generic definitions. */ + /* */ +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef NULL +#define NULL (void*)0 +#endif + +#ifndef UNUSED +#define UNUSED( arg ) ( (arg)=(arg) ) +#endif + + + /*************************************************************************/ + /* */ + /* The min and max functions missing in C. As usual, be careful not to */ + /* write things like MIN( a++, b++ ) to avoid side effects. */ + /* */ +#ifndef MIN +#define MIN( a, b ) ( (a) < (b) ? (a) : (b) ) +#endif + +#ifndef MAX +#define MAX( a, b ) ( (a) > (b) ? (a) : (b) ) +#endif + +#ifndef ABS +#define ABS( a ) ( (a) < 0 ? -(a) : (a) ) +#endif + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** M O D U L E S ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* */ + /* FT_ModuleRec */ + /* */ + /* */ + /* A module object instance. */ + /* */ + /* */ + /* clazz :: A pointer to the module's class. */ + /* */ + /* library :: A handle to the parent library object. */ + /* */ + /* memory :: A handle to the memory manager. */ + /* */ + /* generic :: A generic structure for user-level extensibility (?). */ + /* */ + typedef struct FT_ModuleRec_ + { + FT_Module_Class* clazz; + FT_Library library; + FT_Memory memory; + FT_Generic generic; + + } FT_ModuleRec; + + + /* typecast an object to a FT_Module */ +#define FT_MODULE( x ) ((FT_Module)(x)) +#define FT_MODULE_CLASS( x ) FT_MODULE(x)->clazz +#define FT_MODULE_LIBRARY( x ) FT_MODULE(x)->library +#define FT_MODULE_MEMORY( x ) FT_MODULE(x)->memory + +#define FT_MODULE_IS_DRIVER( x ) ( FT_MODULE_CLASS( x )->module_flags & \ + ft_module_font_driver ) + +#define FT_MODULE_IS_RENDERER( x ) ( FT_MODULE_CLASS( x )->module_flags & \ + ft_module_renderer ) + +#define FT_MODULE_IS_HINTER( x ) ( FT_MODULE_CLASS( x )->module_flags & \ + ft_module_hinter ) + +#define FT_MODULE_IS_STYLER( x ) ( FT_MODULE_CLASS( x )->module_flags & \ + ft_module_styler ) + +#define FT_DRIVER_IS_SCALABLE( x ) ( FT_MODULE_CLASS(x)->module_flags & \ + ft_module_driver_scalable ) + +#define FT_DRIVER_USES_OUTLINES( x ) !( FT_MODULE_CLASS(x)->module_flags & \ + ft_module_driver_no_outlines ) + +#define FT_DRIVER_HAS_HINTER( x ) ( FT_MODULE_CLASS(x)->module_flags & \ + ft_module_driver_has_hinter ) + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Get_Module_Interface */ + /* */ + /* */ + /* Finds a module and returns its specific interface as a typeless */ + /* pointer. */ + /* */ + /* */ + /* library :: A handle to the library object. */ + /* */ + /* module_name :: The module's name (as an ASCII string). */ + /* */ + /* */ + /* A module-specific interface if available, 0 otherwise. */ + /* */ + /* */ + /* You should better be familiar with FreeType internals to know */ + /* which module to look for, and what its interface is :-) */ + /* */ + BASE_DEF( const void* ) FT_Get_Module_Interface( FT_Library library, + const char* mod_name ); + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** FACE, SIZE & GLYPH SLOT OBJECTS ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + /* a few macros used to perform easy typecasts with minimal brain damage */ + +#define FT_FACE( x ) ((FT_Face)(x)) +#define FT_SIZE( x ) ((FT_Size)(x)) +#define FT_SLOT( x ) ((FT_GlyphSlot)(x)) + +#define FT_FACE_DRIVER( x ) FT_FACE( x )->driver +#define FT_FACE_LIBRARY( x ) FT_FACE_DRIVER( x )->root.library +#define FT_FACE_MEMORY( x ) FT_FACE( x )->memory + +#define FT_SIZE_FACE( x ) FT_SIZE( x )->face +#define FT_SLOT_FACE( x ) FT_SLOT( x )->face + +#define FT_FACE_SLOT( x ) FT_FACE( x )->glyph +#define FT_FACE_SIZE( x ) FT_FACE( x )->size + + + /* this must be kept exported -- tt will be used later in our own */ + /* high-level caching font manager called SemTex (way after the */ + /* 2.0 release though */ + FT_EXPORT_DEF( FT_Error ) FT_New_Size( FT_Face face, + FT_Size* size ); + + FT_EXPORT_DEF( FT_Error ) FT_Done_Size( FT_Size size ); + + + FT_EXPORT_DEF( FT_Error ) FT_New_GlyphSlot( FT_Face face, + FT_GlyphSlot* aslot ); + + FT_EXPORT_DEF( void ) FT_Done_GlyphSlot( FT_GlyphSlot slot ); + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** G L Y P H L O A D E R ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + +#define FT_SUBGLYPH_FLAG_ARGS_ARE_WORDS 1 +#define FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES 2 +#define FT_SUBGLYPH_FLAG_ROUND_XY_TO_GRID 4 +#define FT_SUBGLYPH_FLAG_SCALE 8 +#define FT_SUBGLYPH_FLAG_XY_SCALE 0x40 +#define FT_SUBGLYPH_FLAG_2X2 0x80 +#define FT_SUBGLYPH_FLAG_USE_MY_METRICS 0x200 + + + enum + { + ft_glyph_own_bitmap = 1 + }; + + + struct FT_SubGlyph_ + { + FT_Int index; + FT_UShort flags; + FT_Int arg1; + FT_Int arg2; + FT_Matrix transform; + }; + + + typedef struct FT_GlyphLoad_ + { + FT_Outline outline; /* outline */ + FT_UInt num_subglyphs; /* number of subglyphs */ + FT_SubGlyph* subglyphs; /* subglyphs */ + FT_Vector* extra_points; /* extra points table */ + + } FT_GlyphLoad; + + + struct FT_GlyphLoader_ + { + FT_Memory memory; + FT_UInt max_points; + FT_UInt max_contours; + FT_UInt max_subglyphs; + FT_Bool use_extra; + + FT_GlyphLoad base; + FT_GlyphLoad current; + + void* other; /* for possible future extension? */ + + }; + + + BASE_DEF( FT_Error ) FT_GlyphLoader_New( FT_Memory memory, + FT_GlyphLoader** aloader ); + + BASE_DEF( FT_Error ) FT_GlyphLoader_Create_Extra( + FT_GlyphLoader* loader ); + + BASE_DEF( void ) FT_GlyphLoader_Done( FT_GlyphLoader* loader ); + + BASE_DEF( void ) FT_GlyphLoader_Reset( FT_GlyphLoader* loader ); + + BASE_DEF( void ) FT_GlyphLoader_Rewind( FT_GlyphLoader* loader ); + + BASE_DEF( FT_Error ) FT_GlyphLoader_Check_Points( + FT_GlyphLoader* loader, + FT_UInt n_points, + FT_UInt n_contours ); + + BASE_DEF( FT_Error ) FT_GlyphLoader_Check_Subglyphs( + FT_GlyphLoader* loader, + FT_UInt n_subs ); + + BASE_DEF( void ) FT_GlyphLoader_Prepare( FT_GlyphLoader* loader ); + + BASE_DEF( void ) FT_GlyphLoader_Add( FT_GlyphLoader* loader ); + + BASE_DEF( FT_Error ) FT_GlyphLoader_Copy_Points( FT_GlyphLoader* target, + FT_GlyphLoader* source ); + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** R E N D E R E R S ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + +#define FT_RENDERER( x ) ((FT_Renderer)( x )) +#define FT_GLYPH( x ) ((FT_Glyph)( x )) +#define FT_BITMAP_GLYPH( x ) ((FT_BitmapGlyph)( x )) +#define FT_OUTLINE_GLYPH( x ) ((FT_OutlineGlyph)( x )) + + + typedef struct FT_RendererRec_ + { + FT_ModuleRec root; + FT_Renderer_Class* clazz; + FT_Glyph_Format glyph_format; + const FT_Glyph_Class glyph_class; + + FT_Raster raster; + FT_Raster_Render_Func raster_render; + FTRenderer_render render; + + } FT_RendererRec; + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** F O N T D R I V E R S ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /* typecast a module into a driver easily */ +#define FT_DRIVER( x ) ((FT_Driver)(x)) + + /* typecast a module as a driver, and get its driver class */ +#define FT_DRIVER_CLASS( x ) FT_DRIVER( x )->clazz + + + /*************************************************************************/ + /* */ + /* */ + /* FT_DriverRec */ + /* */ + /* */ + /* The root font driver class. A font driver is responsible for */ + /* managing and loading font files of a given format. */ + /* */ + /* */ + /* root :: Contains the fields of the root module class. */ + /* */ + /* clazz :: A pointer to the font driver's class. Note that */ + /* this is NOT root.clazz. `class' wasn't used */ + /* as it is a reserved word in C++. */ + /* */ + /* faces_list :: The list of faces currently opened by this */ + /* driver. */ + /* */ + /* extensions :: A typeless pointer to the driver's extensions */ + /* registry, if they are supported through the */ + /* configuration macro FT_CONFIG_OPTION_EXTENSIONS. */ + /* */ + /* glyph_loader :: The glyph loader for all faces managed by this */ + /* driver. This object isn't defined for unscalable */ + /* formats. */ + /* */ + typedef struct FT_DriverRec_ + { + FT_ModuleRec root; + FT_Driver_Class* clazz; + + FT_ListRec faces_list; + void* extensions; + + FT_GlyphLoader* glyph_loader; + + } FT_DriverRec; + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** L I B R A R I E S ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + +#define FT_DEBUG_HOOK_TRUETYPE 0 +#define FT_DEBUG_HOOK_TYPE1 1 + + + /*************************************************************************/ + /* */ + /* */ + /* FT_LibraryRec */ + /* */ + /* */ + /* The FreeType library class. This is the root of all FreeType */ + /* data. Use FT_New_Library() to create a library object, and */ + /* FT_Done_Library() to discard it and all child objects. */ + /* */ + /* */ + /* memory :: The library's memory object. Manages memory */ + /* allocation. */ + /* */ + /* generic :: Client data variable. Used to extend the */ + /* Library class by higher levels and clients. */ + /* */ + /* num_modules :: The number of modules currently registered */ + /* within this library. This is set to 0 for new */ + /* libraries. New modules are added through the */ + /* FT_Add_Module() API function. */ + /* */ + /* modules :: A table used to store handles to the currently */ + /* registered modules. Note that each font driver */ + /* contains a list of its opened faces. */ + /* */ + /* renderers :: The list of renderers currently registered */ + /* within the library. */ + /* */ + /* cur_renderer :: The current outline renderer. This is a */ + /* shortcut used to avoid parsing the list on */ + /* each call to FT_Outline_Render(). It is a */ + /* handle to the current renderer for the */ + /* ft_glyph_format_outline format. */ + /* */ + /* auto_hinter :: XXX */ + /* */ + /* raster_pool :: The raster object's render pool. This can */ + /* ideally be changed dynamically at run-time. */ + /* */ + /* raster_pool_size :: The size of the render pool in bytes. */ + /* */ + /* debug_hooks :: XXX */ + /* */ + typedef struct FT_LibraryRec_ + { + FT_Memory memory; /* library's memory manager */ + + FT_Generic generic; + + FT_UInt num_modules; + FT_Module modules[FT_MAX_MODULES]; /* module objects */ + + FT_ListRec renderers; /* list of renderers */ + FT_Renderer cur_renderer; /* current outline renderer */ + FT_Module auto_hinter; + + FT_Byte* raster_pool; /* scan-line conversion */ + /* render pool */ + FT_ULong raster_pool_size; /* size of render pool in bytes */ + + FT_DebugHook_Func debug_hooks[4]; + + } FT_LibraryRec; + + + BASE_DEF( FT_Renderer ) FT_Lookup_Renderer( FT_Library library, + FT_Glyph_Format format, + FT_ListNode* node ); + + BASE_DEF( FT_Error ) FT_Render_Glyph_Internal( FT_Library library, + FT_GlyphSlot slot, + FT_UInt render_mode ); + + typedef FT_Error (*FT_Glyph_Name_Requester)( FT_Face face, + FT_UInt glyph_index, + FT_Pointer buffer, + FT_UInt buffer_max ); + + +#ifndef FT_CONFIG_OPTION_NO_DEFAULT_SYSTEM + + + FT_EXPORT_DEF( FT_Error ) FT_New_Stream( const char* filepathname, + FT_Stream astream ); + + FT_EXPORT_DEF( void ) FT_Done_Stream( FT_Stream stream ); + + FT_EXPORT_DEF( FT_Memory ) FT_New_Memory( void ); + + +#endif /* !FT_CONFIG_OPTION_NO_DEFAULT_SYSTEM */ + + + /* Define default raster's interface. The default raster is located in */ + /* `src/base/ftraster.c' */ + /* */ + /* Client applications can register new rasters through the */ + /* FT_Set_Raster() API. */ + +#ifndef FT_NO_DEFAULT_RASTER + FT_EXPORT_VAR( FT_Raster_Funcs ) ft_default_raster; +#endif + + +#ifdef __cplusplus + } +#endif + + +#endif /* FTOBJS_H */ + + +/* END */ diff --git a/src/freetype/freetype/internal/ftstream.h b/src/freetype/freetype/internal/ftstream.h new file mode 100644 index 0000000000..365f479a8a --- /dev/null +++ b/src/freetype/freetype/internal/ftstream.h @@ -0,0 +1,361 @@ +/***************************************************************************/ +/* */ +/* ftstream.h */ +/* */ +/* Stream handling(specification). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef FTSTREAM_H +#define FTSTREAM_H + +#include + + +#ifdef __cplusplus + extern "C" { +#endif + + + /* format of an 8-bit frame_op value = [ xxxxx | e | s ] */ + /* s is set to 1 if the value is signed, */ + /* e is set to 1 if the value is little-endian */ + /* xxxxx is a command */ + +#define FT_FRAME_OP_SHIFT 2 +#define FT_FRAME_OP_SIGNED 1 +#define FT_FRAME_OP_LITTLE 2 +#define FT_FRAME_OP_COMMAND( x ) ( x >> FT_FRAME_OP_SHIFT ) + +#define FT_MAKE_FRAME_OP( command, little, sign ) \ + ( ( command << FT_FRAME_OP_SHIFT ) | ( little << 1 ) | sign ) + +#define FT_FRAME_OP_END 0 +#define FT_FRAME_OP_START 1 /* start a new frame */ +#define FT_FRAME_OP_BYTE 2 /* read 1-byte value */ +#define FT_FRAME_OP_SHORT 3 /* read 2-byte value */ +#define FT_FRAME_OP_LONG 4 /* read 4-byte value */ +#define FT_FRAME_OP_OFF3 5 /* read 3-byte value */ +#define FT_FRAME_OP_BYTES 6 /* read a bytes sequence */ + + + typedef enum FT_Frame_Op_ + { + ft_frame_end = 0, + ft_frame_start = FT_MAKE_FRAME_OP( FT_FRAME_OP_START, 0, 0 ), + + ft_frame_byte = FT_MAKE_FRAME_OP( FT_FRAME_OP_BYTE, 0, 0 ), + ft_frame_schar = FT_MAKE_FRAME_OP( FT_FRAME_OP_BYTE, 0, 1 ), + + ft_frame_ushort_be = FT_MAKE_FRAME_OP( FT_FRAME_OP_SHORT, 0, 0 ), + ft_frame_short_be = FT_MAKE_FRAME_OP( FT_FRAME_OP_SHORT, 0, 1 ), + ft_frame_ushort_le = FT_MAKE_FRAME_OP( FT_FRAME_OP_SHORT, 1, 0 ), + ft_frame_short_le = FT_MAKE_FRAME_OP( FT_FRAME_OP_SHORT, 1, 1 ), + + ft_frame_ulong_be = FT_MAKE_FRAME_OP( FT_FRAME_OP_LONG, 0, 0 ), + ft_frame_ulong_le = FT_MAKE_FRAME_OP( FT_FRAME_OP_LONG, 0, 1 ), + ft_frame_long_be = FT_MAKE_FRAME_OP( FT_FRAME_OP_LONG, 1, 0 ), + ft_frame_long_le = FT_MAKE_FRAME_OP( FT_FRAME_OP_LONG, 1, 1 ), + + ft_frame_uoff3_be = FT_MAKE_FRAME_OP( FT_FRAME_OP_OFF3, 0, 0 ), + ft_frame_uoff3_le = FT_MAKE_FRAME_OP( FT_FRAME_OP_OFF3, 0, 1 ), + ft_frame_off3_be = FT_MAKE_FRAME_OP( FT_FRAME_OP_OFF3, 1, 0 ), + ft_frame_off3_le = FT_MAKE_FRAME_OP( FT_FRAME_OP_OFF3, 1, 1 ), + + ft_frame_bytes = FT_MAKE_FRAME_OP( FT_FRAME_OP_BYTES, 0, 0 ), + ft_frame_skip = FT_MAKE_FRAME_OP( FT_FRAME_OP_BYTES, 0, 1 ) + + } FT_Frame_Op; + + + typedef struct FT_Frame_Field_ + { + FT_Frame_Op value; + char size; + FT_UShort offset; + + } FT_Frame_Field; + + + /* make-up a FT_Frame_Field out of a structure type and a field name */ +#define FT_FIELD_REF( s, f ) (((s*)0)->f) + +#define FT_FRAME_FIELD( frame_op, struct_type, field ) \ + { \ + frame_op, \ + sizeof ( FT_FIELD_REF( struct_type,field ) ), \ + (FT_UShort)(char*)&FT_FIELD_REF( struct_type, field ) \ + } + +#define FT_MAKE_EMPTY_FIELD( frame_op ) { frame_op, 0, 0 } + +#define FT_FRAME_START( s ) { ft_frame_start, 0, s } +#define FT_FRAME_END { ft_frame_end, 0, 0 } + +#define FT_FRAME_LONG( s, f ) FT_FRAME_FIELD( ft_frame_long_be, s, f ) +#define FT_FRAME_ULONG( s, f ) FT_FRAME_FIELD( ft_frame_ulong_be, s, f ) +#define FT_FRAME_SHORT( s, f ) FT_FRAME_FIELD( ft_frame_short_be, s, f ) +#define FT_FRAME_USHORT( s, f ) FT_FRAME_FIELD( ft_frame_ushort_be, s, f ) +#define FT_FRAME_BYTE( s, f ) FT_FRAME_FIELD( ft_frame_byte, s, f ) +#define FT_FRAME_CHAR( s, f ) FT_FRAME_FIELD( ft_frame_schar, s, f ) + +#define FT_FRAME_LONG_LE( s, f ) FT_FRAME_FIELD( ft_frame_long_le, s, f ) +#define FT_FRAME_ULONG_LE( s, f ) FT_FRAME_FIELD( ft_frame_ulong_le, s, f ) +#define FT_FRAME_SHORT_LE( s, f ) FT_FRAME_FIELD( ft_frame_short_le, s, f ) +#define FT_FRAME_USHORT_LE( s, f ) FT_FRAME_FIELD( ft_frame_ushort_le, s, f ) + +#define FT_FRAME_SKIP_LONG { ft_frame_long_be, 0, 0 } +#define FT_FRAME_SKIP_SHORT { ft_frame_short_be, 0, 0 } +#define FT_FRAME_SKIP_BYTE { ft_frame_byte, 0, 0 } + +#define FT_FRAME_BYTES( struct_type, field, count ) \ + { \ + ft_frame_bytes, \ + count, \ + (FT_UShort)(char*)&FT_FIELD_REF( struct_type, field ) \ + } +#define FT_FRAME_SKIP_BYTES( count ) { ft_frame_skip, count, 0 } + + + + /*************************************************************************/ + /* */ + /* integer extraction macros -- the `buffer' parameter must ALWAYS be of */ + /* type `char*' or equivalent (1-byte elements). */ + /* */ +#define NEXT_Char( buffer ) \ + ( (signed char)*buffer++ ) +#define NEXT_Byte( buffer ) \ + ( (unsigned char)*buffer++ ) + +#define NEXT_Short( buffer ) \ + ( buffer += 2, \ + ( (short)( (signed char)buffer[-2] << 8 ) | \ + (unsigned char)buffer[-1] ) ) + +#define NEXT_UShort( buffer ) \ + ( (unsigned short)NEXT_Short( buffer ) ) + +#define NEXT_Offset( buffer ) \ + ( buffer += 3, \ + ( ( (long)(signed char)buffer[-3] << 16 ) | \ + ( (long)(unsigned char)buffer[-2] << 8 ) | \ + (long)(unsigned char)buffer[-1] ) ) + +#define NEXT_UOffset( buffer ) \ + ( (unsigned long)NEXT_Offset( buffer ) ) + +#define NEXT_Long( buffer ) \ + ( buffer += 4, \ + ( ( (long)(signed char)buffer[-4] << 24 ) | \ + ( (long)(unsigned char)buffer[-3] << 16 ) | \ + ( (long)(unsigned char)buffer[-2] << 8 ) | \ + (long)(unsigned char)buffer[-1] ) ) + +#define NEXT_ULong( buffer ) \ + ( (unsigned long)NEXT_Long( buffer ) ) + + +#define NEXT_ShortLE( buffer ) \ + ( buffer += 2, \ + ( (short)( (signed char)buffer[-1] << 8 ) | \ + (unsigned char)buffer[-2] ) ) + +#define NEXT_UShortLE( buffer ) \ + ( (unsigned short)NEXT_ShortLE( buffer ) ) + +#define NEXT_OffsetLE( buffer ) \ + ( buffer += 3, \ + ( ( (long)(signed char)buffer[-1] << 16 ) | \ + ( (long)(unsigned char)buffer[-2] << 8 ) | \ + (long)(unsigned char)buffer[-3] ) ) + +#define NEXT_UOffsetLE( buffer ) \ + ( (unsigned long)NEXT_OffsetLE( buffer ) ) + + +#define NEXT_LongLE( buffer ) \ + ( buffer += 4, \ + ( ( (long)(signed char)buffer[-1] << 24 ) | \ + ( (long)(unsigned char)buffer[-2] << 16 ) | \ + ( (long)(unsigned char)buffer[-3] << 8 ) | \ + (long)(unsigned char)buffer[-4] ) ) + +#define NEXT_ULongLE( buffer ) \ + ( (unsigned long)NEXT_LongLE( buffer ) ) + + + /*************************************************************************/ + /* */ + /* Each GET_xxxx() macro uses an implicit `stream' variable. */ + /* */ +#define FT_GET_MACRO( func, type ) ( (type)func( stream ) ) + +#define GET_Char() FT_GET_MACRO( FT_Get_Char, FT_Char ) +#define GET_Byte() FT_GET_MACRO( FT_Get_Char, FT_Byte ) +#define GET_Short() FT_GET_MACRO( FT_Get_Short, FT_Short ) +#define GET_UShort() FT_GET_MACRO( FT_Get_Short, FT_UShort ) +#define GET_Offset() FT_GET_MACRO( FT_Get_Offset, FT_Long ) +#define GET_UOffset() FT_GET_MACRO( FT_Get_Offset, FT_ULong ) +#define GET_Long() FT_GET_MACRO( FT_Get_Long, FT_Long ) +#define GET_ULong() FT_GET_MACRO( FT_Get_Long, FT_ULong ) +#define GET_Tag4() FT_GET_MACRO( FT_Get_Long, FT_ULong ) + +#define GET_ShortLE() FT_GET_MACRO( FT_Get_ShortLE, FT_Short ) +#define GET_UShortLE() FT_GET_MACRO( FT_Get_ShortLE, FT_UShort ) +#define GET_LongLE() FT_GET_MACRO( FT_Get_LongLE, FT_Short ) +#define GET_ULongLE() FT_GET_MACRO( FT_Get_LongLE, FT_Short ) + +#define FT_READ_MACRO( func, type, var ) \ + ( var = (type)func( stream, &error ), \ + error != FT_Err_Ok ) + +#define READ_Byte( var ) FT_READ_MACRO( FT_Read_Char, FT_Byte, var ) +#define READ_Char( var ) FT_READ_MACRO( FT_Read_Char, FT_Char, var ) +#define READ_Short( var ) FT_READ_MACRO( FT_Read_Short, FT_Short, var ) +#define READ_UShort( var ) FT_READ_MACRO( FT_Read_Short, FT_UShort, var ) +#define READ_Offset( var ) FT_READ_MACRO( FT_Read_Offset, FT_Long, var ) +#define READ_UOffset( var ) FT_READ_MACRO( FT_Read_Offset, FT_ULong, var ) +#define READ_Long( var ) FT_READ_MACRO( FT_Read_Long, FT_Long, var ) +#define READ_ULong( var ) FT_READ_MACRO( FT_Read_Long, FT_ULong, var ) + +#define READ_ShortLE( var ) FT_READ_MACRO( FT_Read_ShortLE, FT_Short, var ) +#define READ_UShortLE( var ) FT_READ_MACRO( FT_Read_ShortLE, FT_UShort, var ) +#define READ_LongLE( var ) FT_READ_MACRO( FT_Read_LongLE, FT_Long, var ) +#define READ_ULongLE( var ) FT_READ_MACRO( FT_Read_LongLE, FT_ULong, var ) + + + BASE_DEF( void ) FT_New_Memory_Stream( FT_Library library, + FT_Byte* base, + FT_ULong size, + FT_Stream stream ); + + BASE_DEF( FT_Error ) FT_Seek_Stream( FT_Stream stream, + FT_ULong pos ); + + BASE_DEF( FT_Error ) FT_Skip_Stream( FT_Stream stream, + FT_Long distance ); + + BASE_DEF( FT_Long ) FT_Stream_Pos( FT_Stream stream ); + + + BASE_DEF( FT_Error ) FT_Read_Stream( FT_Stream stream, + FT_Byte* buffer, + FT_ULong count ); + + BASE_DEF( FT_Error ) FT_Read_Stream_At( FT_Stream stream, + FT_ULong pos, + FT_Byte* buffer, + FT_ULong count ); + + BASE_DEF( FT_Error ) FT_Access_Frame( FT_Stream stream, + FT_ULong count ); + + BASE_DEF( void ) FT_Forget_Frame( FT_Stream stream ); + + BASE_DEF( FT_Error ) FT_Extract_Frame( FT_Stream stream, + FT_ULong count, + FT_Byte** pbytes ); + + BASE_DEF( void ) FT_Release_Frame( FT_Stream stream, + FT_Byte** pbytes ); + + BASE_DEF( FT_Char ) FT_Get_Char( FT_Stream stream ); + + BASE_DEF( FT_Short ) FT_Get_Short( FT_Stream stream ); + + BASE_DEF( FT_Long ) FT_Get_Offset( FT_Stream stream ); + + BASE_DEF( FT_Long ) FT_Get_Long( FT_Stream stream ); + + BASE_DEF( FT_Short ) FT_Get_ShortLE( FT_Stream stream ); + + BASE_DEF( FT_Long ) FT_Get_LongLE( FT_Stream stream ); + + + BASE_DEF( FT_Char ) FT_Read_Char( FT_Stream stream, + FT_Error* error ); + + BASE_DEF( FT_Short ) FT_Read_Short( FT_Stream stream, + FT_Error* error ); + + BASE_DEF( FT_Long ) FT_Read_Offset( FT_Stream stream, + FT_Error* error ); + + BASE_DEF( FT_Long ) FT_Read_Long( FT_Stream stream, + FT_Error* error ); + + BASE_DEF( FT_Short ) FT_Read_ShortLE( FT_Stream stream, + FT_Error* error ); + + BASE_DEF( FT_Long ) FT_Read_LongLE( FT_Stream stream, + FT_Error* error ); + + BASE_DEF( FT_Error ) FT_Read_Fields( FT_Stream stream, + const FT_Frame_Field* fields, + void* structure ); + + +#define USE_Stream( resource, stream ) \ + FT_SET_ERROR( FT_Open_Stream( resource, stream ) ) + +#define DONE_Stream( stream ) \ + FT_Done_Stream( stream ) + + +#define ACCESS_Frame( size ) \ + FT_SET_ERROR( FT_Access_Frame( stream, size ) ) + +#define FORGET_Frame() \ + FT_Forget_Frame( stream ) + +#define EXTRACT_Frame( size, bytes ) \ + FT_SET_ERROR( FT_Extract_Frame( stream, size, \ + (FT_Byte**)&(bytes) ) ) + +#define RELEASE_Frame( bytes ) \ + FT_Release_Frame( stream, (FT_Byte**)&(bytes) ) + +#define FILE_Seek( position ) \ + FT_SET_ERROR( FT_Seek_Stream( stream, position ) ) + +#define FILE_Skip( distance ) \ + FT_SET_ERROR( FT_Skip_Stream( stream, distance ) ) + +#define FILE_Pos() \ + FT_Stream_Pos( stream ) + +#define FILE_Read( buffer, count ) \ + FT_SET_ERROR( FT_Read_Stream( stream, \ + (FT_Byte*)buffer, \ + count ) ) + +#define FILE_Read_At( position, buffer, count ) \ + FT_SET_ERROR( FT_Read_Stream_At( stream, \ + position, \ + (FT_Byte*)buffer, \ + count ) ) + +#define READ_Fields( fields, object ) \ + ( ( error = FT_Read_Fields( stream, fields, object ) ) != FT_Err_Ok ) + + +#ifdef __cplusplus + } +#endif + + +#endif /* FTSTREAM_H */ + + +/* END */ diff --git a/src/freetype/freetype/internal/psnames.h b/src/freetype/freetype/internal/psnames.h new file mode 100644 index 0000000000..ed862359e2 --- /dev/null +++ b/src/freetype/freetype/internal/psnames.h @@ -0,0 +1,220 @@ +/***************************************************************************/ +/* */ +/* psnames.h */ +/* */ +/* High-level interface for the `PSNames' module (in charge of */ +/* various functions related to Postscript glyph names conversion). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef PSNAMES_H +#define PSNAMES_H + + +#include + + + /*************************************************************************/ + /* */ + /* */ + /* PS_Unicode_Value_Func */ + /* */ + /* */ + /* A function used to return the Unicode index corresponding to a */ + /* given glyph name. */ + /* */ + /* */ + /* glyph_name :: The glyph name. */ + /* */ + /* */ + /* The Unicode character index resp. the non-Unicode value 0xFFFF if */ + /* the glyph name has no known Unicode meaning. */ + /* */ + /* */ + /* This function is able to map several different glyph names to the */ + /* same Unicode value, according to the rules defined in the Adobe */ + /* Glyph List table. */ + /* */ + /* This function will not be compiled if the configuration macro */ + /* FT_CONFIG_OPTION_ADOBE_GLYPH_LIST is undefined. */ + /* */ + typedef FT_ULong (*PS_Unicode_Value_Func)( const char* glyph_name ); + + + /*************************************************************************/ + /* */ + /* */ + /* PS_Unicode_Index_Func */ + /* */ + /* */ + /* A function used to return the glyph index corresponding to a given */ + /* Unicode value. */ + /* */ + /* */ + /* num_glyphs :: The number of glyphs in the face. */ + /* */ + /* glyph_names :: An array of glyph name pointers. */ + /* */ + /* unicode :: The Unicode value. */ + /* */ + /* */ + /* The glyph index resp. 0xFFFF if no glyph corresponds to this */ + /* Unicode value. */ + /* */ + /* */ + /* This function is able to recognize several glyph names per Unicode */ + /* value, according to the Adobe Glyph List. */ + /* */ + /* This function will not be compiled if the configuration macro */ + /* FT_CONFIG_OPTION_ADOBE_GLYPH_LIST is undefined. */ + /* */ + typedef FT_UInt (*PS_Unicode_Index_Func)( FT_UInt num_glyphs, + const char** glyph_names, + FT_ULong unicode ); + + + /*************************************************************************/ + /* */ + /* */ + /* PS_Macintosh_Name_Func */ + /* */ + /* */ + /* A function used to return the glyph name corresponding to an Apple */ + /* glyph name index. */ + /* */ + /* */ + /* name_index :: The index of the Mac name. */ + /* */ + /* */ + /* The glyph name, or 0 if the index is invalid. */ + /* */ + /* */ + /* This function will not be compiled if the configuration macro */ + /* FT_CONFIG_OPTION_POSTSCRIPT_NAMES is undefined. */ + /* */ + typedef const char* (*PS_Macintosh_Name_Func)( FT_UInt name_index ); + + + typedef const char* (*PS_Adobe_Std_Strings_Func)( FT_UInt string_index ); + + + typedef struct PS_UniMap_ + { + FT_UInt unicode; + FT_UInt glyph_index; + + } PS_UniMap; + + + /*************************************************************************/ + /* */ + /* */ + /* PS_Unicodes */ + /* */ + /* */ + /* A simple table used to map Unicode values to glyph indices. It is */ + /* built by the PS_Build_Unicodes table according to the glyphs */ + /* present in a font file. */ + /* */ + /* */ + /* num_codes :: The number of glyphs in the font that match a given */ + /* Unicode value. */ + /* */ + /* unicodes :: An array of unicode values, sorted in increasing */ + /* order. */ + /* */ + /* gindex :: An array of glyph indices, corresponding to each */ + /* Unicode value. */ + /* */ + /* */ + /* Use the function PS_Lookup_Unicode() to retrieve the glyph index */ + /* corresponding to a given Unicode character code. */ + /* */ + typedef struct PS_Unicodes_ + { + FT_UInt num_maps; + PS_UniMap* maps; + + } PS_Unicodes; + + + typedef FT_Error (*PS_Build_Unicodes_Func)( FT_Memory memory, + FT_UInt num_glyphs, + const char** glyph_names, + PS_Unicodes* unicodes ); + + typedef FT_UInt (*PS_Lookup_Unicode_Func)( PS_Unicodes* unicodes, + FT_UInt unicode ); + + + /*************************************************************************/ + /* */ + /* */ + /* PSNames_Interface */ + /* */ + /* */ + /* This structure defines the PSNames interface. */ + /* */ + /* */ + /* unicode_value :: A function used to convert a glyph name */ + /* into a Unicode character code. */ + /* */ + /* build_unicodes :: A function which builds up the Unicode */ + /* mapping table. */ + /* */ + /* lookup_unicode :: A function used to return the glyph index */ + /* corresponding to a given Unicode */ + /* character. */ + /* */ + /* macintosh_name :: A function used to return the standard */ + /* Apple glyph Postscript name corresponding */ + /* to a given string index (used by the */ + /* TrueType `post' table). */ + /* */ + /* adobe_std_strings :: A function that returns a pointer to a */ + /* Adobe Standard String for a given SID. */ + /* */ + /* adobe_std_encoding :: A table of 256 unsigned shorts that maps */ + /* character codes in the Adobe Standard */ + /* Encoding to SIDs. */ + /* */ + /* adobe_expert_encoding :: A table of 256 unsigned shorts that maps */ + /* character codes in the Adobe Expert */ + /* Encoding to SIDs. */ + /* */ + /* */ + /* `unicode_value' and `unicode_index' will be set to 0 if the */ + /* configuration macro FT_CONFIG_OPTION_ADOBE_GLYPH_LIST is */ + /* undefined. */ + /* */ + /* `macintosh_name' will be set to 0 if the configuration macro */ + /* FT_CONFIG_OPTION_POSTSCRIPT_NAMES is undefined. */ + /* */ + typedef struct PSNames_Interface_ + { + PS_Unicode_Value_Func unicode_value; + PS_Build_Unicodes_Func build_unicodes; + PS_Lookup_Unicode_Func lookup_unicode; + PS_Macintosh_Name_Func macintosh_name; + + PS_Adobe_Std_Strings_Func adobe_std_strings; + const unsigned short* adobe_std_encoding; + const unsigned short* adobe_expert_encoding; + + } PSNames_Interface; + + +#endif /* PSNAMES_H */ + + +/* END */ diff --git a/src/freetype/freetype/internal/sfnt.h b/src/freetype/freetype/internal/sfnt.h new file mode 100644 index 0000000000..380ee93dec --- /dev/null +++ b/src/freetype/freetype/internal/sfnt.h @@ -0,0 +1,492 @@ +/***************************************************************************/ +/* */ +/* sfnt.h */ +/* */ +/* High-level `sfnt' driver interface (specification). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef SFNT_H +#define SFNT_H + + +#include +#include +#include + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Init_Face_Func */ + /* */ + /* */ + /* First part of the SFNT face object initialization. This will find */ + /* the face in a SFNT file or collection, and load its format tag in */ + /* face->format_tag. */ + /* */ + /* */ + /* stream :: The input stream. */ + /* */ + /* face :: A handle to the target face object. */ + /* */ + /* face_index :: The index of the TrueType font, if we are opening a */ + /* collection. */ + /* */ + /* num_params :: The number of additional parameters. */ + /* */ + /* params :: Optional additional parameters. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* The stream cursor must be at the font file's origin. */ + /* */ + /* This function recognizes fonts embedded in a `TrueType */ + /* collection'. */ + /* */ + /* Once the format tag has been validated by the font driver, it */ + /* should then call the TT_Load_Face_Func() callback to read the rest */ + /* of the SFNT tables in the object. */ + /* */ + typedef + FT_Error (*TT_Init_Face_Func)( FT_Stream stream, + TT_Face face, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ); + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Load_Face_Func */ + /* */ + /* */ + /* Second part of the SFNT face object initialization. This will */ + /* load the common SFNT tables (head, OS/2, maxp, metrics, etc.) in */ + /* the face object. */ + /* */ + /* */ + /* stream :: The input stream. */ + /* */ + /* face :: A handle to the target face object. */ + /* */ + /* face_index :: The index of the TrueType font, if we are opening a */ + /* collection. */ + /* */ + /* num_params :: The number of additional parameters. */ + /* */ + /* params :: Optional additional parameters. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* This function must be called after TT_Init_Face_Func(). */ + /* */ + typedef + FT_Error (*TT_Load_Face_Func)( FT_Stream stream, + TT_Face face, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ); + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Done_Face_Func */ + /* */ + /* */ + /* A callback used to delete the common SFNT data from a face. */ + /* */ + /* */ + /* face :: A handle to the target face object. */ + /* */ + /* */ + /* This function does NOT destroy the face object. */ + /* */ + typedef + void (*TT_Done_Face_Func)( TT_Face face ); + + + typedef + FT_Module_Interface (*SFNT_Get_Interface_Func)( FT_Module module, + const char* interface ); + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Load_SFNT_Header_Func */ + /* */ + /* */ + /* Loads the header of a SFNT font file. Supports collections. */ + /* */ + /* */ + /* face :: A handle to the target face object. */ + /* */ + /* stream :: The input stream. */ + /* */ + /* face_index :: The index of the TrueType font, if we are opening a */ + /* collection. */ + /* */ + /* */ + /* sfnt :: The SFNT header. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* The stream cursor must be at the font file's origin. */ + /* */ + /* This function recognizes fonts embedded in a `TrueType */ + /* collection'. */ + /* */ + /* This function checks that the header is valid by looking at the */ + /* values of `search_range', `entry_selector', and `range_shift'. */ + /* */ + typedef + FT_Error (*TT_Load_SFNT_Header_Func)( TT_Face face, + FT_Stream stream, + FT_Long face_index, + SFNT_Header* sfnt ); + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Load_Directory_Func */ + /* */ + /* */ + /* Loads the table directory into a face object. */ + /* */ + /* */ + /* face :: A handle to the target face object. */ + /* */ + /* stream :: The input stream. */ + /* */ + /* sfnt :: The SFNT header. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* The stream cursor must be on the first byte after the 4-byte font */ + /* format tag. This is the case just after a call to */ + /* TT_Load_Format_Tag(). */ + /* */ + typedef + FT_Error (*TT_Load_Directory_Func)( TT_Face face, + FT_Stream stream, + SFNT_Header* sfnt ); + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Load_Any_Func */ + /* */ + /* */ + /* Loads any font table into client memory. */ + /* */ + /* */ + /* face :: The face object to look for. */ + /* */ + /* tag :: The tag of table to load. Use the value 0 if you want */ + /* to access the whole font file, else set this parameter */ + /* to a valid TrueType table tag that you can forge with */ + /* the MAKE_TT_TAG macro. */ + /* */ + /* offset :: The starting offset in the table (or the file if */ + /* tag == 0). */ + /* */ + /* length :: The address of the decision variable: */ + /* */ + /* If length == NULL: */ + /* Loads the whole table. Returns an error if */ + /* `offset' == 0! */ + /* */ + /* If *length == 0: */ + /* Exits immediately; returning the length of the given */ + /* table or of the font file, depending on the value of */ + /* `tag'. */ + /* */ + /* If *length != 0: */ + /* Loads the next `length' bytes of table or font, */ + /* starting at offset `offset' (in table or font too). */ + /* */ + /* */ + /* buffer :: The address of target buffer. */ + /* */ + /* */ + /* TrueType error code. 0 means success. */ + /* */ + typedef + FT_Error (*TT_Load_Any_Func)( TT_Face face, + FT_ULong tag, + FT_Long offset, + FT_Byte* buffer, + FT_ULong* length ); + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Load_SBit_Image_Func */ + /* */ + /* */ + /* Loads a given glyph sbit image from the font resource. This also */ + /* returns its metrics. */ + /* */ + /* */ + /* face :: The target face object. */ + /* */ + /* x_ppem :: The horizontal resolution in points per EM. */ + /* */ + /* y_ppem :: The vertical resolution in points per EM. */ + /* */ + /* glyph_index :: The current glyph index. */ + /* */ + /* stream :: The input stream. */ + /* */ + /* */ + /* map :: The target pixmap. */ + /* */ + /* metrics :: A big sbit metrics structure for the glyph image. */ + /* */ + /* */ + /* FreeType error code. 0 means success. Returns an error if no */ + /* glyph sbit exists for the index. */ + /* */ + /* */ + /* The `map.buffer' field is always freed before the glyph is loaded. */ + /* */ + typedef + FT_Error (*TT_Load_SBit_Image_Func)( TT_Face face, + FT_Int x_ppem, + FT_Int y_ppem, + FT_UInt glyph_index, + FT_UInt load_flags, + FT_Stream stream, + FT_Bitmap* map, + TT_SBit_Metrics* metrics ); + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Get_PS_Name_Func */ + /* */ + /* */ + /* Gets the PostScript glyph name of a glyph. */ + /* */ + /* */ + /* index :: The glyph index. */ + /* */ + /* PSname :: The address of a string pointer. Will be NULL in case */ + /* of error, otherwise it is a pointer to the glyph name. */ + /* */ + /* You must not modify the returned string! */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + typedef + FT_Error (*TT_Get_PS_Name_Func)( TT_Face face, + FT_UInt index, + FT_String** PSname ); + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Load_Metrics_Func */ + /* */ + /* */ + /* Loads the horizontal or vertical header in a face object. */ + /* */ + /* */ + /* face :: A handle to the target face object. */ + /* */ + /* stream :: The input stream. */ + /* */ + /* vertical :: A boolean flag. If set, load vertical metrics. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + typedef + FT_Error (*TT_Load_Metrics_Func)( TT_Face face, + FT_Stream stream, + FT_Bool vertical ); + + + /*************************************************************************/ + /* */ + /* */ + /* TT_CharMap_Load_Func */ + /* */ + /* */ + /* Loads a given TrueType character map into memory. */ + /* */ + /* */ + /* face :: A handle to the parent face object. */ + /* */ + /* stream :: A handle to the current stream object. */ + /* */ + /* */ + /* cmap :: A pointer to a cmap object. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* The function assumes that the stream is already in use (i.e., */ + /* opened). In case of error, all partially allocated tables are */ + /* released. */ + /* */ + typedef + FT_Error (*TT_CharMap_Load_Func)( TT_Face face, + TT_CMapTable* cmap, + FT_Stream input ); + + + /*************************************************************************/ + /* */ + /* */ + /* TT_CharMap_Free_Func */ + /* */ + /* */ + /* Destroys a character mapping table. */ + /* */ + /* */ + /* face :: A handle to the parent face object. */ + /* */ + /* cmap :: A handle to a cmap object. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + typedef + FT_Error (*TT_CharMap_Free_Func)( TT_Face face, + TT_CMapTable* cmap ); + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Load_Table_Func */ + /* */ + /* */ + /* Loads a given TrueType table. */ + /* */ + /* */ + /* face :: A handle to the target face object. */ + /* */ + /* stream :: The input stream. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* The function will use `face->goto_table' to seek the stream to */ + /* the start of the table. */ + /* */ + typedef + FT_Error (*TT_Load_Table_Func)( TT_Face face, + FT_Stream stream ); + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Free_Table_Func */ + /* */ + /* */ + /* Frees a given TrueType table. */ + /* */ + /* */ + /* face :: A handle to the target face object. */ + /* */ + typedef + void (*TT_Free_Table_Func)( TT_Face face ); + + + /*************************************************************************/ + /* */ + /* */ + /* SFNT_Interface */ + /* */ + /* */ + /* This structure holds pointers to the functions used to load and */ + /* free the basic tables that are required in a `sfnt' font file. */ + /* */ + /* */ + /* Check the various xxx_Func() descriptions for details. */ + /* */ + typedef struct SFNT_Interface_ + { + TT_Goto_Table_Func goto_table; + + TT_Init_Face_Func init_face; + TT_Load_Face_Func load_face; + TT_Done_Face_Func done_face; + SFNT_Get_Interface_Func get_interface; + + TT_Load_Any_Func load_any; + TT_Load_SFNT_Header_Func load_sfnt_header; + TT_Load_Directory_Func load_directory; + + /* these functions are called by `load_face' but they can also */ + /* be called from external modules, if there is a need to do so */ + TT_Load_Table_Func load_header; + TT_Load_Metrics_Func load_metrics; + TT_Load_Table_Func load_charmaps; + TT_Load_Table_Func load_max_profile; + TT_Load_Table_Func load_os2; + TT_Load_Table_Func load_psnames; + + TT_Load_Table_Func load_names; + TT_Free_Table_Func free_names; + + /* optional tables */ + TT_Load_Table_Func load_hdmx; + TT_Free_Table_Func free_hdmx; + + TT_Load_Table_Func load_kerning; + TT_Load_Table_Func load_gasp; + TT_Load_Table_Func load_pclt; + + /* see `ttsbit.h' */ + TT_Load_Table_Func load_sbits; + TT_Load_SBit_Image_Func load_sbit_image; + TT_Free_Table_Func free_sbits; + + /* see `ttpost.h' */ + TT_Get_PS_Name_Func get_psname; + TT_Free_Table_Func free_psnames; + + /* see `ttcmap.h' */ + TT_CharMap_Load_Func load_charmap; + TT_CharMap_Free_Func free_charmap; + + } SFNT_Interface; + + +#endif /* SFNT_H */ + + +/* END */ diff --git a/src/freetype/freetype/internal/t1errors.h b/src/freetype/freetype/internal/t1errors.h new file mode 100644 index 0000000000..58566d8ee5 --- /dev/null +++ b/src/freetype/freetype/internal/t1errors.h @@ -0,0 +1,67 @@ +/***************************************************************************/ +/* */ +/* t1errors.h */ +/* */ +/* Type 1 error ID definitions (specification only). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef T1ERRORS_H +#define T1ERRORS_H + + + /************************ error codes declaration **************/ + + /* The error codes are grouped into `classes' used to indicate the */ + /* `level' at which the error happened. */ + /* */ + /* The class is given by an error code's high byte. */ + + + /* ------------- Success is always 0 -------- */ + +#define T1_Err_Ok FT_Err_Ok + + /* ----------- high level API errors -------- */ + +#define T1_Err_Invalid_File_Format FT_Err_Invalid_File_Format +#define T1_Err_Invalid_Argument FT_Err_Invalid_Argument +#define T1_Err_Invalid_Driver_Handle FT_Err_Invalid_Driver_Handle +#define T1_Err_Invalid_Face_Handle FT_Err_Invalid_Face_Handle +#define T1_Err_Invalid_Size_Handle FT_Err_Invalid_Size_Handle +#define T1_Err_Invalid_Glyph_Handle FT_Err_Invalid_Slot_Handle +#define T1_Err_Invalid_CharMap_Handle FT_Err_Invalid_CharMap_Handle +#define T1_Err_Invalid_Glyph_Index FT_Err_Invalid_Glyph_Index + +#define T1_Err_Unimplemented_Feature FT_Err_Unimplemented_Feature + +#define T1_Err_Invalid_Engine FT_Err_Invalid_Driver_Handle + + /* ------------- internal errors ------------ */ + +#define T1_Err_Out_Of_Memory FT_Err_Out_Of_Memory +#define T1_Err_Unlisted_Object FT_Err_Unlisted_Object + + /* ------------ general glyph outline errors ------ */ + +#define T1_Err_Invalid_Composite FT_Err_Invalid_Composite + +#define T1_Err_Syntax_Error FT_Err_Invalid_File_Format +#define T1_Err_Stack_Underflow FT_Err_Invalid_File_Format +#define T1_Err_Stack_Overflow FT_Err_Invalid_File_Format + + +#endif /* T1ERRORS_H */ + + +/* END */ diff --git a/src/freetype/freetype/internal/t1types.h b/src/freetype/freetype/internal/t1types.h new file mode 100644 index 0000000000..4d41a6b591 --- /dev/null +++ b/src/freetype/freetype/internal/t1types.h @@ -0,0 +1,188 @@ +/***************************************************************************/ +/* */ +/* t1types.h */ +/* */ +/* Basic Type1/Type2 type definitions and interface (specification */ +/* only). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef T1TYPES_H +#define T1TYPES_H + + +#include +#include + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*** ***/ + /*** ***/ + /*** REQUIRED TYPE1/TYPE2 TABLES DEFINITIONS ***/ + /*** ***/ + /*** ***/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* */ + /* T1_Encoding */ + /* */ + /* */ + /* A structure modeling a custom encoding */ + /* */ + /* */ + /* num_chars :: The number of character codes in the encoding. */ + /* Usually 256. */ + /* */ + /* code_first :: The lowest valid character code in the encoding. */ + /* */ + /* code_last :: The highest valid character code in the encoding. */ + /* */ + /* char_index :: An array of corresponding glyph indices. */ + /* */ + /* char_name :: An array of corresponding glyph names. */ + /* */ + typedef struct T1_Encoding_ + { + FT_Int num_chars; + FT_Int code_first; + FT_Int code_last; + + FT_UShort* char_index; + FT_String** char_name; + + } T1_Encoding; + + + typedef enum T1_EncodingType_ + { + t1_encoding_none = 0, + t1_encoding_array, + t1_encoding_standard, + t1_encoding_expert + + } T1_EncodingType; + + + typedef struct T1_Font_ + { + + /* font info dictionary */ + T1_FontInfo font_info; + + /* private dictionary */ + T1_Private private_dict; + + /* top-level dictionary */ + FT_String* font_name; + + T1_EncodingType encoding_type; + T1_Encoding encoding; + + FT_Byte* subrs_block; + FT_Byte* charstrings_block; + FT_Byte* glyph_names_block; + + FT_Int num_subrs; + FT_Byte** subrs; + FT_Int* subrs_len; + + FT_Int num_glyphs; + FT_String** glyph_names; /* array of glyph names */ + FT_Byte** charstrings; /* array of glyph charstrings */ + FT_Int* charstrings_len; + + FT_Byte paint_type; + FT_Byte font_type; + FT_Matrix font_matrix; + FT_BBox font_bbox; + FT_Long font_id; + + FT_Int stroke_width; + + } T1_Font; + + + typedef struct CID_Subrs_ + { + FT_UInt num_subrs; + FT_Byte** code; + + } CID_Subrs; + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*** ***/ + /*** ***/ + /*** ORIGINAL T1_FACE CLASS DEFINITION ***/ + /*** ***/ + /*** ***/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* This structure/class is defined here because it is common to the */ + /* following formats: TTF, OpenType-TT, and OpenType-CFF. */ + /* */ + /* Note, however, that the classes TT_Size, TT_GlyphSlot, and TT_CharMap */ + /* are not shared between font drivers, and are thus defined normally in */ + /* `ttobjs.h'. */ + /* */ + /*************************************************************************/ + + typedef struct T1_FaceRec_* T1_Face; + typedef struct CID_FaceRec_* CID_Face; + + + typedef struct T1_FaceRec_ + { + FT_FaceRec root; + T1_Font type1; + void* psnames; + void* afm_data; + FT_CharMapRec charmaprecs[2]; + FT_CharMap charmaps[2]; + PS_Unicodes unicode_map; + + /* support for Multiple Masters fonts */ + T1_Blend* blend; + + } T1_FaceRec; + + + typedef struct CID_FaceRec_ + { + FT_FaceRec root; + void* psnames; + CID_Info cid; + void* afm_data; + CID_Subrs* subrs; + + } CID_FaceRec; + + +#endif /* T1TYPES_H */ + + +/* END */ diff --git a/src/freetype/freetype/internal/t2errors.h b/src/freetype/freetype/internal/t2errors.h new file mode 100644 index 0000000000..d685220013 --- /dev/null +++ b/src/freetype/freetype/internal/t2errors.h @@ -0,0 +1,121 @@ +/***************************************************************************/ +/* */ +/* t2errors.h */ +/* */ +/* OpenType error ID definitions (specification only). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef T2ERRORS_H +#define T2ERRORS_H + + + /*************************************************************************/ + /* */ + /* Error codes declaration */ + /* */ + /* The error codes are grouped in `classes' used to indicate the `level' */ + /* at which the error happened. The class is given by an error code's */ + /* high byte. */ + /* */ + /*************************************************************************/ + + + /* Success is always 0. */ + +#define T2_Err_Ok FT_Err_Ok + + /* High level API errors. */ + +#define T2_Err_Invalid_File_Format FT_Err_Invalid_File_Format +#define T2_Err_Invalid_Argument FT_Err_Invalid_Argument +#define T2_Err_Invalid_Driver_Handle FT_Err_Invalid_Driver_Handle +#define T2_Err_Invalid_Face_Handle FT_Err_Invalid_Face_Handle +#define T2_Err_Invalid_Instance_Handle FT_Err_Invalid_Size_Handle +#define T2_Err_Invalid_Glyph_Handle FT_Err_Invalid_Slot_Handle +#define T2_Err_Invalid_CharMap_Handle FT_Err_Invalid_CharMap_Handle +#define T2_Err_Invalid_Glyph_Index FT_Err_Invalid_Glyph_Index + +#define T2_Err_Unimplemented_Feature FT_Err_Unimplemented_Feature + +#define T2_Err_Invalid_Engine FT_Err_Invalid_Driver_Handle + + /* Internal errors. */ + +#define T2_Err_Out_Of_Memory FT_Err_Out_Of_Memory +#define T2_Err_Unlisted_Object FT_Err_Unlisted_Object + + /* General glyph outline errors. */ + +#define T2_Err_Invalid_Composite FT_Err_Invalid_Composite + + /* Bytecode interpreter error codes. */ + + /* These error codes are produced by the TrueType */ + /* bytecode interpreter. They usually indicate a */ + /* broken font file, a broken glyph within a font */ + /* file, or a bug in the interpreter! */ + +#define T2_Err_Invalid_Opcode 0x500 +#define T2_Err_Too_Few_Arguments 0x501 +#define T2_Err_Stack_Overflow 0x502 +#define T2_Err_Code_Overflow 0x503 +#define T2_Err_Bad_Argument 0x504 +#define T2_Err_Divide_By_Zero 0x505 +#define T2_Err_Storage_Overflow 0x506 +#define T2_Err_Cvt_Overflow 0x507 +#define T2_Err_Invalid_Reference 0x508 +#define T2_Err_Invalid_Distance 0x509 +#define T2_Err_Interpolate_Twilight 0x50A +#define T2_Err_Debug_OpCode 0x50B +#define T2_Err_ENDF_In_Exec_Stream 0x50C +#define T2_Err_Out_Of_CodeRanges 0x50D +#define T2_Err_Nested_DEFS 0x50E +#define T2_Err_Invalid_CodeRange 0x50F +#define T2_Err_Invalid_Displacement 0x510 +#define T2_Err_Execution_Too_Long 0x511 + +#define T2_Err_Too_Many_Instruction_Defs 0x512 +#define T2_Err_Too_Many_Function_Defs 0x513 + + /* Other TrueType specific error codes. */ + +#define T2_Err_Table_Missing 0x520 +#define T2_Err_Too_Many_Extensions 0x521 +#define T2_Err_Extensions_Unsupported 0x522 +#define T2_Err_Invalid_Extension_Id 0x523 + +#define T2_Err_No_Vertical_Data 0x524 + +#define T2_Err_Max_Profile_Missing 0x530 +#define T2_Err_Header_Table_Missing 0x531 +#define T2_Err_Horiz_Header_Missing 0x532 +#define T2_Err_Locations_Missing 0x533 +#define T2_Err_Name_Table_Missing 0x534 +#define T2_Err_CMap_Table_Missing 0x535 +#define T2_Err_Hmtx_Table_Missing 0x536 +#define T2_Err_OS2_Table_Missing 0x537 +#define T2_Err_Post_Table_Missing 0x538 + +#define T2_Err_Invalid_Horiz_Metrics 0x540 +#define T2_Err_Invalid_CharMap_Format 0x541 +#define T2_Err_Invalid_PPem 0x542 +#define T2_Err_Invalid_Vert_Metrics 0x543 + +#define T2_Err_Could_Not_Find_Context 0x550 + + +#endif /* T2ERRORS_H */ + + +/* END */ diff --git a/src/freetype/freetype/internal/t2types.h b/src/freetype/freetype/internal/t2types.h new file mode 100644 index 0000000000..033f315e95 --- /dev/null +++ b/src/freetype/freetype/internal/t2types.h @@ -0,0 +1,218 @@ +/***************************************************************************/ +/* */ +/* t2types.h */ +/* */ +/* Basic OpenType/CFF type definitions and interface (specification */ +/* only). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef T2TYPES_H +#define T2TYPES_H + + +#include + + + /*************************************************************************/ + /* */ + /* */ + /* CFF_Index */ + /* */ + /* */ + /* A structure used to model a CFF Index table. */ + /* */ + /* */ + /* stream :: XXX */ + /* */ + /* count :: The number of elements in the index. */ + /* */ + /* off_size :: The size in bytes of object offsets in index. */ + /* */ + /* data_offset :: The position of first data byte in the index's */ + /* bytes. */ + /* */ + /* offsets :: XXX */ + /* */ + /* bytes :: If the index is loaded in memory, its bytes. */ + /* */ + typedef struct CFF_Index_ + { + FT_Stream stream; + FT_UInt count; + FT_Byte off_size; + FT_ULong data_offset; + + FT_ULong* offsets; + FT_Byte* bytes; + + } CFF_Index; + + + typedef struct CFF_Font_Dict_ + { + FT_UInt version; + FT_UInt notice; + FT_UInt copyright; + FT_UInt full_name; + FT_UInt family_name; + FT_UInt weight; + FT_Bool is_fixed_pitch; + FT_Fixed italic_angle; + FT_Pos underline_position; + FT_Pos underline_thickness; + FT_Int paint_type; + FT_Int charstring_type; + FT_Matrix font_matrix; + FT_ULong unique_id; + FT_BBox font_bbox; + FT_Pos stroke_width; + FT_ULong charset_offset; + FT_ULong encoding_offset; + FT_ULong charstrings_offset; + FT_ULong private_offset; + FT_ULong private_size; + FT_Long synthetic_base; + FT_UInt embedded_postscript; + FT_UInt base_font_name; + FT_UInt postscript; + + /* these should only be used for the top-level font dictionary */ + FT_UInt cid_registry; + FT_UInt cid_ordering; + FT_ULong cid_supplement; + + FT_Long cid_font_version; + FT_Long cid_font_revision; + FT_Long cid_font_type; + FT_Long cid_count; + FT_ULong cid_uid_base; + FT_ULong cid_fd_array_offset; + FT_ULong cid_fd_select_offset; + FT_UInt cid_font_name; + + } CFF_Font_Dict; + + + typedef struct CFF_Private_ + { + FT_Byte num_blue_values; + FT_Byte num_other_blues; + FT_Byte num_family_blues; + FT_Byte num_family_other_blues; + + FT_Pos blue_values[14]; + FT_Pos other_blues[10]; + FT_Pos family_blues[14]; + FT_Pos family_other_blues[10]; + + FT_Fixed blue_scale; + FT_Pos blue_shift; + FT_Pos blue_fuzz; + FT_Pos standard_width; + FT_Pos standard_height; + + FT_Byte num_snap_widths; + FT_Byte num_snap_heights; + FT_Pos snap_widths[13]; + FT_Pos snap_heights[13]; + FT_Bool force_bold; + FT_Fixed force_bold_threshold; + FT_Int lenIV; + FT_Int language_group; + FT_Fixed expansion_factor; + FT_Long initial_random_seed; + FT_ULong local_subrs_offset; + FT_Pos default_width; + FT_Pos nominal_width; + + } CFF_Private; + + + typedef struct CFF_FD_Select_ + { + FT_Byte format; + FT_UInt range_count; + + /* that's the table, taken from the file `as is' */ + FT_Byte* data; + FT_UInt data_size; + + /* small cache for format 3 only */ + FT_UInt cache_first; + FT_UInt cache_count; + FT_Byte cache_fd; + + } CFF_FD_Select; + + + /* A SubFont packs a font dict and a private dict together. They are */ + /* needed to support CID-keyed CFF fonts. */ + typedef struct CFF_SubFont_ + { + CFF_Font_Dict font_dict; + CFF_Private private_dict; + + CFF_Index local_subrs_index; + FT_UInt num_local_subrs; + FT_Byte** local_subrs; + + } CFF_SubFont; + + + /* maximum number of sub-fonts in a CID-keyed file */ +#define CFF_MAX_CID_FONTS 16 + + + typedef struct CFF_Font_ + { + FT_Stream stream; + FT_Memory memory; + FT_UInt num_faces; + FT_UInt num_glyphs; + + FT_Byte version_major; + FT_Byte version_minor; + FT_Byte header_size; + FT_Byte absolute_offsize; + + + CFF_Index name_index; + CFF_Index top_dict_index; + CFF_Index string_index; + CFF_Index global_subrs_index; + + /* we don't load the Encoding and CharSet tables */ + + CFF_Index charstrings_index; + CFF_Index font_dict_index; + CFF_Index private_index; + CFF_Index local_subrs_index; + + FT_String* font_name; + FT_UInt num_global_subrs; + FT_Byte** global_subrs; + + CFF_SubFont top_font; + FT_UInt num_subfonts; + CFF_SubFont* subfonts[CFF_MAX_CID_FONTS]; + + CFF_FD_Select fd_select; + + } CFF_Font; + + +#endif /* T2TYPES_H */ + + +/* END */ diff --git a/src/freetype/freetype/internal/tterrors.h b/src/freetype/freetype/internal/tterrors.h new file mode 100644 index 0000000000..b53e9f3da4 --- /dev/null +++ b/src/freetype/freetype/internal/tterrors.h @@ -0,0 +1,121 @@ +/***************************************************************************/ +/* */ +/* tterrors.h */ +/* */ +/* TrueType error ID definitions (specification only). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef TTERRORS_H +#define TTERRORS_H + + + /*************************************************************************/ + /* */ + /* Error codes declaration */ + /* */ + /* The error codes are grouped in `classes' used to indicate the `level' */ + /* at which the error happened. The class is given by an error code's */ + /* high byte. */ + /* */ + /*************************************************************************/ + + + /* Success is always 0. */ + +#define TT_Err_Ok FT_Err_Ok + + /* High level API errors. */ + +#define TT_Err_Invalid_File_Format FT_Err_Invalid_File_Format +#define TT_Err_Invalid_Argument FT_Err_Invalid_Argument +#define TT_Err_Invalid_Driver_Handle FT_Err_Invalid_Driver_Handle +#define TT_Err_Invalid_Face_Handle FT_Err_Invalid_Face_Handle +#define TT_Err_Invalid_Instance_Handle FT_Err_Invalid_Size_Handle +#define TT_Err_Invalid_Glyph_Handle FT_Err_Invalid_Slot_Handle +#define TT_Err_Invalid_CharMap_Handle FT_Err_Invalid_CharMap_Handle +#define TT_Err_Invalid_Glyph_Index FT_Err_Invalid_Glyph_Index + +#define TT_Err_Unimplemented_Feature FT_Err_Unimplemented_Feature + +#define TT_Err_Invalid_Engine FT_Err_Invalid_Driver_Handle + + /* Internal errors. */ + +#define TT_Err_Out_Of_Memory FT_Err_Out_Of_Memory +#define TT_Err_Unlisted_Object FT_Err_Unlisted_Object + + /* General glyph outline errors. */ + +#define TT_Err_Too_Many_Ins FT_Err_Too_Many_Hints +#define TT_Err_Invalid_Composite FT_Err_Invalid_Composite + + /* Bytecode interpreter error codes. */ + + /* These error codes are produced by the TrueType */ + /* bytecode interpreter. They usually indicate a */ + /* broken font file, a broken glyph within a font */ + /* file, or a bug in the interpreter! */ + +#define TT_Err_Invalid_Opcode 0x400 +#define TT_Err_Too_Few_Arguments 0x401 +#define TT_Err_Stack_Overflow 0x402 +#define TT_Err_Code_Overflow 0x403 +#define TT_Err_Bad_Argument 0x404 +#define TT_Err_Divide_By_Zero 0x405 +#define TT_Err_Storage_Overflow 0x406 +#define TT_Err_Cvt_Overflow 0x407 +#define TT_Err_Invalid_Reference 0x408 +#define TT_Err_Invalid_Distance 0x409 +#define TT_Err_Interpolate_Twilight 0x40A +#define TT_Err_Debug_OpCode 0x40B +#define TT_Err_ENDF_In_Exec_Stream 0x40C +#define TT_Err_Out_Of_CodeRanges 0x40D +#define TT_Err_Nested_DEFS 0x40E +#define TT_Err_Invalid_CodeRange 0x40F +#define TT_Err_Invalid_Displacement 0x410 +#define TT_Err_Execution_Too_Long 0x411 +#define TT_Err_Too_Many_Function_Defs 0x412 +#define TT_Err_Too_Many_Instruction_Defs 0x413 + + /* Other TrueType specific error codes. */ + +#define TT_Err_Table_Missing 0x420 +#define TT_Err_Too_Many_Extensions 0x421 +#define TT_Err_Extensions_Unsupported 0x422 +#define TT_Err_Invalid_Extension_Id 0x423 + +#define TT_Err_No_Vertical_Data 0x424 + +#define TT_Err_Max_Profile_Missing 0x430 +#define TT_Err_Header_Table_Missing 0x431 +#define TT_Err_Horiz_Header_Missing 0x432 +#define TT_Err_Locations_Missing 0x433 +#define TT_Err_Name_Table_Missing 0x434 +#define TT_Err_CMap_Table_Missing 0x435 +#define TT_Err_Hmtx_Table_Missing 0x436 +#define TT_Err_OS2_Table_Missing 0x437 +#define TT_Err_Post_Table_Missing 0x438 + +#define TT_Err_Invalid_Horiz_Metrics 0x440 +#define TT_Err_Invalid_CharMap_Format 0x441 +#define TT_Err_Invalid_PPem 0x442 +#define TT_Err_Invalid_Vert_Metrics 0x443 + +#define TT_Err_Could_Not_Find_Context 0x450 + + +#endif /* TTERRORS_H */ + + +/* END */ diff --git a/src/freetype/freetype/internal/tttypes.h b/src/freetype/freetype/internal/tttypes.h new file mode 100644 index 0000000000..1fd43ceb50 --- /dev/null +++ b/src/freetype/freetype/internal/tttypes.h @@ -0,0 +1,1582 @@ +/***************************************************************************/ +/* */ +/* tttypes.h */ +/* */ +/* Basic SFNT/TrueType type definitions and interface (specification */ +/* only). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef TTTYPES_H +#define TTTYPES_H + + +#include + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*** ***/ + /*** ***/ + /*** REQUIRED TRUETYPE/OPENTYPE TABLES DEFINITIONS ***/ + /*** ***/ + /*** ***/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* */ + /* TTC_Header */ + /* */ + /* */ + /* TrueType collection header. This table contains the offsets of */ + /* the font headers of each distinct TrueType face in the file. */ + /* */ + /* */ + /* tag :: Must be `ttc ' to indicate a TrueType collection. */ + /* */ + /* version :: The version number. */ + /* */ + /* count :: The number of faces in the collection. The */ + /* specification says this should be an unsigned long, but */ + /* we use a signed long since we need the value -1 for */ + /* specific purposes. */ + /* */ + /* offsets :: The offsets of the font headers, one per face. */ + /* */ + typedef struct TTC_Header_ + { + FT_ULong tag; + FT_Fixed version; + FT_Long count; + FT_ULong* offsets; + + } TTC_Header; + + + /*************************************************************************/ + /* */ + /* */ + /* SFNT_Header */ + /* */ + /* */ + /* SFNT file format header. */ + /* */ + /* */ + /* format_tag :: The font format tag. */ + /* */ + /* num_tables :: The number of tables in file. */ + /* */ + /* search_range :: Must be 16*(max power of 2 <= num_tables). */ + /* */ + /* entry_selector :: Must be log2 of search_range/16. */ + /* */ + /* range_shift :: Must be num_tables*16 - search_range. */ + /* */ + typedef struct SFNT_Header_ + { + FT_ULong format_tag; + FT_UShort num_tables; + FT_UShort search_range; + FT_UShort entry_selector; + FT_UShort range_shift; + + } SFNT_Header; + + + /*************************************************************************/ + /* */ + /* */ + /* TT_TableDir */ + /* */ + /* */ + /* This structure models a TrueType table directory. It is used to */ + /* access the various tables of the font face. */ + /* */ + /* */ + /* version :: The version number; starts with 0x00010000. */ + /* */ + /* numTables :: The number of tables. */ + /* */ + /* searchRange :: Unused. */ + /* */ + /* entrySelector :: Unused. */ + /* */ + /* rangeShift :: Unused. */ + /* */ + /* */ + /* This structure is only used during font opening. */ + /* */ + typedef struct TT_TableDir_ + { + FT_Fixed version; /* should be 0x10000 */ + FT_UShort numTables; /* number of tables */ + + FT_UShort searchRange; /* These parameters are only used */ + FT_UShort entrySelector; /* for a dichotomy search in the */ + FT_UShort rangeShift; /* directory. We ignore them. */ + + } TT_TableDir; + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Table */ + /* */ + /* */ + /* This structure describes a given table of a TrueType font. */ + /* */ + /* */ + /* Tag :: A four-bytes tag describing the table. */ + /* */ + /* CheckSum :: The table checksum. This value can be ignored. */ + /* */ + /* Offset :: The offset of the table from the start of the TrueType */ + /* font in its resource. */ + /* */ + /* Length :: The table length (in bytes). */ + /* */ + typedef struct TT_Table_ + { + FT_ULong Tag; /* table type */ + FT_ULong CheckSum; /* table checksum */ + FT_ULong Offset; /* table file offset */ + FT_ULong Length; /* table length */ + + } TT_Table; + + + /*************************************************************************/ + /* */ + /* */ + /* TT_CMapDir */ + /* */ + /* */ + /* This structure describes the directory of the `cmap' table, */ + /* containing the font's character mappings table. */ + /* */ + /* */ + /* tableVersionNumber :: The version number. */ + /* */ + /* numCMaps :: The number of charmaps in the font. */ + /* */ + /* */ + /* This structure is only used during font loading. */ + /* */ + typedef struct TT_CMapDir_ + { + FT_UShort tableVersionNumber; + FT_UShort numCMaps; + + } TT_CMapDir; + + + /*************************************************************************/ + /* */ + /* */ + /* TT_CMapDirEntry */ + /* */ + /* */ + /* This structure describes a charmap in a TrueType font. */ + /* */ + /* */ + /* platformID :: An ID used to specify for which platform this */ + /* charmap is defined (FreeType manages all platforms). */ + /* */ + /* encodingID :: A platform-specific ID used to indicate which source */ + /* encoding is used in this charmap. */ + /* */ + /* offset :: The offset of the charmap relative to the start of */ + /* the `cmap' table. */ + /* */ + /* */ + /* This structure is only used during font loading. */ + /* */ + typedef struct TT_CMapDirEntry_ + { + FT_UShort platformID; + FT_UShort platformEncodingID; + FT_Long offset; + + } TT_CMapDirEntry; + + + /*************************************************************************/ + /* */ + /* */ + /* TT_LongMetrics */ + /* */ + /* */ + /* A structure modeling the long metrics of the `hmtx' and `vmtx' */ + /* TrueType tables. The values are expressed in font units. */ + /* */ + /* */ + /* advance :: The advance width or height for the glyph. */ + /* */ + /* bearing :: The left-side or top-side bearing for the glyph. */ + /* */ + typedef struct TT_LongMetrics_ + { + FT_UShort advance; + FT_Short bearing; + + } TT_LongMetrics; + + + /*************************************************************************/ + /* */ + /* TT_ShortMetrics */ + /* */ + /* */ + /* A simple type to model the short metrics of the `hmtx' and `vmtx' */ + /* tables. */ + /* */ + typedef FT_Short TT_ShortMetrics; + + + /*************************************************************************/ + /* */ + /* */ + /* TT_NameRec */ + /* */ + /* */ + /* A structure modeling TrueType name records. Name records are used */ + /* to store important strings like family name, style name, */ + /* copyright, etc. in _localized_ versions (i.e., language, encoding, */ + /* etc). */ + /* */ + /* */ + /* platformID :: The ID of the name's encoding platform. */ + /* */ + /* encodingID :: The platform-specific ID for the name's encoding. */ + /* */ + /* languageID :: The platform-specific ID for the name's language. */ + /* */ + /* nameID :: The ID specifying what kind of name this is. */ + /* */ + /* stringLength :: The length of the string in bytes. */ + /* */ + /* stringOffset :: The offset to the string in the `name' table. */ + /* */ + /* string :: A pointer to the string's bytes. Note that these */ + /* are usually UTF-16 encoded characters. */ + /* */ + typedef struct TT_NameRec_ + { + FT_UShort platformID; + FT_UShort encodingID; + FT_UShort languageID; + FT_UShort nameID; + FT_UShort stringLength; + FT_UShort stringOffset; + + /* this last field is not defined in the spec */ + /* but used by the FreeType engine */ + + FT_Byte* string; + + } TT_NameRec; + + + /*************************************************************************/ + /* */ + /* */ + /* TT_NameTable */ + /* */ + /* */ + /* A structure modeling the TrueType name table. */ + /* */ + /* */ + /* format :: The format of the name table. */ + /* */ + /* numNameRecords :: The number of names in table. */ + /* */ + /* storageOffset :: The offset of the name table in the `name' */ + /* TrueType table. */ + /* */ + /* names :: An array of name records. */ + /* */ + /* storage :: The names storage area. */ + /* */ + typedef struct TT_NameTable_ + { + FT_UShort format; + FT_UShort numNameRecords; + FT_UShort storageOffset; + TT_NameRec* names; + FT_Byte* storage; + + } TT_NameTable; + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*** ***/ + /*** ***/ + /*** OPTIONAL TRUETYPE/OPENTYPE TABLES DEFINITIONS ***/ + /*** ***/ + /*** ***/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* */ + /* TT_GaspRange */ + /* */ + /* */ + /* A tiny structure used to model a gasp range according to the */ + /* TrueType specification. */ + /* */ + /* */ + /* maxPPEM :: The maximum ppem value to which `gaspFlag' applies. */ + /* */ + /* gaspFlag :: A flag describing the grid-fitting and anti-aliasing */ + /* modes to be used. */ + /* */ + typedef struct TT_GaspRange_ + { + FT_UShort maxPPEM; + FT_UShort gaspFlag; + + } TT_GaspRange; + + +#define TT_GASP_GRIDFIT 0x01 +#define TT_GASP_DOGRAY 0x02 + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Gasp */ + /* */ + /* */ + /* A structure modeling the TrueType `gasp' table used to specify */ + /* grid-fitting and anti-aliasing behaviour. */ + /* */ + /* */ + /* version :: The version number. */ + /* */ + /* numRanges :: The number of gasp ranges in table. */ + /* */ + /* gaspRanges :: An array of gasp ranges. */ + /* */ + typedef struct TT_Gasp_ + { + FT_UShort version; + FT_UShort numRanges; + TT_GaspRange* gaspRanges; + + } TT_Gasp; + + + /*************************************************************************/ + /* */ + /* */ + /* TT_HdmxRec */ + /* */ + /* */ + /* A small structure used to model the pre-computed widths of a given */ + /* size. They are found in the `hdmx' table. */ + /* */ + /* */ + /* ppem :: The pixels per EM value at which these metrics apply. */ + /* */ + /* max_width :: The maximum advance width for this metric. */ + /* */ + /* widths :: An array of widths. Note: These are 8-bit bytes. */ + /* */ + typedef struct TT_HdmxRec_ + { + FT_Byte ppem; + FT_Byte max_width; + FT_Byte* widths; + + } TT_HdmxRec; + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Hdmx */ + /* */ + /* */ + /* A structure used to model the `hdmx' table, which contains */ + /* pre-computed widths for a set of given sizes/dimensions. */ + /* */ + /* */ + /* version :: The version number. */ + /* */ + /* num_records :: The number of hdmx records. */ + /* */ + /* records :: An array of hdmx records. */ + /* */ + typedef struct TT_Hdmx_ + { + FT_UShort version; + FT_Short num_records; + TT_HdmxRec* records; + + } TT_Hdmx; + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Kern_0_Pair */ + /* */ + /* */ + /* A structure used to model a kerning pair for the kerning table */ + /* format 0. The engine now loads this table if it finds one in the */ + /* font file. */ + /* */ + /* */ + /* left :: The index of the left glyph in pair. */ + /* */ + /* right :: The index of the right glyph in pair. */ + /* */ + /* value :: The kerning distance. A positive value spaces the */ + /* glyphs, a negative one makes them closer. */ + /* */ + typedef struct TT_Kern_0_Pair_ + { + FT_UShort left; /* index of left glyph in pair */ + FT_UShort right; /* index of right glyph in pair */ + FT_FWord value; /* kerning value */ + + } TT_Kern_0_Pair; + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*** ***/ + /*** ***/ + /*** EMBEDDED BITMAPS SUPPORT ***/ + /*** ***/ + /*** ***/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* */ + /* TT_SBit_Metrics */ + /* */ + /* */ + /* A structure used to hold the big metrics of a given glyph bitmap */ + /* in a TrueType or OpenType font. These are usually found in the */ + /* `EBDT' (Microsoft) or `bdat' (Apple) table. */ + /* */ + /* */ + /* height :: The glyph height in pixels. */ + /* */ + /* width :: The glyph width in pixels. */ + /* */ + /* horiBearingX :: The horizontal left bearing. */ + /* */ + /* horiBearingY :: The horizontal top bearing. */ + /* */ + /* horiAdvance :: The horizontal advance. */ + /* */ + /* vertBearingX :: The vertical left bearing. */ + /* */ + /* vertBearingY :: The vertical top bearing. */ + /* */ + /* vertAdvance :: The vertical advance. */ + /* */ + typedef struct TT_SBit_Metrics_ + { + FT_Byte height; + FT_Byte width; + + FT_Char horiBearingX; + FT_Char horiBearingY; + FT_Byte horiAdvance; + + FT_Char vertBearingX; + FT_Char vertBearingY; + FT_Byte vertAdvance; + + } TT_SBit_Metrics; + + + /*************************************************************************/ + /* */ + /* */ + /* TT_SBit_Small_Metrics */ + /* */ + /* */ + /* A structure used to hold the small metrics of a given glyph bitmap */ + /* in a TrueType or OpenType font. These are usually found in the */ + /* `EBDT' (Microsoft) or the `bdat' (Apple) table. */ + /* */ + /* */ + /* height :: The glyph height in pixels. */ + /* */ + /* width :: The glyph width in pixels. */ + /* */ + /* bearingX :: The left-side bearing. */ + /* */ + /* bearingY :: The top-side bearing. */ + /* */ + /* advance :: The advance width or height. */ + /* */ + typedef struct TT_SBit_Small_Metrics_ + { + FT_Byte height; + FT_Byte width; + + FT_Char bearingX; + FT_Char bearingY; + FT_Byte advance; + + } TT_SBit_Small_Metrics; + + + /*************************************************************************/ + /* */ + /* */ + /* TT_SBit_Line_Metrics */ + /* */ + /* */ + /* A structure used to describe the text line metrics of a given */ + /* bitmap strike, for either a horizontal or vertical layout. */ + /* */ + /* */ + /* ascender :: The ascender in pixels. */ + /* */ + /* descender :: The descender in pixels. */ + /* */ + /* max_width :: The maximum glyph width in pixels. */ + /* */ + /* caret_slope_enumerator :: Rise of the caret slope, typically set */ + /* to 1 for non-italic fonts. */ + /* */ + /* caret_slope_denominator :: Rise of the caret slope, typically set */ + /* to 0 for non-italic fonts. */ + /* */ + /* caret_offset :: Offset in pixels to move the caret for */ + /* proper positioning. */ + /* */ + /* min_origin_SB :: Minimum of horiBearingX (resp. */ + /* vertBearingY). */ + /* min_advance_SB :: Minimum of */ + /* */ + /* horizontal advance - */ + /* ( horiBearingX + width ) */ + /* */ + /* resp. */ + /* */ + /* vertical advance - */ + /* ( vertBearingY + height ) */ + /* */ + /* max_before_BL :: Maximum of horiBearingY (resp. */ + /* vertBearingY). */ + /* */ + /* min_after_BL :: Minimum of */ + /* */ + /* horiBearingY - height */ + /* */ + /* resp. */ + /* */ + /* vertBearingX - width */ + /* */ + /* pads :: Unused (to make the size of the record */ + /* a multiple of 32 bits. */ + /* */ + typedef struct TT_SBit_Line_Metrics_ + { + FT_Char ascender; + FT_Char descender; + FT_Byte max_width; + FT_Char caret_slope_numerator; + FT_Char caret_slope_denominator; + FT_Char caret_offset; + FT_Char min_origin_SB; + FT_Char min_advance_SB; + FT_Char max_before_BL; + FT_Char min_after_BL; + FT_Char pads[2]; + + } TT_SBit_Line_Metrics; + + + /*************************************************************************/ + /* */ + /* */ + /* TT_SBit_Range */ + /* */ + /* */ + /* A TrueType/OpenType subIndexTable as defined in the `EBLC' */ + /* (Microsoft) or `bloc' (Apple) tables. */ + /* */ + /* */ + /* first_glyph :: The first glyph index in the range. */ + /* */ + /* last_glyph :: The last glyph index in the range. */ + /* */ + /* index_format :: The format of index table. Valid values are 1 */ + /* to 5. */ + /* */ + /* image_format :: The format of `EBDT' image data. */ + /* */ + /* image_offset :: The offset to image data in `EBDT'. */ + /* */ + /* image_size :: For index formats 2 and 5. This is the size in */ + /* bytes of each glyph bitmap. */ + /* */ + /* big_metrics :: For index formats 2 and 5. This is the big */ + /* metrics for each glyph bitmap. */ + /* */ + /* num_glyphs :: For index formats 4 and 5. This is the number of */ + /* glyphs in the code array. */ + /* */ + /* glyph_offsets :: For index formats 1 and 3. */ + /* */ + /* glyph_codes :: For index formats 4 and 5. */ + /* */ + /* table_offset :: The offset of the index table in the `EBLC' */ + /* table. Only used during strike loading. */ + /* */ + typedef struct TT_SBit_Range + { + FT_UShort first_glyph; + FT_UShort last_glyph; + + FT_UShort index_format; + FT_UShort image_format; + FT_ULong image_offset; + + FT_ULong image_size; + TT_SBit_Metrics metrics; + FT_ULong num_glyphs; + + FT_ULong* glyph_offsets; + FT_UShort* glyph_codes; + + FT_ULong table_offset; + + } TT_SBit_Range; + + + /*************************************************************************/ + /* */ + /* */ + /* TT_SBit_Strike */ + /* */ + /* */ + /* A structure used describe a given bitmap strike in the `EBLC' */ + /* (Microsoft) or `bloc' (Apple) tables. */ + /* */ + /* */ + /* num_index_ranges :: The number of index ranges. */ + /* */ + /* index_ranges :: An array of glyph index ranges. */ + /* */ + /* color_ref :: Unused. A color reference? */ + /* */ + /* hori :: The line metrics for horizontal layouts. */ + /* */ + /* vert :: The line metrics for vertical layouts. */ + /* */ + /* start_glyph :: The lowest glyph index for this strike. */ + /* */ + /* end_glyph :: The highest glyph index for this strike. */ + /* */ + /* x_ppem :: The number of horizontal pixels per EM. */ + /* */ + /* y_ppem :: The number of vertical pixels per EM. */ + /* */ + /* bit_depth :: The bit depth. Valid values are 1, 2, 4, */ + /* and 8. */ + /* */ + /* flags :: Is this a vertical or horizontal strike? */ + /* */ + typedef struct TT_SBit_Strike_ + { + FT_Int num_ranges; + TT_SBit_Range* sbit_ranges; + FT_ULong ranges_offset; + + FT_ULong color_ref; + + TT_SBit_Line_Metrics hori; + TT_SBit_Line_Metrics vert; + + FT_UShort start_glyph; + FT_UShort end_glyph; + + FT_Byte x_ppem; + FT_Byte y_ppem; + + FT_Byte bit_depth; + FT_Char flags; + + } TT_SBit_Strike; + + + /*************************************************************************/ + /* */ + /* */ + /* TT_SBit_Component */ + /* */ + /* */ + /* A simple structure to describe a compound sbit element. */ + /* */ + /* */ + /* glyph_code :: The element's glyph index. */ + /* */ + /* x_offset :: The element's left bearing. */ + /* */ + /* y_offset :: The element's top bearing. */ + /* */ + typedef struct TT_SBit_Component_ + { + FT_UShort glyph_code; + + FT_Char x_offset; + FT_Char y_offset; + + } TT_SBit_Component; + + + /*************************************************************************/ + /* */ + /* */ + /* TT_SBit_Scale */ + /* */ + /* */ + /* A structure used describe a given bitmap scaling table, as defined */ + /* in the `EBSC' table. */ + /* */ + /* */ + /* hori :: The horizontal line metrics. */ + /* */ + /* vert :: The vertical line metrics. */ + /* */ + /* x_ppem :: The number of horizontal pixels per EM. */ + /* */ + /* y_ppem :: The number of vertical pixels per EM. */ + /* */ + /* x_ppem_substitute :: Substitution x_ppem value. */ + /* */ + /* y_ppem_substitute :: Substitution y_ppem value. */ + /* */ + typedef struct TT_SBit_Scale_ + { + TT_SBit_Line_Metrics hori; + TT_SBit_Line_Metrics vert; + + FT_Byte x_ppem; + FT_Byte y_ppem; + + FT_Byte x_ppem_substitute; + FT_Byte y_ppem_substitute; + + } TT_SBit_Scale; + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*** ***/ + /*** ***/ + /*** POSTSCRIPT GLYPH NAMES SUPPORT ***/ + /*** ***/ + /*** ***/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Post_20 */ + /* */ + /* */ + /* Postscript names sub-table, format 2.0. Stores the PS name of */ + /* each glyph in the font face. */ + /* */ + /* */ + /* num_glyphs :: The number of named glyphs in the table. */ + /* */ + /* num_names :: The number of PS names stored in the table. */ + /* */ + /* glyph_indices :: The indices of the glyphs in the names arrays. */ + /* */ + /* glyph_names :: The PS names not in Mac Encoding. */ + /* */ + typedef struct TT_Post_20_ + { + FT_UShort num_glyphs; + FT_UShort num_names; + FT_UShort* glyph_indices; + FT_Char** glyph_names; + + } TT_Post_20; + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Post_25 */ + /* */ + /* */ + /* Postscript names sub-table, format 2.5. Stores the PS name of */ + /* each glyph in the font face. */ + /* */ + /* */ + /* num_glyphs :: The number of glyphs in the table. */ + /* */ + /* offsets :: An array of signed offsets in a normal Mac */ + /* Postscript name encoding. */ + /* */ + typedef struct TT_Post_25_ + { + FT_UShort num_glyphs; + FT_Char* offsets; + + } TT_Post_25; + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Post_Names */ + /* */ + /* */ + /* Postscript names table, either format 2.0 or 2.5. */ + /* */ + /* */ + /* loaded :: A flag to indicate whether the PS names are loaded. */ + /* */ + /* format_20 :: The sub-table used for format 2.0. */ + /* */ + /* format_25 :: The sub-table used for format 2.5. */ + /* */ + typedef struct TT_Post_Names_ + { + FT_Bool loaded; + + union + { + TT_Post_20 format_20; + TT_Post_25 format_25; + + } names; + + } TT_Post_Names; + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*** ***/ + /*** ***/ + /*** TRUETYPE CHARMAPS SUPPORT ***/ + /*** ***/ + /*** ***/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /* format 0 */ + + typedef struct TT_CMap0_ + { + FT_Byte* glyphIdArray; + + } TT_CMap0; + + + /* format 2 */ + + typedef struct TT_CMap2SubHeader_ + { + FT_UShort firstCode; /* first valid low byte */ + FT_UShort entryCount; /* number of valid low bytes */ + FT_Short idDelta; /* delta value to glyphIndex */ + FT_UShort idRangeOffset; /* offset from here to 1st code */ + + } TT_CMap2SubHeader; + + + typedef struct TT_CMap2_ + { + FT_UShort* subHeaderKeys; + /* high byte mapping table */ + /* value = subHeader index * 8 */ + + TT_CMap2SubHeader* subHeaders; + FT_UShort* glyphIdArray; + FT_UShort numGlyphId; /* control value */ + + } TT_CMap2; + + + /* format 4 */ + + typedef struct TT_CMap4Segment_ + { + FT_UShort endCount; + FT_UShort startCount; + FT_Short idDelta; + FT_UShort idRangeOffset; + + } TT_CMap4Segment; + + + typedef struct TT_CMap4_ + { + FT_UShort segCountX2; /* number of segments * 2 */ + FT_UShort searchRange; /* these parameters can be used */ + FT_UShort entrySelector; /* for a binary search */ + FT_UShort rangeShift; + + TT_CMap4Segment* segments; + FT_UShort* glyphIdArray; + FT_UShort numGlyphId; /* control value */ + + TT_CMap4Segment* last_segment; /* last used segment; this is a small */ + /* cache to potentially increase speed */ + } TT_CMap4; + + + /* format 6 */ + + typedef struct TT_CMap6_ + { + FT_UShort firstCode; /* first character code of subrange */ + FT_UShort entryCount; /* number of character codes in subrange */ + + FT_UShort* glyphIdArray; + + } TT_CMap6; + + + typedef struct TT_CMapTable_ TT_CMapTable; + + + typedef + FT_UInt (*TT_CharMap_Func)( TT_CMapTable* charmap, + FT_ULong char_code ); + + + /* charmap table */ + struct TT_CMapTable_ + { + FT_UShort platformID; + FT_UShort platformEncodingID; + FT_UShort format; + FT_UShort length; + FT_UShort version; + + FT_Bool loaded; + FT_ULong offset; + + union + { + TT_CMap0 cmap0; + TT_CMap2 cmap2; + TT_CMap4 cmap4; + TT_CMap6 cmap6; + } c; + + TT_CharMap_Func get_index; + }; + + + /*************************************************************************/ + /* */ + /* */ + /* TT_CharMapRec */ + /* */ + /* */ + /* The TrueType character map object type. */ + /* */ + /* */ + /* root :: The parent character map structure. */ + /* */ + /* cmap :: The used character map. */ + /* */ + typedef struct TT_CharMapRec_ + { + FT_CharMapRec root; + TT_CMapTable cmap; + + } TT_CharMapRec; + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*** ***/ + /*** ***/ + /*** ORIGINAL TT_FACE CLASS DEFINITION ***/ + /*** ***/ + /*** ***/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* This structure/class is defined here because it is common to the */ + /* following formats: TTF, OpenType-TT, and OpenType-CFF. */ + /* */ + /* Note, however, that the classes TT_Size, TT_GlyphSlot, and TT_CharMap */ + /* are not shared between font drivers, and are thus defined normally in */ + /* `ttobjs.h'. */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Face */ + /* */ + /* */ + /* A handle to a TrueType face/font object. A TT_Face encapsulates */ + /* the resolution and scaling independent parts of a TrueType font */ + /* resource. */ + /* */ + /* */ + /* The TT_Face structure is also used as a `parent class' for the */ + /* OpenType-CFF class (T2_Face). */ + /* */ + typedef struct TT_FaceRec_* TT_Face; + + + /*************************************************************************/ + /* */ + /* */ + /* TT_CharMap */ + /* */ + /* */ + /* A handle to a TrueType character mapping object. */ + /* */ + typedef struct TT_CharMapRec_* TT_CharMap; + + + /* a function type used for the truetype bytecode interpreter hooks */ + typedef FT_Error (*TT_Interpreter)( void* exec_context ); + + /* forward declaration */ + typedef struct TT_Loader_ TT_Loader; + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Goto_Table_Func */ + /* */ + /* */ + /* Seeks a stream to the start of a given TrueType table. */ + /* */ + /* */ + /* face :: A handle to the target face object. */ + /* */ + /* tag :: A 4-byte tag used to name the table. */ + /* */ + /* stream :: The input stream. */ + /* */ + /* */ + /* length :: The length of the table in bytes. Set to 0 if not */ + /* needed. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* The stream cursor must be at the font file's origin. */ + /* */ + typedef + FT_Error (*TT_Goto_Table_Func)( TT_Face face, + FT_ULong tag, + FT_Stream stream, + FT_ULong* length ); + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Access_Glyph_Frame_Func */ + /* */ + /* */ + /* Seeks a stream to the start of a given glyph element, and opens a */ + /* frame for it. */ + /* */ + /* */ + /* loader :: The current TrueType glyph loader object. */ + /* */ + /* glyph index :: The index of the glyph to access. */ + /* */ + /* offset :: The offset of the glyph according to the */ + /* `locations' table. */ + /* */ + /* byte_count :: The size of the frame in bytes. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* This function is normally equivalent to FILE_Seek(offset) */ + /* followed by ACCESS_Frame(byte_count) with the loader's stream, but */ + /* alternative formats (e.g. compressed ones) might use something */ + /* different. */ + /* */ + typedef + FT_Error (*TT_Access_Glyph_Frame_Func)( TT_Loader* loader, + FT_UInt glyph_index, + FT_ULong offset, + FT_UInt byte_count ); + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Load_Glyph_Element_Func */ + /* */ + /* */ + /* Reads one glyph element (its header, a simple glyph, or a */ + /* composite) from the loader's current stream frame. */ + /* */ + /* */ + /* loader :: The current TrueType glyph loader object. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + typedef + FT_Error (*TT_Load_Glyph_Element_Func)( TT_Loader* loader ); + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Forget_Glyph_Frame_Func */ + /* */ + /* */ + /* Closes the current loader stream frame for the glyph. */ + /* */ + /* */ + /* loader :: The current TrueType glyph loader object. */ + /* */ + typedef + void (*TT_Forget_Glyph_Frame_Func)( TT_Loader* loader ); + + + + /*************************************************************************/ + /* */ + /* TrueType Face Type */ + /* */ + /* */ + /* TT_Face */ + /* */ + /* */ + /* The TrueType face class. These objects model the resolution and */ + /* point-size independent data found in a TrueType font file. */ + /* */ + /* */ + /* root :: The base FT_Face structure, managed by the */ + /* base layer. */ + /* */ + /* ttc_header :: The TrueType collection header, used when */ + /* the file is a `ttc' rather than a `ttf'. */ + /* For ordinary font files, the field */ + /* `ttc_header.count' is set to 0. */ + /* */ + /* format_tag :: The font format tag. */ + /* */ + /* num_tables :: The number of TrueType tables in this font */ + /* file. */ + /* */ + /* dir_tables :: The directory of TrueType tables for this */ + /* font file. */ + /* */ + /* header :: The font's font header (`head' table). */ + /* Read on font opening. */ + /* */ + /* horizontal :: The font's horizontal header (`hhea' */ + /* table). This field also contains the */ + /* associated horizontal metrics table */ + /* (`hmtx'). */ + /* */ + /* max_profile :: The font's maximum profile table. Read on */ + /* font opening. Note that some maximum */ + /* values cannot be taken directly from this */ + /* table. We thus define additional fields */ + /* below to hold the computed maxima. */ + /* */ + /* max_components :: The maximum number of glyph components */ + /* required to load any composite glyph from */ + /* this font. Used to size the load stack. */ + /* */ + /* vertical_info :: A boolean which is set when the font file */ + /* contains vertical metrics. If not, the */ + /* value of the `vertical' field is */ + /* undefined. */ + /* */ + /* vertical :: The font's vertical header (`vhea' table). */ + /* This field also contains the associated */ + /* vertical metrics table (`vmtx'), if found. */ + /* IMPORTANT: The contents of this field is */ + /* undefined if the `verticalInfo' field is */ + /* unset. */ + /* */ + /* num_names :: The number of name records within this */ + /* TrueType font. */ + /* */ + /* name_table :: The table of name records (`name'). */ + /* */ + /* os2 :: The font's OS/2 table (`OS/2'). */ + /* */ + /* postscript :: The font's PostScript table (`post' */ + /* table). The PostScript glyph names are */ + /* not loaded by the driver on face opening. */ + /* See the `ttpost' module for more details. */ + /* */ + /* num_charmaps :: The number of character mappings in the */ + /* font. */ + /* */ + /* charmaps :: The array of charmap objects for this font */ + /* file. Note that this field is a typeless */ + /* pointer. The Reason is that the format of */ + /* charmaps varies with the underlying font */ + /* format and cannot be determined here. */ + /* */ + /* goto_table :: A function called by each TrueType table */ + /* loader to position a stream's cursor to */ + /* the start of a given table according to */ + /* its tag. It defaults to TT_Goto_Face but */ + /* can be different for strange formats (e.g. */ + /* Type 42). */ + /* */ + /* access_glyph_frame :: XXX */ + /* */ + /* read_glyph_header :: XXX */ + /* */ + /* read_simple_glyph :: XXX */ + /* */ + /* read_composite_glyph :: XXX */ + /* */ + /* forget_glyph_frame :: XXX */ + /* */ + /* sfnt :: A pointer to the SFNT `driver' interface. */ + /* */ + /* psnames :: A pointer to the `PSNames' module */ + /* interface. */ + /* */ + /* hdmx :: The face's horizontal device metrics */ + /* (`hdmx' table). This table is optional in */ + /* TrueType/OpenType fonts. */ + /* */ + /* gasp :: The grid-fitting and scaling properties */ + /* table (`gasp'). This table is optional in */ + /* TrueType/OpenType fonts. */ + /* */ + /* pclt :: XXX */ + /* */ + /* num_sbit_strikes :: The number of sbit strikes, i.e., bitmap */ + /* sizes, embedded in this font. */ + /* */ + /* sbit_strikes :: An array of sbit strikes embedded in this */ + /* font. This table is optional in a */ + /* TrueType/OpenType font. */ + /* */ + /* num_sbit_scales :: The number of sbit scales for this font. */ + /* */ + /* sbit_scales :: Array of sbit scales embedded in this */ + /* font. This table is optional in a */ + /* TrueType/OpenType font. */ + /* */ + /* postscript_names :: A table used to store the Postscript names */ + /* of the glyphs for this font. See the */ + /* file `ttconfig.h' for comments on the */ + /* TT_CONFIG_OPTION_POSTSCRIPT_NAMES option. */ + /* */ + /* num_locations :: The number of glyph locations in this */ + /* TrueType file. This should be */ + /* identical to the number of glyphs. */ + /* Ignored for Type 2 fonts. */ + /* */ + /* glyph_locations :: An array of longs. These are offsets to */ + /* glyph data within the `glyf' table. */ + /* Ignored for Type 2 font faces. */ + /* */ + /* font_program_size :: Size in bytecodes of the face's font */ + /* program. 0 if none defined. Ignored for */ + /* Type 2 fonts. */ + /* */ + /* font_program :: The face's font program (bytecode stream) */ + /* executed at load time, also used during */ + /* glyph rendering. Comes from the `fpgm' */ + /* table. Ignored for Type 2 font fonts. */ + /* */ + /* cvt_program_size :: The size in bytecodes of the face's cvt */ + /* program. Ignored for Type 2 fonts. */ + /* */ + /* cvt_program :: The face's cvt program (bytecode stream) */ + /* executed each time an instance/size is */ + /* changed/reset. Comes from the `prep' */ + /* table. Ignored for Type 2 fonts. */ + /* */ + /* cvt_size :: Size of the control value table (in */ + /* entries). Ignored for Type 2 fonts. */ + /* */ + /* cvt :: The face's original control value table. */ + /* Coordinates are expressed in unscaled font */ + /* units. Comes from the `cvt ' table. */ + /* Ignored for Type 2 fonts. */ + /* */ + /* num_kern_pairs :: The number of kerning pairs present in the */ + /* font file. The engine only loads the */ + /* first horizontal format 0 kern table it */ + /* finds in the font file. You should use */ + /* the `ttxkern' structures if you want to */ + /* access other kerning tables. Ignored */ + /* for Type 2 fonts. */ + /* */ + /* kern_table_index :: The index of the kerning table in the font */ + /* kerning directory. Only used by the */ + /* ttxkern extension to avoid data */ + /* duplication. Ignored for Type 2 fonts. */ + /* */ + /* interpreter :: A pointer to the TrueType bytecode */ + /* interpreters field is also used to hook */ + /* the debugger in `ttdebug'. */ + /* */ + /* extra :: XXX */ + /* */ + typedef struct TT_FaceRec_ + { + FT_FaceRec root; + + TTC_Header ttc_header; + + FT_ULong format_tag; + FT_UShort num_tables; + TT_Table* dir_tables; + + TT_Header header; /* TrueType header table */ + TT_HoriHeader horizontal; /* TrueType horizontal header */ + + TT_MaxProfile max_profile; + FT_ULong max_components; + + FT_Bool vertical_info; + TT_VertHeader vertical; /* TT Vertical header, if present */ + + FT_Int num_names; /* number of name records */ + TT_NameTable name_table; /* name table */ + + TT_OS2 os2; /* TrueType OS/2 table */ + TT_Postscript postscript; /* TrueType Postscript table */ + + FT_Int num_charmaps; + TT_CharMap charmaps; /* array of TT_CharMapRec */ + + TT_Goto_Table_Func goto_table; + + TT_Access_Glyph_Frame_Func access_glyph_frame; + TT_Load_Glyph_Element_Func read_glyph_header; + TT_Load_Glyph_Element_Func read_simple_glyph; + TT_Load_Glyph_Element_Func read_composite_glyph; + TT_Forget_Glyph_Frame_Func forget_glyph_frame; + + /* a typeless pointer to the SFNT_Interface table used to load */ + /* the basic TrueType tables in the face object */ + void* sfnt; + + /* a typeless pointer to the PSNames_Interface table used to */ + /* handle glyph names <-> unicode & Mac values */ + void* psnames; + + /***********************************************************************/ + /* */ + /* Optional TrueType/OpenType tables */ + /* */ + /***********************************************************************/ + + /* horizontal device metrics */ + TT_Hdmx hdmx; + + /* grid-fitting and scaling table */ + TT_Gasp gasp; /* the `gasp' table */ + + /* PCL 5 table */ + TT_PCLT pclt; + + /* embedded bitmaps support */ + FT_Int num_sbit_strikes; + TT_SBit_Strike* sbit_strikes; + + FT_Int num_sbit_scales; + TT_SBit_Scale* sbit_scales; + + /* postscript names table */ + TT_Post_Names postscript_names; + + + /***********************************************************************/ + /* */ + /* TrueType-specific fields (ignored by the OTF-Type2 driver) */ + /* */ + /***********************************************************************/ + + /* the glyph locations */ + FT_UShort num_locations; + FT_Long* glyph_locations; + + /* the font program, if any */ + FT_ULong font_program_size; + FT_Byte* font_program; + + /* the cvt program, if any */ + FT_ULong cvt_program_size; + FT_Byte* cvt_program; + + /* the original, unscaled, control value table */ + FT_ULong cvt_size; + FT_Short* cvt; + + /* the format 0 kerning table, if any */ + FT_Int num_kern_pairs; + FT_Int kern_table_index; + TT_Kern_0_Pair* kern_pairs; + + /* A pointer to the bytecode interpreter to use. This is also */ + /* used to hook the debugger for the `ttdebug' utility. */ + TT_Interpreter interpreter; + + + /***********************************************************************/ + /* */ + /* Other tables or fields. This is used by derivative formats like */ + /* OpenType. */ + /* */ + /***********************************************************************/ + + FT_Generic extra; + + } TT_FaceRec; + + + /*************************************************************************/ + /* */ + /* */ + /* TT_GlyphZone */ + /* */ + /* */ + /* A glyph zone is used to load, scale and hint glyph outline */ + /* coordinates. */ + /* */ + /* */ + /* memory :: A handle to the memory manager. */ + /* */ + /* max_points :: The maximal size in points of the zone. */ + /* */ + /* max_contours :: Max size in links contours of thez one. */ + /* */ + /* n_points :: The current number of points in the zone. */ + /* */ + /* n_contours :: The current number of contours in the zone. */ + /* */ + /* org :: The original glyph coordinates (font */ + /* units/scaled). */ + /* */ + /* cur :: The current glyph coordinates (scaled/hinted). */ + /* */ + /* tags :: The point control tags. */ + /* */ + /* contours :: The contours end points. */ + /* */ + typedef struct TT_GlyphZone_ + { + FT_Memory memory; + FT_UShort max_points; + FT_UShort max_contours; + FT_UShort n_points; /* number of points in zone */ + FT_Short n_contours; /* number of contours */ + + FT_Vector* org; /* original point coordinates */ + FT_Vector* cur; /* current point coordinates */ + + FT_Byte* tags; /* current touch flags */ + FT_UShort* contours; /* contour end points */ + + } TT_GlyphZone; + + + /* handle to execution context */ + typedef struct TT_ExecContextRec_* TT_ExecContext; + + /* glyph loader structure */ + struct TT_Loader_ + { + FT_Face face; + FT_Size size; + FT_GlyphSlot glyph; + FT_GlyphLoader* gloader; + + FT_ULong load_flags; + FT_UInt glyph_index; + + FT_Stream stream; + FT_Int byte_len; + + FT_Short n_contours; + FT_BBox bbox; + FT_Int left_bearing; + FT_Int advance; + FT_Bool preserve_pps; + FT_Vector pp1; + FT_Vector pp2; + + FT_ULong glyf_offset; + + /* the zone where we load our glyphs */ + TT_GlyphZone base; + TT_GlyphZone zone; + + TT_ExecContext exec; + FT_Byte* instructions; + FT_ULong ins_pos; + + /* for possible extensibility in other formats */ + void* other; + + }; + + +#endif /* TTTYPES_H */ + + +/* END */ diff --git a/src/freetype/freetype/t1tables.h b/src/freetype/freetype/t1tables.h new file mode 100644 index 0000000000..323e0130c1 --- /dev/null +++ b/src/freetype/freetype/t1tables.h @@ -0,0 +1,235 @@ +/***************************************************************************/ +/* */ +/* t1tables.h */ +/* */ +/* Basic Type 1/Type 2 tables definitions and interface (specification */ +/* only). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef T1TABLES_H +#define T1TABLES_H + + +#include + + + /* Note that we separate font data in T1_FontInfo and T1_Private */ + /* structures in order to support Multiple Master fonts. */ + + + /*************************************************************************/ + /* */ + /* */ + /* T1_FontInfo */ + /* */ + /* */ + /* A structure used to model a Type1/Type2 FontInfo dictionary. Note */ + /* that for Multiple Master fonts, each instance has its own */ + /* FontInfo. */ + /* */ + typedef struct T1_FontInfo + { + FT_String* version; + FT_String* notice; + FT_String* full_name; + FT_String* family_name; + FT_String* weight; + FT_Long italic_angle; + FT_Bool is_fixed_pitch; + FT_Short underline_position; + FT_UShort underline_thickness; + + } T1_FontInfo; + + + /*************************************************************************/ + /* */ + /* */ + /* T1_Private */ + /* */ + /* */ + /* A structure used to model a Type1/Type2 FontInfo dictionary. Note */ + /* that for Multiple Master fonts, each instance has its own Private */ + /* dict. */ + /* */ + typedef struct T1_Private + { + FT_Int unique_id; + FT_Int lenIV; + + FT_Byte num_blue_values; + FT_Byte num_other_blues; + FT_Byte num_family_blues; + FT_Byte num_family_other_blues; + + FT_Short blue_values[14]; + FT_Short other_blues[10]; + + FT_Short family_blues [14]; + FT_Short family_other_blues[10]; + + FT_Fixed blue_scale; + FT_Int blue_shift; + FT_Int blue_fuzz; + + FT_UShort standard_width[1]; + FT_UShort standard_height[1]; + + FT_Byte num_snap_widths; + FT_Byte num_snap_heights; + FT_Bool force_bold; + FT_Bool round_stem_up; + + FT_Short snap_widths [13]; /* reserve one place for the std */ + FT_Short snap_heights[13]; /* reserve one place for the std */ + + FT_Long language_group; + FT_Long password; + + FT_Short min_feature[2]; + + } T1_Private; + + + /*************************************************************************/ + /* */ + /* */ + /* T1_Blend_Flags */ + /* */ + /* */ + /* A set of flags used to indicate which fields are present in a */ + /* given blen dictionary (font info or private). Used to support */ + /* Multiple Masters fonts. */ + /* */ + typedef enum + { + /* required fields in a FontInfo blend dictionary */ + t1_blend_underline_position = 0, + t1_blend_underline_thickness, + t1_blend_italic_angle, + + /* required fields in a Private blend dictionary */ + t1_blend_blue_values, + t1_blend_other_blues, + t1_blend_standard_width, + t1_blend_standard_height, + t1_blend_stem_snap_widths, + t1_blend_stem_snap_heights, + t1_blend_blue_scale, + t1_blend_blue_shift, + t1_blend_family_blues, + t1_blend_family_other_blues, + t1_blend_force_bold, + + /* never remove */ + t1_blend_max + + } T1_Blend_Flags; + + + /* maximum number of Multiple Masters designs, as defined in the spec */ +#define T1_MAX_MM_DESIGNS 16 + + /* maximum number of Multiple Masters axes, as defined in the spec */ +#define T1_MAX_MM_AXIS 4 + + /* maximum number of elements in a design map */ +#define T1_MAX_MM_MAP_POINTS 20 + + + /* this structure is used to store the BlendDesignMap entry for an axis */ + typedef struct T1_DesignMap_ + { + FT_Byte num_points; + FT_Fixed* design_points; + FT_Fixed* blend_points; + + } T1_DesignMap; + + + typedef struct T1_Blend_ + { + FT_UInt num_designs; + FT_UInt num_axis; + + FT_String* axis_names[T1_MAX_MM_AXIS]; + FT_Fixed* design_pos[T1_MAX_MM_DESIGNS]; + T1_DesignMap design_map[T1_MAX_MM_AXIS]; + + FT_Fixed* weight_vector; + FT_Fixed* default_weight_vector; + + T1_FontInfo* font_infos[T1_MAX_MM_DESIGNS + 1]; + T1_Private* privates [T1_MAX_MM_DESIGNS + 1]; + + FT_ULong blend_bitflags; + + } T1_Blend; + + + typedef struct CID_FontDict_ + { + T1_Private private_dict; + + FT_UInt len_buildchar; + FT_Fixed forcebold_threshold; + FT_Pos stroke_width; + FT_Fixed expansion_factor; + + FT_Byte paint_type; + FT_Byte font_type; + FT_Matrix font_matrix; + + FT_UInt num_subrs; + FT_ULong subrmap_offset; + FT_Int sd_bytes; + + } CID_FontDict; + + + typedef struct CID_Info_ + { + FT_String* cid_font_name; + FT_Fixed cid_version; + FT_Int cid_font_type; + + FT_String* registry; + FT_String* ordering; + FT_Int supplement; + + T1_FontInfo font_info; + FT_BBox font_bbox; + FT_ULong uid_base; + + FT_Int num_xuid; + FT_ULong xuid[16]; + + + FT_ULong cidmap_offset; + FT_Int fd_bytes; + FT_Int gd_bytes; + FT_ULong cid_count; + + FT_Int num_dicts; + CID_FontDict* font_dicts; + + FT_ULong data_offset; + + } CID_Info; + + +#endif /* T1TABLES_H */ + + +/* END */ diff --git a/src/freetype/freetype/ttnameid.h b/src/freetype/freetype/ttnameid.h new file mode 100644 index 0000000000..4890242415 --- /dev/null +++ b/src/freetype/freetype/ttnameid.h @@ -0,0 +1,698 @@ +/***************************************************************************/ +/* */ +/* ttmakeid.h */ +/* */ +/* TrueType name ID definitions (specification only). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef TTNAMEID_H +#define TTNAMEID_H + + + /*************************************************************************/ + /* */ + /* Possible values for the `platform' identifier code in the name */ + /* records of the TTF `name' table. */ + /* */ +#define TT_PLATFORM_APPLE_UNICODE 0 +#define TT_PLATFORM_MACINTOSH 1 +#define TT_PLATFORM_ISO 2 /* deprecated */ +#define TT_PLATFORM_MICROSOFT 3 + + + /*************************************************************************/ + /* */ + /* Possible values of the platform specific encoding identifier field in */ + /* the name records of the TTF `name' table if the `platform' identifier */ + /* code is TT_PLATFORM_APPLE_UNICODE. */ + /* */ +#define TT_APPLE_ID_DEFAULT 0 +#define TT_APPLE_ID_UNICODE_1_1 1 /* specify Hangul at U+34xx */ +#define TT_APPLE_ID_ISO_10646 2 /* deprecated */ +#define TT_APPLE_ID_UNICODE_2_0 3 /* or later */ + + + /*************************************************************************/ + /* */ + /* Possible values of the platform specific encoding identifier field in */ + /* the name records of the TTF `name' table if the `platform' identifier */ + /* code is TT_PLATFORM_MACINTOSH. */ + /* */ +#define TT_MAC_ID_ROMAN 0 +#define TT_MAC_ID_JAPANESE 1 +#define TT_MAC_ID_TRADITIONAL_CHINESE 2 +#define TT_MAC_ID_KOREAN 3 +#define TT_MAC_ID_ARABIC 4 +#define TT_MAC_ID_HEBREW 5 +#define TT_MAC_ID_GREEK 6 +#define TT_MAC_ID_RUSSIAN 7 +#define TT_MAC_ID_RSYMBOL 8 +#define TT_MAC_ID_DEVANAGARI 9 +#define TT_MAC_ID_GURMUKHI 10 +#define TT_MAC_ID_GUJARATI 11 +#define TT_MAC_ID_ORIYA 12 +#define TT_MAC_ID_BENGALI 13 +#define TT_MAC_ID_TAMIL 14 +#define TT_MAC_ID_TELUGU 15 +#define TT_MAC_ID_KANNADA 16 +#define TT_MAC_ID_MALAYALAM 17 +#define TT_MAC_ID_SINHALESE 18 +#define TT_MAC_ID_BURMESE 19 +#define TT_MAC_ID_KHMER 20 +#define TT_MAC_ID_THAI 21 +#define TT_MAC_ID_LAOTIAN 22 +#define TT_MAC_ID_GEORGIAN 23 +#define TT_MAC_ID_ARMENIAN 24 +#define TT_MAC_ID_MALDIVIAN 25 +#define TT_MAC_ID_SIMPLIFIED_CHINESE 25 +#define TT_MAC_ID_TIBETAN 26 +#define TT_MAC_ID_MONGOLIAN 27 +#define TT_MAC_ID_GEEZ 28 +#define TT_MAC_ID_SLAVIC 29 +#define TT_MAC_ID_VIETNAMESE 30 +#define TT_MAC_ID_SINDHI 31 +#define TT_MAC_ID_UNINTERP 32 + + + /*************************************************************************/ + /* */ + /* Possible values of the platform specific encoding identifier field in */ + /* the name records of the TTF `name' table if the `platform' identifier */ + /* code is TT_PLATFORM_ISO. */ + /* */ + /* This use is now deprecated. */ + /* */ +#define TT_ISO_ID_7BIT_ASCII 0 +#define TT_ISO_ID_10646 1 +#define TT_ISO_ID_8859_1 2 + + + /*************************************************************************/ + /* */ + /* possible values of the platform specific encoding identifier field in */ + /* the name records of the TTF `name' table if the `platform' identifier */ + /* code is TT_PLATFORM_MICROSOFT. */ + /* */ +#define TT_MS_ID_SYMBOL_CS 0 +#define TT_MS_ID_UNICODE_CS 1 +#define TT_MS_ID_SJIS 2 +#define TT_MS_ID_GB2312 3 +#define TT_MS_ID_BIG_5 4 +#define TT_MS_ID_WANSUNG 5 +#define TT_MS_ID_JOHAB 6 + + + /*************************************************************************/ + /* */ + /* Possible values of the language identifier field in the name records */ + /* of the TTF `name' table if the `platform' identifier code is */ + /* TT_PLATFORM_MACINTOSH. */ + /* */ + /* The canonical source for the Apple assigned Language ID's is at */ + /* */ + /* http://fonts.apple.com/TTRefMan/RM06/Chap6name.html */ + /* */ +#define TT_MAC_LANGID_ENGLISH 0 +#define TT_MAC_LANGID_FRENCH 1 +#define TT_MAC_LANGID_GERMAN 2 +#define TT_MAC_LANGID_ITALIAN 3 +#define TT_MAC_LANGID_DUTCH 4 +#define TT_MAC_LANGID_SWEDISH 5 +#define TT_MAC_LANGID_SPANISH 6 +#define TT_MAC_LANGID_DANISH 7 +#define TT_MAC_LANGID_PORTUGUESE 8 +#define TT_MAC_LANGID_NORWEGIAN 9 +#define TT_MAC_LANGID_HEBREW 10 +#define TT_MAC_LANGID_JAPANESE 11 +#define TT_MAC_LANGID_ARABIC 12 +#define TT_MAC_LANGID_FINNISH 13 +#define TT_MAC_LANGID_GREEK 14 +#define TT_MAC_LANGID_ICELANDIC 15 +#define TT_MAC_LANGID_MALTESE 16 +#define TT_MAC_LANGID_TURKISH 17 +#define TT_MAC_LANGID_CROATIAN 18 +#define TT_MAC_LANGID_CHINESE_TRADITIONAL 19 +#define TT_MAC_LANGID_URDU 20 +#define TT_MAC_LANGID_HINDI 21 +#define TT_MAC_LANGID_THAI 22 +#define TT_MAC_LANGID_KOREAN 23 +#define TT_MAC_LANGID_LITHUANIAN 24 +#define TT_MAC_LANGID_POLISH 25 +#define TT_MAC_LANGID_HUNGARIAN 26 +#define TT_MAC_LANGID_ESTONIAN 27 +#define TT_MAC_LANGID_LETTISH 28 +#define TT_MAC_LANGID_SAAMISK 29 +#define TT_MAC_LANGID_FAEROESE 30 +#define TT_MAC_LANGID_FARSI 31 +#define TT_MAC_LANGID_RUSSIAN 32 +#define TT_MAC_LANGID_CHINESE_SIMPLIFIED 33 +#define TT_MAC_LANGID_FLEMISH 34 +#define TT_MAC_LANGID_IRISH 35 +#define TT_MAC_LANGID_ALBANIAN 36 +#define TT_MAC_LANGID_ROMANIAN 37 +#define TT_MAC_LANGID_CZECH 38 +#define TT_MAC_LANGID_SLOVAK 39 +#define TT_MAC_LANGID_SLOVENIAN 40 +#define TT_MAC_LANGID_YIDDISH 41 +#define TT_MAC_LANGID_SERBIAN 42 +#define TT_MAC_LANGID_MACEDONIAN 43 +#define TT_MAC_LANGID_BULGARIAN 44 +#define TT_MAC_LANGID_UKRAINIAN 45 +#define TT_MAC_LANGID_BYELORUSSIAN 46 +#define TT_MAC_LANGID_UZBEK 47 +#define TT_MAC_LANGID_KAZAKH 48 +#define TT_MAC_LANGID_AZERBAIJANI 49 +#define TT_MAC_LANGID_AZERBAIJANI_CYRILLIC_SCRIPT 49 +#define TT_MAC_LANGID_AZERBAIJANI_ARABIC_SCRIPT 50 +#define TT_MAC_LANGID_ARMENIAN 51 +#define TT_MAC_LANGID_GEORGIAN 52 +#define TT_MAC_LANGID_MOLDAVIAN 53 +#define TT_MAC_LANGID_KIRGHIZ 54 +#define TT_MAC_LANGID_TAJIKI 55 +#define TT_MAC_LANGID_TURKMEN 56 +#define TT_MAC_LANGID_MONGOLIAN 57 +#define TT_MAC_LANGID_MONGOLIAN_MONGOLIAN_SCRIPT 57 +#define TT_MAC_LANGID_MONGOLIAN_CYRILLIC_SCRIPT 58 +#define TT_MAC_LANGID_PASHTO 59 +#define TT_MAC_LANGID_KURDISH 60 +#define TT_MAC_LANGID_KASHMIRI 61 +#define TT_MAC_LANGID_SINDHI 62 +#define TT_MAC_LANGID_TIBETAN 63 +#define TT_MAC_LANGID_NEPALI 64 +#define TT_MAC_LANGID_SANSKRIT 65 +#define TT_MAC_LANGID_MARATHI 66 +#define TT_MAC_LANGID_BENGALI 67 +#define TT_MAC_LANGID_ASSAMESE 68 +#define TT_MAC_LANGID_GUJARATI 69 +#define TT_MAC_LANGID_PUNJABI 70 +#define TT_MAC_LANGID_ORIYA 71 +#define TT_MAC_LANGID_MALAYALAM 72 +#define TT_MAC_LANGID_KANNADA 73 +#define TT_MAC_LANGID_TAMIL 74 +#define TT_MAC_LANGID_TELUGU 75 +#define TT_MAC_LANGID_SINHALESE 76 +#define TT_MAC_LANGID_BURMESE 77 +#define TT_MAC_LANGID_KHMER 78 +#define TT_MAC_LANGID_LAO 79 +#define TT_MAC_LANGID_VIETNAMESE 80 +#define TT_MAC_LANGID_INDONESIAN 81 +#define TT_MAC_LANGID_TAGALOG 82 +#define TT_MAC_LANGID_MALAY_ROMAN_SCRIPT 83 +#define TT_MAC_LANGID_MALAY_ARABIC_SCRIPT 84 +#define TT_MAC_LANGID_AMHARIC 85 +#define TT_MAC_LANGID_TIGRINYA 86 +#define TT_MAC_LANGID_GALLA 87 +#define TT_MAC_LANGID_SOMALI 88 +#define TT_MAC_LANGID_SWAHILI 89 +#define TT_MAC_LANGID_RUANDA 90 +#define TT_MAC_LANGID_RUNDI 91 +#define TT_MAC_LANGID_CHEWA 92 +#define TT_MAC_LANGID_MALAGASY 93 +#define TT_MAC_LANGID_ESPERANTO 94 +#define TT_MAC_LANGID_WELSH 128 +#define TT_MAC_LANGID_BASQUE 129 +#define TT_MAC_LANGID_CATALAN 130 +#define TT_MAC_LANGID_LATIN 131 +#define TT_MAC_LANGID_QUECHUA 132 +#define TT_MAC_LANGID_GUARANI 133 +#define TT_MAC_LANGID_AYMARA 134 +#define TT_MAC_LANGID_TATAR 135 +#define TT_MAC_LANGID_UIGHUR 136 +#define TT_MAC_LANGID_DZONGKHA 137 +#define TT_MAC_LANGID_JAVANESE 138 +#define TT_MAC_LANGID_SUNDANESE 139 + + +#if 0 /* these seem to be errors that have been dropped */ + +#define TT_MAC_LANGID_SCOTTISH_GAELIC 140 +#define TT_MAC_LANGID_IRISH_GAELIC 141 + +#endif + + + /* The following codes are new as of 2000-03-10 */ +#define TT_MAC_LANGID_GALICIAN 140 +#define TT_MAC_LANGID_AFRIKAANS 141 +#define TT_MAC_LANGID_BRETON 142 +#define TT_MAC_LANGID_INUKTITUT 143 +#define TT_MAC_LANGID_SCOTTISH_GAELIC 144 +#define TT_MAC_LANGID_MANX_GAELIC 145 +#define TT_MAC_LANGID_IRISH_GAELIC 146 +#define TT_MAC_LANGID_TONGAN 147 +#define TT_MAC_LANGID_GREEK_POLYTONIC 148 +#define TT_MAC_LANGID_GREELANDIC 149 +#define TT_MAC_LANGID_AZERBAIJANI_ROMAN_SCRIPT 150 + + + /*************************************************************************/ + /* */ + /* Possible values of the language identifier field in the name records */ + /* of the TTF `name' table if the `platform' identifier code is */ + /* TT_PLATFORM_MICROSOFT. */ + /* */ + /* The canonical source for the MS assigned LCID's is at */ + /* */ + /* http://www.microsoft.com/typography/OTSPEC/lcid-cp.txt */ + /* */ +#define TT_MS_LANGID_ARABIC_SAUDI_ARABIA 0x0401 +#define TT_MS_LANGID_ARABIC_IRAQ 0x0801 +#define TT_MS_LANGID_ARABIC_EGYPT 0x0c01 +#define TT_MS_LANGID_ARABIC_LIBYA 0x1001 +#define TT_MS_LANGID_ARABIC_ALGERIA 0x1401 +#define TT_MS_LANGID_ARABIC_MOROCCO 0x1801 +#define TT_MS_LANGID_ARABIC_TUNISIA 0x1c01 +#define TT_MS_LANGID_ARABIC_OMAN 0x2001 +#define TT_MS_LANGID_ARABIC_YEMEN 0x2401 +#define TT_MS_LANGID_ARABIC_SYRIA 0x2801 +#define TT_MS_LANGID_ARABIC_JORDAN 0x2c01 +#define TT_MS_LANGID_ARABIC_LEBANON 0x3001 +#define TT_MS_LANGID_ARABIC_KUWAIT 0x3401 +#define TT_MS_LANGID_ARABIC_UAE 0x3801 +#define TT_MS_LANGID_ARABIC_BAHRAIN 0x3c01 +#define TT_MS_LANGID_ARABIC_QATAR 0x4001 +#define TT_MS_LANGID_BULGARIAN_BULGARIA 0x0402 +#define TT_MS_LANGID_CATALAN_SPAIN 0x0403 +#define TT_MS_LANGID_CHINESE_TAIWAN 0x0404 +#define TT_MS_LANGID_CHINESE_PRC 0x0804 +#define TT_MS_LANGID_CHINESE_HONG_KONG 0x0c04 +#define TT_MS_LANGID_CHINESE_SINGAPORE 0x1004 +#define TT_MS_LANGID_CHINESE_MACAU 0x1404 +#define TT_MS_LANGID_CZECH_CZECH_REPUBLIC 0x0405 +#define TT_MS_LANGID_DANISH_DENMARK 0x0406 +#define TT_MS_LANGID_GERMAN_GERMANY 0x0407 +#define TT_MS_LANGID_GERMAN_SWITZERLAND 0x0807 +#define TT_MS_LANGID_GERMAN_AUSTRIA 0x0c07 +#define TT_MS_LANGID_GERMAN_LUXEMBOURG 0x1007 +#define TT_MS_LANGID_GERMAN_LIECHTENSTEI 0x1407 +#define TT_MS_LANGID_GREEK_GREECE 0x0408 +#define TT_MS_LANGID_ENGLISH_UNITED_STATES 0x0409 +#define TT_MS_LANGID_ENGLISH_UNITED_KINGDOM 0x0809 +#define TT_MS_LANGID_ENGLISH_AUSTRALIA 0x0c09 +#define TT_MS_LANGID_ENGLISH_CANADA 0x1009 +#define TT_MS_LANGID_ENGLISH_NEW_ZEALAND 0x1409 +#define TT_MS_LANGID_ENGLISH_IRELAND 0x1809 +#define TT_MS_LANGID_ENGLISH_SOUTH_AFRICA 0x1c09 +#define TT_MS_LANGID_ENGLISH_JAMAICA 0x2009 +#define TT_MS_LANGID_ENGLISH_CARIBBEAN 0x2409 +#define TT_MS_LANGID_ENGLISH_BELIZE 0x2809 +#define TT_MS_LANGID_ENGLISH_TRINIDAD 0x2c09 +#define TT_MS_LANGID_ENGLISH_ZIMBABWE 0x3009 +#define TT_MS_LANGID_ENGLISH_PHILIPPINES 0x3409 +#define TT_MS_LANGID_SPANISH_SPAIN_TRADITIONAL_SORT 0x040a +#define TT_MS_LANGID_SPANISH_MEXICO 0x080a +#define TT_MS_LANGID_SPANISH_SPAIN_INTERNATIONAL_SORT 0x0c0a +#define TT_MS_LANGID_SPANISH_GUATEMALA 0x100a +#define TT_MS_LANGID_SPANISH_COSTA_RICA 0x140a +#define TT_MS_LANGID_SPANISH_PANAMA 0x180a +#define TT_MS_LANGID_SPANISH_DOMINICAN_REPUBLIC 0x1c0a +#define TT_MS_LANGID_SPANISH_VENEZUELA 0x200a +#define TT_MS_LANGID_SPANISH_COLOMBIA 0x240a +#define TT_MS_LANGID_SPANISH_PERU 0x280a +#define TT_MS_LANGID_SPANISH_ARGENTINA 0x2c0a +#define TT_MS_LANGID_SPANISH_ECUADOR 0x300a +#define TT_MS_LANGID_SPANISH_CHILE 0x340a +#define TT_MS_LANGID_SPANISH_URUGUAY 0x380a +#define TT_MS_LANGID_SPANISH_PARAGUAY 0x3c0a +#define TT_MS_LANGID_SPANISH_BOLIVIA 0x400a +#define TT_MS_LANGID_SPANISH_EL_SALVADOR 0x440a +#define TT_MS_LANGID_SPANISH_HONDURAS 0x480a +#define TT_MS_LANGID_SPANISH_NICARAGUA 0x4c0a +#define TT_MS_LANGID_SPANISH_PUERTO_RICO 0x500a +#define TT_MS_LANGID_FINNISH_FINLAND 0x040b +#define TT_MS_LANGID_FRENCH_FRANCE 0x040c +#define TT_MS_LANGID_FRENCH_BELGIUM 0x080c +#define TT_MS_LANGID_FRENCH_CANADA 0x0c0c +#define TT_MS_LANGID_FRENCH_SWITZERLAND 0x100c +#define TT_MS_LANGID_FRENCH_LUXEMBOURG 0x140c +#define TT_MS_LANGID_FRENCH_MONACO 0x180c +#define TT_MS_LANGID_HEBREW_ISRAEL 0x040d +#define TT_MS_LANGID_HUNGARIAN_HUNGARY 0x040e +#define TT_MS_LANGID_ICELANDIC_ICELAND 0x040f +#define TT_MS_LANGID_ITALIAN_ITALY 0x0410 +#define TT_MS_LANGID_ITALIAN_SWITZERLAND 0x0810 +#define TT_MS_LANGID_JAPANESE_JAPAN 0x0411 +#define TT_MS_LANGID_KOREAN_EXTENDED_WANSUNG_KOREA 0x0412 +#define TT_MS_LANGID_KOREAN_JOHAB_KOREA 0x0812 +#define TT_MS_LANGID_DUTCH_NETHERLANDS 0x0413 +#define TT_MS_LANGID_DUTCH_BELGIUM 0x0813 +#define TT_MS_LANGID_NORWEGIAN_NORWAY_BOKMAL 0x0414 +#define TT_MS_LANGID_NORWEGIAN_NORWAY_NYNORSK 0x0814 +#define TT_MS_LANGID_POLISH_POLAND 0x0415 +#define TT_MS_LANGID_PORTUGUESE_BRAZIL 0x0416 +#define TT_MS_LANGID_PORTUGUESE_PORTUGAL 0x0816 +#define TT_MS_LANGID_RHAETO_ROMANIC_SWITZERLAND 0x0417 +#define TT_MS_LANGID_ROMANIAN_ROMANIA 0x0418 +#define TT_MS_LANGID_MOLDAVIAN_MOLDAVIA 0x0818 +#define TT_MS_LANGID_RUSSIAN_RUSSIA 0x0419 +#define TT_MS_LANGID_RUSSIAN_MOLDAVIA 0x0819 +#define TT_MS_LANGID_CROATIAN_CROATIA 0x041a +#define TT_MS_LANGID_SERBIAN_SERBIA_LATIN 0x081a +#define TT_MS_LANGID_SERBIAN_SERBIA_CYRILLIC 0x0c1a +#define TT_MS_LANGID_SLOVAK_SLOVAKIA 0x041b +#define TT_MS_LANGID_ALBANIAN_ALBANIA 0x041c +#define TT_MS_LANGID_SWEDISH_SWEDEN 0x041d +#define TT_MS_LANGID_SWEDISH_FINLAND 0x081d +#define TT_MS_LANGID_THAI_THAILAND 0x041e +#define TT_MS_LANGID_TURKISH_TURKEY 0x041f +#define TT_MS_LANGID_URDU_PAKISTAN 0x0420 +#define TT_MS_LANGID_INDONESIAN_INDONESIA 0x0421 +#define TT_MS_LANGID_UKRAINIAN_UKRAINE 0x0422 +#define TT_MS_LANGID_BELARUSIAN_BELARUS 0x0423 +#define TT_MS_LANGID_SLOVENE_SLOVENIA 0x0424 +#define TT_MS_LANGID_ESTONIAN_ESTONIA 0x0425 +#define TT_MS_LANGID_LATVIAN_LATVIA 0x0426 +#define TT_MS_LANGID_LITHUANIAN_LITHUANIA 0x0427 +#define TT_MS_LANGID_CLASSIC_LITHUANIAN_LITHUANIA 0x0827 +#define TT_MS_LANGID_MAORI_NEW_ZEALAND 0x0428 +#define TT_MS_LANGID_FARSI_IRAN 0x0429 +#define TT_MS_LANGID_VIETNAMESE_VIET_NAM 0x042a +#define TT_MS_LANGID_ARMENIAN_ARMENIA 0x042b +#define TT_MS_LANGID_AZERI_AZERBAIJAN_LATIN 0x042c +#define TT_MS_LANGID_AZERI_AZERBAIJAN_CYRILLIC 0x082c +#define TT_MS_LANGID_BASQUE_SPAIN 0x042d +#define TT_MS_LANGID_SORBIAN_GERMANY 0x042e +#define TT_MS_LANGID_MACEDONIAN_MACEDONIA 0x042f +#define TT_MS_LANGID_SUTU_SOUTH_AFRICA 0x0430 +#define TT_MS_LANGID_TSONGA_SOUTH_AFRICA 0x0431 +#define TT_MS_LANGID_TSWANA_SOUTH_AFRICA 0x0432 +#define TT_MS_LANGID_VENDA_SOUTH_AFRICA 0x0433 +#define TT_MS_LANGID_XHOSA_SOUTH_AFRICA 0x0434 +#define TT_MS_LANGID_ZULU_SOUTH_AFRICA 0x0435 +#define TT_MS_LANGID_AFRIKAANS_SOUTH_AFRICA 0x0436 +#define TT_MS_LANGID_GEORGIAN_GEORGIA 0x0437 +#define TT_MS_LANGID_FAEROESE_FAEROE_ISLANDS 0x0438 +#define TT_MS_LANGID_HINDI_INDIA 0x0439 +#define TT_MS_LANGID_MALTESE_MALTA 0x043a +#define TT_MS_LANGID_SAAMI_LAPONIA 0x043b +#define TT_MS_LANGID_IRISH_GAELIC_IRELAND 0x043c +#define TT_MS_LANGID_SCOTTISH_GAELIC_UNITED_KINGDOM 0x083c +#define TT_MS_LANGID_MALAY_MALAYSIA 0x043e +#define TT_MS_LANGID_MALAY_BRUNEI_DARUSSALAM 0x083e +#define TT_MS_LANGID_KAZAK_KAZAKSTAN 0x043f +#define TT_MS_LANGID_SWAHILI_KENYA 0x0441 +#define TT_MS_LANGID_UZBEK_UZBEKISTAN_LATIN 0x0443 +#define TT_MS_LANGID_UZBEK_UZBEKISTAN_CYRILLIC 0x0843 +#define TT_MS_LANGID_TATAR_TATARSTAN 0x0444 +#define TT_MS_LANGID_BENGALI_INDIA 0x0445 +#define TT_MS_LANGID_PUNJABI_INDIA 0x0446 +#define TT_MS_LANGID_GUJARATI_INDIA 0x0447 +#define TT_MS_LANGID_ORIYA_INDIA 0x0448 +#define TT_MS_LANGID_TAMIL_INDIA 0x0449 +#define TT_MS_LANGID_TELUGU_INDIA 0x044a +#define TT_MS_LANGID_KANNADA_INDIA 0x044b +#define TT_MS_LANGID_MALAYALAM_INDIA 0x044c +#define TT_MS_LANGID_ASSAMESE_INDIA 0x044d +#define TT_MS_LANGID_MARATHI_INDIA 0x044e +#define TT_MS_LANGID_SANSKRIT_INDIA 0x044f +#define TT_MS_LANGID_KONKANI_INDIA 0x0457 + + + /*************************************************************************/ + /* */ + /* Possible values of the `name' identifier field in the name records of */ + /* the TTF `name' table. These values are platform independent. */ + /* */ +#define TT_NAME_ID_COPYRIGHT 0 +#define TT_NAME_ID_FONT_FAMILY 1 +#define TT_NAME_ID_FONT_SUBFAMILY 2 +#define TT_NAME_ID_UNIQUE_ID 3 +#define TT_NAME_ID_FULL_NAME 4 +#define TT_NAME_ID_VERSION_STRING 5 +#define TT_NAME_ID_PS_NAME 6 +#define TT_NAME_ID_TRADEMARK 7 + +/* the following values are from the OpenType spec */ +#define TT_NAME_ID_MANUFACTURER 8 +#define TT_NAME_ID_DESIGNER 9 +#define TT_NAME_ID_DESCRIPTION 10 +#define TT_NAME_ID_VENDOR_URL 11 +#define TT_NAME_ID_DESIGNER_URL 12 +#define TT_NAME_ID_LICENSE 13 +#define TT_NAME_ID_LICENSE_URL 14 +/* number 15 is reserved */ +#define TT_NAME_ID_PREFERRED_FAMILY 16 +#define TT_NAME_ID_PREFERRED_SUBFAMILY 17 +#define TT_NAME_ID_MAC_FULL_NAME 18 + +/* The following code is new as of 2000-01-21 */ +#define TT_NAME_ID_SAMPLE_TEXT 19 + + + /*************************************************************************/ + /* */ + /* Bit mask values for the Unicode Ranges from the TTF `OS2 ' table. */ + /* */ + /* Updated 02-Jul-2000. */ + /* */ + + /* General Scripts Area */ + + /* Bit 0 C0 Controls and Basic Latin */ +#define TT_UCR_BASIC_LATIN (1L << 0) /* U+0020-U+007E */ + /* Bit 1 C1 Controls and Latin-1 Supplement */ +#define TT_UCR_LATIN1_SUPPLEMENT (1L << 1) /* U+00A0-U+00FF */ + /* Bit 2 Latin Extended-A */ +#define TT_UCR_LATIN_EXTENDED_A (1L << 2) /* U+0100-U+017F */ + /* Bit 3 Latin Extended-B */ +#define TT_UCR_LATIN_EXTENDED_B (1L << 3) /* U+0180-U+024F */ + /* Bit 4 IPA Extensions */ +#define TT_UCR_IPA_EXTENSIONS (1L << 4) /* U+0250-U+02AF */ + /* Bit 5 Spacing Modifier Letters */ +#define TT_UCR_SPACING_MODIFIER (1L << 5) /* U+02B0-U+02FF */ + /* Bit 6 Combining Diacritical Marks */ +#define TT_UCR_COMBINING_DIACRITICS (1L << 6) /* U+0300-U+036F */ + /* Bit 7 Greek */ +#define TT_UCR_GREEK (1L << 7) /* U+0370-U+03FF */ + /* Bit 8 is reserved (was: Greek Symbols and Coptic) */ + /* Bit 9 Cyrillic */ +#define TT_UCR_CYRILLIC (1L << 9) /* U+0400-U+04FF */ + /* Bit 10 Armenian */ +#define TT_UCR_ARMENIAN (1L << 10) /* U+0530-U+058F */ + /* Bit 11 Hebrew */ +#define TT_UCR_HEBREW (1L << 11) /* U+0590-U+05FF */ + /* Bit 12 is reserved (was: Hebrew Extended) */ + /* Bit 13 Arabic */ +#define TT_UCR_ARABIC (1L << 13) /* U+0600-U+06FF */ + /* Bit 14 is reserved (was: Arabic Extended) */ + /* Bit 15 Devanagari */ +#define TT_UCR_DEVANAGARI (1L << 15) /* U+0900-U+097F */ + /* Bit 16 Bengali */ +#define TT_UCR_BENGALI (1L << 16) /* U+0980-U+09FF */ + /* Bit 17 Gurmukhi */ +#define TT_UCR_GURMUKHI (1L << 17) /* U+0A00-U+0A7F */ + /* Bit 18 Gujarati */ +#define TT_UCR_GUJARATI (1L << 18) /* U+0A80-U+0AFF */ + /* Bit 19 Oriya */ +#define TT_UCR_ORIYA (1L << 19) /* U+0B00-U+0B7F */ + /* Bit 20 Tamil */ +#define TT_UCR_TAMIL (1L << 20) /* U+0B80-U+0BFF */ + /* Bit 21 Telugu */ +#define TT_UCR_TELUGU (1L << 21) /* U+0C00-U+0C7F */ + /* Bit 22 Kannada */ +#define TT_UCR_KANNADA (1L << 22) /* U+0C80-U+0CFF */ + /* Bit 23 Malayalam */ +#define TT_UCR_MALAYALAM (1L << 23) /* U+0D00-U+0D7F */ + /* Bit 24 Thai */ +#define TT_UCR_THAI (1L << 24) /* U+0E00-U+0E7F */ + /* Bit 25 Lao */ +#define TT_UCR_LAO (1L << 25) /* U+0E80-U+0EFF */ + /* Bit 26 Georgian */ +#define TT_UCR_GEORGIAN (1L << 26) /* U+10A0-U+10FF */ + /* Bit 27 is reserved (was Georgian Extended) */ + /* Bit 28 Hangul Jamo */ +#define TT_UCR_HANGUL_JAMO (1L << 28) /* U+1100-U+11FF */ + /* Bit 29 Latin Extended Additional */ +#define TT_UCR_LATIN_EXTENDED_ADDITIONAL (1L << 29) /* U+1E00-U+1EFF */ + /* Bit 30 Greek Extended */ +#define TT_UCR_GREEK_EXTENDED (1L << 30) /* U+1F00-U+1FFF */ + + /* Symbols Area */ + + /* Bit 31 General Punctuation */ +#define TT_UCR_GENERAL_PUNCTUATION (1L << 31) /* U+2000-U+206F */ + /* Bit 32 Superscripts And Subscripts */ +#define TT_UCR_SUPERSCRIPTS_SUBSCRIPTS (1L << 0) /* U+2070-U+209F */ + /* Bit 33 Currency Symbols */ +#define TT_UCR_CURRENCY_SYMBOLS (1L << 1) /* U+20A0-U+20CF */ + /* Bit 34 Combining Diacritical Marks For Symbols */ +#define TT_UCR_COMBINING_DIACRITICS_SYMB (1L << 2) /* U+20D0-U+20FF */ + /* Bit 35 Letterlike Symbols */ +#define TT_UCR_LETTERLIKE_SYMBOLS (1L << 3) /* U+2100-U+214F */ + /* Bit 36 Number Forms */ +#define TT_UCR_NUMBER_FORMS (1L << 4) /* U+2150-U+218F */ + /* Bit 37 Arrows */ +#define TT_UCR_ARROWS (1L << 5) /* U+2190-U+21FF */ + /* Bit 38 Mathematical Operators */ +#define TT_UCR_MATHEMATICAL_OPERATORS (1L << 6) /* U+2200-U+22FF */ + /* Bit 39 Miscellaneous Technical */ +#define TT_UCR_MISCELLANEOUS_TECHNICAL (1L << 7) /* U+2300-U+23FF */ + /* Bit 40 Control Pictures */ +#define TT_UCR_CONTROL_PICTURES (1L << 8) /* U+2400-U+243F */ + /* Bit 41 Optical Character Recognition */ +#define TT_UCR_OCR (1L << 9) /* U+2440-U+245F */ + /* Bit 42 Enclosed Alphanumerics */ +#define TT_UCR_ENCLOSED_ALPHANUMERICS (1L << 10) /* U+2460-U+24FF */ + /* Bit 43 Box Drawing */ +#define TT_UCR_BOX_DRAWING (1L << 11) /* U+2500-U+257F */ + /* Bit 44 Block Elements */ +#define TT_UCR_BLOCK_ELEMENTS (1L << 12) /* U+2580-U+259F */ + /* Bit 45 Geometric Shapes */ +#define TT_UCR_GEOMETRIC_SHAPES (1L << 13) /* U+25A0-U+25FF */ + /* Bit 46 Miscellaneous Symbols */ +#define TT_UCR_MISCELLANEOUS_SYMBOLS (1L << 14) /* U+2600-U+26FF */ + /* Bit 47 Dingbats */ +#define TT_UCR_DINGBATS (1L << 15) /* U+2700-U+27BF */ + + /* CJK Phonetics and Symbols Area */ + + /* Bit 48 CJK Symbols And Punctuation */ +#define TT_UCR_CJK_SYMBOLS (1L << 16) /* U+3000-U+303F */ + /* Bit 49 Hiragana */ +#define TT_UCR_HIRAGANA (1L << 17) /* U+3040-U+309F */ + /* Bit 50 Katakana */ +#define TT_UCR_KATAKANA (1L << 18) /* U+30A0-U+30FF */ + /* Bit 51 Bopomofo + Extended Bopomofo */ +#define TT_UCR_BOPOMOFO (1L << 19) /* U+3100-U+312F */ + /* U+31A0-U+31BF */ + /* Bit 52 Hangul Compatibility Jamo */ +#define TT_UCR_HANGUL_COMPATIBILITY_JAMO (1L << 20) /* U+3130-U+318F */ + /* Bit 53 CJK Miscellaneous */ +#define TT_UCR_CJK_MISC (1L << 21) /* U+3190-U+319F */ + /* Bit 54 Enclosed CJK Letters And Months */ +#define TT_UCR_ENCLOSED_CJK_LETTERS_MONTHS (1L << 22) /* U+3200-U+32FF */ + /* Bit 55 CJK Compatibility */ +#define TT_UCR_CJK_COMPATIBILITY (1L << 23) /* U+3300-U+33FF */ + + /* Hangul Syllables Area */ + + /* Bit 56 Hangul */ +#define TT_UCR_HANGUL (1L << 24) /* U+AC00-U+D7A3 */ + + /* Surrogates Area */ + + /* Bit 57 Surrogates */ +#define TT_UCR_SURROGATES (1L << 25) /* U+D800-U+DFFF */ + /* Bit 58 is reserved for Unicode SubRanges */ + + /* CJK Ideographs Area */ + + /* Bit 59 CJK Unified Ideographs + */ + /* CJK Radical Supplement + */ + /* Kangxi Radicals + */ + /* Ideographic Description + */ + /* CJK Unified Ideographs Extension A */ +#define TT_UCR_CJK_UNIFIED_IDEOGRAPHS (1L << 27) /* U+4E00-U+9FFF */ + /* U+2E80-U+2EFF */ + /* U+2F00-U+2FDF */ + /* U+2FF0-U+2FFF */ + /* U+34E0-U+4DB5 */ + + /* Private Use Area */ + + /* Bit 60 Private Use */ +#define TT_UCR_PRIVATE_USE (1L << 28) /* U+E000-U+F8FF */ + + /* Compatibility Area and Specials */ + + /* Bit 61 CJK Compatibility Ideographs */ +#define TT_UCR_CJK_COMPATIBILITY_IDEOGRAPHS (1L << 29) /* U+F900-U+FAFF */ + /* Bit 62 Alphabetic Presentation Forms */ +#define TT_UCR_ALPHABETIC_PRESENTATION_FORMS (1L << 30) /* U+FB00-U+FB4F */ + /* Bit 63 Arabic Presentation Forms-A */ +#define TT_UCR_ARABIC_PRESENTATIONS_A (1L << 31) /* U+FB50-U+FDFF */ + /* Bit 64 Combining Half Marks */ +#define TT_UCR_COMBINING_HALF_MARKS (1L << 0) /* U+FE20-U+FE2F */ + /* Bit 65 CJK Compatibility Forms */ +#define TT_UCR_CJK_COMPATIBILITY_FORMS (1L << 1) /* U+FE30-U+FE4F */ + /* Bit 66 Small Form Variants */ +#define TT_UCR_SMALL_FORM_VARIANTS (1L << 2) /* U+FE50-U+FE6F */ + /* Bit 67 Arabic Presentation Forms-B */ +#define TT_UCR_ARABIC_PRESENTATIONS_B (1L << 3) /* U+FE70-U+FEFE */ + /* Bit 68 Halfwidth And Fullwidth Forms */ +#define TT_UCR_HALFWIDTH_FULLWIDTH_FORMS (1L << 4) /* U+FF00-U+FFEF */ + /* Bit 69 Specials */ +#define TT_UCR_SPECIALS (1L << 5) /* U+FFF0-U+FFFD */ + /* Bit 70 Tibetan */ +#define TT_UCR_TIBETAN (1L << 6) /* U+0F00-U+0FCF */ + /* Bit 71 Syriac */ +#define TT_UCR_SYRIAC (1L << 7) /* U+0700-U+074F */ + /* Bit 72 Thaana */ +#define TT_UCR_THAANA (1L << 8) /* U+0780-U+07BF */ + /* Bit 73 Sinhala */ +#define TT_UCR_SINHALA (1L << 9) /* U+0D80-U+0DFF */ + /* Bit 74 Myanmar */ +#define TT_UCR_MYANMAR (1L << 10) /* U+1000-U+109F */ + /* Bit 75 Ethiopic */ +#define TT_UCR_ETHIOPIC (1L << 11) /* U+1200-U+12BF */ + /* Bit 76 Cherokee */ +#define TT_UCR_CHEROKEE (1L << 12) /* U+13A0-U+13FF */ + /* Bit 77 Canadian Aboriginal Syllabics */ +#define TT_UCR_CANADIAN_ABORIGINAL_SYLLABICS (1L << 13) /* U+1400-U+14DF */ + /* Bit 78 Ogham */ +#define TT_UCR_OGHAM (1L << 14) /* U+1680-U+169F */ + /* Bit 79 Runic */ +#define TT_UCR_RUNIC (1L << 15) /* U+16A0-U+16FF */ + /* Bit 80 Khmer */ +#define TT_UCR_KHMER (1L << 16) /* U+1780-U+17FF */ + /* Bit 81 Mongolian */ +#define TT_UCR_MONGOLIAN (1L << 17) /* U+1800-U+18AF */ + /* Bit 82 Braille */ +#define TT_UCR_BRAILLE (1L << 18) /* U+2800-U+28FF */ + /* Bit 83 Yi + Yi Radicals */ +#define TT_UCR_YI (1L << 19) /* U+A000-U+A48C */ + /* U+A490-U+A4CF */ + + + /*************************************************************************/ + /* */ + /* Some compilers have a very limited length of identifiers. */ + /* */ +#if defined( __TURBOC__ ) && __TURBOC__ < 0x0410 || defined( __PACIFIC__ ) +#define HAVE_LIMIT_ON_IDENTS +#endif + + +#ifndef HAVE_LIMIT_ON_IDENTS + + + /*************************************************************************/ + /* */ + /* Here some alias #defines in order to be clearer. */ + /* */ + /* These are not always #defined to stay within the 31 character limit */ + /* which some compilers have. */ + /* */ + /* Credits go to Dave Hoo for pointing out that modern */ + /* Borland compilers (read: from BC++ 3.1 on) can increase this limit. */ + /* If you get a warning with such a compiler, use the -i40 switch. */ + /* */ +#define TT_UCR_ARABIC_PRESENTATION_FORMS_A \ + TT_UCR_ARABIC_PRESENTATIONS_A +#define TT_UCR_ARABIC_PRESENTATION_FORMS_B \ + TT_UCR_ARABIC_PRESENTATIONS_B + +#define TT_UCR_COMBINING_DIACRITICAL_MARKS \ + TT_UCR_COMBINING_DIACRITICS +#define TT_UCR_COMBINING_DIACRITICAL_MARKS_SYMB \ + TT_UCR_COMBINING_DIACRITICS_SYMB + + +#endif /* !HAVE_LIMIT_ON_IDENTS */ + + +#endif /* TTNAMEID_H */ + + +/* END */ diff --git a/src/freetype/freetype/tttables.h b/src/freetype/freetype/tttables.h new file mode 100644 index 0000000000..27c46f3c99 --- /dev/null +++ b/src/freetype/freetype/tttables.h @@ -0,0 +1,583 @@ +/***************************************************************************/ +/* */ +/* tttables.h */ +/* */ +/* Basic SFNT/TrueType tables definitions and interface */ +/* (specification only). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef TTTABLES_H +#define TTTABLES_H + + +#include + + +#ifdef __cplusplus + extern "C" { +#endif + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Header */ + /* */ + /* */ + /* A structure used to model a TrueType font header table. All */ + /* fields follow the TrueType specification. */ + /* */ + typedef struct TT_Header_ + { + FT_Fixed Table_Version; + FT_Fixed Font_Revision; + + FT_Long CheckSum_Adjust; + FT_Long Magic_Number; + + FT_UShort Flags; + FT_UShort Units_Per_EM; + + FT_Long Created [2]; + FT_Long Modified[2]; + + FT_Short xMin; + FT_Short yMin; + FT_Short xMax; + FT_Short yMax; + + FT_UShort Mac_Style; + FT_UShort Lowest_Rec_PPEM; + + FT_Short Font_Direction; + FT_Short Index_To_Loc_Format; + FT_Short Glyph_Data_Format; + + } TT_Header; + + + /*************************************************************************/ + /* */ + /* */ + /* TT_HoriHeader */ + /* */ + /* */ + /* A structure used to model a TrueType horizontal header, the `hhea' */ + /* table, as well as the corresponding horizontal metrics table, */ + /* i.e., the `hmtx' table. */ + /* */ + /* */ + /* Version :: The table version. */ + /* */ + /* Ascender :: The font's ascender, i.e., the distance */ + /* from the baseline to the top-most of all */ + /* glyph points found in the font. */ + /* */ + /* This value is invalid in many fonts, as */ + /* it is usually set by the font designer, */ + /* and often reflects only a portion of the */ + /* glyphs found in the font (maybe ASCII). */ + /* */ + /* You should use the `sTypoAscender' field */ + /* of the OS/2 table instead if you want */ + /* the correct one. */ + /* */ + /* Descender :: The font's descender, i.e., the distance */ + /* from the baseline to the bottom-most of */ + /* all glyph points found in the font. It */ + /* is negative. */ + /* */ + /* This value is invalid in many fonts, as */ + /* it is usually set by the font designer, */ + /* and often reflects only a portion of the */ + /* glyphs found in the font (maybe ASCII). */ + /* */ + /* You should use the `sTypoDescender' */ + /* field of the OS/2 table instead if you */ + /* want the correct one. */ + /* */ + /* Line_Gap :: The font's line gap, i.e., the distance */ + /* to add to the ascender and descender to */ + /* get the BTB, i.e., the */ + /* baseline-to-baseline distance for the */ + /* font. */ + /* */ + /* advance_Width_Max :: This field is the maximum of all advance */ + /* widths found in the font. It can be */ + /* used to compute the maximum width of an */ + /* arbitrary string of text. */ + /* */ + /* min_Left_Side_Bearing :: The minimum left side bearing of all */ + /* glyphs within the font. */ + /* */ + /* min_Right_Side_Bearing :: The minimum right side bearing of all */ + /* glyphs within the font. */ + /* */ + /* xMax_Extent :: The maximum horizontal extent (i.e., the */ + /* `width' of a glyph's bounding box) for */ + /* all glyphs in the font. */ + /* */ + /* caret_Slope_Rise :: The rise coefficient of the cursor's */ + /* slope of the cursor (slope=rise/run). */ + /* */ + /* caret_Slope_Run :: The run coefficient of the cursor's */ + /* slope. */ + /* */ + /* Reserved :: 10 reserved bytes. */ + /* */ + /* metric_Data_Format :: Always 0. */ + /* */ + /* number_Of_HMetrics :: Number of HMetrics entries in the `hmtx' */ + /* table -- this value can be smaller than */ + /* the total number of glyphs in the font. */ + /* */ + /* long_metrics :: A pointer into the `hmtx' table. */ + /* */ + /* short_metrics :: A pointer into the `hmtx' table. */ + /* */ + /* */ + /* IMPORTANT: The TT_HoriHeader and TT_VertHeader structures should */ + /* be identical except for the names of their fields which */ + /* are different. */ + /* */ + /* This ensures that a single function in the `ttload' */ + /* module is able to read both the horizontal and vertical */ + /* headers. */ + /* */ + typedef struct TT_HoriHeader_ + { + FT_Fixed Version; + FT_Short Ascender; + FT_Short Descender; + FT_Short Line_Gap; + + FT_UShort advance_Width_Max; /* advance width maximum */ + + FT_Short min_Left_Side_Bearing; /* minimum left-sb */ + FT_Short min_Right_Side_Bearing; /* minimum right-sb */ + FT_Short xMax_Extent; /* xmax extents */ + FT_Short caret_Slope_Rise; + FT_Short caret_Slope_Run; + FT_Short caret_Offset; + + FT_Short Reserved[4]; + + FT_Short metric_Data_Format; + FT_UShort number_Of_HMetrics; + + /* The following fields are not defined by the TrueType specification */ + /* but they're used to connect the metrics header to the relevant */ + /* `HMTX' table. */ + + void* long_metrics; + void* short_metrics; + + } TT_HoriHeader; + + + /*************************************************************************/ + /* */ + /* */ + /* TT_VertHeader */ + /* */ + /* */ + /* A structure used to model a TrueType vertical header, the `vhea' */ + /* table, as well as the corresponding vertical metrics table, i.e., */ + /* the `vmtx' table. */ + /* */ + /* */ + /* Version :: The table version. */ + /* */ + /* Ascender :: The font's ascender, i.e., the distance */ + /* from the baseline to the top-most of */ + /* all glyph points found in the font. */ + /* */ + /* This value is invalid in many fonts, as */ + /* it is usually set by the font designer, */ + /* and often reflects only a portion of */ + /* the glyphs found in the font (maybe */ + /* ASCII). */ + /* */ + /* You should use the `sTypoAscender' */ + /* field of the OS/2 table instead if you */ + /* want the correct one. */ + /* */ + /* Descender :: The font's descender, i.e., the */ + /* distance from the baseline to the */ + /* bottom-most of all glyph points found */ + /* in the font. It is negative. */ + /* */ + /* This value is invalid in many fonts, as */ + /* it is usually set by the font designer, */ + /* and often reflects only a portion of */ + /* the glyphs found in the font (maybe */ + /* ASCII). */ + /* */ + /* You should use the `sTypoDescender' */ + /* field of the OS/2 table instead if you */ + /* want the correct one. */ + /* */ + /* Line_Gap :: The font's line gap, i.e., the distance */ + /* to add to the ascender and descender to */ + /* get the BTB, i.e., the */ + /* baseline-to-baseline distance for the */ + /* font. */ + /* */ + /* advance_Height_Max :: This field is the maximum of all */ + /* advance heights found in the font. It */ + /* can be used to compute the maximum */ + /* height of an arbitrary string of text. */ + /* */ + /* min_Top_Side_Bearing :: The minimum top side bearing of all */ + /* glyphs within the font. */ + /* */ + /* min_Bottom_Side_Bearing :: The minimum bottom side bearing of all */ + /* glyphs within the font. */ + /* */ + /* yMax_Extent :: The maximum vertical extent (i.e., the */ + /* `height' of a glyph's bounding box) for */ + /* all glyphs in the font. */ + /* */ + /* caret_Slope_Rise :: The rise coefficient of the cursor's */ + /* slope of the cursor (slope=rise/run). */ + /* */ + /* caret_Slope_Run :: The run coefficient of the cursor's */ + /* slope. */ + /* */ + /* Reserved :: 10 reserved bytes. */ + /* */ + /* metric_Data_Format :: Always 0. */ + /* */ + /* number_Of_HMetrics :: Number of VMetrics entries in the */ + /* `vmtx' table -- this value can be */ + /* smaller than the total number of glyphs */ + /* in the font. */ + /* */ + /* long_metrics :: A pointer into the `vmtx' table. */ + /* */ + /* short_metrics :: A pointer into the `vmtx' table. */ + /* */ + /* */ + /* IMPORTANT: The TT_HoriHeader and TT_VertHeader structures should */ + /* be identical except for the names of their fields which */ + /* are different. */ + /* */ + /* This ensures that a single function in the `ttload' */ + /* module is able to read both the horizontal and vertical */ + /* headers. */ + /* */ + typedef struct TT_VertHeader_ + { + FT_Fixed Version; + FT_Short Ascender; + FT_Short Descender; + FT_Short Line_Gap; + + FT_UShort advance_Height_Max; /* advance height maximum */ + + FT_Short min_Top_Side_Bearing; /* minimum left-sb or top-sb */ + FT_Short min_Bottom_Side_Bearing; /* minimum right-sb or bottom-sb */ + FT_Short yMax_Extent; /* xmax or ymax extents */ + FT_Short caret_Slope_Rise; + FT_Short caret_Slope_Run; + FT_Short caret_Offset; + + FT_Short Reserved[4]; + + FT_Short metric_Data_Format; + FT_UShort number_Of_VMetrics; + + /* The following fields are not defined by the TrueType specification */ + /* but they're used to connect the metrics header to the relevant */ + /* `HMTX' or `VMTX' table. */ + + void* long_metrics; + void* short_metrics; + + } TT_VertHeader; + + + /*************************************************************************/ + /* */ + /* */ + /* TT_OS2 */ + /* */ + /* */ + /* A structure used to model a TrueType OS/2 table. This is the long */ + /* table version. All fields comply to the TrueType specification. */ + /* */ + /* Note that we now support old Mac fonts which do not include an */ + /* OS/2 table. In this case, the `version' field is always set to */ + /* 0xFFFF. */ + /* */ + typedef struct TT_OS2_ + { + FT_UShort version; /* 0x0001 - more or 0xFFFF */ + FT_Short xAvgCharWidth; + FT_UShort usWeightClass; + FT_UShort usWidthClass; + FT_Short fsType; + FT_Short ySubscriptXSize; + FT_Short ySubscriptYSize; + FT_Short ySubscriptXOffset; + FT_Short ySubscriptYOffset; + FT_Short ySuperscriptXSize; + FT_Short ySuperscriptYSize; + FT_Short ySuperscriptXOffset; + FT_Short ySuperscriptYOffset; + FT_Short yStrikeoutSize; + FT_Short yStrikeoutPosition; + FT_Short sFamilyClass; + + FT_Byte panose[10]; + + FT_ULong ulUnicodeRange1; /* Bits 0-31 */ + FT_ULong ulUnicodeRange2; /* Bits 32-63 */ + FT_ULong ulUnicodeRange3; /* Bits 64-95 */ + FT_ULong ulUnicodeRange4; /* Bits 96-127 */ + + FT_Char achVendID[4]; + + FT_UShort fsSelection; + FT_UShort usFirstCharIndex; + FT_UShort usLastCharIndex; + FT_Short sTypoAscender; + FT_Short sTypoDescender; + FT_Short sTypoLineGap; + FT_UShort usWinAscent; + FT_UShort usWinDescent; + + /* only version 1 tables: */ + + FT_ULong ulCodePageRange1; /* Bits 0-31 */ + FT_ULong ulCodePageRange2; /* Bits 32-63 */ + + /* only version 2 tables: */ + + FT_Short sxHeight; + FT_Short sCapHeight; + FT_UShort usDefaultChar; + FT_UShort usBreakChar; + FT_UShort usMaxContext; + + } TT_OS2; + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Postscript */ + /* */ + /* */ + /* A structure used to model a TrueType Postscript table. All fields */ + /* comply to the TrueType table. This structure does not reference */ + /* the Postscript glyph names, which can be nevertheless accessed */ + /* with the `ttpost' module. */ + /* */ + typedef struct TT_Postscript_ + { + FT_Fixed FormatType; + FT_Fixed italicAngle; + FT_Short underlinePosition; + FT_Short underlineThickness; + FT_ULong isFixedPitch; + FT_ULong minMemType42; + FT_ULong maxMemType42; + FT_ULong minMemType1; + FT_ULong maxMemType1; + + /* Glyph names follow in the file, but we don't */ + /* load them by default. See the ttpost.c file. */ + + } TT_Postscript; + + + /*************************************************************************/ + /* */ + /* */ + /* TT_PCLT */ + /* */ + /* */ + /* A structure used to model a TrueType PCLT table. All fields */ + /* comply to the TrueType table. */ + /* */ + typedef struct TT_PCLT_ + { + FT_Fixed Version; + FT_ULong FontNumber; + FT_UShort Pitch; + FT_UShort xHeight; + FT_UShort Style; + FT_UShort TypeFamily; + FT_UShort CapHeight; + FT_UShort SymbolSet; + FT_Char TypeFace[16]; + FT_Char CharacterComplement[8]; + FT_Char FileName[6]; + FT_Char StrokeWeight; + FT_Char WidthType; + FT_Byte SerifStyle; + FT_Byte Reserved; + + } TT_PCLT; + + + /*************************************************************************/ + /* */ + /* */ + /* TT_MaxProfile */ + /* */ + /* */ + /* The maximum profile is a table containing many max values which */ + /* can be used to pre-allocate arrays. This ensures that no memory */ + /* allocation occurs during a glyph load. */ + /* */ + /* */ + /* version :: The version number. */ + /* */ + /* numGlyphs :: The number of glyphs in this TrueType */ + /* font. */ + /* */ + /* maxPoints :: The maximum number of points in a */ + /* non-composite TrueType glyph. See also */ + /* the structure element */ + /* `maxCompositePoints'. */ + /* */ + /* maxContours :: The maximum number of contours in a */ + /* non-composite TrueType glyph. See also */ + /* the structure element */ + /* `maxCompositeContours'. */ + /* */ + /* maxCompositePoints :: The maximum number of points in a */ + /* composite TrueType glyph. See also the */ + /* structure element `maxPoints'. */ + /* */ + /* maxCompositeContours :: The maximum number of contours in a */ + /* composite TrueType glyph. See also the */ + /* structure element `maxContours'. */ + /* */ + /* maxZones :: The maximum number of zones used for */ + /* glyph hinting. */ + /* */ + /* maxTwilightPoints :: The maximum number of points in the */ + /* twilight zone used for glyph hinting. */ + /* */ + /* maxStorage :: The maximum number of elements in the */ + /* storage area used for glyph hinting. */ + /* */ + /* maxFunctionDefs :: The maximum number of function */ + /* definitions in the TrueType bytecode for */ + /* this font. */ + /* */ + /* maxInstructionDefs :: The maximum number of instruction */ + /* definitions in the TrueType bytecode for */ + /* this font. */ + /* */ + /* maxStackElements :: The maximum number of stack elements used */ + /* during bytecode interpretation. */ + /* */ + /* maxSizeOfInstructions :: The maximum number of TrueType opcodes */ + /* used for glyph hinting. */ + /* */ + /* maxComponentElements :: An obscure value related to composite */ + /* glyphs definitions. */ + /* */ + /* maxComponentDepth :: An obscure value related to composite */ + /* glyphs definitions. Probably the maximum */ + /* number of simple glyphs in a composite. */ + /* */ + /* */ + /* This structure is only used during font loading. */ + /* */ + typedef struct TT_MaxProfile_ + { + FT_Fixed version; + FT_UShort numGlyphs; + FT_UShort maxPoints; + FT_UShort maxContours; + FT_UShort maxCompositePoints; + FT_UShort maxCompositeContours; + FT_UShort maxZones; + FT_UShort maxTwilightPoints; + FT_UShort maxStorage; + FT_UShort maxFunctionDefs; + FT_UShort maxInstructionDefs; + FT_UShort maxStackElements; + FT_UShort maxSizeOfInstructions; + FT_UShort maxComponentElements; + FT_UShort maxComponentDepth; + + } TT_MaxProfile; + + + typedef enum + { + ft_sfnt_head = 0, + ft_sfnt_maxp = 1, + ft_sfnt_os2 = 2, + ft_sfnt_hhea = 3, + ft_sfnt_vhea = 4, + ft_sfnt_post = 5, + ft_sfnt_pclt = 6, + + sfnt_max /* don't remove */ + + } FT_Sfnt_Tag; + + + /* internal use only */ + typedef void* (*FT_Get_Sfnt_Table_Func)( FT_Face face, + FT_Sfnt_Tag tag ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Get_Sfnt_Table */ + /* */ + /* */ + /* Returns a pointer to a given SFNT table within a face. */ + /* */ + /* */ + /* face :: A handle to the source. */ + /* */ + /* tag :: The index of the SFNT table. */ + /* */ + /* */ + /* A type-less pointer to the table. This will be 0 in case of */ + /* error, or if the corresponding table was not found *OR* loaded */ + /* from the file. */ + /* */ + /* */ + /* The table is owned by the face object and disappears with it. */ + /* */ + /* This function is only useful to access SFNT tables that are loaded */ + /* by the sfnt/truetype/opentype drivers. See FT_Sfnt_tag for a */ + /* list. */ + /* */ + /* You can load any table using the (internal) SFNT_Interface */ + /* structure -- this is available via FT_Get_Module_Interface(). */ + /* */ + FT_EXPORT_DEF( void* ) FT_Get_Sfnt_Table( FT_Face face, + FT_Sfnt_Tag tag ); + +#ifdef __cplusplus + } +#endif + + +#endif /* TTTABLES_H */ + + +/* END */ diff --git a/src/freetype/freetype/tttags.h b/src/freetype/freetype/tttags.h new file mode 100644 index 0000000000..9de9810e99 --- /dev/null +++ b/src/freetype/freetype/tttags.h @@ -0,0 +1,66 @@ +/***************************************************************************/ +/* */ +/* tttags.h */ +/* */ +/* Tags for TrueType tables (specification only). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef TTAGS_H +#define TTAGS_H + + +#include /* for MAKE_TT_TAG() */ + + +#define TTAG_cmap FT_MAKE_TAG( 'c', 'm', 'a', 'p' ) +#define TTAG_cvt FT_MAKE_TAG( 'c', 'v', 't', ' ' ) +#define TTAG_CFF FT_MAKE_TAG( 'C', 'F', 'F', ' ' ) +#define TTAG_DSIG FT_MAKE_TAG( 'D', 'S', 'I', 'G' ) +#define TTAG_bdat FT_MAKE_TAG( 'b', 'd', 'a', 't' ) +#define TTAG_bloc FT_MAKE_TAG( 'b', 'l', 'o', 'c' ) +#define TTAG_EBDT FT_MAKE_TAG( 'E', 'B', 'D', 'T' ) +#define TTAG_EBLC FT_MAKE_TAG( 'E', 'B', 'L', 'C' ) +#define TTAG_EBSC FT_MAKE_TAG( 'E', 'B', 'S', 'C' ) +#define TTAG_fpgm FT_MAKE_TAG( 'f', 'p', 'g', 'm' ) +#define TTAG_fvar FT_MAKE_TAG( 'f', 'v', 'a', 'r' ) +#define TTAG_gasp FT_MAKE_TAG( 'g', 'a', 's', 'p' ) +#define TTAG_glyf FT_MAKE_TAG( 'g', 'l', 'y', 'f' ) +#define TTAG_GSUB FT_MAKE_TAG( 'G', 'S', 'U', 'B' ) +#define TTAG_hdmx FT_MAKE_TAG( 'h', 'd', 'm', 'x' ) +#define TTAG_head FT_MAKE_TAG( 'h', 'e', 'a', 'd' ) +#define TTAG_hhea FT_MAKE_TAG( 'h', 'h', 'e', 'a' ) +#define TTAG_hmtx FT_MAKE_TAG( 'h', 'm', 't', 'x' ) +#define TTAG_kern FT_MAKE_TAG( 'k', 'e', 'r', 'n' ) +#define TTAG_loca FT_MAKE_TAG( 'l', 'o', 'c', 'a' ) +#define TTAG_LTSH FT_MAKE_TAG( 'L', 'T', 'S', 'H' ) +#define TTAG_maxp FT_MAKE_TAG( 'm', 'a', 'x', 'p' ) +#define TTAG_MMSD FT_MAKE_TAG( 'M', 'M', 'S', 'D' ) +#define TTAG_MMFX FT_MAKE_TAG( 'M', 'M', 'F', 'X' ) +#define TTAG_name FT_MAKE_TAG( 'n', 'a', 'm', 'e' ) +#define TTAG_OS2 FT_MAKE_TAG( 'O', 'S', '/', '2' ) +#define TTAG_OTTO FT_MAKE_TAG( 'O', 'T', 'T', 'O' ) +#define TTAG_PCLT FT_MAKE_TAG( 'P', 'C', 'L', 'T' ) +#define TTAG_post FT_MAKE_TAG( 'p', 'o', 's', 't' ) +#define TTAG_prep FT_MAKE_TAG( 'p', 'r', 'e', 'p' ) +#define TTAG_true FT_MAKE_TAG( 't', 'r', 'u', 'e' ) +#define TTAG_ttc FT_MAKE_TAG( 't', 't', 'c', ' ' ) +#define TTAG_ttcf FT_MAKE_TAG( 't', 't', 'c', 'f' ) +#define TTAG_VDMX FT_MAKE_TAG( 'V', 'D', 'M', 'X' ) +#define TTAG_vhea FT_MAKE_TAG( 'v', 'h', 'e', 'a' ) +#define TTAG_vmtx FT_MAKE_TAG( 'v', 'm', 't', 'x' ) + +#endif /* TTAGS_H */ + + +/* END */ diff --git a/src/freetype/ftconfig.h b/src/freetype/ftconfig.h new file mode 100644 index 0000000000..f21a164bdd --- /dev/null +++ b/src/freetype/ftconfig.h @@ -0,0 +1,168 @@ +/* ftconfig.h. Generated automatically by configure. */ +/***************************************************************************/ +/* */ +/* ftconfig.in */ +/* */ +/* UNIX-specific configuration file (specification only). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + + /*************************************************************************/ + /* */ + /* This header file contains a number of macro definitions that are used */ + /* by the rest of the engine. Most of the macros here are automatically */ + /* determined at compile time, and you should not need to change it to */ + /* port FreeType, except to compile the library with a non-ANSI */ + /* compiler. */ + /* */ + /* Note however that if some specific modifications are needed, we */ + /* advise you to place a modified copy in your build directory. */ + /* */ + /* The build directory is usually `freetype/builds/', and */ + /* contains system-specific files that are always included first when */ + /* building the library. */ + /* */ + /*************************************************************************/ + + +#ifndef FTCONFIG_H +#define FTCONFIG_H + + + /* Include the header file containing all developer build options */ +#include + + + /*************************************************************************/ + /* */ + /* PLATFORM-SPECIFIC CONFIGURATION MACROS */ + /* */ + /* These macros can be toggled to suit a specific system. The current */ + /* ones are defaults used to compile FreeType in an ANSI C environment */ + /* (16bit compilers are also supported). Copy this file to your own */ + /* `freetype/builds/' directory, and edit it to port the engine. */ + /* */ + /*************************************************************************/ + + +#include "wx/setup.h" + +#define FT_SIZEOF_INT SIZEOF_INT +#define FT_SIZEOF_LONG SIZEOF_LONG + + + /* Preferred alignment of data */ +#define FT_ALIGNMENT 8 + + + /* UNUSED is a macro used to indicate that a given parameter is not used */ + /* -- this is only used to get rid of unpleasant compiler warnings */ +#ifndef FT_UNUSED +#define FT_UNUSED( arg ) ( (arg) = (arg) ) +#endif + + + /*************************************************************************/ + /* */ + /* AUTOMATIC CONFIGURATION MACROS */ + /* */ + /* These macros are computed from the ones defined above. Don't touch */ + /* their definition, unless you know precisely what you are doing. No */ + /* porter should need to mess with them. */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* IntN types */ + /* */ + /* Used to guarantee the size of some specific integers. */ + /* */ + typedef signed short FT_Int16; + typedef unsigned short FT_UInt16; + +#if FT_SIZEOF_INT == 4 + + typedef signed int FT_Int32; + typedef unsigned int FT_UInt32; + +#elif FT_SIZEOF_LONG == 4 + + typedef signed long FT_Int32; + typedef unsigned long FT_UInt32; + +#else +#error "no 32bit type found -- please check your configuration files" +#endif + +#if FT_SIZEOF_LONG == 8 + + /* FT_LONG64 must be defined if a 64-bit type is available */ +#define FT_LONG64 +#define FT_INT64 long + +#else + + + /*************************************************************************/ + /* */ + /* Many compilers provide the non-ANSI `long long' 64-bit type. You can */ + /* activate it by defining the FTCALC_USE_LONG_LONG macro in */ + /* `ftoption.h'. */ + /* */ + /* Note that this will produce many -ansi warnings during library */ + /* compilation, and that in many cases, the generated code will be */ + /* neither smaller nor faster! */ + /* */ +#ifdef FTCALC_USE_LONG_LONG + +#define FT_LONG64 +#define FT_INT64 long long + +#endif /* FTCALC_USE_LONG_LONG */ +#endif /* FT_SIZEOF_LONG == 8 */ + + +#ifdef FT_MAKE_OPTION_SINGLE_OBJECT +#define LOCAL_DEF static +#define LOCAL_FUNC static +#else +#define LOCAL_DEF extern +#define LOCAL_FUNC /* nothing */ +#endif + +#ifdef FT_MAKE_OPTION_SINGLE_LIBRARY_OBJECT +#define BASE_DEF( x ) static x +#define BASE_FUNC( x ) static x +#else +#define BASE_DEF( x ) extern x +#define BASE_FUNC( x ) extern x +#endif + +#ifndef FT_EXPORT_DEF +#define FT_EXPORT_DEF( x ) extern x +#endif + +#ifndef FT_EXPORT_FUNC +#define FT_EXPORT_FUNC( x ) extern x +#endif + +#ifndef FT_EXPORT_VAR +#define FT_EXPORT_VAR( x ) extern x +#endif + +#endif /* FTCONFIG_H */ + + +/* END */ diff --git a/src/freetype/macfond/fonddrvr.c b/src/freetype/macfond/fonddrvr.c new file mode 100644 index 0000000000..45a9141649 --- /dev/null +++ b/src/freetype/macfond/fonddrvr.c @@ -0,0 +1,616 @@ +/***************************************************************************/ +/* */ +/* fonddrvr.c */ +/* */ +/* Mac FOND font driver. Written by just@letterror.com. */ +/* */ +/* Copyright 1996-2000 by */ +/* Just van Rossum, David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +/* + Notes + + Mac suitcase files can (and often do!) contain multiple fonts. To + support this I use the face_index argument of FT_(Open|New)_Face() + functions, and pretend the suitcase file is a collection. + Warning: although the FOND driver sets face->num_faces field to the + number of available fonts, but the Type 1 driver sets it to 1 anyway. + So this field is currently not reliable, and I don't see a clean way + to resolve that. The face_index argument translates to + Get1IndResource( 'FOND', face_index + 1 ); + so clients should figure out the resource index of the FOND. + (I'll try to provide some example code for this at some point.) + + The Mac FOND driver works roughly like this: + + - Check whether the offered stream points to a Mac suitcase file. + This is done by checking the file type: it has to be 'FFIL' or 'tfil'. + The stream that gets passed to our init_face() routine is a stdio + stream, which isn't usable for us, since the FOND resources live + in the resource fork. So we just grab the stream->pathname field. + + - Read the FOND resource into memory, then check whether there is + a TrueType font and/or (!) a Type 1 font available. + + - If there is a Type 1 font available (as a separate 'LWFN' file), + read its data into memory, massage it slightly so it becomes + PFB data, wrap it into a memory stream, load the Type 1 driver + and delegate the rest of the work to it, by calling the init_face() + method of the Type 1 driver. + (XXX TODO: after this has been done, the kerning data from the FOND + resource should be appended to the face: on the Mac there are usually + no AFM files available. However, this is tricky since we need to map + Mac char codes to ps glyph names to glyph ID's...) + + - If there is a TrueType font (an 'sfnt' resource), read it into + memory, wrap it into a memory stream, load the TrueType driver + and delegate the rest of the work to it, by calling the init_face() + method if the TrueType driver. + + - In both cases, the original stream gets closed and *reinitialized* + to become a memory stream. Additionally, the face->driver field -- + which is set to the FOND driver upon entering our init_face() -- + gets *reset* to either the TT or the T1 driver. I had to make a minor + change to ftobjs.c to make this work. + + - We might consider creating an FT_New_Face_Mac() API call, as this + would avoid some of the mess described above. +*/ + +#include +#include + +#include +#include +#include + +#include /* for isupper() and isalnum() */ +#include /* for malloc() and free() */ + + +/* set PREFER_LWFN to 1 if LWFN (Type 1) is preferred over + TrueType in case *both* are available */ +#ifndef PREFER_LWFN +#define PREFER_LWFN 1 +#endif + + + static + FT_Error init_driver( FT_Driver driver ) + { + /* we don't keep no stinkin' state ;-) */ + return FT_Err_Ok; + } + + static + FT_Error done_driver( FT_Driver driver ) + { + return FT_Err_Ok; + } + + + /* MacRoman glyph names, needed for FOND kerning support. */ + /* XXX which is not implemented yet! */ + static const char* mac_roman_glyph_names[256] = { + ".null", + }; + + + /* The FOND face object is just a union of TT and T1: both is possible, + and we don't need anything else. We still need to be able to hold + either, as the face object is not allocated by us. Again, creating + an FT_New_Face_Mac() would avoid this kludge. */ + typedef union FOND_FaceRec_ + { + TT_FaceRec tt; + T1_FaceRec t1; + } FOND_FaceRec, *FOND_Face; + + + /* given a pathname, fill in a File Spec */ + static + int make_file_spec( char* pathname, FSSpec *spec ) + { + Str255 p_path; + int path_len; + + /* convert path to a pascal string */ + path_len = strlen( pathname ); + if ( path_len > 255 ) + return -1; + p_path[0] = path_len; + strncpy( (char*)p_path+1, pathname, path_len ); + + if ( FSMakeFSSpec( 0, 0, p_path, spec ) != noErr ) + return -1; + else + return 0; + } + + + /* is_suitcase() returns true if the file specified by 'pathname' + is a Mac suitcase file, and false if it ain't. */ + static + int is_suitcase( FSSpec *spec ) + { + FInfo finfo; + + if ( FSpGetFInfo( spec, &finfo ) != noErr ) + return 0; + if ( finfo.fdType == 'FFIL' || finfo.fdType == 'tfil' ) + return 1; + else + return 0; + } + + + /* Quick 'n' Dirty Pascal string to C string converter. + Warning: this call is not thread safe! Use with caution. */ + static + char * p2c_str( unsigned char *pstr ) + { + static char cstr[256]; + + strncpy( cstr, (char*)pstr+1, pstr[0] ); + cstr[pstr[0]] = '\0'; + return cstr; + } + + + /* Given a PostScript font name, create the Macintosh LWFN file name */ + static + void create_lwfn_name( char* ps_name, Str255 lwfn_file_name ) + { + int max = 5, count = 0; + unsigned char* p = lwfn_file_name; + char* q = ps_name; + + lwfn_file_name[0] = 0; + + while ( *q ) + { + if ( isupper(*q) ) + { + if ( count ) + max = 3; + count = 0; + } + if ( count < max && (isalnum(*q) || *q == '_' ) ) + { + *++p = *q; + lwfn_file_name[0]++; + count++; + } + q++; + } + } + + + /* Suck the relevant info out of the FOND data */ + static + FT_Error parse_fond( char* fond_data, + short *have_sfnt, + short *sfnt_id, + Str255 lwfn_file_name ) + { + AsscEntry* assoc; + FamRec* fond; + + *sfnt_id = *have_sfnt = 0; + lwfn_file_name[0] = 0; + + fond = (FamRec*)fond_data; + assoc = (AsscEntry*)(fond_data + sizeof(FamRec) + 2); + + if ( assoc->fontSize == 0 ) + { + *have_sfnt = 1; + *sfnt_id = assoc->fontID; + } + + if ( fond->ffStylOff ) + { + unsigned char* p = (unsigned char*)fond_data; + StyleTable* style; + unsigned short string_count; + unsigned char* name_table = 0; + char ps_name[256]; + unsigned char* names[64]; + int i; + + p += fond->ffStylOff; + style = (StyleTable*)p; + p += sizeof(StyleTable); + string_count = *(unsigned short*)(p); + p += sizeof(short); + + for ( i=0 ; iindexes[0] > 1 ) + { + unsigned char* suffixes = names[style->indexes[0]-1]; + for ( i=1; i<=suffixes[0]; i++ ) + strcat( ps_name, p2c_str(names[suffixes[i]-1]) ); + } + create_lwfn_name( ps_name, lwfn_file_name ); + } + return FT_Err_Ok; + } + + + /* Read Type 1 data from the POST resources inside the LWFN file, return a + PFB buffer -- apparently FT doesn't like a pure binary T1 stream. */ + static + unsigned char* read_type1_data( FT_Memory memory, FSSpec* lwfn_spec, unsigned long *size ) + { + short res_ref, res_id; + unsigned char *buffer, *p, *size_p; + unsigned long total_size = 0; + unsigned long post_size, pfb_chunk_size; + Handle post_data; + char code, last_code; + + res_ref = FSpOpenResFile( lwfn_spec, fsRdPerm ); + if ( ResError() ) + return NULL; + UseResFile( res_ref ); + + /* first pass: load all POST resources, and determine the size of + the output buffer */ + res_id = 501; + last_code = -1; + for (;;) + { + post_data = Get1Resource( 'POST', res_id++ ); + if ( post_data == NULL ) + break; + code = (*post_data)[0]; + if ( code != last_code ) + { + if ( code == 5 ) + total_size += 2; /* just the end code */ + else + total_size += 6; /* code + 4 bytes chunk length */ + } + total_size += GetHandleSize( post_data ) - 2; + last_code = code; + } + + buffer = memory->alloc( memory, total_size ); + if ( !buffer ) + goto error; + + /* second pass: append all POST data to the buffer, add PFB fields */ + p = buffer; + res_id = 501; + last_code = -1; + pfb_chunk_size = 0; + for (;;) + { + post_data = Get1Resource( 'POST', res_id++ ); + if ( post_data == NULL ) + break; + post_size = GetHandleSize( post_data ) - 2; + code = (*post_data)[0]; + if ( code != last_code ) + { + if ( last_code != -1 ) + { + /* we're done adding a chunk, fill in the size field */ + *size_p++ = pfb_chunk_size & 0xFF; + *size_p++ = (pfb_chunk_size >> 8) & 0xFF; + *size_p++ = (pfb_chunk_size >> 16) & 0xFF; + *size_p++ = (pfb_chunk_size >> 24) & 0xFF; + pfb_chunk_size = 0; + } + *p++ = 0x80; + if ( code == 5 ) + *p++ = 0x03; /* the end */ + else if ( code == 2 ) + *p++ = 0x02; /* binary segment */ + else + *p++ = 0x01; /* ASCII segment */ + if ( code != 5 ) + { + size_p = p; /* save for later */ + p += 4; /* make space for size field */ + } + } + memcpy( p, *post_data + 2, post_size ); + pfb_chunk_size += post_size; + p += post_size; + last_code = code; + } + + CloseResFile( res_ref ); + + *size = total_size; +/* printf( "XXX %d %d\n", p - buffer, total_size ); */ + return buffer; + +error: + CloseResFile( res_ref ); + return NULL; + } + + + /* Finalizer for the sfnt stream */ + static + void sfnt_stream_close( FT_Stream stream ) + { + Handle sfnt_data = stream->descriptor.pointer; + HUnlock( sfnt_data ); + DisposeHandle( sfnt_data ); + + stream->descriptor.pointer = NULL; + stream->size = 0; + stream->base = 0; + stream->close = 0; + } + + + /* Finalizer for the LWFN stream */ + static + void lwfn_stream_close( FT_Stream stream ) + { + stream->memory->free( stream->memory, stream->base ); + stream->descriptor.pointer = NULL; + stream->size = 0; + stream->base = 0; + stream->close = 0; + } + + + /* Main entry point. Determine whether we're dealing with a Mac + suitcase or not; then determine if we're dealing with Type 1 + or TrueType; delegate the work to the proper driver. */ + static + FT_Error init_face( FT_Stream stream, + FT_Face face, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* parameters ) + { + FT_Error err; + FSSpec suit_spec, lwfn_spec; + short res_ref; + Handle fond_data, sfnt_data; + short res_index, sfnt_id, have_sfnt; + Str255 lwfn_file_name; + + if ( !stream->pathname.pointer ) + return FT_Err_Unknown_File_Format; + + if ( make_file_spec( stream->pathname.pointer, &suit_spec ) ) + return FT_Err_Invalid_Argument; + + if ( !is_suitcase( &suit_spec ) ) + return FT_Err_Unknown_File_Format; + + res_ref = FSpOpenResFile( &suit_spec, fsRdPerm ); + if ( ResError() ) + return FT_Err_Invalid_File_Format; + UseResFile( res_ref ); + + /* face_index may be -1, in which case we + just need to do a sanity check */ + if ( face_index < 0) + res_index = 1; + else + { + res_index = face_index + 1; + face_index = 0; + } + fond_data = Get1IndResource( 'FOND', res_index ); + if ( ResError() ) + { + CloseResFile( res_ref ); + return FT_Err_Invalid_File_Format; + } + /* Set the number of faces. Not that it helps much: the t1 driver + just sets it to 1 anyway :-( */ + face->num_faces = Count1Resources('FOND'); + + HLock( fond_data ); + err = parse_fond( *fond_data, &have_sfnt, &sfnt_id, lwfn_file_name ); + HUnlock( fond_data ); + if ( err ) + { + CloseResFile( res_ref ); + return FT_Err_Invalid_Handle; + } + + if ( lwfn_file_name[0] ) + { + /* We look for the LWFN file in the same directory as the suitcase + file. ATM would look in other places, too, but this is the usual + situation. */ + err = FSMakeFSSpec( suit_spec.vRefNum, suit_spec.parID, lwfn_file_name, &lwfn_spec ); + if ( err != noErr ) + lwfn_file_name[0] = 0; /* no LWFN file found */ + } + + if ( lwfn_file_name[0] && ( !have_sfnt || PREFER_LWFN ) ) + { + FT_Driver t1_driver; + unsigned char* type1_data; + unsigned long size; + + CloseResFile( res_ref ); /* XXX still need to read kerning! */ + + type1_data = read_type1_data( stream->memory, &lwfn_spec, &size ); + if ( !type1_data ) + { + return FT_Err_Out_Of_Memory; + } + +#if 0 + { + FILE* f; + char * path; + + path = p2c_str( lwfn_file_name ); + strcat( path, ".PFB" ); + f = fopen(path, "wb"); + if ( f ) + { + fwrite( type1_data, 1, size, f ); + fclose( f ); + } + } +#endif + + /* reinitialize the stream */ + if ( stream->close ) + stream->close( stream ); + stream->close = lwfn_stream_close; + stream->read = 0; /* it's now memory based */ + stream->base = type1_data; + stream->size = size; + stream->pos = 0; /* just in case */ + + /* delegate the work to the Type 1 module */ + t1_driver = (FT_Driver)FT_Get_Module( face->driver->root.library, "type1z" ); + if ( t1_driver ) + { + face->driver = t1_driver; + return t1_driver->clazz->init_face( stream, face, face_index, 0, NULL ); + } + else + return FT_Err_Invalid_Driver_Handle; + } + else if ( have_sfnt ) + { + FT_Driver tt_driver; + + sfnt_data = Get1Resource( 'sfnt', sfnt_id ); + if ( ResError() ) + { + CloseResFile( res_ref ); + return FT_Err_Invalid_Handle; + } + DetachResource( sfnt_data ); + CloseResFile( res_ref ); + HLockHi( sfnt_data ); + + /* reinitialize the stream */ + if ( stream->close ) + stream->close( stream ); + stream->close = sfnt_stream_close; + stream->descriptor.pointer = sfnt_data; + stream->read = 0; /* it's now memory based */ + stream->base = (unsigned char *)*sfnt_data; + stream->size = GetHandleSize( sfnt_data ); + stream->pos = 0; /* just in case */ + + /* delegate the work to the TrueType driver */ + tt_driver = (FT_Driver)FT_Get_Module( face->driver->root.library, "truetype" ); + if ( tt_driver ) + { + face->driver = tt_driver; + return tt_driver->clazz->init_face( stream, face, face_index, 0, NULL ); + } + else + return FT_Err_Invalid_Driver_Handle; + } + else + { + CloseResFile( res_ref ); + } + return FT_Err_Invalid_File_Format; + } + + + static + void done_face( FT_Face face ) + { + /* nothing to do */ + } + + /* The FT_DriverInterface structure is defined in ftdriver.h. */ + + const FT_Driver_Class fond_driver_class = + { + { + ft_module_font_driver | ft_module_driver_scalable, + sizeof ( FT_DriverRec ), + + "fond", /* driver name */ + 0x10000L, /* driver version == 1.0 */ + 0x20000L, /* driver requires FreeType 2.0 or above */ + + (void*)0, + + (FT_Module_Constructor) init_driver, + (FT_Module_Destructor) done_driver, + (FT_Module_Requester) 0 + }, + + sizeof ( FOND_FaceRec ), + 0, + 0, + + (FTDriver_initFace) init_face, + (FTDriver_doneFace) done_face, + (FTDriver_initSize) 0, + (FTDriver_doneSize) 0, + (FTDriver_initGlyphSlot) 0, + (FTDriver_doneGlyphSlot) 0, + + (FTDriver_setCharSizes) 0, + (FTDriver_setPixelSizes) 0, + (FTDriver_loadGlyph) 0, + (FTDriver_getCharIndex) 0, + + (FTDriver_getKerning) 0, + (FTDriver_attachFile) 0, + (FTDriver_getAdvances) 0 + }; + + + + /*************************************************************************/ + /* */ + /* */ + /* getDriverInterface */ + /* */ + /* */ + /* This function is used when compiling the FOND driver as a */ + /* shared library (`.DLL' or `.so'). It will be used by the */ + /* high-level library of FreeType to retrieve the address of the */ + /* driver's generic interface. */ + /* */ + /* It shouldn't be implemented in a static build, as each driver must */ + /* have the same function as an exported entry point. */ + /* */ + /* */ + /* The address of the TrueType's driver generic interface. The */ + /* format-specific interface can then be retrieved through the method */ + /* interface->get_format_interface. */ + /* */ +#ifdef FT_CONFIG_OPTION_DYNAMIC_DRIVERS + + FT_EXPORT_FUNC(const FT_Driver_Class*) getDriverClass( void ) + { + return &fond_driver_class; + } + +#endif /* CONFIG_OPTION_DYNAMIC_DRIVERS */ + + +/* END */ diff --git a/src/freetype/otlayout/oltypes.c b/src/freetype/otlayout/oltypes.c new file mode 100644 index 0000000000..bd2fa2204c --- /dev/null +++ b/src/freetype/otlayout/oltypes.c @@ -0,0 +1,614 @@ +#include + + LOCAL_FUNC + TT_Error OTL_Table_Init( OTL_Table* table, + FT_Memory memory ) + { + MEM_Set( table, 0, sizeof(*table) ); + table->memory = memory; + } + + /* read a script list table */ + /* use with any table */ + LOCAL_FUNC + TT_Error OTL_Table_Set_Scripts( OTL_Table* table, + TT_Byte* bytes, + TT_Long len, + OTL_Type otl_type ) + { + TT_Byte* p; + TT_Byte* start = bytes; + TT_UInt count, max_langs; + TT_Error error; + + /* skip version of the JSTF table */ + if (otl_type == otl_jstf) + start += 4; + + p = start; + + /* we must allocate the script_tags and language_tags arrays */ + /* this requires that we compute the maximum number of languages */ + /* per script.. */ + + count = table->num_scripts = OTL_UShort(p); + max_langs = 0; + for ( ; count > 0; count++ ) + { + TT_Byte* script; + TT_UInt num_langs; + + p += 4; /* skip tag */ + script = bytes + OTL_UShort(p); + + /* skip the baseValues or extenders field of the BASE and JSTF table */ + if (otl_type == otl_type_base || otl_type == otl_type_jstf) + script += 2; + + /* test if there is a default language system */ + if ( OTL_UShort(script) ) + num_langs++; + + /* test other language systems */ + num_langs += OTL_UShort(script); /* add other lang sys */ + + if (num_langs > max_langs) + max_langs = num_langs; + } + + /* good, now allocate the tag arrays */ + if ( !ALLOC_ARRAY( table->script_tags, + table->num_scripts + max_langs, + TT_ULong ) ) + { + table->language_tags = table->script_tags + table->num_scripts; + table->max_languages = max_langs; + table->num_languages = 0; + table->otl_type = otl_type; + + table->scripts_table = bytes; + table->scripts_len = len; + + /* fill the script_tags array */ + { + TT_UInt n; + TT_Byte* p = start + 2; /* skip count */ + + for ( n = 0; n < table->num_scripts; n++ ) + { + table->script_tags[n] = OTL_ULong(p); + p += 2; /* skip offset */ + } + } + } + return error; + } + + + + /* add a features list to the table */ + /* use only with a GSUB or GPOS table */ + LOCAL_FUNC + TT_Error OTL_Table_Set_Features( OTL_Table* table, + TT_Byte* bytes, + TT_Long len ) + { + TT_Error error; + TT_Byte* p = bytes; + TT_UInt count; + + table->max_features = count = OTL_UShort(p); + if ( !ALLOC_ARRAY( table->feature_tags, count, TT_ULong ) && + !ALLOC_ARRAY( table->features, count, TT_Bool ) ) + { + table->features_table = bytes; + table->features_len = len; + } + return error; + } + + + /* add a lookup list to the table */ + /* use only with a GSUB or GPOS table */ + LOCAL_FUNC + TT_Error OTL_Table_Set_Lookups( OTL_Table* table, + TT_Byte* bytes, + TT_Long len ) + { + TT_Error error; + TT_Byte* p = bytes; + TT_UInt count; + + table->max_lookups = count = OTL_UShort(p); + if ( !ALLOC_ARRAY( table->lookups, count, TT_Bool ) ) + { + table->lookups_table = bytes; + table->lookups_len = len; + } + return error; + } + + /* discard table arrays */ + LOCAL_FUNC + void OTL_Table_Done( OTL_Table* table ) + { + FREE( table->scrip_tags ); + FREE( table->language_tags ); + FREE( table->feature_tags ); + FREE( table->lookups ); + } + + + /* return the list of available languages for a given script */ + /* use with any table.. */ + LOCAL_FUNC + void OTL_Get_Languages_List( OTL_Table* table, + TT_ULong script_tag ) + { + TT_UInt n; + TT_Byte* p; + TT_Byte* script = 0; + TT_Byte* start = table->scripts_table; + + if ( table->otl_type == otl_type_jstf ) /* skip version for JSTF */ + start += 4; + + p = start + 6; /* skip count+first tag */ + + for ( n = 0; n < table->num_scripts; n++, p += 6 ) + { + if ( table->script_tags[n] == script_tag ) + { + script = table->scripts_table + OTL_UShort(p); + break; + } + } + + table->cur_script = script; + if (!script) + table->num_languages = 0; + else + { + /* now fill the language_tags array with the appropriate values */ + /* not that we put a '0' tag in front of the list to indicate that */ + /* there is a default language for this script.. */ + TT_ULong* tags = table->language_tags; + + switch (table->otl_type) + { + case otl_type_base: + case otl_type_jstf: + script += 2; /* skip basevalue or extenders */ + /* fall-through */ + + default: + if ( OTL_UShort(script) ) + *tags++ = 0; + } + + count = OTL_UShort(script); + for ( ; count > 0; count-- ) + { + *tags++ = OTL_ULong(script); + script += 2; /* skip offset */ + } + + table->num_langs = tags - table->language_tags; + } + } + + + /* return the list of available features for the current script/language */ + /* use with a GPOS or GSUB script table */ + LOCAL_FUNC + void OTL_Get_Features_List( OTL_Table* table, + TT_ULong language_tag ) + { + TT_UInt n; + TT_Byte* script = table->cur_script; + TT_Byte* language = 0; + TT_UShort offset; + + /* clear feature selection table */ + for ( n = 0; n < table->max_features; n++ ) + table->features[n] = 0; + + /* now, look for the current language */ + if ( language_tag == 0 ) + { + offset = OTL_UShort(script); + if (!offset) return; /* if there is no default language, exit */ + + language = script - 2 + offset; + } + else + { + TT_Byte* p = script + 8; /* skip default+count+1st tag */ + TT_UShort index; + + for ( n = 0; n < table->num_languages; n++, p+=6 ) + { + if ( table->language_tags[n] == language_tag ) + { + language = script + OTL_UShort(p); + break; + } + } + + table->cur_language = language; + if (!language) return; + + p = language + 2; /* skip lookup order */ + index = OTL_UShort(p); /* required feature index */ + if (index != 0xFFFF) + { + if (index < table->max_features) + table->features[index] = 1; + } + + count = OTL_UShort(p); + for ( ; count > 0; count-- ) + { + index = OTL_UShort(p); + if (index < table->max_features) + table->features[index] = 1; + } + } + } + + + /* return the list of lookups for the current features list */ + /* use only with a GSUB or GPOS table */ + LOCAL_FUNC + void OTL_Get_Lookups_List( OTL_Table* table ) + { + TT_UInt n; + TT_Byte* features = table->features_table; + TT_Byte* p = features + 6; /* skip count+1st tag */ + + /* clear lookup list */ + for ( n = 0; n < table->max_lookups; n++ ) + table->lookups[n] = 0; + + /* now, parse the features list */ + for ( n = 0; n < table->features; n++ ) + { + if (table->features[n]) + { + TT_UInt count; + TT_UShort index; + TT_Byte* feature; + + feature = features + OTL_UShort(p); + p += 4; /* skip tag */ + + /* now, select all lookups from this feature */ + count = OTL_UShort(feature); + for ( ; count > 0; count-- ) + { + index = OTL_UShort(feature); + if (index < table->max_lookups) + table->lookups[index] = 1; + } + } + } + } + + + /* find the basevalues and minmax for the current script/language */ + /* only use it with a BASE table.. */ + LOCAL_FUNC + void OTL_Get_Baseline_Values( OTL_Table* table, + TT_ULong language_tag ) + { + TT_Byte* script = table->cur_script; + TT_Byte* p = script; + TT_UShort offset, count; + + table->cur_basevalues = 0; + table->cur_minmax = 0; + + /* read basevalues */ + offset = OTL_UShort(p); + if (offset) + table->cur_basevalues = script + offset; + + offset = OTL_UShort(p); + if (offset) + table->cur_minmax = script + offset; + + count = OTL_UShort(p); + for ( ; count > 0; count-- ) + { + TT_ULong tag; + + tag = OTL_ULong(p); + if ( language_tag == tag ) + { + table->cur_minmax = script + OTL_UShort(p); + break; + } + p += 2; /* skip offset */ + } + } + + + /* compute the coverage value of a given glyph id */ + LOCAL_FUNC + TT_Long OTL_Get_Coverage_Index( TT_Byte* coverage, + TT_UInt glyph_id ) + { + TT_Long result = -1; + TT_UInt count, index, start, end; + TT_Byte* p = coverage; + + switch ( OTL_UShort(p) ) + { + case 1: /* coverage format 1 - array of glyph indices */ + { + count = OTL_UShort(p); + for ( index = 0; index < count; index++ ) + { + if ( OTL_UShort(p) == glyph_id ) + { + result = index; + break; + } + } + } + break; + + case 2: + { + count = OTL_UShort(p); + for ( ; count > 0; count-- ) + { + start = OTL_UShort(p); + end = OTL_UShort(p); + index = OTL_UShort(p); + if (start <= glyph_id && glyph_id <= end) + { + result = glyph_id - start + index; + break; + } + } + } + break; + } + return result; + } + + + /* compute the class value of a given glyph_id */ + LOCAL_FUNC + TT_UInt OTL_Get_Glyph_Class( TT_Byte* class_def, + TT_UInt glyph_id ) + { + TT_Byte* p = class_def; + TT_UInt result = 0; + TT_UInt start, end, count, index; + + switch ( OTL_UShort(p) ) + { + case 1: + { + start = OTL_UShort(p); + count = OTL_UShort(p); + + glyph_id -= start; + if (glyph_id < count) + { + p += 2*glyph_id; + result = OTL_UShort(p); + } + } + break; + + case 2: + { + count = OTL_UShort(p); + for ( ; count > 0; count-- ) + { + start = OTL_UShort(p); + end = OTL_UShort(p); + index = OTL_UShort(p); + if ( start <= glyph_id && glyph_id <= end ) + { + result = index; + break; + } + } + } + break; + } + return result; + } + + + /* compute the adjustement necessary for a given device size */ + LOCAL_FUNC + TT_Int OTL_Get_Device_Adjustment( TT_Byte* device, + TT_UInt size ) + { + TT_Byte* p = device; + TT_Int result = 0; + TT_UInt start, end; + TT_Short value; + + start = OTL_UShort(p); + end = OTL_UShort(p); + if (size >= start && size <= end) + { + /* I know we could do all of this without a switch, with */ + /* clever shifts and everything, but it makes the code */ + /* really difficult to understand.. */ + + size -= start; + switch ( OTL_UShort(p) ) + { + case 1: /* 2-bits per value */ + { + p += 2*(size >> 3); + size = (size & 7) << 1; + value = (TT_Short)((TT_Short)OTL_UShort(p) << size); + result = value >> 14; + } + break; + + case 2: /* 4-bits per value */ + { + p += 2*(size >> 2); + size = (size & 3) << 2; + value = (TT_Short)((TT_Short)OTL_UShort(p) << size); + result = value >> 12; + } + break; + + case 3: /* 8-bits per value */ + { + p += 2*(size >> 1); + size = (size & 1) << 3; + value = (TT_Short)((TT_Short)OTL_UShort(p) << size); + result = value >> 8; + } + break; + } + } + return result; + } + + /* extract a BaseCoord value */ + LOCAL_FUNC + void OTL_Get_Base_Coordinate( TT_Byte* base_coord, + OTL_ValueRecord* coord ) + { + TT_Byte* p = base_coord; + TT_Int result = 0; + + coord->format = OTL_UShort(p); + coord->coordinate = OTL_Short(p); + coord->device = 0; + + switch (coord->format) + { + case 2: /* format 2 */ + coord->ref_glyph = OTL_UShort(p); + coord->ref_point = OTL_UShort(p); + break; + + case 3: /* format 3 */ + coord->device = p - 4 + OTL_UShort(p); + break; + + default: + ; + } + } + + + /* compute size of ValueRecord */ + LOCAL_FUNC + TT_Int OTL_ValueRecord_Size( TT_UShort format ) + { + TT_Int count; + + /* each bit in the value format corresponds to a single ushort */ + /* we thus count the bits, and multiply the result by 2 */ + + count = (TT_Int)(format & 0xFF); + count = ((count & 0xAA) >> 1) + (count & 0x55); + count = ((count & 0xCC) >> 2) + (count & 0x33); + count = ((count & 0xF0) >> 4) + (count & 0x0F); + + return count*2; + } + + + + /* extract ValueRecord */ + LOCAL_FUNC + void OTL_Get_ValueRecord( TT_Byte* value_record, + TT_UShort value_format, + TT_Byte* pos_table, + OTL_ValueRecord* record ) + { + TT_Byte* p = value_record; + + /* clear vectors */ + record->placement.x = 0; + record->placement.y = 0; + record->advance.x = 0; + record->advance.y = 0; + + record->device_pla_x = 0; + record->device_pla_y = 0; + record->device_adv_x = 0; + record->device_adv_y = 0; + + if (value_format & 1) record->placement.x = NEXT_Short(p); + if (value_format & 2) record->placement.y = NEXT_Short(p); + if (value_format & 4) record->advance.x = NEXT_Short(p); + if (value_format & 8) record->advance.y = NEXT_Short(p); + + if (value_format & 16) record->device_pla_x = pos_table + NEXT_UShort(p); + if (value_format & 32) record->device_pla_y = pos_table + NEXT_UShort(p); + if (value_format & 64) record->device_adv_x = pos_table + NEXT_UShort(p); + if (value_format & 128) record->device_adv_y = pos_table + NEXT_UShort(p); + } + + + + /* extract Anchor */ + LOCAL_FUNC + void OTL_Get_Anchor( TT_Byte* anchor_table, + OTL_Anchor* anchor ) + { + TT_Byte* p = anchor_table; + + anchor->format = NEXT_UShort(p); + anchor->coord.x = NEXT_Short(p); + anchor->coord.y = NEXT_Short(p); + anchor->point = 0; + anchor->device_x = 0; + anchor->device_y = 0; + + switch (anchor->format) + { + case 2: + anchor->point = NEXT_UShort(p); + break; + + case 3: + anchor->device_x = anchor_table + NEXT_UShort(p); + anchor->device_y = anchor_table + NEXT_UShort(p); + break; + + default: + ; + } + } + + + + /* extract Mark from MarkArray */ + LOCAL_FUNC + void OTL_Get_Mark( TT_Byte* mark_array, + TT_UInt index, + TT_UShort* clazz, + OTL_Anchor* anchor ) + { + TT_Byte* p = mark_array; + TT_UInt count; + + *clazz = 0; + MEM_Set( anchor, 0, sizeof(*anchor) ); + + count = NEXT_UShort(p); + if (index < count) + { + p += 4*index; + *clazz = NEXT_UShort(p); + OTL_Get_Anchor( mark_array + NEXT_UShort(p), anchor ); + } + } + diff --git a/src/freetype/otlayout/oltypes.h b/src/freetype/otlayout/oltypes.h new file mode 100644 index 0000000000..b4a4d802eb --- /dev/null +++ b/src/freetype/otlayout/oltypes.h @@ -0,0 +1,310 @@ +#ifndef OLTYPES_H +#define OLTYPES_H + +#include +#include + + /************************************************************* + * + * OTL_Table + * + * + * The base table of most OpenType Layout sub-tables. + * Provides a simple way to scan a table for script, + * languages, features and lookups.. + * + * + * num_scripts :: number of scripts in table's script list + * script_tags :: array of tags for each table script + * + * max_languages :: max number of languages for any script in + * the table. + * num_languages :: number of languages available for current script + * language_tags :: tags of all languages available for current script. + * + * max_features :: total number of features in table + * feature_tags :: tags of all features for current script/language + * features :: selection flags for all features in current script/lang + * + * max_lookups :: total number of lookups in table + * lookups :: selection flags for all lookups for current + * feature list. + * + ****************************************************************/ + + typedef enum OTL_Type_ + { + otl_type_none = 0, + otl_type_base, + otl_type_gdef, + otl_type_gpos, + otl_type_gsub, + otl_type_jstf + + } OTL_Type; + + + typedef struct OTL_Table_ + { + FT_Memory memory; + + TT_Int num_scripts; + TT_Tag* script_tags; + + TT_Int max_languages; + TT_Int num_languages; + TT_Tag* language_tags; + + TT_Int max_features; + TT_Tag* feature_tags; + TT_Bool* features; + + TT_Int max_lookups; + TT_Bool* lookups; + + TT_Byte* scripts_table; + TT_Long scripts_len; + + TT_Byte* features_table; + TT_Long* features_len; + + TT_Byte* lookups_table; + TT_Byte* lookups_len; + + TT_Byte* cur_script; /* current script */ + TT_Byte* cur_language; /* current language */ + + TT_Byte* cur_base_values; + TT_Byte* cur_min_max; + + OTL_Type otl_type; + + } OTL_Table; + + + typedef struct OTL_BaseCoord_ + { + TT_UShort format; + TT_Short coordinate; + TT_UShort ref_glyph; + TT_UShort ref_point; + TT_Byte* device; + + } OTL_BaseCoord; + + + typedef struct OTL_ValueRecord_ + { + TT_Vector placement; + TT_Vector advance; + + TT_Byte* device_pla_x; + TT_Byte* device_pla_y; + TT_Byte* device_adv_x; + TT_Byte* device_adv_y; + + } OTL_ValueRecord; + + + typedef struct OTL_Anchor_ + { + TT_UInt format; + TT_Vector coord; + TT_UInt anchor_point; + TT_Byte* device_x; + TT_Byte* device_y; + + } OTL_Anchor; + + LOCAL_DEF + TT_Error OTL_Table_Init( OTL_Table* table, + FT_Memory memory ); + + LOCAL_DEF + TT_Error OTL_Table_Set_Scripts( OTL_Table* table, + TT_Byte* bytes, + TT_Long len, + OTL_Type otl_type ); + + LOCAL_DEF + TT_Error OTL_Table_Set_Features( OTL_Table* table, + TT_Byte* bytes, + TT_Long len ); + + LOCAL_DEF + TT_Error OTL_Table_Set_Lookups( OTL_Table* table, + TT_Byte* bytes, + TT_Long len ); + + LOCAL_DEF + void OTL_Table_Done( OTL_Table* table ); + + + +/***************************************************** + * + * Typical uses: + * + * - after OTL_Table_Set_Scripts have been called : + * + * table->script_tags contains the list of tags of all + * scripts defined for this table. + * + * table->num_scripts is the number of scripts + * + */ + +/******************************************************** + * + * - after calling OTL_Table_Set_Features: + * + * table->max_features is the number of all features + * in the table + * + * table->feature_tags is the list of tags of all + * features in the table + * + * table->features[] is an array of boolean used to + * indicate which feature is active for a given script/language + * it is empty (zero-filled) by default. + * + */ + +/******************************************************************* + * + * - after calling OTL_Get_Languages_List(script_tag): + * + * table->num_languages is the number of language systems + * available for the script, including the default + * langsys if there is one + * + * table->language_tags contains the list of tags of all + * languages for the script. Note that the default langsys + * has tag "0" and is always placed first in "language_tags". + * + * + * + */ + LOCAL_DEF + void OTL_Get_Languages_List( OTL_Table* table, + TT_ULong script_tag ); + + +/******************************************************************* + * + * - after calling OTL_Get_Features_List(language_tag): + * + * table->features[] is an array of booleans used to indicate + * which features are active for the current script/language + * + * note that this function must be called after OTL_Get_Languages + * which remembers the last "script_tag" used.. + * + * A client application can change the table->features[] array + * to add or remove features from the list. + * + * + * + */ + LOCAL_DEF + void OTL_Get_Features_List( OTL_Table* table, + TT_ULong language_tag ); + + LOCAL_DEF + void OTL_Get_Baseline_Values( OTL_Table* table, + TT_ULong language_tag ); + + LOCAL_DEF + void OTL_Get_Justification( OTL_Table* table, + TT_ULong language_tag ); + +/******************************************************************* + * + * - after calling OTL_Get_Lookups_List(): + * + * The function uses the table->features[] array of boolean + * to determine which lookups must be processed. + * + * It fills the table->lookups[] array accordingly. It is also + * an array of booleans (one for each lookup). + * + * + */ + + LOCAL_DEF + void OTL_Get_Lookups_List( OTL_Table* table ); + + +/*************************************************************** + * + * So the whole thing looks like: + * + * + * 1. A client specifies a given script and requests available + * language through OTL_Get_Languages_List() + * + * 2. It selects the language tag it needs, then calls + * OTL_Get_Features_List() + * + * 3. It updates the list of active features if it needs to + * + * 4. It calls OTL_Get_Lookups_List() + * It now has a list of active lookups in "table->lookups[]" + * + * 5. The lookups are processed according to the table's type.. + * + */ + + + + + LOCAL_DEF + TT_Long OTL_Get_Coverage_Index( TT_Byte* coverage, + TT_UInt glyph_id ); + + LOCAL_DEF + TT_UInt OTL_Get_Glyph_Class( TT_Byte* class_def, + TT_UInt glyph_id ); + + LOCAL_DEF + TT_Int OTL_Get_Device_Adjustment( TT_Byte* device, + TT_UInt size ); + + LOCAL_DEF + void OTL_Get_Base_Coordinate( TT_Byte* base_coord, + OTL_BaseCoord* coord ); + + + LOCAL_DEF + TT_Int OTL_ValueRecord_Size( TT_UShort value_format ); + + + LOCAL_DEF + void OTL_Get_ValueRecord( TT_Byte* value_record, + TT_UShort value_format, + TT_Byte* pos_table, + OTL_ValueRecord* record ); + + + LOCAL_DEF + void OTL_Get_Anchor( TT_Byte* anchor_table, + OTL_Anchor* anchor ); + + + LOCAL_DEF + void OTL_Get_Mark( TT_Byte* mark_array, + TT_UInt index, + TT_UShort* clazz, + OTL_Anchor* anchor ); + + + +#define OTL_Byte(p) (p++, p[-1]) + +#define OTL_UShort(p) (p+=2, ((TT_UShort)p[-2] << 8) | p[-1]) + +#define OTL_ULong(p) (p+=4, ((TT_ULong)p[-4] << 24) | \ + ((TT_ULong)p[-3] << 16) | \ + ((TT_ULong)p[-2] << 8 ) | p[-1] ) + +#endif /* OLTYPES_H */ diff --git a/src/freetype/psnames/module.mk b/src/freetype/psnames/module.mk new file mode 100644 index 0000000000..3d33c120dd --- /dev/null +++ b/src/freetype/psnames/module.mk @@ -0,0 +1,7 @@ +make_module_list: add_psnames_module + +add_psnames_module: + $(OPEN_DRIVER)psnames_module_class$(CLOSE_DRIVER) + $(ECHO_DRIVER)psnames $(ECHO_DRIVER_DESC)Postscript & Unicode Glyph name handling$(ECHO_DRIVER_DONE) + +# EOF diff --git a/src/freetype/psnames/psmodule.c b/src/freetype/psnames/psmodule.c new file mode 100644 index 0000000000..55ab5dfce0 --- /dev/null +++ b/src/freetype/psnames/psmodule.c @@ -0,0 +1,320 @@ +/***************************************************************************/ +/* */ +/* psmodule.c */ +/* */ +/* PSNames module implementation (body). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#include +#include + + +#ifdef FT_FLAT_COMPILE + +#include "psmodule.h" +#include "pstables.h" + +#else + +#include +#include + +#endif + + +#include /* for qsort() */ +#include /* for strcmp(), strncpy() */ + + +#ifndef FT_CONFIG_OPTION_NO_POSTSCRIPT_NAMES + + + + +#ifdef FT_CONFIG_OPTION_ADOBE_GLYPH_LIST + + + /* return the Unicode value corresponding to a given glyph. Note that */ + /* we do deal with glyph variants by detecting a non-initial dot in */ + /* the name, as in `A.swash' or `e.final', etc. */ + /* */ + static + FT_ULong PS_Unicode_Value( const char* glyph_name ) + { + FT_Int n; + char first = glyph_name[0]; + char temp[64]; + + + /* if the name begins with `uni', then the glyph name may be a */ + /* hard-coded unicode character code. */ + if ( glyph_name[0] == 'u' && + glyph_name[1] == 'n' && + glyph_name[2] == 'i' ) + { + /* determine whether the next four characters following are */ + /* hexadecimal. */ + + /* XXX: Add code to deal with ligatures, i.e. glyph names like */ + /* `uniXXXXYYYYZZZZ'... */ + + FT_Int count; + FT_ULong value = 0; + const char* p = glyph_name + 4; + + + for ( count = 4; count > 0; count--, p++ ) + { + char c = *p; + unsigned char d; + + + d = (unsigned char)c - '0'; + if ( d >= 10 ) + { + d = (unsigned char)c - 'A'; + if ( d >= 6 ) + d = 16; + else + d += 10; + } + + /* exit if a non-uppercase hexadecimal character was found */ + if ( d >= 16 ) + break; + + value = ( value << 4 ) + d; + + if ( count == 0 ) + return value; + } + } + + /* look for a non-initial dot in the glyph name in order to */ + /* sort-out variants like `A.swash', `e.final', etc. */ + { + const char* p; + int len; + + + p = glyph_name; + + while ( *p && *p != '.' ) + p++; + + len = p - glyph_name; + + if ( *p && len < 64 ) + { + strncpy( temp, glyph_name, len ); + temp[len] = 0; + glyph_name = temp; + } + } + + /* now, look up the glyph in the Adobe Glyph List */ + for ( n = 0; n < NUM_ADOBE_GLYPHS; n++ ) + { + const char* name = t1_standard_glyphs[n]; + + + if ( first == name[0] && strcmp( glyph_name, name ) == 0 ) + return names_to_unicode[n]; + } + + /* not found, there is probably no Unicode value for this glyph name */ + return 0; + } + + + /* qsort callback to sort the unicode map */ + static + int compare_uni_maps( const void* a, + const void* b ) + { + PS_UniMap* map1 = (PS_UniMap*)a; + PS_UniMap* map2 = (PS_UniMap*)b; + + + return ( map1->unicode - map2->unicode ); + } + + + /* Builds a table that maps Unicode values to glyph indices */ + static + FT_Error PS_Build_Unicode_Table( FT_Memory memory, + FT_UInt num_glyphs, + const char** glyph_names, + PS_Unicodes* table ) + { + FT_Error error; + + + /* we first allocate the table */ + table->num_maps = 0; + table->maps = 0; + + if ( !ALLOC_ARRAY( table->maps, num_glyphs, PS_UniMap ) ) + { + FT_UInt n; + FT_UInt count; + PS_UniMap* map; + FT_ULong uni_char; + + + map = table->maps; + + for ( n = 0; n < num_glyphs; n++ ) + { + const char* gname = glyph_names[n]; + + + if ( gname ) + { + uni_char = PS_Unicode_Value( gname ); + + if ( uni_char && uni_char != 0xFFFF ) + { + map->unicode = uni_char; + map->glyph_index = n; + map++; + } + } + } + + /* now, compress the table a bit */ + count = map - table->maps; + + if ( count > 0 && REALLOC( table->maps, + num_glyphs * sizeof ( PS_UniMap ), + count * sizeof ( PS_UniMap ) ) ) + count = 0; + + if ( count == 0 ) + { + FREE( table->maps ); + if ( !error ) + error = FT_Err_Invalid_Argument; /* no unicode chars here! */ + } + else + /* sort the table in increasing order of unicode values */ + qsort( table->maps, count, sizeof ( PS_UniMap ), compare_uni_maps ); + + table->num_maps = count; + } + + return error; + } + + + static + FT_UInt PS_Lookup_Unicode( PS_Unicodes* table, + FT_ULong unicode ) + { + PS_UniMap *min, *max, *mid; + + + /* perform a binary search on the table */ + + min = table->maps; + max = min + table->num_maps - 1; + + while ( min <= max ) + { + mid = min + ( max - min ) / 2; + if ( mid->unicode == unicode ) + return mid->glyph_index; + + if ( min == max ) + break; + + if ( mid->unicode < unicode ) + min = mid + 1; + else + max = mid - 1; + } + + return 0xFFFF; + } + + +#endif /* FT_CONFIG_OPTION_ADOBE_GLYPH_LIST */ + + + static + const char* PS_Macintosh_Name( FT_UInt name_index ) + { + if ( name_index >= 258 ) + name_index = 0; + + return standard_glyph_names[mac_standard_names[name_index]]; + } + + + static + const char* PS_Standard_Strings( FT_UInt sid ) + { + return ( sid < NUM_STD_GLYPHS ? t1_standard_glyphs[sid] : 0 ); + } + + + static const PSNames_Interface psnames_interface = + { +#ifdef FT_CONFIG_OPTION_ADOBE_GLYPH_LIST + + (PS_Unicode_Value_Func) PS_Unicode_Value, + (PS_Build_Unicodes_Func) PS_Build_Unicode_Table, + (PS_Lookup_Unicode_Func) PS_Lookup_Unicode, + +#else + + 0, + 0, + 0, + +#endif /* FT_CONFIG_OPTION_ADOBE_GLYPH_LIST */ + + (PS_Macintosh_Name_Func) PS_Macintosh_Name, + (PS_Adobe_Std_Strings_Func)PS_Standard_Strings, + + t1_standard_encoding, + t1_expert_encoding + }; + + +#endif /* !FT_CONFIG_OPTION_NO_POSTSCRIPT_NAMES */ + + + const FT_Module_Class psnames_module_class = + { + 0, /* this is not a font driver, nor a renderer */ + sizeof( FT_ModuleRec ), + + "psnames", /* driver name */ + 0x10000L, /* driver version */ + 0x20000L, /* driver requires FreeType 2 or above */ + +#ifdef FT_CONFIG_OPTION_NO_POSTSCRIPT_NAMES + 0, +#else + (void*)&psnames_interface, /* module specific interface */ +#endif + + (FT_Module_Constructor)0, + (FT_Module_Destructor) 0, + (FT_Module_Requester) 0 + }; + + +/* END */ diff --git a/src/freetype/psnames/psmodule.h b/src/freetype/psnames/psmodule.h new file mode 100644 index 0000000000..ff7ef06503 --- /dev/null +++ b/src/freetype/psnames/psmodule.h @@ -0,0 +1,29 @@ +/***************************************************************************/ +/* */ +/* psmodule.h */ +/* */ +/* High-level PSNames module interface (specification). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef PSDRIVER_H +#define PSDRIVER_H + +#include + + FT_EXPORT_VAR( const FT_Module_Class ) psnames_module_class; + +#endif /* PSDRIVER_H */ + + +/* END */ diff --git a/src/freetype/psnames/psnames.c b/src/freetype/psnames/psnames.c new file mode 100644 index 0000000000..0491b4814e --- /dev/null +++ b/src/freetype/psnames/psnames.c @@ -0,0 +1,24 @@ +/***************************************************************************/ +/* */ +/* psnames.c */ +/* */ +/* FreeType PSNames module component (body only). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#define FT_MAKE_OPTION_SINGLE_OBJECT + +#include + + +/* END */ diff --git a/src/freetype/psnames/pstables.h b/src/freetype/psnames/pstables.h new file mode 100644 index 0000000000..094bc27c33 --- /dev/null +++ b/src/freetype/psnames/pstables.h @@ -0,0 +1,2942 @@ +/***************************************************************************/ +/* */ +/* pstables.h */ +/* */ +/* PostScript glyph names (specification only). */ +/* */ +/* Copyright 2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + + /* this file has been generated automatically -- do not edit! */ + + + static const char* standard_glyph_names[] = + { + ".null", + "CR", + "notequal", + "infinity", + "lessequal", + "greaterequal", + "partialdiff", + "summation", + "product", + "pi", + "integral", + "Omega", + "radical", + "approxequal", + "Delta", + "nbspace", + "lozenge", + "periodcentered", + "apple", + "lslash", + "franc", + "Gbreve", + "gbreve", + "Idot", + "Scedilla", + "scedilla", + "Cacute", + "cacute", + "Ccaron", + "ccaron", + "dmacron", + ".notdef", + "space", + "exclam", + "quotedbl", + "numbersign", + "dollar", + "percent", + "ampersand", + "quoteright", + "parenleft", + "parenright", + "asterisk", + "plus", + "comma", + "hyphen", + "period", + "slash", + "zero", + "one", + "two", + "three", + "four", + "five", + "six", + "seven", + "eight", + "nine", + "colon", + "semicolon", + "less", + "equal", + "greater", + "question", + "at", + "A", + "B", + "C", + "D", + "E", + "F", + "G", + "H", + "I", + "J", + "K", + "L", + "M", + "N", + "O", + "P", + "Q", + "R", + "S", + "T", + "U", + "V", + "W", + "X", + "Y", + "Z", + "bracketleft", + "backslash", + "bracketright", + "asciicircum", + "underscore", + "quoteleft", + "a", + "b", + "c", + "d", + "e", + "f", + "g", + "h", + "i", + "j", + "k", + "l", + "m", + "n", + "o", + "p", + "q", + "r", + "s", + "t", + "u", + "v", + "w", + "x", + "y", + "z", + "braceleft", + "bar", + "braceright", + "asciitilde", + "exclamdown", + "cent", + "sterling", + "fraction", + "yen", + "florin", + "section", + "currency", + "quotesingle", + "quotedblleft", + "guillemotleft", + "guilsinglleft", + "guilsinglright", + "fi", + "fl", + "endash", + "dagger", + "daggerdbl", + "periodcenter", + "paragraph", + "bullet", + "quotesinglbase", + "quotedblbase", + "quotedblright", + "guillemotright", + "ellipsis", + "perthousand", + "questiondown", + "grave", + "acute", + "circumflex", + "tilde", + "macron", + "breve", + "dotaccent", + "dieresis", + "ring", + "cedilla", + "hungarumlaut", + "ogonek", + "caron", + "emdash", + "AE", + "ordfeminine", + "Lslash", + "Oslash", + "OE", + "ordmasculine", + "ae", + "dotlessi", + "Islash", + "oslash", + "oe", + "germandbls", + "onesuperior", + "logicalnot", + "mu", + "trademark", + "Eth", + "onehalf", + "plusminus", + "Thorn", + "onequarter", + "divide", + "brokenbar", + "degree", + "thorn", + "threequarters", + "twosuperior", + "registered", + "minus", + "eth", + "multiply", + "threesuperior", + "copyright", + "Aacute", + "Acircumflex", + "Adieresis", + "Agrave", + "Aring", + "Atilde", + "Ccedilla", + "Eacute", + "Ecircumflex", + "Edieresis", + "Egrave", + "Iacute", + "Icircumflex", + "Idieresis", + "Igrave", + "Ntilde", + "Oacute", + "Ocircumflex", + "Odieresis", + "Ograve", + "Otilde", + "Scaron", + "Uacute", + "Ucircumflex", + "Udieresis", + "Ugrave", + "Yacute", + "Ydieresis", + "Zcaron", + "aacute", + "acircumflex", + "adieresis", + "agrave", + "aring", + "atilde", + "ccedilla", + "eacute", + "ecircumflex", + "edieresis", + "egrave", + "iacute", + "icircumflex", + "idieresis", + "igrave", + "ntilde", + "oacute", + "ocircumflex", + "odieresis", + "ograve", + "otilde", + "scaron", + "uacute", + "ucircumflex", + "udieresis", + "ugrave", + "yacute", + "ydieresis", + "zcaron", + "exclamsmall", + "Hungarumlautsmall", + "dollaroldstyle", + "dollarsuperior", + "ampersandsmall", + "Acutesmall", + "parenleftsuperior", + "parenrightsuperior", + "twodotenleader", + "onedotenleader", + "zerooldstyle", + "oneoldstyle", + "twooldstyle", + "threeoldstyle", + "fouroldstyle", + "fiveoldstyle", + "sixoldstyle", + "sevenoldstyle", + "eightoldstyle", + "nineoldstyle", + "commasuperior", + "threequartersemdash", + "periodsuperior", + "questionsmall", + "asuperior", + "bsuperior", + "centsuperior", + "dsuperior", + "esuperior", + "isuperior", + "lsuperior", + "msuperior", + "nsuperior", + "osuperior", + "rsuperior", + "ssuperior", + "tsuperior", + "ff", + "ffi", + "ffl", + "parenleftinferior", + "parenrightinferior", + "Circumflexsmall", + "hyphensuperior", + "Gravesmall", + "Asmall", + "Bsmall", + "Csmall", + "Dsmall", + "Esmall", + "Fsmall", + "Gsmall", + "Hsmall", + "Ismall", + "Jsmall", + "Ksmall", + "Lsmall", + "Msmall", + "Nsmall", + "Osmall", + "Psmall", + "Qsmall", + "Rsmall", + "Ssmall", + "Tsmall", + "Usmall", + "Vsmall", + "Wsmall", + "Xsmall", + "Ysmall", + "Zsmall", + "colonmonetary", + "onefitted", + "rupiah", + "Tildesmall", + "exclamdownsmall", + "centoldstyle", + "Lslashsmall", + "Scaronsmall", + "Zcaronsmall", + "Dieresissmall", + "Brevesmall", + "Caronsmall", + "Dotaccentsmall", + "Macronsmall", + "figuredash", + "hypheninferior", + "Ogoneksmall", + "Ringsmall", + "Cedillasmall", + "questiondownsmall", + "oneeighth", + "threeeighths", + "fiveeighths", + "seveneighths", + "onethird", + "twothirds", + "zerosuperior", + "foursuperior", + "fivesuperior", + "sixsuperior", + "sevensuperior", + "eightsuperior", + "ninesuperior", + "zeroinferior", + "oneinferior", + "twoinferior", + "threeinferior", + "fourinferior", + "fiveinferior", + "sixinferior", + "seveninferior", + "eightinferior", + "nineinferior", + "centinferior", + "dollarinferior", + "periodinferior", + "commainferior", + "Agravesmall", + "Aacutesmall", + "Acircumflexsmall", + "Atildesmall", + "Adieresissmall", + "Aringsmall", + "AEsmall", + "Ccedillasmall", + "Egravesmall", + "Eacutesmall", + "Ecircumflexsmall", + "Edieresissmall", + "Igravesmall", + "Iacutesmall", + "Icircumflexsmall", + "Idieresissmall", + "Ethsmall", + "Ntildesmall", + "Ogravesmall", + "Oacutesmall", + "Ocircumflexsmall", + "Otildesmall", + "Odieresissmall", + "OEsmall", + "Oslashsmall", + "Ugravesmall", + "Uacautesmall", + "Ucircumflexsmall", + "Udieresissmall", + "Yacutesmall", + "Thornsmall", + "Ydieresissmall", + "001.000", + "001.001", + "001.002", + "001.003", + "Black", + "Bold", + "Book", + "Light", + "Medium", + "Regular", + "Roman", + "Semibold", + +#ifdef FT_CONFIG_OPTION_ADOBE_GLYPH_LIST + + "AEacute", + "Abreve", + "Acute", + "Alpha", + "Alphatonos", + "Amacron", + "Aogonek", + "Aringacute", + "Beta", + "Caron", + "Ccircumflex", + "Cdotaccent", + "Chi", + "Dcaron", + "Dcroat", + "Dieresis", + "DieresisAcute", + "DieresisGrave", + "Ebreve", + "Ecaron", + "Edotaccent", + "Emacron", + "Eng", + "Eogonek", + "Epsilon", + "Epsilontonos", + "Eta", + "Etatonos", + "Euro", + "Gamma", + "Gcaron", + "Gcircumflex", + "Gcommaaccent", + "Gdotaccent", + "Grave", + "H18533", + "H18543", + "H18551", + "H22073", + "Hbar", + "Hcircumflex", + "Hungarumlaut", + "IJ", + "Ibreve", + "Idotaccent", + "Ifraktur", + "Imacron", + "Iogonek", + "Iota", + "Iotadieresis", + "Iotatonos", + "Itilde", + "Jcircumflex", + "Kappa", + "Kcommaaccent", + "LL", + "Lacute", + "Lambda", + "Lcaron", + "Lcommaaccent", + "Ldot", + "Macron", + "Mu", + "Nacute", + "Ncaron", + "Ncommaaccent", + "Nu", + "Obreve", + "Ohorn", + "Ohungarumlaut", + "Omacron", + "Omegatonos", + "Omicron", + "Omicrontonos", + "Oslashacute", + "Phi", + "Pi", + "Psi", + "Racute", + "Rcaron", + "Rcommaaccent", + "Rfraktur", + "Rho", + "SF010000", + "SF020000", + "SF030000", + "SF040000", + "SF050000", + "SF060000", + "SF070000", + "SF080000", + "SF090000", + "SF100000", + "SF110000", + "SF190000", + "SF200000", + "SF210000", + "SF220000", + "SF230000", + "SF240000", + "SF250000", + "SF260000", + "SF270000", + "SF280000", + "SF360000", + "SF370000", + "SF380000", + "SF390000", + "SF400000", + "SF410000", + "SF420000", + "SF430000", + "SF440000", + "SF450000", + "SF460000", + "SF470000", + "SF480000", + "SF490000", + "SF500000", + "SF510000", + "SF520000", + "SF530000", + "SF540000", + "Sacute", + "Scircumflex", + "Scommaaccent", + "Sigma", + "Tau", + "Tbar", + "Tcaron", + "Tcommaaccent", + "Tcommaaccent", + "Theta", + "Uacutesmall", + "Ubreve", + "Uhorn", + "Uhungarumlaut", + "Umacron", + "Uogonek", + "Upsilon", + "Upsilon1", + "Upsilondieresis", + "Upsilontonos", + "Uring", + "Utilde", + "Wacute", + "Wcircumflex", + "Wdieresis", + "Wgrave", + "Xi", + "Ycircumflex", + "Ygrave", + "Zacute", + "Zdotaccent", + "Zeta", + "abreve", + "acutecomb", + "aeacute", + "afii00208", + "afii10017", + "afii10018", + "afii10019", + "afii10020", + "afii10021", + "afii10022", + "afii10023", + "afii10024", + "afii10025", + "afii10026", + "afii10027", + "afii10028", + "afii10029", + "afii10030", + "afii10031", + "afii10032", + "afii10033", + "afii10034", + "afii10035", + "afii10036", + "afii10037", + "afii10038", + "afii10039", + "afii10040", + "afii10041", + "afii10042", + "afii10043", + "afii10044", + "afii10045", + "afii10046", + "afii10047", + "afii10048", + "afii10049", + "afii10050", + "afii10051", + "afii10052", + "afii10053", + "afii10054", + "afii10055", + "afii10056", + "afii10057", + "afii10058", + "afii10059", + "afii10060", + "afii10061", + "afii10062", + "afii10063", + "afii10064", + "afii10065", + "afii10066", + "afii10067", + "afii10068", + "afii10069", + "afii10070", + "afii10071", + "afii10072", + "afii10073", + "afii10074", + "afii10075", + "afii10076", + "afii10077", + "afii10078", + "afii10079", + "afii10080", + "afii10081", + "afii10082", + "afii10083", + "afii10084", + "afii10085", + "afii10086", + "afii10087", + "afii10088", + "afii10089", + "afii10090", + "afii10091", + "afii10092", + "afii10093", + "afii10094", + "afii10095", + "afii10096", + "afii10097", + "afii10098", + "afii10099", + "afii10100", + "afii10101", + "afii10102", + "afii10103", + "afii10104", + "afii10105", + "afii10106", + "afii10107", + "afii10108", + "afii10109", + "afii10110", + "afii10145", + "afii10146", + "afii10147", + "afii10148", + "afii10192", + "afii10193", + "afii10194", + "afii10195", + "afii10196", + "afii10831", + "afii10832", + "afii10846", + "afii299", + "afii300", + "afii301", + "afii57381", + "afii57388", + "afii57392", + "afii57393", + "afii57394", + "afii57395", + "afii57396", + "afii57397", + "afii57398", + "afii57399", + "afii57400", + "afii57401", + "afii57403", + "afii57407", + "afii57409", + "afii57410", + "afii57411", + "afii57412", + "afii57413", + "afii57414", + "afii57415", + "afii57416", + "afii57417", + "afii57418", + "afii57419", + "afii57420", + "afii57421", + "afii57422", + "afii57423", + "afii57424", + "afii57425", + "afii57426", + "afii57427", + "afii57428", + "afii57429", + "afii57430", + "afii57431", + "afii57432", + "afii57433", + "afii57434", + "afii57440", + "afii57441", + "afii57442", + "afii57443", + "afii57444", + "afii57445", + "afii57446", + "afii57448", + "afii57449", + "afii57450", + "afii57451", + "afii57452", + "afii57453", + "afii57454", + "afii57455", + "afii57456", + "afii57457", + "afii57458", + "afii57470", + "afii57505", + "afii57506", + "afii57507", + "afii57508", + "afii57509", + "afii57511", + "afii57512", + "afii57513", + "afii57514", + "afii57519", + "afii57534", + "afii57636", + "afii57645", + "afii57658", + "afii57664", + "afii57665", + "afii57666", + "afii57667", + "afii57668", + "afii57669", + "afii57670", + "afii57671", + "afii57672", + "afii57673", + "afii57674", + "afii57675", + "afii57676", + "afii57677", + "afii57678", + "afii57679", + "afii57680", + "afii57681", + "afii57682", + "afii57683", + "afii57684", + "afii57685", + "afii57686", + "afii57687", + "afii57688", + "afii57689", + "afii57690", + "afii57694", + "afii57695", + "afii57700", + "afii57705", + "afii57716", + "afii57717", + "afii57718", + "afii57723", + "afii57793", + "afii57794", + "afii57795", + "afii57796", + "afii57797", + "afii57798", + "afii57799", + "afii57800", + "afii57801", + "afii57802", + "afii57803", + "afii57804", + "afii57806", + "afii57807", + "afii57839", + "afii57841", + "afii57842", + "afii57929", + "afii61248", + "afii61289", + "afii61352", + "afii61573", + "afii61574", + "afii61575", + "afii61664", + "afii63167", + "afii64937", + "aleph", + "alpha", + "alphatonos", + "amacron", + "angle", + "angleleft", + "angleright", + "anoteleia", + "aogonek", + "aringacute", + "arrowboth", + "arrowdblboth", + "arrowdbldown", + "arrowdblleft", + "arrowdblright", + "arrowdblup", + "arrowdown", + "arrowhorizex", + "arrowleft", + "arrowright", + "arrowup", + "arrowupdn", + "arrowupdnbse", + "arrowvertex", + "asteriskmath", + "beta", + "block", + "braceex", + "braceleftbt", + "braceleftmid", + "bracelefttp", + "bracerightbt", + "bracerightmid", + "bracerighttp", + "bracketleftbt", + "bracketleftex", + "bracketlefttp", + "bracketrightbt", + "bracketrightex", + "bracketrighttp", + "carriagereturn", + "ccircumflex", + "cdotaccent", + "chi", + "circle", + "circlemultiply", + "circleplus", + "club", + "commaaccent", + "congruent", + "copyrightsans", + "copyrightserif", + "cyrBreve", + "cyrFlex", + "cyrbreve", + "cyrflex", + "dblGrave", + "dblgrave", + "dcaron", + "dcroat", + "delta", + "diamond", + "dieresisacute", + "dieresisgrave", + "dieresistonos", + "dkshade", + "dnblock", + "dong", + "dotbelowcomb", + "dotlessj", + "dotmath", + "ebreve", + "ecaron", + "edotaccent", + "element", + "emacron", + "emptyset", + "eng", + "eogonek", + "epsilon", + "epsilontonos", + "equivalence", + "estimated", + "eta", + "etatonos", + "exclamdbl", + "existential", + "female", + "filledbox", + "filledrect", + "gamma", + "gcaron", + "gcircumflex", + "gcommaaccent", + "gdotaccent", + "gradient", + "gravecomb", + "hbar", + "hcircumflex", + "heart", + "hookabovecomb", + "house", + "ibreve", + "ij", + "imacron", + "integralbt", + "integralex", + "integraltp", + "intersection", + "invbullet", + "invcircle", + "invsmileface", + "iogonek", + "iota", + "iotadieresis", + "iotadieresistonos", + "iotatonos", + "itilde", + "jcircumflex", + "kappa", + "kcommaaccent", + "kgreenlandic", + "lacute", + "lambda", + "lcaron", + "lcommaaccent", + "ldot", + "lfblock", + "lira", + "ll", + "logicaland", + "logicalor", + "longs", + "ltshade", + "male", + "minute", + "musicalnote", + "musicalnotedbl", + "nacute", + "napostrophe", + "ncaron", + "ncommaaccent", + "notelement", + "notsubset", + "nu", + "obreve", + "ohorn", + "ohungarumlaut", + "omacron", + "omega", + "omega1", + "omegatonos", + "omicron", + "omicrontonos", + "openbullet", + "orthogonal", + "oslashacute", + "parenleftbt", + "parenleftex", + "parenlefttp", + "parenrightbt", + "parenrightex", + "parenrighttp", + "perpendicular", + "peseta", + "phi", + "phi1", + "prescription", + "propersubset", + "propersuperset", + "proportional", + "psi", + "quotereversed", + "racute", + "radicalex", + "rcaron", + "rcommaaccent", + "reflexsubset", + "reflexsuperset", + "registersans", + "registerserif", + "revlogicalnot", + "rho", + "rtblock", + "sacute", + "scircumflex", + "scommaaccent", + "second", + "shade", + "sigma", + "sigma1", + "similar", + "smileface", + "spade", + "suchthat", + "sun", + "tau", + "tbar", + "tcaron", + "tcommaaccent", + "tcommaaccent", + "therefore", + "theta", + "theta1", + "tildecomb", + "tonos", + "trademarksans", + "trademarkserif", + "triagdn", + "triaglf", + "triagrt", + "triagup", + "ubreve", + "uhorn", + "uhungarumlaut", + "umacron", + "underscoredbl", + "union", + "universal", + "uogonek", + "upblock", + "upsilon", + "upsilondieresis", + "upsilondieresistonos", + "upsilontonos", + "uring", + "utilde", + "wacute", + "wcircumflex", + "wdieresis", + "weierstrass", + "wgrave", + "xi", + "ycircumflex", + "ygrave", + "zacute", + "zdotaccent", + "zeta", + +#endif /* FT_CONFIG_OPTION_ADOBE_GLYPH_LIST */ + + 0 + }; + + + static const char** t1_standard_glyphs = standard_glyph_names + 31; + + +#define NUM_STD_GLYPHS 391 + +#ifdef FT_CONFIG_OPTION_ADOBE_GLYPH_LIST +#define NUM_ADOBE_GLYPHS 1032 +#else +#define NUM_ADOBE_GLYPHS 391 +#endif + + + static const unsigned short mac_standard_names[259] = + { + 0, + 0, + 1, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 104, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62, + 63, + 64, + 124, + 66, + 67, + 68, + 69, + 70, + 71, + 72, + 73, + 74, + 75, + 76, + 77, + 78, + 79, + 80, + 81, + 82, + 83, + 84, + 85, + 86, + 87, + 88, + 89, + 90, + 91, + 92, + 93, + 94, + 95, + 173, + 175, + 177, + 178, + 186, + 189, + 195, + 200, + 203, + 201, + 202, + 205, + 204, + 206, + 207, + 210, + 208, + 209, + 211, + 214, + 212, + 213, + 215, + 216, + 219, + 217, + 218, + 220, + 222, + 225, + 223, + 224, + 112, + 161, + 97, + 98, + 102, + 116, + 115, + 149, + 165, + 170, + 153, + 125, + 131, + 2, + 138, + 141, + 3, + 156, + 4, + 5, + 100, + 152, + 6, + 7, + 8, + 9, + 10, + 139, + 143, + 11, + 144, + 147, + 123, + 96, + 151, + 12, + 101, + 13, + 14, + 106, + 120, + 121, + 15, + 174, + 176, + 191, + 142, + 148, + 111, + 137, + 105, + 119, + 65, + 8, + 159, + 16, + 227, + 198, + 99, + 103, + 107, + 108, + 109, + 110, + 113, + 17, + 117, + 118, + 122, + 172, + 179, + 171, + 180, + 181, + 182, + 183, + 184, + 185, + 187, + 188, + 18, + 190, + 193, + 194, + 196, + 145, + 126, + 127, + 128, + 129, + 130, + 132, + 133, + 134, + 135, + 136, + 140, + 19, + 192, + 221, + 199, + 228, + 160, + 154, + 167, + 197, + 226, + 157, + 162, + 166, + 168, + 150, + 164, + 169, + 155, + 158, + 163, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 0 + }; + + + + static const unsigned short names_to_unicode[1033] = + { + 0, + 0x0020, + 0x0021, + 0x0022, + 0x0023, + 0x0024, + 0x0025, + 0x0026, + 0x2019, + 0x0028, + 0x0029, + 0x002A, + 0x002B, + 0x002C, + 0x002D, + 0x002E, + 0x002F, + 0x0030, + 0x0031, + 0x0032, + 0x0033, + 0x0034, + 0x0035, + 0x0036, + 0x0037, + 0x0038, + 0x0039, + 0x003A, + 0x003B, + 0x003C, + 0x003D, + 0x003E, + 0x003F, + 0x0040, + 0x0041, + 0x0042, + 0x0043, + 0x0044, + 0x0045, + 0x0046, + 0x0047, + 0x0048, + 0x0049, + 0x004A, + 0x004B, + 0x004C, + 0x004D, + 0x004E, + 0x004F, + 0x0050, + 0x0051, + 0x0052, + 0x0053, + 0x0054, + 0x0055, + 0x0056, + 0x0057, + 0x0058, + 0x0059, + 0x005A, + 0x005B, + 0x005C, + 0x005D, + 0x005E, + 0x005F, + 0x2018, + 0x0061, + 0x0062, + 0x0063, + 0x0064, + 0x0065, + 0x0066, + 0x0067, + 0x0068, + 0x0069, + 0x006A, + 0x006B, + 0x006C, + 0x006D, + 0x006E, + 0x006F, + 0x0070, + 0x0071, + 0x0072, + 0x0073, + 0x0074, + 0x0075, + 0x0076, + 0x0077, + 0x0078, + 0x0079, + 0x007A, + 0x007B, + 0x007C, + 0x007D, + 0x007E, + 0x00A1, + 0x00A2, + 0x00A3, + 0x2044, + 0x00A5, + 0x0192, + 0x00A7, + 0x00A4, + 0x0027, + 0x201C, + 0x00AB, + 0x2039, + 0x203A, + 0xFB01, + 0xFB02, + 0x2013, + 0x2020, + 0x2021, + 0, + 0x00B6, + 0x2022, + 0x201A, + 0x201E, + 0x201D, + 0x00BB, + 0x2026, + 0x2030, + 0x00BF, + 0x0060, + 0x00B4, + 0x02C6, + 0x02DC, + 0x00AF, + 0x02D8, + 0x02D9, + 0x00A8, + 0x02DA, + 0x00B8, + 0x02DD, + 0x02DB, + 0x02C7, + 0x2014, + 0x00C6, + 0x00AA, + 0x0141, + 0x00D8, + 0x0152, + 0x00BA, + 0x00E6, + 0x0131, + 0, + 0x00F8, + 0x0153, + 0x00DF, + 0x00B9, + 0x00AC, + 0x00B5, + 0x2122, + 0x00D0, + 0x00BD, + 0x00B1, + 0x00DE, + 0x00BC, + 0x00F7, + 0x00A6, + 0x00B0, + 0x00FE, + 0x00BE, + 0x00B2, + 0x00AE, + 0x2212, + 0x00F0, + 0x00D7, + 0x00B3, + 0x00A9, + 0x00C1, + 0x00C2, + 0x00C4, + 0x00C0, + 0x00C5, + 0x00C3, + 0x00C7, + 0x00C9, + 0x00CA, + 0x00CB, + 0x00C8, + 0x00CD, + 0x00CE, + 0x00CF, + 0x00CC, + 0x00D1, + 0x00D3, + 0x00D4, + 0x00D6, + 0x00D2, + 0x00D5, + 0x0160, + 0x00DA, + 0x00DB, + 0x00DC, + 0x00D9, + 0x00DD, + 0x0178, + 0x017D, + 0x00E1, + 0x00E2, + 0x00E4, + 0x00E0, + 0x00E5, + 0x00E3, + 0x00E7, + 0x00E9, + 0x00EA, + 0x00EB, + 0x00E8, + 0x00ED, + 0x00EE, + 0x00EF, + 0x00EC, + 0x00F1, + 0x00F3, + 0x00F4, + 0x00F6, + 0x00F2, + 0x00F5, + 0x0161, + 0x00FA, + 0x00FB, + 0x00FC, + 0x00F9, + 0x00FD, + 0x00FF, + 0x017E, + 0xF721, + 0xF6F8, + 0xF724, + 0xF6E4, + 0xF726, + 0xF7B4, + 0x207D, + 0x207E, + 0x2025, + 0x2024, + 0xF730, + 0xF731, + 0xF732, + 0xF733, + 0xF734, + 0xF735, + 0xF736, + 0xF737, + 0xF738, + 0xF739, + 0xF6E2, + 0xF6DE, + 0xF6E8, + 0xF73F, + 0xF6E9, + 0xF6EA, + 0xF6E0, + 0xF6EB, + 0xF6EC, + 0xF6ED, + 0xF6EE, + 0xF6EF, + 0x207F, + 0xF6F0, + 0xF6F1, + 0xF6F2, + 0xF6F3, + 0xFB00, + 0xFB03, + 0xFB04, + 0x208D, + 0x208E, + 0xF6F6, + 0xF6E6, + 0xF760, + 0xF761, + 0xF762, + 0xF763, + 0xF764, + 0xF765, + 0xF766, + 0xF767, + 0xF768, + 0xF769, + 0xF76A, + 0xF76B, + 0xF76C, + 0xF76D, + 0xF76E, + 0xF76F, + 0xF770, + 0xF771, + 0xF772, + 0xF773, + 0xF774, + 0xF775, + 0xF776, + 0xF777, + 0xF778, + 0xF779, + 0xF77A, + 0x20A1, + 0xF6DC, + 0xF6DD, + 0xF6FE, + 0xF7A1, + 0xF7A2, + 0xF6F9, + 0xF6FD, + 0xF6FF, + 0xF7A8, + 0xF6F4, + 0xF6F5, + 0xF6F7, + 0xF7AF, + 0x2012, + 0xF6E5, + 0xF6FB, + 0xF6FC, + 0xF7B8, + 0xF7BF, + 0x215B, + 0x215C, + 0x215D, + 0x215E, + 0x2153, + 0x2154, + 0x2070, + 0x2074, + 0x2075, + 0x2076, + 0x2077, + 0x2078, + 0x2079, + 0x2080, + 0x2081, + 0x2082, + 0x2083, + 0x2084, + 0x2085, + 0x2086, + 0x2087, + 0x2088, + 0x2089, + 0xF6DF, + 0xF6E3, + 0xF6E7, + 0xF6E1, + 0xF7E0, + 0xF7E1, + 0xF7E2, + 0xF7E3, + 0xF7E4, + 0xF7E5, + 0xF7E6, + 0xF7E7, + 0xF7E8, + 0xF7E9, + 0xF7EA, + 0xF7EB, + 0xF7EC, + 0xF7ED, + 0xF7EE, + 0xF7EF, + 0xF7F0, + 0xF7F1, + 0xF7F2, + 0xF7F3, + 0xF7F4, + 0xF7F5, + 0xF7F6, + 0xF6FA, + 0xF7F8, + 0xF7F9, + 0, + 0xF7FB, + 0xF7FC, + 0xF7FD, + 0xF7FE, + 0xF7FF, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + +#ifdef FT_CONFIG_OPTION_ADOBE_GLYPH_LIST + + 0x01FC, + 0x0102, + 0xF6C9, + 0x0391, + 0x0386, + 0x0100, + 0x0104, + 0x01FA, + 0x0392, + 0xF6CA, + 0x0108, + 0x010A, + 0x03A7, + 0x010E, + 0x0110, + 0xF6CB, + 0xF6CC, + 0xF6CD, + 0x0114, + 0x011A, + 0x0116, + 0x0112, + 0x014A, + 0x0118, + 0x0395, + 0x0388, + 0x0397, + 0x0389, + 0x20AC, + 0x0393, + 0x01E6, + 0x011C, + 0x0122, + 0x0120, + 0xF6CE, + 0x25CF, + 0x25AA, + 0x25AB, + 0x25A1, + 0x0126, + 0x0124, + 0xF6CF, + 0x0132, + 0x012C, + 0x0130, + 0x2111, + 0x012A, + 0x012E, + 0x0399, + 0x03AA, + 0x038A, + 0x0128, + 0x0134, + 0x039A, + 0x0136, + 0xF6BF, + 0x0139, + 0x039B, + 0x013D, + 0x013B, + 0x013F, + 0xF6D0, + 0x039C, + 0x0143, + 0x0147, + 0x0145, + 0x039D, + 0x014E, + 0x01A0, + 0x0150, + 0x014C, + 0x038F, + 0x039F, + 0x038C, + 0x01FE, + 0x03A6, + 0x03A0, + 0x03A8, + 0x0154, + 0x0158, + 0x0156, + 0x211C, + 0x03A1, + 0x250C, + 0x2514, + 0x2510, + 0x2518, + 0x253C, + 0x252C, + 0x2534, + 0x251C, + 0x2524, + 0x2500, + 0x2502, + 0x2561, + 0x2562, + 0x2556, + 0x2555, + 0x2563, + 0x2551, + 0x2557, + 0x255D, + 0x255C, + 0x255B, + 0x255E, + 0x255F, + 0x255A, + 0x2554, + 0x2569, + 0x2566, + 0x2560, + 0x2550, + 0x256C, + 0x2567, + 0x2568, + 0x2564, + 0x2565, + 0x2559, + 0x2558, + 0x2552, + 0x2553, + 0x256B, + 0x256A, + 0x015A, + 0x015C, + 0x0218, + 0x03A3, + 0x03A4, + 0x0166, + 0x0164, + 0x0162, + 0x0162, + 0x0398, + 0xF7FA, + 0x016C, + 0x01AF, + 0x0170, + 0x016A, + 0x0172, + 0x03A5, + 0x03D2, + 0x03AB, + 0x038E, + 0x016E, + 0x0168, + 0x1E82, + 0x0174, + 0x1E84, + 0x1E80, + 0x039E, + 0x0176, + 0x1EF2, + 0x0179, + 0x017B, + 0x0396, + 0x0103, + 0x0301, + 0x01FD, + 0x2015, + 0x0410, + 0x0411, + 0x0412, + 0x0413, + 0x0414, + 0x0415, + 0x0401, + 0x0416, + 0x0417, + 0x0418, + 0x0419, + 0x041A, + 0x041B, + 0x041C, + 0x041D, + 0x041E, + 0x041F, + 0x0420, + 0x0421, + 0x0422, + 0x0423, + 0x0424, + 0x0425, + 0x0426, + 0x0427, + 0x0428, + 0x0429, + 0x042A, + 0x042B, + 0x042C, + 0x042D, + 0x042E, + 0x042F, + 0x0490, + 0x0402, + 0x0403, + 0x0404, + 0x0405, + 0x0406, + 0x0407, + 0x0408, + 0x0409, + 0x040A, + 0x040B, + 0x040C, + 0x040E, + 0xF6C4, + 0xF6C5, + 0x0430, + 0x0431, + 0x0432, + 0x0433, + 0x0434, + 0x0435, + 0x0451, + 0x0436, + 0x0437, + 0x0438, + 0x0439, + 0x043A, + 0x043B, + 0x043C, + 0x043D, + 0x043E, + 0x043F, + 0x0440, + 0x0441, + 0x0442, + 0x0443, + 0x0444, + 0x0445, + 0x0446, + 0x0447, + 0x0448, + 0x0449, + 0x044A, + 0x044B, + 0x044C, + 0x044D, + 0x044E, + 0x044F, + 0x0491, + 0x0452, + 0x0453, + 0x0454, + 0x0455, + 0x0456, + 0x0457, + 0x0458, + 0x0459, + 0x045A, + 0x045B, + 0x045C, + 0x045E, + 0x040F, + 0x0462, + 0x0472, + 0x0474, + 0xF6C6, + 0x045F, + 0x0463, + 0x0473, + 0x0475, + 0xF6C7, + 0xF6C8, + 0x04D9, + 0x200E, + 0x200F, + 0x200D, + 0x066A, + 0x060C, + 0x0660, + 0x0661, + 0x0662, + 0x0663, + 0x0664, + 0x0665, + 0x0666, + 0x0667, + 0x0668, + 0x0669, + 0x061B, + 0x061F, + 0x0621, + 0x0622, + 0x0623, + 0x0624, + 0x0625, + 0x0626, + 0x0627, + 0x0628, + 0x0629, + 0x062A, + 0x062B, + 0x062C, + 0x062D, + 0x062E, + 0x062F, + 0x0630, + 0x0631, + 0x0632, + 0x0633, + 0x0634, + 0x0635, + 0x0636, + 0x0637, + 0x0638, + 0x0639, + 0x063A, + 0x0640, + 0x0641, + 0x0642, + 0x0643, + 0x0644, + 0x0645, + 0x0646, + 0x0648, + 0x0649, + 0x064A, + 0x064B, + 0x064C, + 0x064D, + 0x064E, + 0x064F, + 0x0650, + 0x0651, + 0x0652, + 0x0647, + 0x06A4, + 0x067E, + 0x0686, + 0x0698, + 0x06AF, + 0x0679, + 0x0688, + 0x0691, + 0x06BA, + 0x06D2, + 0x06D5, + 0x20AA, + 0x05BE, + 0x05C3, + 0x05D0, + 0x05D1, + 0x05D2, + 0x05D3, + 0x05D4, + 0x05D5, + 0x05D6, + 0x05D7, + 0x05D8, + 0x05D9, + 0x05DA, + 0x05DB, + 0x05DC, + 0x05DD, + 0x05DE, + 0x05DF, + 0x05E0, + 0x05E1, + 0x05E2, + 0x05E3, + 0x05E4, + 0x05E5, + 0x05E6, + 0x05E7, + 0x05E8, + 0x05E9, + 0x05EA, + 0xFB2A, + 0xFB2B, + 0xFB4B, + 0xFB1F, + 0x05F0, + 0x05F1, + 0x05F2, + 0xFB35, + 0x05B4, + 0x05B5, + 0x05B6, + 0x05BB, + 0x05B8, + 0x05B7, + 0x05B0, + 0x05B2, + 0x05B1, + 0x05B3, + 0x05C2, + 0x05C1, + 0x05B9, + 0x05BC, + 0x05BD, + 0x05BF, + 0x05C0, + 0x02BC, + 0x2105, + 0x2113, + 0x2116, + 0x202C, + 0x202D, + 0x202E, + 0x200C, + 0x066D, + 0x02BD, + 0x2135, + 0x03B1, + 0x03AC, + 0x0101, + 0x2220, + 0x2329, + 0x232A, + 0x0387, + 0x0105, + 0x01FB, + 0x2194, + 0x21D4, + 0x21D3, + 0x21D0, + 0x21D2, + 0x21D1, + 0x2193, + 0xF8E7, + 0x2190, + 0x2192, + 0x2191, + 0x2195, + 0x21A8, + 0xF8E6, + 0x2217, + 0x03B2, + 0x2588, + 0xF8F4, + 0xF8F3, + 0xF8F2, + 0xF8F1, + 0xF8FE, + 0xF8FD, + 0xF8FC, + 0xF8F0, + 0xF8EF, + 0xF8EE, + 0xF8FB, + 0xF8FA, + 0xF8F9, + 0x21B5, + 0x0109, + 0x010B, + 0x03C7, + 0x25CB, + 0x2297, + 0x2295, + 0x2663, + 0xF6C3, + 0x2245, + 0xF8E9, + 0xF6D9, + 0xF6D1, + 0xF6D2, + 0xF6D4, + 0xF6D5, + 0xF6D3, + 0xF6D6, + 0x010F, + 0x0111, + 0x03B4, + 0x2666, + 0xF6D7, + 0xF6D8, + 0x0385, + 0x2593, + 0x2584, + 0x20AB, + 0x0323, + 0xF6BE, + 0x22C5, + 0x0115, + 0x011B, + 0x0117, + 0x2208, + 0x0113, + 0x2205, + 0x014B, + 0x0119, + 0x03B5, + 0x03AD, + 0x2261, + 0x212E, + 0x03B7, + 0x03AE, + 0x203C, + 0x2203, + 0x2640, + 0x25A0, + 0x25AC, + 0x03B3, + 0x01E7, + 0x011D, + 0x0123, + 0x0121, + 0x2207, + 0x0300, + 0x0127, + 0x0125, + 0x2665, + 0x0309, + 0x2302, + 0x012D, + 0x0133, + 0x012B, + 0x2321, + 0xF8F5, + 0x2320, + 0x2229, + 0x25D8, + 0x25D9, + 0x263B, + 0x012F, + 0x03B9, + 0x03CA, + 0x0390, + 0x03AF, + 0x0129, + 0x0135, + 0x03BA, + 0x0137, + 0x0138, + 0x013A, + 0x03BB, + 0x013E, + 0x013C, + 0x0140, + 0x258C, + 0x20A4, + 0xF6C0, + 0x2227, + 0x2228, + 0x017F, + 0x2591, + 0x2642, + 0x2032, + 0x266A, + 0x266B, + 0x0144, + 0x0149, + 0x0148, + 0x0146, + 0x2209, + 0x2284, + 0x03BD, + 0x014F, + 0x01A1, + 0x0151, + 0x014D, + 0x03C9, + 0x03D6, + 0x03CE, + 0x03BF, + 0x03CC, + 0x25E6, + 0x221F, + 0x01FF, + 0xF8ED, + 0xF8EC, + 0xF8EB, + 0xF8F8, + 0xF8F7, + 0xF8F6, + 0x22A5, + 0x20A7, + 0x03C6, + 0x03D5, + 0x211E, + 0x2282, + 0x2283, + 0x221D, + 0x03C8, + 0x201B, + 0x0155, + 0xF8E5, + 0x0159, + 0x0157, + 0x2286, + 0x2287, + 0xF8E8, + 0xF6DA, + 0x2310, + 0x03C1, + 0x2590, + 0x015B, + 0x015D, + 0x0219, + 0x2033, + 0x2592, + 0x03C3, + 0x03C2, + 0x223C, + 0x263A, + 0x2660, + 0x220B, + 0x263C, + 0x03C4, + 0x0167, + 0x0165, + 0x0163, + 0x0163, + 0x2234, + 0x03B8, + 0x03D1, + 0x0303, + 0x0384, + 0xF8EA, + 0xF6DB, + 0x25BC, + 0x25C4, + 0x25BA, + 0x25B2, + 0x016D, + 0x01B0, + 0x0171, + 0x016B, + 0x2017, + 0x222A, + 0x2200, + 0x0173, + 0x2580, + 0x03C5, + 0x03CB, + 0x03B0, + 0x03CD, + 0x016F, + 0x0169, + 0x1E83, + 0x0175, + 0x1E85, + 0x2118, + 0x1E81, + 0x03BE, + 0x0177, + 0x1EF3, + 0x017A, + 0x017C, + 0x03B6, + +#endif /* FT_CONFIG_OPTION_ADOBE_GLYPH_LIST */ + 0 + }; + + + + static const unsigned short t1_standard_encoding[257] = + { + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62, + 63, + 64, + 65, + 66, + 67, + 68, + 69, + 70, + 71, + 72, + 73, + 74, + 75, + 76, + 77, + 78, + 79, + 80, + 81, + 82, + 83, + 84, + 85, + 86, + 87, + 88, + 89, + 90, + 91, + 92, + 93, + 94, + 95, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 96, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 106, + 107, + 108, + 109, + 110, + 0, + 111, + 112, + 113, + 114, + 0, + 115, + 116, + 117, + 118, + 119, + 120, + 121, + 122, + 0, + 123, + 0, + 124, + 125, + 126, + 127, + 128, + 129, + 130, + 131, + 0, + 132, + 133, + 0, + 134, + 135, + 136, + 137, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 138, + 0, + 139, + 0, + 0, + 0, + 0, + 140, + 141, + 142, + 143, + 0, + 0, + 0, + 0, + 0, + 144, + 0, + 0, + 0, + 145, + 0, + 0, + 146, + 147, + 148, + 149, + 0, + 0, + 0, + 0, + 0 + }; + + + static const unsigned short t1_expert_encoding[257] = + { + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 229, + 230, + 0, + 231, + 232, + 233, + 234, + 235, + 236, + 237, + 238, + 13, + 14, + 15, + 99, + 239, + 240, + 241, + 242, + 243, + 244, + 245, + 246, + 247, + 248, + 27, + 28, + 249, + 250, + 251, + 252, + 0, + 253, + 254, + 255, + 256, + 257, + 0, + 0, + 0, + 258, + 0, + 0, + 259, + 260, + 261, + 262, + 0, + 0, + 263, + 264, + 265, + 0, + 266, + 109, + 110, + 267, + 268, + 269, + 0, + 270, + 271, + 272, + 273, + 274, + 275, + 276, + 277, + 278, + 279, + 280, + 281, + 282, + 283, + 284, + 285, + 286, + 287, + 288, + 289, + 290, + 291, + 292, + 293, + 294, + 295, + 296, + 297, + 298, + 299, + 300, + 301, + 302, + 303, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 304, + 305, + 306, + 0, + 0, + 307, + 308, + 309, + 310, + 311, + 0, + 312, + 0, + 0, + 312, + 0, + 0, + 314, + 315, + 0, + 0, + 316, + 317, + 318, + 0, + 0, + 0, + 158, + 155, + 163, + 319, + 320, + 321, + 322, + 323, + 324, + 325, + 0, + 0, + 326, + 150, + 164, + 169, + 327, + 328, + 329, + 330, + 331, + 332, + 333, + 334, + 335, + 336, + 337, + 338, + 339, + 340, + 341, + 342, + 343, + 344, + 345, + 346, + 347, + 348, + 349, + 350, + 351, + 352, + 353, + 354, + 355, + 356, + 357, + 358, + 359, + 360, + 361, + 362, + 363, + 364, + 365, + 366, + 367, + 368, + 369, + 370, + 371, + 372, + 373, + 374, + 375, + 376, + 377, + 378, + 0 + }; + + +/* END */ diff --git a/src/freetype/psnames/rules.mk b/src/freetype/psnames/rules.mk new file mode 100644 index 0000000000..25552b2663 --- /dev/null +++ b/src/freetype/psnames/rules.mk @@ -0,0 +1,70 @@ +# +# FreeType 2 PSNames driver configuration rules +# + + +# Copyright 1996-2000 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +# PSNames driver directory +# +PSNAMES_DIR := $(SRC_)psnames +PSNAMES_DIR_ := $(PSNAMES_DIR)$(SEP) + + +# compilation flags for the driver +# +PSNAMES_COMPILE := $(FT_COMPILE) + + +# PSNames driver sources (i.e., C files) +# +PSNAMES_DRV_SRC := $(PSNAMES_DIR_)psmodule.c + + +# PSNames driver headers +# +PSNAMES_DRV_H := $(PSNAMES_DRV_SRC:%.c=%.h) \ + $(PSNAMES_DIR_)pstables.h + + +# PSNames driver object(s) +# +# PSNAMES_DRV_OBJ_M is used during `multi' builds +# PSNAMES_DRV_OBJ_S is used during `single' builds +# +PSNAMES_DRV_OBJ_M := $(PSNAMES_DRV_SRC:$(PSNAMES_DIR_)%.c=$(OBJ_)%.$O) +PSNAMES_DRV_OBJ_S := $(OBJ_)psnames.$O + +# PSNames driver source file for single build +# +PSNAMES_DRV_SRC_S := $(PSNAMES_DIR_)psmodule.c + + +# PSNames driver - single object +# +$(PSNAMES_DRV_OBJ_S): $(PSNAMES_DRV_SRC_S) $(PSNAMES_DRV_SRC) \ + $(FREETYPE_H) $(PSNAMES_DRV_H) + $(PSNAMES_COMPILE) $T$@ $(PSNAMES_DRV_SRC_S) + + +# PSNames driver - multiple objects +# +$(OBJ_)%.$O: $(PSNAMES_DIR_)%.c $(FREETYPE_H) $(PSNAMES_DRV_H) + $(PSNAMES_COMPILE) $T$@ $< + + +# update main driver object lists +# +DRV_OBJS_S += $(PSNAMES_DRV_OBJ_S) +DRV_OBJS_M += $(PSNAMES_DRV_OBJ_M) + + +# EOF diff --git a/src/freetype/raster1/ftraster.c b/src/freetype/raster1/ftraster.c new file mode 100644 index 0000000000..65d04057d7 --- /dev/null +++ b/src/freetype/raster1/ftraster.c @@ -0,0 +1,3300 @@ +/***************************************************************************/ +/* */ +/* ftraster.c */ +/* */ +/* The FreeType glyph rasterizer (body). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + /*************************************************************************/ + /* */ + /* This is a rewrite of the FreeType 1.x scan-line converter */ + /* */ + /*************************************************************************/ + + +#include "ftraster.h" +#include /* for FT_MulDiv() only */ + + + /*************************************************************************/ + /* */ + /* A simple technical note on how the raster works */ + /* ----------------------------------------------- */ + /* */ + /* Converting an outline into a bitmap is achieved in several steps: */ + /* */ + /* 1 - Decomposing the outline into successive `profiles'. Each */ + /* profile is simply an array of scanline intersections on a given */ + /* dimension. A profile's main attributes are */ + /* */ + /* o its scanline position boundaries, i.e. `Ymin' and `Ymax'. */ + /* */ + /* o an array of intersection coordinates for each scanline */ + /* between `Ymin' and `Ymax'. */ + /* */ + /* o a direction, indicating whether it was built going `up' or */ + /* `down', as this is very important for filling rules. */ + /* */ + /* 2 - Sweeping the target map's scanlines in order to compute segment */ + /* `spans' which are then filled. Additionally, this pass */ + /* performs drop-out control. */ + /* */ + /* The outline data is parsed during step 1 only. The profiles are */ + /* built from the bottom of the render pool, used as a stack. The */ + /* following graphics shows the profile list under construction: */ + /* */ + /* ____________________________________________________________ _ _ */ + /* | | | | | */ + /* | profile | coordinates for | profile | coordinates for |--> */ + /* | 1 | profile 1 | 2 | profile 2 |--> */ + /* |_________|___________________|_________|_________________|__ _ _ */ + /* */ + /* ^ ^ */ + /* | | */ + /* start of render pool top */ + /* */ + /* The top of the profile stack is kept in the `top' variable. */ + /* */ + /* As you can see, a profile record is pushed on top of the render */ + /* pool, which is then followed by its coordinates/intersections. If */ + /* a change of direction is detected in the outline, a new profile is */ + /* generated until the end of the outline. */ + /* */ + /* Note that when all profiles have been generated, the function */ + /* Finalize_Profile_Table() is used to record, for each profile, its */ + /* bottom-most scanline as well as the scanline above its upmost */ + /* boundary. These positions are called `y-turns' because they (sort */ + /* of) correspond to local extrema. They are stored in a sorted list */ + /* built from the top of the render pool as a downwards stack: */ + /* */ + /* _ _ _______________________________________ */ + /* | | */ + /* <--| sorted list of | */ + /* <--| extrema scanlines | */ + /* _ _ __________________|____________________| */ + /* */ + /* ^ ^ */ + /* | | */ + /* maxBuff sizeBuff = end of pool */ + /* */ + /* This list is later used during the sweep phase in order to */ + /* optimize performance (see technical note on the sweep below). */ + /* */ + /* Of course, the raster detects whether the two stacks collide and */ + /* handles the situation propertly. */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /*************************************************************************/ + /** **/ + /** CONFIGURATION MACROS **/ + /** **/ + /*************************************************************************/ + /*************************************************************************/ + + /* define DEBUG_RASTER if you want to compile a debugging version */ +#define xxxDEBUG_RASTER + + /* The default render pool size in bytes */ +#define RASTER_RENDER_POOL 8192 + + /* undefine FT_RASTER_OPTION_ANTI_ALIASING if you do not want to support */ + /* 5-levels anti-aliasing */ +#ifdef FT_CONFIG_OPTION_5_GRAY_LEVELS +#define FT_RASTER_OPTION_ANTI_ALIASING +#endif + + /* The size of the two-lines intermediate bitmap used */ + /* for anti-aliasing, in bytes. */ +#define RASTER_GRAY_LINES 2048 + + + /*************************************************************************/ + /*************************************************************************/ + /** **/ + /** OTHER MACROS (do not change) **/ + /** **/ + /*************************************************************************/ + /*************************************************************************/ + + /*************************************************************************/ + /* */ + /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ + /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ + /* messages during execution. */ + /* */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_raster + + +#ifdef _STANDALONE_ + + + /* This macro is used to indicate that a function parameter is unused. */ + /* Its purpose is simply to reduce compiler warnings. Note also that */ + /* simply defining it as `(void)x' doesn't avoid warnings with certain */ + /* ANSI compilers (e.g. LCC). */ +#define FT_UNUSED( x ) (x) = (x) + + /* Disable the tracing mechanism for simplicity -- developers can */ + /* activate it easily by redefining these two macros. */ +#ifndef FT_ERROR +#define FT_ERROR( x ) do ; while ( 0 ) /* nothing */ +#endif + +#ifndef FT_TRACE +#define FT_TRACE( x ) do ; while ( 0 ) /* nothing */ +#endif + +#define Raster_Err_None 0 +#define Raster_Err_Not_Ini -1 +#define Raster_Err_Overflow -2 +#define Raster_Err_Neg_Height -3 +#define Raster_Err_Invalid -4 +#define Raster_Err_Unsupported -5 + + +#else /* _STANDALONE_ */ + + +#include +#include /* for FT_TRACE() and FT_ERROR() */ + +#define Raster_Err_None FT_Err_Ok +#define Raster_Err_Not_Ini FT_Err_Raster_Uninitialized +#define Raster_Err_Overflow FT_Err_Raster_Overflow +#define Raster_Err_Neg_Height FT_Err_Raster_Negative_Height +#define Raster_Err_Invalid FT_Err_Invalid_Outline +#define Raster_Err_Unsupported FT_Err_Unimplemented_Feature + + +#endif /* _STANDALONE_ */ + + + /* FMulDiv means `Fast MulDiv'; it is used in case where `b' is */ + /* typically a small value and the result of a*b is known to fit into */ + /* 32 bits. */ +#define FMulDiv( a, b, c ) ( (a) * (b) / (c) ) + + /* On the other hand, SMulDiv means `Slow MulDiv', and is used typically */ + /* for clipping computations. It simply uses the FT_MulDiv() function */ + /* defined in `ftcalc.h'. */ +#define SMulDiv FT_MulDiv + + /* The rasterizer is a very general purpose component; please leave */ + /* the following redefinitions there (you never know your target */ + /* environment). */ + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef NULL +#define NULL (void*)0 +#endif + +#ifndef SUCCESS +#define SUCCESS 0 +#endif + +#ifndef FAILURE +#define FAILURE 1 +#endif + + +#define MaxBezier 32 /* The maximum number of stacked Bezier curves. */ + /* Setting this constant to more than 32 is a */ + /* pure waste of space. */ + +#define Pixel_Bits 6 /* fractional bits of *input* coordinates */ + + + /*************************************************************************/ + /*************************************************************************/ + /** **/ + /** SIMPLE TYPE DECLARATIONS **/ + /** **/ + /*************************************************************************/ + /*************************************************************************/ + + typedef int Int; + typedef unsigned int UInt; + typedef short Short; + typedef unsigned short UShort, *PUShort; + typedef long Long, *PLong; + typedef unsigned long ULong; + + typedef unsigned char Byte, *PByte; + typedef char Bool; + + typedef struct TPoint_ + { + Long x; + Long y; + + } TPoint; + + + typedef enum TFlow_ + { + Flow_None = 0, + Flow_Up = 1, + Flow_Down = -1 + + } TFlow; + + + /* States of each line, arc, and profile */ + typedef enum TStates_ + { + Unknown, + Ascending, + Descending, + Flat + + } TStates; + + + typedef struct TProfile_ TProfile; + typedef TProfile* PProfile; + + struct TProfile_ + { + FT_F26Dot6 X; /* current coordinate during sweep */ + PProfile link; /* link to next profile - various purpose */ + PLong offset; /* start of profile's data in render pool */ + Int flow; /* Profile orientation: Asc/Descending */ + Long height; /* profile's height in scanlines */ + Long start; /* profile's starting scanline */ + + UShort countL; /* number of lines to step before this */ + /* profile becomes drawable */ + + PProfile next; /* next profile in same contour, used */ + /* during drop-out control */ + }; + + typedef PProfile TProfileList; + typedef PProfile* PProfileList; + + + /* Simple record used to implement a stack of bands, required */ + /* by the sub-banding mechanism */ + typedef struct TBand_ + { + Short y_min; /* band's minimum */ + Short y_max; /* band's maximum */ + + } TBand; + + +#define AlignProfileSize \ + ( ( sizeof ( TProfile ) + sizeof ( long ) - 1 ) / sizeof ( long ) ) + + +#ifdef TT_STATIC_RASTER + + +#define RAS_ARGS /* void */ +#define RAS_ARG /* void */ + +#define RAS_VARS /* void */ +#define RAS_VAR /* void */ + +#define FT_UNUSED_RASTER do ; while ( 0 ) + + +#else /* TT_STATIC_RASTER */ + + +#define RAS_ARGS TRaster_Instance* raster, +#define RAS_ARG TRaster_Instance* raster + +#define RAS_VARS raster, +#define RAS_VAR raster + +#define FT_UNUSED_RASTER FT_UNUSED( raster ) + + +#endif /* TT_STATIC_RASTER */ + + + typedef struct TRaster_Instance_ TRaster_Instance; + + + /* prototypes used for sweep function dispatch */ + typedef void Function_Sweep_Init( RAS_ARGS Short* min, + Short* max ); + + typedef void Function_Sweep_Span( RAS_ARGS Short y, + FT_F26Dot6 x1, + FT_F26Dot6 x2, + PProfile left, + PProfile right ); + + typedef void Function_Sweep_Step( RAS_ARG ); + + + /* NOTE: These operations are only valid on 2's complement processors */ + +#define FLOOR( x ) ( (x) & -ras.precision ) +#define CEILING( x ) ( ( (x) + ras.precision - 1 ) & -ras.precision ) +#define TRUNC( x ) ( (signed long)(x) >> ras.precision_bits ) +#define FRAC( x ) ( (x) & ( ras.precision - 1 ) ) +#define SCALED( x ) ( ( (x) << ras.scale_shift ) - ras.precision_half ) + + /* Note that I have moved the location of some fields in the */ + /* structure to ensure that the most used variables are used */ + /* at the top. Thus, their offset can be coded with less */ + /* opcodes, and it results in a smaller executable. */ + + struct TRaster_Instance_ + { + Int precision_bits; /* precision related variables */ + Int precision; + Int precision_half; + Long precision_mask; + Int precision_shift; + Int precision_step; + Int precision_jitter; + + Int scale_shift; /* == precision_shift for bitmaps */ + /* == precision_shift+1 for pixmaps */ + + PLong buff; /* The profiles buffer */ + PLong sizeBuff; /* Render pool size */ + PLong maxBuff; /* Profiles buffer size */ + PLong top; /* Current cursor in buffer */ + + FT_Error error; + + Int numTurns; /* number of Y-turns in outline */ + + TPoint* arc; /* current Bezier arc pointer */ + + UShort bWidth; /* target bitmap width */ + PByte bTarget; /* target bitmap buffer */ + PByte gTarget; /* target pixmap buffer */ + + Long lastX, lastY, minY, maxY; + + UShort num_Profs; /* current number of profiles */ + + Bool fresh; /* signals a fresh new profile which */ + /* 'start' field must be completed */ + Bool joint; /* signals that the last arc ended */ + /* exactly on a scanline. Allows */ + /* removal of doublets */ + PProfile cProfile; /* current profile */ + PProfile fProfile; /* head of linked list of profiles */ + PProfile gProfile; /* contour's first profile in case */ + /* of impact */ + + TStates state; /* rendering state */ + + FT_Bitmap target; /* description of target bit/pixmap */ + FT_Outline outline; + + Long traceOfs; /* current offset in target bitmap */ + Long traceG; /* current offset in target pixmap */ + + Short traceIncr; /* sweep's increment in target bitmap */ + + Short gray_min_x; /* current min x during gray rendering */ + Short gray_max_x; /* current max x during gray rendering */ + + /* dispatch variables */ + + Function_Sweep_Init* Proc_Sweep_Init; + Function_Sweep_Span* Proc_Sweep_Span; + Function_Sweep_Span* Proc_Sweep_Drop; + Function_Sweep_Step* Proc_Sweep_Step; + + Byte dropOutControl; /* current drop_out control method */ + + Bool second_pass; /* indicates wether a horizontal pass */ + /* should be performed to control */ + /* drop-out accurately when calling */ + /* Render_Glyph. Note that there is */ + /* no horizontal pass during gray */ + /* rendering. */ + + TPoint arcs[2 * MaxBezier + 1]; /* The Bezier stack */ + + TBand band_stack[16]; /* band stack used for sub-banding */ + Int band_top; /* band stack top */ + + Int count_table[256]; /* Look-up table used to quickly count */ + /* set bits in a gray 2x2 cell */ + + void* memory; + +#ifdef FT_RASTER_OPTION_ANTI_ALIASING + + Byte grays[5]; /* Palette of gray levels used for */ + /* render. */ + + Byte gray_lines[RASTER_GRAY_LINES]; + /* Intermediate table used to render the */ + /* graylevels pixmaps. */ + /* gray_lines is a buffer holding two */ + /* monochrome scanlines */ + + Short gray_width; /* width in bytes of one monochrome */ + /* intermediate scanline of gray_lines. */ + /* Each gray pixel takes 2 bits long there */ + + /* The gray_lines must hold 2 lines, thus with size */ + /* in bytes of at least `gray_width*2'. */ + +#endif /* FT_RASTER_ANTI_ALIASING */ + +#if 0 + PByte flags; /* current flags table */ + PUShort outs; /* current outlines table */ + FT_Vector* coords; + + UShort nPoints; /* number of points in current glyph */ + Short nContours; /* number of contours in current glyph */ +#endif + + }; + + +#ifdef FT_CONFIG_OPTION_STATIC_RASTER + + static TRaster_Instance cur_ras; +#define ras cur_ras + +#else + +#define ras (*raster) + +#endif /* FT_CONFIG_OPTION_STATIC_RASTER */ + + + /*************************************************************************/ + /*************************************************************************/ + /** **/ + /** PROFILES COMPUTATION **/ + /** **/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* */ + /* Set_High_Precision */ + /* */ + /* */ + /* Sets precision variables according to param flag. */ + /* */ + /* */ + /* High :: Set to True for high precision (typically for ppem < 18), */ + /* false otherwise. */ + /* */ + static + void Set_High_Precision( RAS_ARGS Int High ) + { + if ( High ) + { + ras.precision_bits = 10; + ras.precision_step = 128; + ras.precision_jitter = 24; + } + else + { + ras.precision_bits = 6; + ras.precision_step = 32; + ras.precision_jitter = 2; + } + + FT_TRACE6(( "Set_High_Precision(%s)\n", High ? "true" : "false" )); + + ras.precision = 1L << ras.precision_bits; + ras.precision_half = ras.precision / 2; + ras.precision_shift = ras.precision_bits - Pixel_Bits; + ras.precision_mask = -ras.precision; + } + + + /*************************************************************************/ + /* */ + /* */ + /* New_Profile */ + /* */ + /* */ + /* Creates a new profile in the render pool. */ + /* */ + /* */ + /* aState :: The state/orientation of the new profile. */ + /* */ + /* */ + /* SUCCESS on success. FAILURE in case of overflow or of incoherent */ + /* profile. */ + /* */ + static + Bool New_Profile( RAS_ARGS TStates aState ) + { + if ( !ras.fProfile ) + { + ras.cProfile = (PProfile)ras.top; + ras.fProfile = ras.cProfile; + ras.top += AlignProfileSize; + } + + if ( ras.top >= ras.maxBuff ) + { + ras.error = Raster_Err_Overflow; + return FAILURE; + } + + switch ( aState ) + { + case Ascending: + ras.cProfile->flow = Flow_Up; + FT_TRACE6(( "New ascending profile = %lx\n", (long)ras.cProfile )); + break; + + case Descending: + ras.cProfile->flow = Flow_Down; + FT_TRACE6(( "New descending profile = %lx\n", (long)ras.cProfile )); + break; + + default: + FT_ERROR(( "New_Profile: invalid profile direction!\n" )); + ras.error = Raster_Err_Invalid; + return FAILURE; + } + + ras.cProfile->start = 0; + ras.cProfile->height = 0; + ras.cProfile->offset = ras.top; + ras.cProfile->link = (PProfile)0; + ras.cProfile->next = (PProfile)0; + + if ( !ras.gProfile ) + ras.gProfile = ras.cProfile; + + ras.state = aState; + ras.fresh = TRUE; + ras.joint = FALSE; + + return SUCCESS; + } + + + /*************************************************************************/ + /* */ + /* */ + /* End_Profile */ + /* */ + /* */ + /* Finalizes the current profile. */ + /* */ + /* */ + /* SUCCESS on success. FAILURE in case of overflow or incoherency. */ + /* */ + static + Bool End_Profile( RAS_ARG ) + { + Long h; + PProfile oldProfile; + + + h = ras.top - ras.cProfile->offset; + + if ( h < 0 ) + { + FT_ERROR(( "End_Profile: negative height encountered!\n" )); + ras.error = Raster_Err_Neg_Height; + return FAILURE; + } + + if ( h > 0 ) + { + FT_TRACE6(( "Ending profile %lx, start = %ld, height = %ld\n", + (long)ras.cProfile, ras.cProfile->start, h )); + + oldProfile = ras.cProfile; + ras.cProfile->height = h; + ras.cProfile = (PProfile)ras.top; + + ras.top += AlignProfileSize; + + ras.cProfile->height = 0; + ras.cProfile->offset = ras.top; + oldProfile->next = ras.cProfile; + ras.num_Profs++; + } + + if ( ras.top >= ras.maxBuff ) + { + FT_TRACE1(( "overflow in End_Profile\n" )); + ras.error = Raster_Err_Overflow; + return FAILURE; + } + + ras.joint = FALSE; + + return SUCCESS; + } + + + /*************************************************************************/ + /* */ + /* */ + /* Insert_Y_Turn */ + /* */ + /* */ + /* Inserts a salient into the sorted list placed on top of the render */ + /* pool. */ + /* */ + /* */ + /* New y scanline position. */ + /* */ + /* */ + /* SUCCESS on success. FAILURE in case of overflow. */ + /* */ + static + Bool Insert_Y_Turn( RAS_ARGS Int y ) + { + PLong y_turns; + Int y2, n; + + + n = ras.numTurns - 1; + y_turns = ras.sizeBuff - ras.numTurns; + + /* look for first y value that is <= */ + while ( n >= 0 && y < y_turns[n] ) + n--; + + /* if it is <, simply insert it, ignore if == */ + if ( n >= 0 && y > y_turns[n] ) + while ( n >= 0 ) + { + y2 = y_turns[n]; + y_turns[n] = y; + y = y2; + n--; + } + + if ( n < 0 ) + { + if ( ras.maxBuff <= ras.top ) + { + ras.error = Raster_Err_Overflow; + return FAILURE; + } + ras.maxBuff--; + ras.numTurns++; + ras.sizeBuff[-ras.numTurns] = y; + } + + return SUCCESS; + } + + + /*************************************************************************/ + /* */ + /* */ + /* Finalize_Profile_Table */ + /* */ + /* */ + /* Adjusts all links in the profiles list. */ + /* */ + /* */ + /* SUCCESS on success. FAILURE in case of overflow. */ + /* */ + static + Bool Finalize_Profile_Table( RAS_ARG ) + { + Int bottom, top; + UShort n; + PProfile p; + + + n = ras.num_Profs; + + if ( n > 1 ) + { + p = ras.fProfile; + while ( n > 0 ) + { + if ( n > 1 ) + p->link = (PProfile)( p->offset + p->height ); + else + p->link = NULL; + + switch ( p->flow ) + { + case Flow_Down: + bottom = p->start - p->height+1; + top = p->start; + p->start = bottom; + p->offset += p->height - 1; + break; + + case Flow_Up: + default: + bottom = p->start; + top = p->start + p->height - 1; + } + + if ( Insert_Y_Turn( RAS_VARS bottom ) || + Insert_Y_Turn( RAS_VARS top + 1 ) ) + return FAILURE; + + p = p->link; + n--; + } + } + else + ras.fProfile = NULL; + + return SUCCESS; + } + + + /*************************************************************************/ + /* */ + /* */ + /* Split_Conic */ + /* */ + /* */ + /* Subdivides one conic Bezier into two joint sub-arcs in the Bezier */ + /* stack. */ + /* */ + /* */ + /* None (subdivided Bezier is taken from the top of the stack). */ + /* */ + /* */ + /* This routine is the `beef' of this component. It is _the_ inner */ + /* loop that should be optimized to hell to get the best performance. */ + /* */ + static + void Split_Conic( TPoint* base ) + { + Long a, b; + + + base[4].x = base[2].x; + b = base[1].x; + a = base[3].x = ( base[2].x + b ) / 2; + b = base[1].x = ( base[0].x + b ) / 2; + base[2].x = ( a + b ) / 2; + + base[4].y = base[2].y; + b = base[1].y; + a = base[3].y = ( base[2].y + b ) / 2; + b = base[1].y = ( base[0].y + b ) / 2; + base[2].y = ( a + b ) / 2; + + /* hand optimized. gcc doesn't seem to be too good at common */ + /* expression substitution and instruction scheduling ;-) */ + } + + + /*************************************************************************/ + /* */ + /* */ + /* Split_Cubic */ + /* */ + /* */ + /* Subdivides a third-order Bezier arc into two joint sub-arcs in the */ + /* Bezier stack. */ + /* */ + /* */ + /* This routine is the `beef' of the component. It is one of _the_ */ + /* inner loops that should be optimized like hell to get the best */ + /* performance. */ + /* */ + static + void Split_Cubic( TPoint* base ) + { + Long a, b, c, d; + + + base[6].x = base[3].x; + c = base[1].x; + d = base[2].x; + base[1].x = a = ( base[0].x + c + 1 ) >> 1; + base[5].x = b = ( base[3].x + d + 1 ) >> 1; + c = ( c + d + 1 ) >> 1; + base[2].x = a = ( a + c + 1 ) >> 1; + base[4].x = b = ( b + c + 1 ) >> 1; + base[3].x = ( a + b + 1 ) >> 1; + + base[6].y = base[3].y; + c = base[1].y; + d = base[2].y; + base[1].y = a = ( base[0].y + c + 1 ) >> 1; + base[5].y = b = ( base[3].y + d + 1 ) >> 1; + c = ( c + d + 1 ) >> 1; + base[2].y = a = ( a + c + 1 ) >> 1; + base[4].y = b = ( b + c + 1 ) >> 1; + base[3].y = ( a + b + 1 ) >> 1; + } + + + /*************************************************************************/ + /* */ + /* */ + /* Line_Up */ + /* */ + /* */ + /* Computes the x-coordinates of an ascending line segment and stores */ + /* them in the render pool. */ + /* */ + /* */ + /* x1 :: The x-coordinate of the segment's start point. */ + /* */ + /* y1 :: The y-coordinate of the segment's start point. */ + /* */ + /* x2 :: The x-coordinate of the segment's end point. */ + /* */ + /* y2 :: The y-coordinate of the segment's end point. */ + /* */ + /* miny :: A lower vertical clipping bound value. */ + /* */ + /* maxy :: An upper vertical clipping bound value. */ + /* */ + /* */ + /* SUCCESS on success, FAILURE on render pool overflow. */ + /* */ + static + Bool Line_Up( RAS_ARGS Long x1, + Long y1, + Long x2, + Long y2, + Long miny, + Long maxy ) + { + Long Dx, Dy; + Int e1, e2, f1, f2, size; /* XXX: is `Short' sufficient? */ + Long Ix, Rx, Ax; + + PLong top; + + + Dx = x2 - x1; + Dy = y2 - y1; + + if ( Dy <= 0 || y2 < miny || y1 > maxy ) + return SUCCESS; + + if ( y1 < miny ) + { + /* Take care: miny-y1 can be a very large value; we use */ + /* a slow MulDiv function to avoid clipping bugs */ + x1 += SMulDiv( Dx, miny - y1, Dy ); + e1 = TRUNC( miny ); + f1 = 0; + } + else + { + e1 = TRUNC( y1 ); + f1 = FRAC( y1 ); + } + + if ( y2 > maxy ) + { + /* x2 += FMulDiv( Dx, maxy - y2, Dy ); UNNECESSARY */ + e2 = TRUNC( maxy ); + f2 = 0; + } + else + { + e2 = TRUNC( y2 ); + f2 = FRAC( y2 ); + } + + if ( f1 > 0 ) + { + if ( e1 == e2 ) + return SUCCESS; + else + { + x1 += FMulDiv( Dx, ras.precision - f1, Dy ); + e1 += 1; + } + } + else + if ( ras.joint ) + { + ras.top--; + ras.joint = FALSE; + } + + ras.joint = ( f2 == 0 ); + + if ( ras.fresh ) + { + ras.cProfile->start = e1; + ras.fresh = FALSE; + } + + size = e2 - e1 + 1; + if ( ras.top + size >= ras.maxBuff ) + { + ras.error = Raster_Err_Overflow; + return FAILURE; + } + + if ( Dx > 0 ) + { + Ix = ( ras.precision * Dx ) / Dy; + Rx = ( ras.precision * Dx ) % Dy; + Dx = 1; + } + else + { + Ix = -( ( ras.precision * -Dx ) / Dy ); + Rx = ( ras.precision * -Dx ) % Dy; + Dx = -1; + } + + Ax = -Dy; + top = ras.top; + + while ( size > 0 ) + { + *top++ = x1; + + x1 += Ix; + Ax += Rx; + if ( Ax >= 0 ) + { + Ax -= Dy; + x1 += Dx; + } + size--; + } + + ras.top = top; + return SUCCESS; + } + + + /*************************************************************************/ + /* */ + /* */ + /* Line_Down */ + /* */ + /* */ + /* Computes the x-coordinates of an descending line segment and */ + /* stores them in the render pool. */ + /* */ + /* */ + /* x1 :: The x-coordinate of the segment's start point. */ + /* */ + /* y1 :: The y-coordinate of the segment's start point. */ + /* */ + /* x2 :: The x-coordinate of the segment's end point. */ + /* */ + /* y2 :: The y-coordinate of the segment's end point. */ + /* */ + /* miny :: A lower vertical clipping bound value. */ + /* */ + /* maxy :: An upper vertical clipping bound value. */ + /* */ + /* */ + /* SUCCESS on success, FAILURE on render pool overflow. */ + /* */ + static + Bool Line_Down( RAS_ARGS Long x1, + Long y1, + Long x2, + Long y2, + Long miny, + Long maxy ) + { + Bool result, fresh; + + + fresh = ras.fresh; + + result = Line_Up( RAS_VARS x1, -y1, x2, -y2, -maxy, -miny ); + + if ( fresh && !ras.fresh ) + ras.cProfile->start = -ras.cProfile->start; + + return result; + } + + + /* A function type describing the functions used to split Bezier arcs */ + typedef void (*TSplitter)( TPoint* base ); + + + /*************************************************************************/ + /* */ + /* */ + /* Bezier_Up */ + /* */ + /* */ + /* Computes the x-coordinates of an ascending Bezier arc and stores */ + /* them in the render pool. */ + /* */ + /* */ + /* degree :: The degree of the Bezier arc (either 2 or 3). */ + /* */ + /* splitter :: The function to split Bezier arcs. */ + /* */ + /* miny :: A lower vertical clipping bound value. */ + /* */ + /* maxy :: An upper vertical clipping bound value. */ + /* */ + /* */ + /* SUCCESS on success, FAILURE on render pool overflow. */ + /* */ + static + Bool Bezier_Up( RAS_ARGS Int degree, + TSplitter splitter, + Long miny, + Long maxy ) + { + Long y1, y2, e, e2, e0; + Short f1; + + TPoint* arc; + TPoint* start_arc; + + PLong top; + + + arc = ras.arc; + y1 = arc[degree].y; + y2 = arc[0].y; + top = ras.top; + + if ( y2 < miny || y1 > maxy ) + goto Fin; + + e2 = FLOOR( y2 ); + + if ( e2 > maxy ) + e2 = maxy; + + e0 = miny; + + if ( y1 < miny ) + e = miny; + else + { + e = CEILING( y1 ); + f1 = FRAC( y1 ); + e0 = e; + + if ( f1 == 0 ) + { + if ( ras.joint ) + { + top--; + ras.joint = FALSE; + } + + *top++ = arc[degree].x; + + e += ras.precision; + } + } + + if ( ras.fresh ) + { + ras.cProfile->start = TRUNC( e0 ); + ras.fresh = FALSE; + } + + if ( e2 < e ) + goto Fin; + + if ( ( top + TRUNC( e2 - e ) + 1 ) >= ras.maxBuff ) + { + ras.top = top; + ras.error = Raster_Err_Overflow; + return FAILURE; + } + + start_arc = arc; + + while ( arc >= start_arc && e <= e2 ) + { + ras.joint = FALSE; + + y2 = arc[0].y; + + if ( y2 > e ) + { + y1 = arc[degree].y; + if ( y2 - y1 >= ras.precision_step ) + { + splitter( arc ); + arc += degree; + } + else + { + *top++ = arc[degree].x + FMulDiv( arc[0].x-arc[degree].x, + e - y1, y2 - y1 ); + arc -= degree; + e += ras.precision; + } + } + else + { + if ( y2 == e ) + { + ras.joint = TRUE; + *top++ = arc[0].x; + + e += ras.precision; + } + arc -= degree; + } + } + + Fin: + ras.top = top; + ras.arc -= degree; + return SUCCESS; + } + + + /*************************************************************************/ + /* */ + /* */ + /* Bezier_Down */ + /* */ + /* */ + /* Computes the x-coordinates of an descending Bezier arc and stores */ + /* them in the render pool. */ + /* */ + /* */ + /* degree :: The degree of the Bezier arc (either 2 or 3). */ + /* */ + /* splitter :: The function to split Bezier arcs. */ + /* */ + /* miny :: A lower vertical clipping bound value. */ + /* */ + /* maxy :: An upper vertical clipping bound value. */ + /* */ + /* */ + /* SUCCESS on success, FAILURE on render pool overflow. */ + /* */ + static + Bool Bezier_Down( RAS_ARGS Int degree, + TSplitter splitter, + Long miny, + Long maxy ) + { + TPoint* arc = ras.arc; + Bool result, fresh; + + + arc[0].y = -arc[0].y; + arc[1].y = -arc[1].y; + arc[2].y = -arc[2].y; + if ( degree > 2 ) + arc[3].y = -arc[3].y; + + fresh = ras.fresh; + + result = Bezier_Up( RAS_VARS degree, splitter, -maxy, -miny ); + + if ( fresh && !ras.fresh ) + ras.cProfile->start = -ras.cProfile->start; + + arc[0].y = -arc[0].y; + return result; + } + + + /*************************************************************************/ + /* */ + /* */ + /* Line_To */ + /* */ + /* */ + /* Injects a new line segment and adjusts Profiles list. */ + /* */ + /* */ + /* x :: The x-coordinate of the segment's end point (its start point */ + /* is stored in `LastX'). */ + /* */ + /* y :: The y-coordinate of the segment's end point (its start point */ + /* is stored in `LastY'). */ + /* */ + /* */ + /* SUCCESS on success, FAILURE on render pool overflow or incorrect */ + /* profile. */ + /* */ + static + Bool Line_To( RAS_ARGS Long x, + Long y ) + { + /* First, detect a change of direction */ + + switch ( ras.state ) + { + case Unknown: + if ( y > ras.lastY ) + { + if ( New_Profile( RAS_VARS Ascending ) ) + return FAILURE; + } + else + { + if ( y < ras.lastY ) + if ( New_Profile( RAS_VARS Descending ) ) + return FAILURE; + } + break; + + case Ascending: + if ( y < ras.lastY ) + { + if ( End_Profile( RAS_VAR ) || + New_Profile( RAS_VARS Descending ) ) + return FAILURE; + } + break; + + case Descending: + if ( y > ras.lastY ) + { + if ( End_Profile( RAS_VAR ) || + New_Profile( RAS_VARS Ascending ) ) + return FAILURE; + } + break; + + default: + ; + } + + /* Then compute the lines */ + + switch ( ras.state ) + { + case Ascending: + if ( Line_Up( RAS_VARS ras.lastX, ras.lastY, + x, y, ras.minY, ras.maxY ) ) + return FAILURE; + break; + + case Descending: + if ( Line_Down( RAS_VARS ras.lastX, ras.lastY, + x, y, ras.minY, ras.maxY ) ) + return FAILURE; + break; + + default: + ; + } + + ras.lastX = x; + ras.lastY = y; + + return SUCCESS; + } + + + /*************************************************************************/ + /* */ + /* */ + /* Conic_To */ + /* */ + /* */ + /* Injects a new conic arc and adjusts the profile list. */ + /* */ + /* */ + /* cx :: The x-coordinate of the arc's new control point. */ + /* */ + /* cy :: The y-coordinate of the arc's new control point. */ + /* */ + /* x :: The x-coordinate of the arc's end point (its start point is */ + /* stored in `LastX'). */ + /* */ + /* y :: The y-coordinate of the arc's end point (its start point is */ + /* stored in `LastY'). */ + /* */ + /* */ + /* SUCCESS on success, FAILURE on render pool overflow or incorrect */ + /* profile. */ + /* */ + static + Bool Conic_To( RAS_ARGS Long cx, + Long cy, + Long x, + Long y ) + { + Long y1, y2, y3, x3, ymin, ymax; + TStates state_bez; + + + ras.arc = ras.arcs; + ras.arc[2].x = ras.lastX; + ras.arc[2].y = ras.lastY; + ras.arc[1].x = cx; ras.arc[1].y = cy; + ras.arc[0].x = x; ras.arc[0].y = y; + + do + { + y1 = ras.arc[2].y; + y2 = ras.arc[1].y; + y3 = ras.arc[0].y; + x3 = ras.arc[0].x; + + /* first, categorize the Bezier arc */ + + if ( y1 <= y3 ) + { + ymin = y1; + ymax = y3; + } + else + { + ymin = y3; + ymax = y1; + } + + if ( y2 < ymin || y2 > ymax ) + { + /* this arc has no given direction, split it! */ + Split_Conic( ras.arc ); + ras.arc += 2; + } + else if ( y1 == y3 ) + { + /* this arc is flat, ignore it and pop it from the Bezier stack */ + ras.arc -= 2; + } + else + { + /* the arc is y-monotonous, either ascending or descending */ + /* detect a change of direction */ + state_bez = y1 < y3 ? Ascending : Descending; + if ( ras.state != state_bez ) + { + /* finalize current profile if any */ + if ( ras.state != Unknown && + End_Profile( RAS_VAR ) ) + goto Fail; + + /* create a new profile */ + if ( New_Profile( RAS_VARS state_bez ) ) + goto Fail; + } + + /* now call the appropriate routine */ + if ( state_bez == Ascending ) + { + if ( Bezier_Up( RAS_VARS 2, Split_Conic, ras.minY, ras.maxY ) ) + goto Fail; + } + else + if ( Bezier_Down( RAS_VARS 2, Split_Conic, ras.minY, ras.maxY ) ) + goto Fail; + } + + } while ( ras.arc >= ras.arcs ); + + ras.lastX = x3; + ras.lastY = y3; + + return SUCCESS; + + Fail: + return FAILURE; + } + + + /*************************************************************************/ + /* */ + /* */ + /* Cubic_To */ + /* */ + /* */ + /* Injects a new cubic arc and adjusts the profile list. */ + /* */ + /* */ + /* cx1 :: The x-coordinate of the arc's first new control point. */ + /* */ + /* cy1 :: The y-coordinate of the arc's first new control point. */ + /* */ + /* cx2 :: The x-coordinate of the arc's second new control point. */ + /* */ + /* cy2 :: The y-coordinate of the arc's second new control point. */ + /* */ + /* x :: The x-coordinate of the arc's end point (its start point is */ + /* stored in `LastX'). */ + /* */ + /* y :: The y-coordinate of the arc's end point (its start point is */ + /* stored in `LastY'). */ + /* */ + /* */ + /* SUCCESS on success, FAILURE on render pool overflow or incorrect */ + /* profile. */ + /* */ + static + Bool Cubic_To( RAS_ARGS Long cx1, + Long cy1, + Long cx2, + Long cy2, + Long x, + Long y ) + { + Long y1, y2, y3, y4, x4, ymin1, ymax1, ymin2, ymax2; + TStates state_bez; + + + ras.arc = ras.arcs; + ras.arc[3].x = ras.lastX; + ras.arc[3].y = ras.lastY; + ras.arc[2].x = cx1; ras.arc[2].y = cy1; + ras.arc[1].x = cx2; ras.arc[1].y = cy2; + ras.arc[0].x = x; ras.arc[0].y = y; + + do + { + y1 = ras.arc[3].y; + y2 = ras.arc[2].y; + y3 = ras.arc[1].y; + y4 = ras.arc[0].y; + x4 = ras.arc[0].x; + + /* first, categorize the Bezier arc */ + + if ( y1 <= y4 ) + { + ymin1 = y1; + ymax1 = y4; + } + else + { + ymin1 = y4; + ymax1 = y1; + } + + if ( y2 <= y3 ) + { + ymin2 = y2; + ymax2 = y3; + } + else + { + ymin2 = y3; + ymax2 = y2; + } + + if ( ymin2 < ymin1 || ymax2 > ymax1 ) + { + /* this arc has no given direction, split it! */ + Split_Cubic( ras.arc ); + ras.arc += 3; + } + else if ( y1 == y4 ) + { + /* this arc is flat, ignore it and pop it from the Bezier stack */ + ras.arc -= 3; + } + else + { + state_bez = ( y1 <= y4 ) ? Ascending : Descending; + + /* detect a change of direction */ + if ( ras.state != state_bez ) + { + if ( ras.state != Unknown && + End_Profile( RAS_VAR ) ) + goto Fail; + + if ( New_Profile( RAS_VARS state_bez ) ) + goto Fail; + } + + /* compute intersections */ + if ( state_bez == Ascending ) + { + if ( Bezier_Up( RAS_VARS 3, Split_Cubic, ras.minY, ras.maxY ) ) + goto Fail; + } + else + if ( Bezier_Down( RAS_VARS 3, Split_Cubic, ras.minY, ras.maxY ) ) + goto Fail; + } + + } while ( ras.arc >= ras.arcs ); + + ras.lastX = x4; + ras.lastY = y4; + + return SUCCESS; + + Fail: + return FAILURE; + } + + +#undef SWAP_ +#define SWAP_( x, y ) do \ + { \ + Long swap = x; \ + \ + \ + x = y; \ + y = swap; \ + } while ( 0 ) + + + /*************************************************************************/ + /* */ + /* */ + /* Decompose_Curve */ + /* */ + /* */ + /* Scans the outline arays in order to emit individual segments and */ + /* Beziers by calling Line_To() and Bezier_To(). It handles all */ + /* weird cases, like when the first point is off the curve, or when */ + /* there are simply no `on' points in the contour! */ + /* */ + /* */ + /* first :: The index of the first point in the contour. */ + /* */ + /* last :: The index of the last point in the contour. */ + /* */ + /* flipped :: If set, flip the direction of the curve. */ + /* */ + /* */ + /* SUCCESS on success, FAILURE on error. */ + /* */ + static + Bool Decompose_Curve( RAS_ARGS UShort first, + UShort last, + int flipped ) + { + FT_Vector v_last; + FT_Vector v_control; + FT_Vector v_start; + + FT_Vector* points; + FT_Vector* point; + FT_Vector* limit; + char* tags; + + char tag; /* current point's state */ + + + points = ras.outline.points; + limit = points + last; + + v_start.x = SCALED( points[first].x ); + v_start.y = SCALED( points[first].y ); + v_last.x = SCALED( points[last].x ); + v_last.y = SCALED( points[last].y ); + + if ( flipped ) + { + SWAP_( v_start.x, v_start.y ); + SWAP_( v_last.x, v_last.y ); + } + + v_control = v_start; + + point = points + first; + tags = ras.outline.tags + first; + tag = FT_CURVE_TAG( tags[0] ); + + /* A contour cannot start with a cubic control point! */ + if ( tag == FT_Curve_Tag_Cubic ) + goto Invalid_Outline; + + /* check first point to determine origin */ + if ( tag == FT_Curve_Tag_Conic ) + { + /* first point is conic control. Yes, this happens. */ + if ( FT_CURVE_TAG( ras.outline.tags[last] ) == FT_Curve_Tag_On ) + { + /* start at last point if it is on the curve */ + v_start = v_last; + limit--; + } + else + { + /* if both first and last points are conic, */ + /* start at their middle and record its position */ + /* for closure */ + v_start.x = ( v_start.x + v_last.x ) / 2; + v_start.y = ( v_start.y + v_last.y ) / 2; + + v_last = v_start; + } + point--; + tags--; + } + + ras.lastX = v_start.x; + ras.lastY = v_start.y; + + while ( point < limit ) + { + point++; + tags++; + + tag = FT_CURVE_TAG( tags[0] ); + + switch ( tag ) + { + case FT_Curve_Tag_On: /* emit a single line_to */ + { + Long x, y; + + + x = SCALED( point->x ); + y = SCALED( point->y ); + if ( flipped ) + SWAP_( x, y ); + + if ( Line_To( RAS_VARS x, y ) ) + goto Fail; + continue; + } + + case FT_Curve_Tag_Conic: /* consume conic arcs */ + v_control.x = SCALED( point[0].x ); + v_control.y = SCALED( point[0].y ); + + if ( flipped ) + SWAP_( v_control.x, v_control.y ); + + Do_Conic: + if ( point < limit ) + { + FT_Vector v_middle; + Long x, y; + + + point++; + tags++; + tag = FT_CURVE_TAG( tags[0] ); + + x = SCALED( point[0].x ); + y = SCALED( point[0].y ); + + if ( flipped ) + SWAP_( x, y ); + + if ( tag == FT_Curve_Tag_On ) + { + if ( Conic_To( RAS_VARS v_control.x, v_control.y, x, y ) ) + goto Fail; + continue; + } + + if ( tag != FT_Curve_Tag_Conic ) + goto Invalid_Outline; + + v_middle.x = ( v_control.x + x ) / 2; + v_middle.y = ( v_control.y + y ) / 2; + + if ( Conic_To( RAS_VARS v_control.x, v_control.y, + v_middle.x, v_middle.y ) ) + goto Fail; + + v_control.x = x; + v_control.y = y; + + goto Do_Conic; + } + + if ( Conic_To( RAS_VARS v_control.x, v_control.y, + v_start.x, v_start.y ) ) + goto Fail; + + goto Close; + + default: /* FT_Curve_Tag_Cubic */ + { + Long x1, y1, x2, y2, x3, y3; + + + if ( point + 1 > limit || + FT_CURVE_TAG( tags[1] ) != FT_Curve_Tag_Cubic ) + goto Invalid_Outline; + + point += 2; + tags += 2; + + x1 = SCALED( point[-2].x ); + y1 = SCALED( point[-2].y ); + x2 = SCALED( point[-1].x ); + y2 = SCALED( point[-1].y ); + x3 = SCALED( point[ 0].x ); + y3 = SCALED( point[ 0].y ); + + if ( flipped ) + { + SWAP_( x1, y1 ); + SWAP_( x2, y2 ); + SWAP_( x3, y3 ); + } + + if ( point <= limit ) + { + if ( Cubic_To( RAS_VARS x1, y1, x2, y2, x3, y3 ) ) + goto Fail; + continue; + } + + if ( Cubic_To( RAS_VARS x1, y1, x2, y2, v_start.x, v_start.y ) ) + goto Fail; + goto Close; + } + } + } + + /* close the contour with a line segment */ + if ( Line_To( RAS_VARS v_start.x, v_start.y ) ) + goto Fail; + + Close: + return SUCCESS; + + Invalid_Outline: + ras.error = Raster_Err_Invalid; + + Fail: + return FAILURE; + } + + + /*************************************************************************/ + /* */ + /* */ + /* Convert_Glyph */ + /* */ + /* */ + /* Converts a glyph into a series of segments and arcs and makes a */ + /* profiles list with them. */ + /* */ + /* */ + /* flipped :: If set, flip the direction of curve. */ + /* */ + /* */ + /* SUCCESS on success, FAILURE if any error was encountered during */ + /* rendering. */ + /* */ + static + Bool Convert_Glyph( RAS_ARGS int flipped ) + { + Short i; + UShort start; + + PProfile lastProfile; + + + ras.fProfile = NULL; + ras.joint = FALSE; + ras.fresh = FALSE; + + ras.maxBuff = ras.sizeBuff - AlignProfileSize; + + ras.numTurns = 0; + + ras.cProfile = (PProfile)ras.top; + ras.cProfile->offset = ras.top; + ras.num_Profs = 0; + + start = 0; + + for ( i = 0; i < ras.outline.n_contours; i++ ) + { + ras.state = Unknown; + ras.gProfile = NULL; + + if ( Decompose_Curve( RAS_VARS start, ras.outline.contours[i], flipped ) ) + return FAILURE; + + start = ras.outline.contours[i] + 1; + + /* We must now see whether the extreme arcs join or not */ + if ( FRAC( ras.lastY ) == 0 && + ras.lastY >= ras.minY && + ras.lastY <= ras.maxY ) + if ( ras.gProfile && ras.gProfile->flow == ras.cProfile->flow ) + ras.top--; + /* Note that ras.gProfile can be nil if the contour was too small */ + /* to be drawn. */ + + lastProfile = ras.cProfile; + if ( End_Profile( RAS_VAR ) ) + return FAILURE; + + /* close the `next profile in contour' linked list */ + if ( ras.gProfile ) + lastProfile->next = ras.gProfile; + } + + if ( Finalize_Profile_Table( RAS_VAR ) ) + return FAILURE; + + return ( ras.top < ras.maxBuff ? SUCCESS : FAILURE ); + } + + + /*************************************************************************/ + /*************************************************************************/ + /** **/ + /** SCAN-LINE SWEEPS AND DRAWING **/ + /** **/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* Init_Linked */ + /* */ + /* Initializes an empty linked list. */ + /* */ + static + void Init_Linked( TProfileList* l ) + { + *l = NULL; + } + + + /*************************************************************************/ + /* */ + /* InsNew */ + /* */ + /* Inserts a new profile in a linked list. */ + /* */ + static + void InsNew( PProfileList list, + PProfile profile ) + { + PProfile *old, current; + Long x; + + + old = list; + current = *old; + x = profile->X; + + while ( current ) + { + if ( x < current->X ) + break; + old = ¤t->link; + current = *old; + } + + profile->link = current; + *old = profile; + } + + + /*************************************************************************/ + /* */ + /* DelOld */ + /* */ + /* Removes an old profile from a linked list. */ + /* */ + static + void DelOld( PProfileList list, + PProfile profile ) + { + PProfile *old, current; + + + old = list; + current = *old; + + while ( current ) + { + if ( current == profile ) + { + *old = current->link; + return; + } + + old = ¤t->link; + current = *old; + } + + /* we should never get there, unless the profile was not part of */ + /* the list. */ + } + + + /*************************************************************************/ + /* */ + /* Update */ + /* */ + /* Update all X offsets of a drawing list. */ + /* */ + static + void Update( PProfile first ) + { + PProfile current = first; + + + while ( current ) + { + current->X = *current->offset; + current->offset += current->flow; + current->height--; + current = current->link; + } + } + + + /*************************************************************************/ + /* */ + /* Sort */ + /* */ + /* Sorts a trace list. In 95%, the list is already sorted. We need */ + /* an algorithm which is fast in this case. Bubble sort is enough */ + /* and simple. */ + /* */ + static + void Sort( PProfileList list ) + { + PProfile *old, current, next; + + + /* First, set the new X coordinate of each profile */ + Update( *list ); + + /* Then sort them */ + old = list; + current = *old; + + if ( !current ) + return; + + next = current->link; + + while ( next ) + { + if ( current->X <= next->X ) + { + old = ¤t->link; + current = *old; + + if ( !current ) + return; + } + else + { + *old = next; + current->link = next->link; + next->link = current; + + old = list; + current = *old; + } + + next = current->link; + } + } + + + /*************************************************************************/ + /* */ + /* Vertical Sweep Procedure Set */ + /* */ + /* These four routines are used during the vertical black/white sweep */ + /* phase by the generic Draw_Sweep() function. */ + /* */ + /*************************************************************************/ + + static + void Vertical_Sweep_Init( RAS_ARGS Short* min, + Short* max ) + { + Long pitch = ras.target.pitch; + + FT_UNUSED( max ); + + + ras.traceIncr = (Short)-pitch; + ras.traceOfs = -*min * pitch; + if ( pitch > 0 ) + ras.traceOfs += ( ras.target.rows - 1 ) * pitch; + + ras.gray_min_x = 0; + ras.gray_max_x = 0; + } + + + static + void Vertical_Sweep_Span( RAS_ARGS Short y, + FT_F26Dot6 x1, + FT_F26Dot6 x2, + PProfile left, + PProfile right ) + { + Long e1, e2; + Short c1, c2; + Byte f1, f2; + Byte* target; + + FT_UNUSED( y ); + FT_UNUSED( left ); + FT_UNUSED( right ); + + + /* Drop-out control */ + + e1 = TRUNC( CEILING( x1 ) ); + + if ( x2 - x1 - ras.precision <= ras.precision_jitter ) + e2 = e1; + else + e2 = TRUNC( FLOOR( x2 ) ); + + if ( e2 >= 0 && e1 < ras.bWidth ) + { + if ( e1 < 0 ) + e1 = 0; + if ( e2 >= ras.bWidth ) + e2 = ras.bWidth - 1; + + c1 = (Short)( e1 >> 3 ); + c2 = (Short)( e2 >> 3 ); + + f1 = (unsigned char)0xFF >> ( e1 & 7 ); + f2 = ~( (unsigned char)0x7F >> ( e2 & 7 ) ); + + if ( ras.gray_min_x > c1 ) ras.gray_min_x = c1; + if ( ras.gray_max_x < c2 ) ras.gray_max_x = c2; + + target = ras.bTarget + ras.traceOfs + c1; + c2 -= c1; + + if ( c2 > 0 ) + { + target[0] |= f1; + + /* memset() is slower than the following code on many platforms. */ + /* This is due to the fact that, in the vast majority of cases, */ + /* the span length in bytes is relatively small. */ + c2--; + while ( c2 > 0 ) + { + *(++target) = 0xFF; + c2--; + } + target[1] |= f2; + } + else + *target |= ( f1 & f2 ); + } + } + + + static + void Vertical_Sweep_Drop( RAS_ARGS Short y, + FT_F26Dot6 x1, + FT_F26Dot6 x2, + PProfile left, + PProfile right ) + { + Long e1, e2; + Short c1, f1; + + + /* Drop-out control */ + + e1 = CEILING( x1 ); + e2 = FLOOR ( x2 ); + + if ( e1 > e2 ) + { + if ( e1 == e2 + ras.precision ) + { + switch ( ras.dropOutControl ) + { + case 1: + e1 = e2; + break; + + case 4: + e1 = CEILING( (x1 + x2 + 1) / 2 ); + break; + + case 2: + case 5: + /* Drop-out Control Rule #4 */ + + /* The spec is not very clear regarding rule #4. It */ + /* presents a method that is way too costly to implement */ + /* while the general idea seems to get rid of `stubs'. */ + /* */ + /* Here, we only get rid of stubs recognized if: */ + /* */ + /* upper stub: */ + /* */ + /* - P_Left and P_Right are in the same contour */ + /* - P_Right is the successor of P_Left in that contour */ + /* - y is the top of P_Left and P_Right */ + /* */ + /* lower stub: */ + /* */ + /* - P_Left and P_Right are in the same contour */ + /* - P_Left is the successor of P_Right in that contour */ + /* - y is the bottom of P_Left */ + /* */ + + /* FIXXXME: uncommenting this line solves the disappearing */ + /* bit problem in the `7' of verdana 10pts, but */ + /* makes a new one in the `C' of arial 14pts */ + +#if 0 + if ( x2 - x1 < ras.precision_half ) +#endif + { + /* upper stub test */ + if ( left->next == right && left->height <= 0 ) + return; + + /* lower stub test */ + if ( right->next == left && left->start == y ) + return; + } + + /* check that the rightmost pixel isn't set */ + + e1 = TRUNC( e1 ); + + c1 = (Short)( e1 >> 3 ); + f1 = e1 & 7; + + if ( e1 >= 0 && e1 < ras.bWidth && + ras.bTarget[ras.traceOfs + c1] & ( 0x80 >> f1 ) ) + return; + + if ( ras.dropOutControl == 2 ) + e1 = e2; + else + e1 = CEILING( ( x1 + x2 + 1 ) / 2 ); + + break; + + default: + return; /* unsupported mode */ + } + } + else + return; + } + + e1 = TRUNC( e1 ); + + if ( e1 >= 0 && e1 < ras.bWidth ) + { + c1 = (Short)( e1 >> 3 ); + f1 = e1 & 7; + + if ( ras.gray_min_x > c1 ) ras.gray_min_x = c1; + if ( ras.gray_max_x < c1 ) ras.gray_max_x = c1; + + ras.bTarget[ras.traceOfs + c1] |= (char)( 0x80 >> f1 ); + } + } + + + static + void Vertical_Sweep_Step( RAS_ARG ) + { + ras.traceOfs += ras.traceIncr; + } + + + /***********************************************************************/ + /* */ + /* Horizontal Sweep Procedure Set */ + /* */ + /* These four routines are used during the horizontal black/white */ + /* sweep phase by the generic Draw_Sweep() function. */ + /* */ + /***********************************************************************/ + + static + void Horizontal_Sweep_Init( RAS_ARGS Short* min, + Short* max ) + { + /* nothing, really */ + FT_UNUSED( raster ); + FT_UNUSED( min ); + FT_UNUSED( max ); + } + + + static + void Horizontal_Sweep_Span( RAS_ARGS Short y, + FT_F26Dot6 x1, + FT_F26Dot6 x2, + PProfile left, + PProfile right ) + { + Long e1, e2; + PByte bits; + Byte f1; + + FT_UNUSED( left ); + FT_UNUSED( right ); + + + if ( x2 - x1 < ras.precision ) + { + e1 = CEILING( x1 ); + e2 = FLOOR ( x2 ); + + if ( e1 == e2 ) + { + bits = ras.bTarget + ( y >> 3 ); + f1 = (Byte)( 0x80 >> ( y & 7 ) ); + + e1 = TRUNC( e1 ); + + if ( e1 >= 0 && e1 < ras.target.rows ) + { + PByte p; + + + p = bits - e1*ras.target.pitch; + if ( ras.target.pitch > 0 ) + p += ( ras.target.rows - 1 ) * ras.target.pitch; + + p[0] |= f1; + } + } + } + } + + + static + void Horizontal_Sweep_Drop( RAS_ARGS Short y, + FT_F26Dot6 x1, + FT_F26Dot6 x2, + PProfile left, + PProfile right ) + { + Long e1, e2; + PByte bits; + Byte f1; + + + /* During the horizontal sweep, we only take care of drop-outs */ + + e1 = CEILING( x1 ); + e2 = FLOOR ( x2 ); + + if ( e1 > e2 ) + { + if ( e1 == e2 + ras.precision ) + { + switch ( ras.dropOutControl ) + { + case 1: + e1 = e2; + break; + + case 4: + e1 = CEILING( ( x1 + x2 + 1 ) / 2 ); + break; + + case 2: + case 5: + + /* Drop-out Control Rule #4 */ + + /* The spec is not very clear regarding rule #4. It */ + /* presents a method that is way too costly to implement */ + /* while the general idea seems to get rid of `stubs'. */ + /* */ + + /* rightmost stub test */ + if ( left->next == right && left->height <= 0 ) + return; + + /* leftmost stub test */ + if ( right->next == left && left->start == y ) + return; + + /* check that the rightmost pixel isn't set */ + + e1 = TRUNC( e1 ); + + bits = ras.bTarget + ( y >> 3 ); + f1 = (Byte)( 0x80 >> ( y & 7 ) ); + + bits -= e1 * ras.target.pitch; + if ( ras.target.pitch > 0 ) + bits += ( ras.target.rows - 1 ) * ras.target.pitch; + + if ( e1 >= 0 && + e1 < ras.target.rows && + *bits & f1 ) + return; + + if ( ras.dropOutControl == 2 ) + e1 = e2; + else + e1 = CEILING( ( x1 + x2 + 1 ) / 2 ); + + break; + + default: + return; /* unsupported mode */ + } + } + else + return; + } + + bits = ras.bTarget + ( y >> 3 ); + f1 = (Byte)( 0x80 >> ( y & 7 ) ); + + e1 = TRUNC( e1 ); + + if ( e1 >= 0 && e1 < ras.target.rows ) + { + bits -= e1 * ras.target.pitch; + if ( ras.target.pitch > 0 ) + bits += ( ras.target.rows - 1 ) * ras.target.pitch; + + bits[0] |= f1; + } + } + + + static + void Horizontal_Sweep_Step( RAS_ARG ) + { + /* Nothing, really */ + FT_UNUSED( raster ); + } + + +#ifdef FT_RASTER_OPTION_ANTI_ALIASING + + + /*************************************************************************/ + /* */ + /* Vertical Gray Sweep Procedure Set */ + /* */ + /* These two routines are used during the vertical gray-levels sweep */ + /* phase by the generic Draw_Sweep() function. */ + /* */ + /* NOTES */ + /* */ + /* - The target pixmap's width *must* be a multiple of 4. */ + /* */ + /* - You have to use the function Vertical_Sweep_Span() for the gray */ + /* span call. */ + /* */ + /*************************************************************************/ + + static + void Vertical_Gray_Sweep_Init( RAS_ARGS Short* min, + Short* max ) + { + Long pitch, byte_len; + + + *min = *min & -2; + *max = ( *max + 3 ) & -2; + + ras.traceOfs = 0; + pitch = ras.target.pitch; + byte_len = -pitch; + ras.traceIncr = (Short)byte_len; + ras.traceG = ( *min / 2 ) * byte_len; + + if ( pitch > 0 ) + { + ras.traceG += ( ras.target.rows - 1 ) * pitch; + byte_len = -byte_len; + } + + ras.gray_min_x = (Short)byte_len; + ras.gray_max_x = -(Short)byte_len; + } + + + static + void Vertical_Gray_Sweep_Step( RAS_ARG ) + { + Int c1, c2; + PByte pix, bit, bit2; + Int* count = ras.count_table; + Byte* grays; + + + ras.traceOfs += ras.gray_width; + + if ( ras.traceOfs > ras.gray_width ) + { + pix = ras.gTarget + ras.traceG + ras.gray_min_x * 4; + grays = ras.grays; + + if ( ras.gray_max_x >= 0 ) + { + Long last_pixel = ras.target.width - 1; + Int last_cell = last_pixel >> 2; + Int last_bit = last_pixel & 3; + Bool over = 0; + + + if ( ras.gray_max_x >= last_cell && last_bit != 3 ) + { + ras.gray_max_x = last_cell - 1; + over = 1; + } + + if ( ras.gray_min_x < 0 ) + ras.gray_min_x = 0; + + bit = ras.bTarget + ras.gray_min_x; + bit2 = bit + ras.gray_width; + + c1 = ras.gray_max_x - ras.gray_min_x; + + while ( c1 >= 0 ) + { + c2 = count[*bit] + count[*bit2]; + + if ( c2 ) + { + pix[0] = grays[(c2 >> 12) & 0x000F]; + pix[1] = grays[(c2 >> 8 ) & 0x000F]; + pix[2] = grays[(c2 >> 4 ) & 0x000F]; + pix[3] = grays[ c2 & 0x000F]; + + *bit = 0; + *bit2 = 0; + } + + bit++; + bit2++; + pix += 4; + c1--; + } + + if ( over ) + { + c2 = count[*bit] + count[*bit2]; + if ( c2 ) + { + switch ( last_bit ) + { + case 2: + pix[2] = grays[(c2 >> 4 ) & 0x000F]; + case 1: + pix[1] = grays[(c2 >> 8 ) & 0x000F]; + default: + pix[0] = grays[(c2 >> 12) & 0x000F]; + } + + *bit = 0; + *bit2 = 0; + } + } + } + + ras.traceOfs = 0; + ras.traceG += ras.traceIncr; + + ras.gray_min_x = 32000; + ras.gray_max_x = -32000; + } + } + + + static + void Horizontal_Gray_Sweep_Span( RAS_ARGS Short y, + FT_F26Dot6 x1, + FT_F26Dot6 x2, + PProfile left, + PProfile right ) + { + /* nothing, really */ + FT_UNUSED( raster ); + FT_UNUSED( y ); + FT_UNUSED( x1 ); + FT_UNUSED( x2 ); + FT_UNUSED( left ); + FT_UNUSED( right ); + } + + + static + void Horizontal_Gray_Sweep_Drop( RAS_ARGS Short y, + FT_F26Dot6 x1, + FT_F26Dot6 x2, + PProfile left, + PProfile right ) + { + Long e1, e2; + PByte pixel; + Byte color; + + + /* During the horizontal sweep, we only take care of drop-outs */ + e1 = CEILING( x1 ); + e2 = FLOOR ( x2 ); + + if ( e1 > e2 ) + { + if ( e1 == e2 + ras.precision ) + { + switch ( ras.dropOutControl ) + { + case 1: + e1 = e2; + break; + + case 4: + e1 = CEILING( ( x1 + x2 + 1 ) / 2 ); + break; + + case 2: + case 5: + + /* Drop-out Control Rule #4 */ + + /* The spec is not very clear regarding rule #4. It */ + /* presents a method that is way too costly to implement */ + /* while the general idea seems to get rid of `stubs'. */ + /* */ + + /* rightmost stub test */ + if ( left->next == right && left->height <= 0 ) + return; + + /* leftmost stub test */ + if ( right->next == left && left->start == y ) + return; + + if ( ras.dropOutControl == 2 ) + e1 = e2; + else + e1 = CEILING( ( x1 + x2 + 1 ) / 2 ); + + break; + + default: + return; /* unsupported mode */ + } + } + else + return; + } + + if ( e1 >= 0 ) + { + if ( x2 - x1 >= ras.precision_half ) + color = ras.grays[2]; + else + color = ras.grays[1]; + + e1 = TRUNC( e1 ) / 2; + if ( e1 < ras.target.rows ) + { + pixel = ras.gTarget - e1 * ras.target.pitch + y / 2; + if ( ras.target.pitch > 0 ) + pixel += ( ras.target.rows - 1 ) * ras.target.pitch; + + if ( pixel[0] == ras.grays[0] ) + pixel[0] = color; + } + } + } + + +#endif /* FT_RASTER_OPTION_ANTI_ALIASING */ + + + /*************************************************************************/ + /* */ + /* Generic Sweep Drawing routine */ + /* */ + /*************************************************************************/ + + static + Bool Draw_Sweep( RAS_ARG ) + { + Short y, y_change, y_height; + + PProfile P, Q, P_Left, P_Right; + + Short min_Y, max_Y, top, bottom, dropouts; + + Long x1, x2, xs, e1, e2; + + TProfileList wait; + TProfileList draw_left, draw_right; + + + /* Init empty linked lists */ + + Init_Linked( &wait ); + + Init_Linked( &draw_left ); + Init_Linked( &draw_right ); + + /* first, compute min and max Y */ + + P = ras.fProfile; + max_Y = (Short)TRUNC( ras.minY ); + min_Y = (Short)TRUNC( ras.maxY ); + + while ( P ) + { + Q = P->link; + + bottom = (Short)P->start; + top = (Short)P->start + P->height - 1; + + if ( min_Y > bottom ) min_Y = bottom; + if ( max_Y < top ) max_Y = top; + + P->X = 0; + InsNew( &wait, P ); + + P = Q; + } + + /* Check the Y-turns */ + if ( ras.numTurns == 0 ) + { + ras.error = Raster_Err_Invalid; + return FAILURE; + } + + /* Now inits the sweep */ + + ras.Proc_Sweep_Init( RAS_VARS &min_Y, &max_Y ); + + /* Then compute the distance of each profile from min_Y */ + + P = wait; + + while ( P ) + { + P->countL = P->start - min_Y; + P = P->link; + } + + /* Let's go */ + + y = min_Y; + y_height = 0; + + if ( ras.numTurns > 0 && + ras.sizeBuff[-ras.numTurns] == min_Y ) + ras.numTurns--; + + while ( ras.numTurns > 0 ) + { + /* look in the wait list for new activations */ + + P = wait; + + while ( P ) + { + Q = P->link; + P->countL -= y_height; + if ( P->countL == 0 ) + { + DelOld( &wait, P ); + + switch ( P->flow ) + { + case Flow_Up: + InsNew( &draw_left, P ); + break; + + case Flow_Down: + InsNew( &draw_right, P ); + break; + } + } + + P = Q; + } + + /* Sort the drawing lists */ + + Sort( &draw_left ); + Sort( &draw_right ); + + y_change = (Short)ras.sizeBuff[-ras.numTurns--]; + y_height = y_change - y; + + while ( y < y_change ) + { + /* Let's trace */ + + dropouts = 0; + + P_Left = draw_left; + P_Right = draw_right; + + while ( P_Left ) + { + x1 = P_Left ->X; + x2 = P_Right->X; + + if ( x1 > x2 ) + { + xs = x1; + x1 = x2; + x2 = xs; + } + + if ( x2 - x1 <= ras.precision ) + { + e1 = FLOOR( x1 ); + e2 = CEILING( x2 ); + + if ( ras.dropOutControl != 0 && + ( e1 > e2 || e2 == e1 + ras.precision ) ) + { + /* a drop out was detected */ + + P_Left ->X = x1; + P_Right->X = x2; + + /* mark profile for drop-out processing */ + P_Left->countL = 1; + dropouts++; + + goto Skip_To_Next; + } + } + + ras.Proc_Sweep_Span( RAS_VARS y, x1, x2, P_Left, P_Right ); + + Skip_To_Next: + + P_Left = P_Left->link; + P_Right = P_Right->link; + } + + /* now perform the dropouts _after_ the span drawing -- */ + /* drop-outs processing has been moved out of the loop */ + /* for performance tuning */ + if ( dropouts > 0 ) + goto Scan_DropOuts; + + Next_Line: + + ras.Proc_Sweep_Step( RAS_VAR ); + + y++; + + if ( y < y_change ) + { + Sort( &draw_left ); + Sort( &draw_right ); + } + } + + /* Now finalize the profiles that needs it */ + + { + PProfile Q, P; + + + P = draw_left; + while ( P ) + { + Q = P->link; + if ( P->height == 0 ) + DelOld( &draw_left, P ); + P = Q; + } + } + + { + PProfile Q, P = draw_right; + + + while ( P ) + { + Q = P->link; + if ( P->height == 0 ) + DelOld( &draw_right, P ); + P = Q; + } + } + } + + /* for gray-scaling, flushes the bitmap scanline cache */ + while ( y <= max_Y ) + { + ras.Proc_Sweep_Step( RAS_VAR ); + y++; + } + + return SUCCESS; + + Scan_DropOuts: + + P_Left = draw_left; + P_Right = draw_right; + + while ( P_Left ) + { + if ( P_Left->countL ) + { + P_Left->countL = 0; +#if 0 + dropouts--; /* -- this is useful when debugging only */ +#endif + ras.Proc_Sweep_Drop( RAS_VARS y, + P_Left->X, + P_Right->X, + P_Left, + P_Right ); + } + + P_Left = P_Left->link; + P_Right = P_Right->link; + } + + goto Next_Line; + } + + + /*************************************************************************/ + /* */ + /* */ + /* Render_Single_Pass */ + /* */ + /* */ + /* Performs one sweep with sub-banding. */ + /* */ + /* */ + /* flipped :: If set, flip the direction of the outline. */ + /* */ + /* */ + /* Renderer error code. */ + /* */ + static + int Render_Single_Pass( RAS_ARGS Bool flipped ) + { + Short i, j, k; + + + while ( ras.band_top >= 0 ) + { + ras.maxY = (Long)ras.band_stack[ras.band_top].y_max * ras.precision; + ras.minY = (Long)ras.band_stack[ras.band_top].y_min * ras.precision; + + ras.top = ras.buff; + + ras.error = Raster_Err_None; + + if ( Convert_Glyph( RAS_VARS flipped ) ) + { + if ( ras.error != Raster_Err_Overflow ) + return FAILURE; + + ras.error = Raster_Err_None; + + /* sub-banding */ + +#ifdef DEBUG_RASTER + ClearBand( RAS_VARS TRUNC( ras.minY ), TRUNC( ras.maxY ) ); +#endif + + i = ras.band_stack[ras.band_top].y_min; + j = ras.band_stack[ras.band_top].y_max; + + k = ( i + j ) / 2; + + if ( ras.band_top >= 7 || k < i ) + { + ras.band_top = 0; + ras.error = Raster_Err_Invalid; + + return ras.error; + } + + ras.band_stack[ras.band_top + 1].y_min = k; + ras.band_stack[ras.band_top + 1].y_max = j; + + ras.band_stack[ras.band_top].y_max = k - 1; + + ras.band_top++; + } + else + { + if ( ras.fProfile ) + if ( Draw_Sweep( RAS_VAR ) ) + return ras.error; + ras.band_top--; + } + } + + return SUCCESS; + } + + + /*************************************************************************/ + /* */ + /* */ + /* Render_Glyph */ + /* */ + /* */ + /* Renders a glyph in a bitmap. Sub-banding if needed. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* XXX Fixme: ftraster's error codes don't harmonize with FT2's ones! */ + /* */ + LOCAL_FUNC + FT_Error Render_Glyph( RAS_ARG ) + { + FT_Error error; + + + Set_High_Precision( RAS_VARS ras.outline.flags & + ft_outline_high_precision ); + ras.scale_shift = ras.precision_shift; + ras.dropOutControl = 2; + ras.second_pass = !( ras.outline.flags & ft_outline_single_pass ); + + /* Vertical Sweep */ + ras.Proc_Sweep_Init = Vertical_Sweep_Init; + ras.Proc_Sweep_Span = Vertical_Sweep_Span; + ras.Proc_Sweep_Drop = Vertical_Sweep_Drop; + ras.Proc_Sweep_Step = Vertical_Sweep_Step; + + ras.band_top = 0; + ras.band_stack[0].y_min = 0; + ras.band_stack[0].y_max = ras.target.rows - 1; + + ras.bWidth = ras.target.width; + ras.bTarget = (Byte*)ras.target.buffer; + + if ( ( error = Render_Single_Pass( RAS_VARS 0 ) ) != 0 ) + return error; + + /* Horizontal Sweep */ + if ( ras.second_pass && ras.dropOutControl != 0 ) + { + ras.Proc_Sweep_Init = Horizontal_Sweep_Init; + ras.Proc_Sweep_Span = Horizontal_Sweep_Span; + ras.Proc_Sweep_Drop = Horizontal_Sweep_Drop; + ras.Proc_Sweep_Step = Horizontal_Sweep_Step; + + ras.band_top = 0; + ras.band_stack[0].y_min = 0; + ras.band_stack[0].y_max = ras.target.width - 1; + + if ( ( error = Render_Single_Pass( RAS_VARS 1 ) ) != 0 ) + return error; + } + + return FT_Err_Ok; + } + + +#ifdef FT_RASTER_OPTION_ANTI_ALIASING + + + /*************************************************************************/ + /* */ + /* */ + /* Render_Gray_Glyph */ + /* */ + /* */ + /* Renders a glyph with grayscaling. Sub-banding if needed. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + LOCAL_FUNC + FT_Error Render_Gray_Glyph( RAS_ARG ) + { + Long pixel_width; + FT_Error error; + + + Set_High_Precision( RAS_VARS ras.outline.flags & + ft_outline_high_precision ); + ras.scale_shift = ras.precision_shift + 1; + ras.dropOutControl = 2; + ras.second_pass = !( ras.outline.flags & ft_outline_single_pass ); + + /* Vertical Sweep */ + + ras.band_top = 0; + ras.band_stack[0].y_min = 0; + ras.band_stack[0].y_max = 2 * ras.target.rows - 1; + + ras.bWidth = ras.gray_width; + pixel_width = 2 * ( ( ras.target.width + 3 ) >> 2 ); + + if ( ras.bWidth > pixel_width ) + ras.bWidth = pixel_width; + + ras.bWidth = ras.bWidth * 8; + ras.bTarget = (Byte*)ras.gray_lines; + ras.gTarget = (Byte*)ras.target.buffer; + + ras.Proc_Sweep_Init = Vertical_Gray_Sweep_Init; + ras.Proc_Sweep_Span = Vertical_Sweep_Span; + ras.Proc_Sweep_Drop = Vertical_Sweep_Drop; + ras.Proc_Sweep_Step = Vertical_Gray_Sweep_Step; + + error = Render_Single_Pass( RAS_VARS 0 ); + if ( error ) + return error; + + /* Horizontal Sweep */ + if ( ras.second_pass && ras.dropOutControl != 0 ) + { + ras.Proc_Sweep_Init = Horizontal_Sweep_Init; + ras.Proc_Sweep_Span = Horizontal_Gray_Sweep_Span; + ras.Proc_Sweep_Drop = Horizontal_Gray_Sweep_Drop; + ras.Proc_Sweep_Step = Horizontal_Sweep_Step; + + ras.band_top = 0; + ras.band_stack[0].y_min = 0; + ras.band_stack[0].y_max = ras.target.width * 2 - 1; + + error = Render_Single_Pass( RAS_VARS 1 ); + if ( error ) + return error; + } + + return FT_Err_Ok; + } + +#else /* FT_RASTER_OPTION_ANTI_ALIASING */ + + LOCAL_FUNC + FT_Error Render_Gray_Glyph( RAS_ARG ) + { + FT_UNUSED_RASTER; + + return FT_Err_Cannot_Render_Glyph; + } + +#endif /* FT_RASTER_OPTION_ANTI_ALIASING */ + + + static + void ft_black_init( TRaster_Instance* raster ) + { + FT_UInt n; + FT_ULong c; + + + /* setup count table */ + for ( n = 0; n < 256; n++ ) + { + c = ( n & 0x55 ) + ( ( n & 0xAA ) >> 1 ); + + c = ( ( c << 6 ) & 0x3000 ) | + ( ( c << 4 ) & 0x0300 ) | + ( ( c << 2 ) & 0x0030 ) | + (c & 0x0003 ); + + raster->count_table[n] = c; + } + +#ifdef FT_RASTER_OPTION_ANTI_ALIASING + + /* set default 5-levels gray palette */ + for ( n = 0; n < 5; n++ ) + raster->grays[n] = n * 255 / 4; + + raster->gray_width = RASTER_GRAY_LINES / 2; + +#endif + } + + + /**** RASTER OBJECT CREATION: In standalone mode, we simply use *****/ + /**** a static object. *****/ + + +#ifdef _STANDALONE_ + + + static + int ft_black_new( void* memory, + FT_Raster *araster ) + { + static FT_RasterRec_ the_raster; + + + *araster = &the_raster; + memset( &the_raster, sizeof ( the_raster ), 0 ); + ft_black_init( &the_raster ); + + return 0; + } + + + static + void ft_black_done( FT_Raster raster ) + { + /* nothing */ + raster->init = 0; + } + + +#else /* _STANDALONE_ */ + + + static + int ft_black_new( FT_Memory memory, + TRaster_Instance** araster ) + { + FT_Error error; + TRaster_Instance* raster; + + + *araster = 0; + if ( !ALLOC( raster, sizeof ( *raster ) ) ) + { + raster->memory = memory; + ft_black_init( raster ); + + *araster = raster; + } + + return error; + } + + + static + void ft_black_done( TRaster_Instance* raster ) + { + FT_Memory memory = (FT_Memory)raster->memory; + FREE( raster ); + } + + +#endif /* _STANDALONE_ */ + + + static + void ft_black_reset( TRaster_Instance* raster, + const char* pool_base, + long pool_size ) + { + if ( raster && pool_base && pool_size >= 4096 ) + { + /* save the pool */ + raster->buff = (PLong)pool_base; + raster->sizeBuff = raster->buff + pool_size / sizeof ( Long ); + } + } + + + static + void ft_black_set_mode( TRaster_Instance* raster, + unsigned long mode, + const char* palette ) + { +#ifdef FT_RASTER_OPTION_ANTI_ALIASING + + if ( mode == FT_MAKE_TAG( 'p', 'a', 'l', '5' ) ) + { + /* set 5-levels gray palette */ + raster->grays[0] = palette[0]; + raster->grays[1] = palette[1]; + raster->grays[2] = palette[2]; + raster->grays[3] = palette[3]; + raster->grays[4] = palette[4]; + } + +#else + + FT_UNUSED( raster ); + FT_UNUSED( mode ); + FT_UNUSED( palette ); + +#endif + } + + + static + int ft_black_render( TRaster_Instance* raster, + FT_Raster_Params* params ) + { + FT_Outline* outline = (FT_Outline*)params->source; + FT_Bitmap* target_map = params->target; + + + if ( !raster || !raster->buff || !raster->sizeBuff ) + return Raster_Err_Not_Ini; + + if ( !outline || !outline->contours || !outline->points ) + return Raster_Err_Invalid; + + /* return immediately if the outline is empty */ + if ( outline->n_points == 0 || outline->n_contours <= 0 ) + return Raster_Err_None; + + if ( outline->n_points != outline->contours[outline->n_contours - 1] + 1 ) + return Raster_Err_Invalid; + + if ( !target_map || !target_map->buffer ) + return Raster_Err_Invalid; + + /* this version of the raster does not support direct rendering, sorry */ + if ( params->flags & ft_raster_flag_direct ) + return Raster_Err_Unsupported; + + ras.outline = *outline; + ras.target = *target_map; + + return ( ( params->flags & ft_raster_flag_aa ) + ? Render_Gray_Glyph( raster ) + : Render_Glyph( raster ) ); + } + + + FT_Raster_Funcs ft_standard_raster = + { + ft_glyph_format_outline, + (FT_Raster_New_Func) ft_black_new, + (FT_Raster_Reset_Func) ft_black_reset, + (FT_Raster_Set_Mode_Func)ft_black_set_mode, + (FT_Raster_Render_Func) ft_black_render, + (FT_Raster_Done_Func) ft_black_done + }; + + +/* END */ diff --git a/src/freetype/raster1/ftraster.h b/src/freetype/raster1/ftraster.h new file mode 100644 index 0000000000..5c7faae5a2 --- /dev/null +++ b/src/freetype/raster1/ftraster.h @@ -0,0 +1,50 @@ +/***************************************************************************/ +/* */ +/* ftraster.h */ +/* */ +/* The FreeType glyph rasterizer (specification). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used */ +/* modified and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef FTRASTER_H +#define FTRASTER_H + +#ifdef __cplusplus + extern "C" { +#endif + +#include + + + /*************************************************************************/ + /* */ + /* Uncomment the following line if you are using ftraster.c as a */ + /* standalone module, fully independent of FreeType. */ + /* */ +/* #define _STANDALONE_ */ + +#ifndef FT_EXPORT_VAR +#define FT_EXPORT_VAR( x ) extern x +#endif + + FT_EXPORT_VAR( FT_Raster_Funcs ) ft_standard_raster; + +#ifdef __cplusplus + } +#endif + + +#endif /* FTRASTER_H */ + + +/* END */ diff --git a/src/freetype/raster1/ftrend1.c b/src/freetype/raster1/ftrend1.c new file mode 100644 index 0000000000..d774cf1d40 --- /dev/null +++ b/src/freetype/raster1/ftrend1.c @@ -0,0 +1,275 @@ +/***************************************************************************/ +/* */ +/* ftrend1.c */ +/* */ +/* The FreeType glyph rasterizer interface (body). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#include +#include + + +#ifdef FT_FLAT_COMPILE + +#include "ftrend1.h" +#include "ftraster.h" + +#else + +#include +#include + +#endif + + + /* initialize renderer -- init its raster */ + static + FT_Error ft_raster1_init( FT_Renderer render ) + { + FT_Library library = FT_MODULE_LIBRARY( render ); + + + render->clazz->raster_class->raster_reset( render->raster, + library->raster_pool, + library->raster_pool_size ); + + return FT_Err_Ok; + } + + + /* set render-specific mode */ + static + FT_Error ft_raster1_set_mode( FT_Renderer render, + FT_ULong mode_tag, + FT_Pointer data ) + { + /* we simply pass it to the raster */ + return render->clazz->raster_class->raster_set_mode( render->raster, + mode_tag, + data ); + } + + + /* transform a given glyph image */ + static + FT_Error ft_raster1_transform( FT_Renderer render, + FT_GlyphSlot slot, + FT_Matrix* matrix, + FT_Vector* delta ) + { + FT_Error error = FT_Err_Ok; + + + if ( slot->format != render->glyph_format ) + { + error = FT_Err_Invalid_Argument; + goto Exit; + } + + if ( matrix ) + FT_Outline_Transform( &slot->outline, matrix ); + + if ( delta ) + FT_Outline_Translate( &slot->outline, delta->x, delta->y ); + + Exit: + return error; + } + + + /* return the glyph's control box */ + static + void ft_raster1_get_cbox( FT_Renderer render, + FT_GlyphSlot slot, + FT_BBox* cbox ) + { + MEM_Set( cbox, 0, sizeof ( *cbox ) ); + + if ( slot->format == render->glyph_format ) + FT_Outline_Get_CBox( &slot->outline, cbox ); + } + + + /* convert a slot's glyph image into a bitmap */ + static + FT_Error ft_raster1_render( FT_Renderer render, + FT_GlyphSlot slot, + FT_UInt mode, + FT_Vector* origin ) + { + FT_Error error; + FT_Outline* outline; + FT_BBox cbox; + FT_UInt width, height, pitch; + FT_Bitmap* bitmap; + FT_Memory memory; + + FT_Raster_Params params; + + + /* check glyph image format */ + if ( slot->format != render->glyph_format ) + { + error = FT_Err_Invalid_Argument; + goto Exit; + } + + /* check rendering mode */ + if ( mode != ft_render_mode_mono ) + { + /* raster1 is only capable of producing monochrome bitmaps */ + if ( render->clazz == &ft_raster1_renderer_class ) + return FT_Err_Cannot_Render_Glyph; + } + else + { + /* raster5 is only capable of producing 5-gray-levels bitmaps */ + if ( render->clazz == &ft_raster5_renderer_class ) + return FT_Err_Cannot_Render_Glyph; + } + + outline = &slot->outline; + + /* translate the outline to the new origin if needed */ + if ( origin ) + FT_Outline_Translate( outline, origin->x, origin->y ); + + /* compute the control box, and grid fit it */ + FT_Outline_Get_CBox( outline, &cbox ); + + cbox.xMin &= -64; + cbox.yMin &= -64; + cbox.xMax = ( cbox.xMax + 63 ) & -64; + cbox.yMax = ( cbox.yMax + 63 ) & -64; + + width = ( cbox.xMax - cbox.xMin ) >> 6; + height = ( cbox.yMax - cbox.yMin ) >> 6; + bitmap = &slot->bitmap; + memory = render->root.memory; + + /* release old bitmap buffer */ + if ( slot->flags & ft_glyph_own_bitmap ) + { + FREE( bitmap->buffer ); + slot->flags &= ~ft_glyph_own_bitmap; + } + + /* allocate new one, depends on pixel format */ + if ( !( mode & ft_render_mode_mono ) ) + { + /* we pad to 32 bits, only for backwards compatibility with FT 1.x */ + pitch = ( width + 3 ) & -4; + bitmap->pixel_mode = ft_pixel_mode_grays; + bitmap->num_grays = 256; + } + else + { + pitch = ( width + 7 ) >> 3; + bitmap->pixel_mode = ft_pixel_mode_mono; + } + + bitmap->width = width; + bitmap->rows = height; + bitmap->pitch = pitch; + + if ( ALLOC( bitmap->buffer, (FT_ULong)pitch * height ) ) + goto Exit; + + slot->flags |= ft_glyph_own_bitmap; + + /* translate outline to render it into the bitmap */ + FT_Outline_Translate( outline, -cbox.xMin, -cbox.yMin ); + + /* set up parameters */ + params.target = bitmap; + params.source = outline; + params.flags = 0; + + if ( bitmap->pixel_mode == ft_pixel_mode_grays ) + params.flags |= ft_raster_flag_aa; + + /* render outline into the bitmap */ + error = render->raster_render( render->raster, ¶ms ); + if ( error ) + goto Exit; + + slot->format = ft_glyph_format_bitmap; + slot->bitmap_left = cbox.xMin >> 6; + slot->bitmap_top = cbox.yMax >> 6; + + Exit: + return error; + } + + + const FT_Renderer_Class ft_raster1_renderer_class = + { + { + ft_module_renderer, + sizeof( FT_RendererRec ), + + "raster1", + 0x10000L, + 0x20000L, + + 0, /* module specific interface */ + + (FT_Module_Constructor)ft_raster1_init, + (FT_Module_Destructor) 0, + (FT_Module_Requester) 0 + }, + + ft_glyph_format_outline, + + (FTRenderer_render) ft_raster1_render, + (FTRenderer_transform)ft_raster1_transform, + (FTRenderer_getCBox) ft_raster1_get_cbox, + (FTRenderer_setMode) ft_raster1_set_mode, + + (FT_Raster_Funcs*) &ft_standard_raster + }; + + + /* this renderer is _NOT_ part of the default modules, you'll need */ + /* to register it by hand in your application. It should only be */ + /* used for backwards-compatibility with FT 1.x anyway. */ + const FT_Renderer_Class ft_raster5_renderer_class = + { + { + ft_module_renderer, + sizeof( FT_RendererRec ), + + "raster5", + 0x10000L, + 0x20000L, + + 0, /* module specific interface */ + + (FT_Module_Constructor)ft_raster1_init, + (FT_Module_Destructor) 0, + (FT_Module_Requester) 0 + }, + + ft_glyph_format_outline, + + (FTRenderer_render) ft_raster1_render, + (FTRenderer_transform)ft_raster1_transform, + (FTRenderer_getCBox) ft_raster1_get_cbox, + (FTRenderer_setMode) ft_raster1_set_mode, + + (FT_Raster_Funcs*) &ft_standard_raster + }; + + +/* END */ diff --git a/src/freetype/raster1/ftrend1.h b/src/freetype/raster1/ftrend1.h new file mode 100644 index 0000000000..b8fff83114 --- /dev/null +++ b/src/freetype/raster1/ftrend1.h @@ -0,0 +1,37 @@ +/***************************************************************************/ +/* */ +/* ftrend1.h */ +/* */ +/* The FreeType glyph rasterizer interface (specification). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef FTREND1_H +#define FTREND1_H + +#include + + + FT_EXPORT_VAR( const FT_Renderer_Class ) ft_raster1_renderer_class; + + /* this renderer is _NOT_ part of the default modules, you'll need */ + /* to register it by hand in your application. It should only be */ + /* used for backwards-compatibility with FT 1.x anyway. */ + /* */ + FT_EXPORT_VAR( const FT_Renderer_Class ) ft_raster5_renderer_class; + + +#endif /* FTREND1_H */ + + +/* END */ diff --git a/src/freetype/raster1/module.mk b/src/freetype/raster1/module.mk new file mode 100644 index 0000000000..c1ceb21293 --- /dev/null +++ b/src/freetype/raster1/module.mk @@ -0,0 +1,7 @@ +make_module_list: add_raster1_module + +add_raster1_module: + $(OPEN_DRIVER)ft_raster1_renderer_class$(CLOSE_DRIVER) + $(ECHO_DRIVER)raster1 $(ECHO_DRIVER_DESC)monochrome bitmap renderer$(ECHO_DRIVER_DONE) + +# EOF diff --git a/src/freetype/raster1/raster1.c b/src/freetype/raster1/raster1.c new file mode 100644 index 0000000000..cf2835abc5 --- /dev/null +++ b/src/freetype/raster1/raster1.c @@ -0,0 +1,35 @@ +/***************************************************************************/ +/* */ +/* raster1.c */ +/* */ +/* FreeType monochrome rasterer module component (body only). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#define FT_MAKE_OPTION_SINGLE_OBJECT + + +#ifdef FT_FLAT_COMPILE + +#include "ftraster.c" +#include "ftrend1.c" + +#else + +#include +#include + +#endif + + +/* END */ diff --git a/src/freetype/raster1/rules.mk b/src/freetype/raster1/rules.mk new file mode 100644 index 0000000000..38108450ef --- /dev/null +++ b/src/freetype/raster1/rules.mk @@ -0,0 +1,69 @@ +# +# FreeType 2 renderer module build rules +# + + +# Copyright 1996-2000 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +# raster1 driver directory +# +RAS1_DIR := $(SRC_)raster1 +RAS1_DIR_ := $(RAS1_DIR)$(SEP) + +# compilation flags for the driver +# +RAS1_COMPILE := $(FT_COMPILE) + + +# raster1 driver sources (i.e., C files) +# +RAS1_DRV_SRC := $(RAS1_DIR_)ftraster.c \ + $(RAS1_DIR_)ftrend1.c + + +# raster1 driver headers +# +RAS1_DRV_H := $(RAS1_DRV_SRC:%.c=%.h) + + +# raster1 driver object(s) +# +# RAS1_DRV_OBJ_M is used during `multi' builds. +# RAS1_DRV_OBJ_S is used during `single' builds. +# +RAS1_DRV_OBJ_M := $(RAS1_DRV_SRC:$(RAS1_DIR_)%.c=$(OBJ_)%.$O) +RAS1_DRV_OBJ_S := $(OBJ_)raster1.$O + +# raster1 driver source file for single build +# +RAS1_DRV_SRC_S := $(RAS1_DIR_)raster1.c + + +# raster1 driver - single object +# +$(RAS1_DRV_OBJ_S): $(RAS1_DRV_SRC_S) $(RAS1_DRV_SRC) \ + $(FREETYPE_H) $(RAS1_DRV_H) + $(RAS1_COMPILE) $T$@ $(RAS1_DRV_SRC_S) + + +# raster1 driver - multiple objects +# +$(OBJ_)%.$O: $(RAS1_DIR_)%.c $(FREETYPE_H) $(RAS1_DRV_H) + $(RAS1_COMPILE) $T$@ $< + + +# update main driver object lists +# +DRV_OBJS_S += $(RAS1_DRV_OBJ_S) +DRV_OBJS_M += $(RAS1_DRV_OBJ_M) + + +# EOF diff --git a/src/freetype/sfnt/module.mk b/src/freetype/sfnt/module.mk new file mode 100644 index 0000000000..48b494f4d2 --- /dev/null +++ b/src/freetype/sfnt/module.mk @@ -0,0 +1,7 @@ +make_module_list: add_sfnt_module + +add_sfnt_module: + $(OPEN_DRIVER)sfnt_module_class$(CLOSE_DRIVER) + $(ECHO_DRIVER)sfnt $(ECHO_DRIVER_DESC)helper module for TrueType & OpenType formats$(ECHO_DRIVER_DONE) + +# EOF diff --git a/src/freetype/sfnt/rules.mk b/src/freetype/sfnt/rules.mk new file mode 100644 index 0000000000..2255e6a087 --- /dev/null +++ b/src/freetype/sfnt/rules.mk @@ -0,0 +1,73 @@ +# +# FreeType 2 SFNT driver configuration rules +# + + +# Copyright 1996-2000 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +# SFNT driver directory +# +SFNT_DIR := $(SRC_)sfnt +SFNT_DIR_ := $(SFNT_DIR)$(SEP) + + +# compilation flags for the driver +# +SFNT_COMPILE := $(FT_COMPILE) + + +# SFNT driver sources (i.e., C files) +# +SFNT_DRV_SRC := $(SFNT_DIR_)ttload.c \ + $(SFNT_DIR_)ttcmap.c \ + $(SFNT_DIR_)ttsbit.c \ + $(SFNT_DIR_)ttpost.c \ + $(SFNT_DIR_)sfobjs.c \ + $(SFNT_DIR_)sfdriver.c + +# SFNT driver headers +# +SFNT_DRV_H := $(SFNT_DRV_SRC:%c=%h) + + +# SFNT driver object(s) +# +# SFNT_DRV_OBJ_M is used during `multi' builds. +# SFNT_DRV_OBJ_S is used during `single' builds. +# +SFNT_DRV_OBJ_M := $(SFNT_DRV_SRC:$(SFNT_DIR_)%.c=$(OBJ_)%.$O) +SFNT_DRV_OBJ_S := $(OBJ_)sfnt.$O + +# SFNT driver source file for single build +# +SFNT_DRV_SRC_S := $(SFNT_DIR_)sfnt.c + + +# SFNT driver - single object +# +$(SFNT_DRV_OBJ_S): $(SFNT_DRV_SRC_S) $(SFNT_DRV_SRC) \ + $(FREETYPE_H) $(SFNT_DRV_H) + $(SFNT_COMPILE) $T$@ $(SFNT_DRV_SRC_S) + + +# SFNT driver - multiple objects +# +$(OBJ_)%.$O: $(SFNT_DIR_)%.c $(FREETYPE_H) $(SFNT_DRV_H) + $(SFNT_COMPILE) $T$@ $< + + +# update main driver object lists +# +DRV_OBJS_S += $(SFNT_DRV_OBJ_S) +DRV_OBJS_M += $(SFNT_DRV_OBJ_M) + + +# EOF diff --git a/src/freetype/sfnt/sfdriver.c b/src/freetype/sfnt/sfdriver.c new file mode 100644 index 0000000000..96a738b43c --- /dev/null +++ b/src/freetype/sfnt/sfdriver.c @@ -0,0 +1,225 @@ +/***************************************************************************/ +/* */ +/* sfdriver.c */ +/* */ +/* High-level SFNT driver interface (body). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#include +#include + + +#ifdef FT_FLAT_COMPILE + +#include "sfdriver.h" +#include "ttload.h" +#include "ttsbit.h" +#include "ttpost.h" +#include "ttcmap.h" +#include "sfobjs.h" + +#else + +#include +#include +#include +#include +#include +#include + +#endif + + +#include /* for strcmp() */ + + + static + void* get_sfnt_table( TT_Face face, + FT_Sfnt_Tag tag ) + { + void* table; + + + switch ( tag ) + { + case ft_sfnt_head: + table = &face->header; + break; + + case ft_sfnt_hhea: + table = &face->horizontal; + break; + + case ft_sfnt_vhea: + table = face->vertical_info ? &face->vertical : 0; + break; + + case ft_sfnt_os2: + table = face->os2.version == 0xFFFF ? 0 : &face->os2; + break; + + case ft_sfnt_post: + table = &face->postscript; + break; + + case ft_sfnt_maxp: + table = &face->max_profile; + break; + + case ft_sfnt_pclt: + table = face->pclt.Version ? &face->pclt : 0; + break; + + default: + table = 0; + } + + return table; + } + + +#ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES + + + static + FT_Error get_sfnt_glyph_name( TT_Face face, + FT_UInt glyph_index, + FT_Pointer buffer, + FT_UInt buffer_max ) + { + FT_String* gname; + FT_Error error; + + + error = TT_Get_PS_Name( face, glyph_index, &gname ); + if ( !error && buffer_max > 0 ) + { + FT_UInt len = strlen( gname ); + + + if ( len >= buffer_max ) + len = buffer_max - 1; + + MEM_Copy( buffer, gname, len ); + ((FT_Byte*)buffer)[len] = 0; + } + + return error; + } + + +#endif /* TT_CONFIG_OPTION_POSTSCRIPT_NAMES */ + + + static + FT_Module_Interface SFNT_Get_Interface( FT_Module module, + const char* interface ) + { + FT_UNUSED( module ); + + if ( strcmp( interface, "get_sfnt" ) == 0 ) + return (FT_Module_Interface)get_sfnt_table; + +#ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES + if ( strcmp( interface, "glyph_name" ) == 0 ) + return (FT_Module_Interface)get_sfnt_glyph_name; +#endif + return 0; + } + + + static + const SFNT_Interface sfnt_interface = + { + TT_Goto_Table, + + SFNT_Init_Face, + SFNT_Load_Face, + SFNT_Done_Face, + SFNT_Get_Interface, + + TT_Load_Any, + TT_Load_SFNT_Header, + TT_Load_Directory, + + TT_Load_Header, + TT_Load_Metrics_Header, + TT_Load_CMap, + TT_Load_MaxProfile, + TT_Load_OS2, + TT_Load_PostScript, + + TT_Load_Names, + TT_Free_Names, + + TT_Load_Hdmx, + TT_Free_Hdmx, + + TT_Load_Kern, + TT_Load_Gasp, + TT_Load_PCLT, + +#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS + + /* see `ttsbit.h' */ + TT_Load_SBit_Strikes, + TT_Load_SBit_Image, + TT_Free_SBit_Strikes, + +#else /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ + + 0, + 0, + 0, + +#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ + +#ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES + + /* see `ttpost.h' */ + TT_Get_PS_Name, + TT_Free_Post_Names, + +#else /* TT_CONFIG_OPTION_POSTSCRIPT_NAMES */ + + 0, + 0, + +#endif /* TT_CONFIG_OPTION_POSTSCRIPT_NAMES */ + + /* see `ttcmap.h' */ + TT_CharMap_Load, + TT_CharMap_Free, + }; + + + const + FT_Module_Class sfnt_module_class = + { + 0, /* not a font driver or renderer */ + sizeof( FT_ModuleRec ), + + "sfnt", /* driver name */ + 0x10000L, /* driver version 1.0 */ + 0x20000L, /* driver requires FreeType 2.0 or higher */ + + (const void*)&sfnt_interface, /* module specific interface */ + + (FT_Module_Constructor)0, + (FT_Module_Destructor) 0, + (FT_Module_Requester) SFNT_Get_Interface + }; + + +/* END */ diff --git a/src/freetype/sfnt/sfdriver.h b/src/freetype/sfnt/sfdriver.h new file mode 100644 index 0000000000..92c9c8129d --- /dev/null +++ b/src/freetype/sfnt/sfdriver.h @@ -0,0 +1,29 @@ +/***************************************************************************/ +/* */ +/* sfdriver.h */ +/* */ +/* High-level SFNT driver interface (specification). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef SFDRIVER_H +#define SFDRIVER_H + +#include + + FT_EXPORT_VAR( const FT_Module_Class ) sfnt_module_class; + +#endif /* SFDRIVER_H */ + + +/* END */ diff --git a/src/freetype/sfnt/sfnt.c b/src/freetype/sfnt/sfnt.c new file mode 100644 index 0000000000..cca73425ce --- /dev/null +++ b/src/freetype/sfnt/sfnt.c @@ -0,0 +1,57 @@ +/***************************************************************************/ +/* */ +/* sfnt.c */ +/* */ +/* Single object library component. */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#define FT_MAKE_OPTION_SINGLE_OBJECT + + +#ifdef FT_FLAT_COMPILE + +#include "ttload.c" +#include "ttcmap.c" +#include "sfobjs.c" + +#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS +#include "ttsbit.c" +#endif + +#ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES +#include "ttpost.c" +#endif + +#include "sfdriver.c" + +#else /* FT_FLAT_COMPILE */ + +#include +#include +#include + +#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS +#include +#endif + +#ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES +#include +#endif + +#include + +#endif /* FT_FLAT_COMPILE */ + + +/* END */ diff --git a/src/freetype/sfnt/sfobjs.c b/src/freetype/sfnt/sfobjs.c new file mode 100644 index 0000000000..4ae85022e8 --- /dev/null +++ b/src/freetype/sfnt/sfobjs.c @@ -0,0 +1,561 @@ +/***************************************************************************/ +/* */ +/* sfobjs.c */ +/* */ +/* SFNT object management (base). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifdef FT_FLAT_COMPILE + +#include "sfobjs.h" + +#else + +#include + +#endif + + +#include +#include +#include +#include + + + /*************************************************************************/ + /* */ + /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ + /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ + /* messages during execution. */ + /* */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_sfobjs + + + /*************************************************************************/ + /* */ + /* */ + /* Get_Name */ + /* */ + /* */ + /* Returns a given ENGLISH name record in ASCII. */ + /* */ + /* */ + /* face :: A handle to the source face object. */ + /* */ + /* nameid :: The name id of the name record to return. */ + /* */ + /* */ + /* Character string. NULL if no name is present. */ + /* */ + static + FT_String* Get_Name( TT_Face face, + FT_UShort nameid ) + { + FT_Memory memory = face->root.memory; + FT_UShort n; + TT_NameRec* rec; + FT_Bool wide_chars = 1; + + + rec = face->name_table.names; + for ( n = 0; n < face->name_table.numNameRecords; n++, rec++ ) + { + if ( rec->nameID == nameid ) + { + /* found the name -- now create an ASCII string from it */ + FT_Bool found = 0; + + + /* test for Microsoft English language */ + if ( rec->platformID == TT_PLATFORM_MICROSOFT && + rec->encodingID <= TT_MS_ID_UNICODE_CS && + ( rec->languageID & 0x3FF ) == 0x009 ) + found = 1; + + /* test for Apple Unicode encoding */ + else if ( rec->platformID == TT_PLATFORM_APPLE_UNICODE ) + found = 1; + + /* test for Apple Roman */ + else if ( rec->platformID == TT_PLATFORM_MACINTOSH && + rec->languageID == TT_MAC_ID_ROMAN ) + { + found = 1; + wide_chars = 0; + } + + /* found a Unicode name */ + if ( found ) + { + FT_String* string; + FT_UInt len; + + + if ( wide_chars ) + { + FT_UInt m; + + + len = (FT_UInt)rec->stringLength / 2; + if ( MEM_Alloc( string, len + 1 ) ) + return NULL; + + for ( m = 0; m < len; m ++ ) + string[m] = rec->string[2 * m + 1]; + } + else + { + len = rec->stringLength; + if ( MEM_Alloc( string, len + 1 ) ) + return NULL; + + MEM_Copy( string, rec->string, len ); + } + + string[len] = '\0'; + return string; + } + } + } + + return NULL; + } + + + static + FT_Encoding find_encoding( int platform_id, + int encoding_id ) + { + typedef struct TEncoding + { + int platform_id; + int encoding_id; + FT_Encoding encoding; + + } TEncoding; + + static + const TEncoding tt_encodings[] = + { + { TT_PLATFORM_ISO, -1, ft_encoding_unicode }, + + { TT_PLATFORM_APPLE_UNICODE, -1, ft_encoding_unicode }, + + { TT_PLATFORM_MACINTOSH, TT_MAC_ID_ROMAN, ft_encoding_apple_roman }, + + { TT_PLATFORM_MICROSOFT, TT_MS_ID_UNICODE_CS, ft_encoding_unicode }, + { TT_PLATFORM_MICROSOFT, TT_MS_ID_SJIS, ft_encoding_sjis }, + { TT_PLATFORM_MICROSOFT, TT_MS_ID_GB2312, ft_encoding_gb2312 }, + { TT_PLATFORM_MICROSOFT, TT_MS_ID_BIG_5, ft_encoding_big5 }, + { TT_PLATFORM_MICROSOFT, TT_MS_ID_WANSUNG, ft_encoding_wansung }, + { TT_PLATFORM_MICROSOFT, TT_MS_ID_JOHAB, ft_encoding_johab } + }; + + const TEncoding *cur, *limit; + + + cur = tt_encodings; + limit = cur + sizeof ( tt_encodings ) / sizeof ( tt_encodings[0] ); + + for ( ; cur < limit; cur++ ) + { + if ( cur->platform_id == platform_id ) + { + if ( cur->encoding_id == encoding_id || + cur->encoding_id == -1 ) + return cur->encoding; + } + } + + return ft_encoding_none; + } + + + LOCAL_FUNC + FT_Error SFNT_Init_Face( FT_Stream stream, + TT_Face face, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ) + { + FT_Error error; + FT_Library library = face->root.driver->root.library; + SFNT_Interface* sfnt; + SFNT_Header sfnt_header; + + /* for now, parameters are unused */ + FT_UNUSED( num_params ); + FT_UNUSED( params ); + + sfnt = (SFNT_Interface*)face->sfnt; + if ( !sfnt ) + { + sfnt = (SFNT_Interface*)FT_Get_Module_Interface( library, "sfnt" ); + if ( !sfnt ) + { + error = FT_Err_Invalid_File_Format; + goto Exit; + } + + face->sfnt = sfnt; + face->goto_table = sfnt->goto_table; + } + + if ( !face->psnames ) + { + face->psnames = (PSNames_Interface*) + FT_Get_Module_Interface( library, "psnames" ); + } + + /* check that we have a valid TrueType file */ + error = sfnt->load_sfnt_header( face, stream, face_index, &sfnt_header ); + if ( error ) + goto Exit; + + face->format_tag = sfnt_header.format_tag; + face->num_tables = sfnt_header.num_tables; + + /* Load font directory */ + error = sfnt->load_directory( face, stream, &sfnt_header ); + if ( error ) + goto Exit; + + face->root.num_faces = face->ttc_header.count; + if ( face->root.num_faces < 1 ) + face->root.num_faces = 1; + + Exit: + return error; + } + + +#undef LOAD_ +#define LOAD_( x ) ( ( error = sfnt->load_##x( face, stream ) ) \ + != TT_Err_Ok ) + + + LOCAL_FUNC + FT_Error SFNT_Load_Face( FT_Stream stream, + TT_Face face, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ) + { + FT_Error error; + SFNT_Interface* sfnt = (SFNT_Interface*)face->sfnt; + + FT_UNUSED( face_index ); + FT_UNUSED( num_params ); + FT_UNUSED( params ); + + + /* Load tables */ + if ( LOAD_( header ) || + LOAD_( max_profile ) || + + /* load the `hhea' & `hmtx' tables at once */ + ( error = sfnt->load_metrics( face, stream, 0 ) ) != TT_Err_Ok || + + /* try to load the `vhea' & `vmtx' at once if present */ + ( error = sfnt->load_metrics( face, stream, 1 ) ) != TT_Err_Ok || + + LOAD_( charmaps ) || + LOAD_( names ) || + LOAD_( os2 ) || + LOAD_( psnames ) ) + goto Exit; + + /* the optional tables */ + +#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS + /* embedded bitmap support. */ + if ( sfnt->load_sbits && LOAD_( sbits ) ) + goto Exit; +#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ + + if ( LOAD_( hdmx ) || + LOAD_( gasp ) || + LOAD_( kerning ) || + LOAD_( pclt ) ) + goto Exit; + +#ifdef TT_CONFIG_OPTION_EXTEND_ENGINE + if ( ( error = TT_Extension_Create( face ) ) != TT_Err_Ok ) + goto Exit; +#endif + + face->root.family_name = Get_Name( face, TT_NAME_ID_FONT_FAMILY ); + face->root.style_name = Get_Name( face, TT_NAME_ID_FONT_SUBFAMILY ); + + /* now set up root fields */ + { + FT_Face root = &face->root; + FT_Int flags; + TT_CharMap charmap; + FT_Int n; + FT_Memory memory; + + + memory = root->memory; + + /*********************************************************************/ + /* */ + /* Compute face flags. */ + /* */ + flags = FT_FACE_FLAG_SCALABLE | /* scalable outlines */ + FT_FACE_FLAG_SFNT | /* SFNT file format */ + FT_FACE_FLAG_HORIZONTAL; /* horizontal data */ + +#ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES + /* might need more polish to detect the presence of a Postscript */ + /* name table in the font */ + flags |= FT_FACE_FLAG_GLYPH_NAMES; +#endif + + /* fixed width font? */ + if ( face->postscript.isFixedPitch ) + flags |= FT_FACE_FLAG_FIXED_WIDTH; + + /* vertical information? */ + if ( face->vertical_info ) + flags |= FT_FACE_FLAG_VERTICAL; + + /* kerning available ? */ + if ( face->kern_pairs ) + flags |= FT_FACE_FLAG_KERNING; + + root->face_flags = flags; + + /*********************************************************************/ + /* */ + /* Compute style flags. */ + /* */ + flags = 0; + + if ( face->os2.version != 0xFFFF ) + { + /* we have an OS/2 table; use the `fsSelection' field */ + if ( face->os2.fsSelection & 1 ) + flags |= FT_STYLE_FLAG_ITALIC; + + if ( face->os2.fsSelection & 32 ) + flags |= FT_STYLE_FLAG_BOLD; + } + else + { + /* this is an old Mac font, use the header field */ + if ( face->header.Mac_Style & 1 ) + flags |= FT_STYLE_FLAG_BOLD; + + if ( face->header.Mac_Style & 2 ) + flags |= FT_STYLE_FLAG_ITALIC; + } + + root->style_flags = flags; + + /*********************************************************************/ + /* */ + /* Polish the charmaps. */ + /* */ + /* Try to set the charmap encoding according to the platform & */ + /* encoding ID of each charmap. */ + /* */ + charmap = face->charmaps; + root->num_charmaps = face->num_charmaps; + + /* allocate table of pointers */ + if ( ALLOC_ARRAY( root->charmaps, root->num_charmaps, FT_CharMap ) ) + goto Exit; + + for ( n = 0; n < root->num_charmaps; n++, charmap++ ) + { + FT_Int platform = charmap->cmap.platformID; + FT_Int encoding = charmap->cmap.platformEncodingID; + + + charmap->root.face = (FT_Face)face; + charmap->root.platform_id = platform; + charmap->root.encoding_id = encoding; + charmap->root.encoding = find_encoding( platform, encoding ); + + /* now, set root->charmap with a unicode charmap */ + /* wherever available */ + if ( !root->charmap && + charmap->root.encoding == ft_encoding_unicode ) + root->charmap = (FT_CharMap)charmap; + + root->charmaps[n] = (FT_CharMap)charmap; + } + +#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS + + if ( face->num_sbit_strikes ) + { + root->num_fixed_sizes = face->num_sbit_strikes; + if ( ALLOC_ARRAY( root->available_sizes, + face->num_sbit_strikes, + FT_Bitmap_Size ) ) + return error; + + for ( n = 0 ; n < face->num_sbit_strikes ; n++ ) + { + root->available_sizes[n].width = + face->sbit_strikes[n].x_ppem; + root->available_sizes[n].height = + face->sbit_strikes[n].y_ppem; + } + } + else + +#else /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ + + { + root->num_fixed_sizes = 0; + root->available_sizes = 0; + } + +#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ + + /*********************************************************************/ + /* */ + /* Set up metrics. */ + /* */ + root->bbox.xMin = face->header.xMin; + root->bbox.yMin = face->header.yMin; + root->bbox.xMax = face->header.xMax; + root->bbox.yMax = face->header.yMax; + root->units_per_EM = face->header.Units_Per_EM; + + /* The ascender/descender/height are computed from the OS/2 table */ + /* when found. Otherwise, they're taken from the horizontal header. */ + if ( face->os2.version != 0xFFFF ) + { + root->ascender = face->os2.sTypoAscender; + root->descender = -face->os2.sTypoDescender; + root->height = root->ascender + root->descender + + face->os2.sTypoLineGap; + } + else + { + root->ascender = face->horizontal.Ascender; + root->descender = face->horizontal.Descender; + root->height = root->ascender + root->descender + + face->horizontal.Line_Gap; + } + + root->max_advance_width = face->horizontal.advance_Width_Max; + + root->max_advance_height = face->vertical_info + ? face->vertical.advance_Height_Max + : root->height; + + root->underline_position = face->postscript.underlinePosition; + root->underline_thickness = face->postscript.underlineThickness; + + /* root->max_points -- already set up */ + /* root->max_contours -- already set up */ + } + + Exit: + return error; + } + + +#undef LOAD_ + + + LOCAL_FUNC + void SFNT_Done_Face( TT_Face face ) + { + FT_Memory memory = face->root.memory; + SFNT_Interface* sfnt = (SFNT_Interface*)face->sfnt; + + + if ( sfnt ) + { + /* destroy the postscript names table if it is loaded */ + if ( sfnt->free_psnames ) + sfnt->free_psnames( face ); + + /* destroy the embedded bitmaps table if it is loaded */ + if ( sfnt->free_sbits ) + sfnt->free_sbits( face ); + } + + /* freeing the kerning table */ + FREE( face->kern_pairs ); + face->num_kern_pairs = 0; + + /* freeing the collection table */ + FREE( face->ttc_header.offsets ); + face->ttc_header.count = 0; + + /* freeing table directory */ + FREE( face->dir_tables ); + face->num_tables = 0; + + /* freeing the character mapping tables */ + if ( sfnt && sfnt->load_charmaps ) + { + FT_UShort n; + + + for ( n = 0; n < face->num_charmaps; n++ ) + sfnt->free_charmap( face, &face->charmaps[n].cmap ); + } + + FREE( face->charmaps ); + face->num_charmaps = 0; + + FREE( face->root.charmaps ); + face->root.num_charmaps = 0; + face->root.charmap = 0; + + /* freeing the horizontal metrics */ + FREE( face->horizontal.long_metrics ); + FREE( face->horizontal.short_metrics ); + + /* freeing the vertical ones, if any */ + if ( face->vertical_info ) + { + FREE( face->vertical.long_metrics ); + FREE( face->vertical.short_metrics ); + face->vertical_info = 0; + } + + /* freeing the gasp table */ + FREE( face->gasp.gaspRanges ); + face->gasp.numRanges = 0; + + /* freeing the name table */ + sfnt->free_names( face ); + + /* freeing the hdmx table */ + sfnt->free_hdmx( face ); + + /* freeing family and style name */ + FREE( face->root.family_name ); + FREE( face->root.style_name ); + + /* freeing sbit size table */ + face->root.num_fixed_sizes = 0; + if ( face->root.available_sizes ) + FREE( face->root.available_sizes ); + + face->sfnt = 0; + } + + +/* END */ diff --git a/src/freetype/sfnt/sfobjs.h b/src/freetype/sfnt/sfobjs.h new file mode 100644 index 0000000000..35d92f9d19 --- /dev/null +++ b/src/freetype/sfnt/sfobjs.h @@ -0,0 +1,57 @@ +/***************************************************************************/ +/* */ +/* sfobjs.h */ +/* */ +/* SFNT object management (specification). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef SFOBJS_H +#define SFOBJS_H + +#include +#include + + +#ifdef __cplusplus + extern "C" { +#endif + + + LOCAL_DEF + FT_Error SFNT_Init_Face( FT_Stream stream, + TT_Face face, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ); + + LOCAL_DEF + FT_Error SFNT_Load_Face( FT_Stream stream, + TT_Face face, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ); + + LOCAL_DEF + void SFNT_Done_Face( TT_Face face ); + + +#ifdef __cplusplus + } +#endif + + +#endif /* SFDRIVER_H */ + + +/* END */ diff --git a/src/freetype/sfnt/ttcmap.c b/src/freetype/sfnt/ttcmap.c new file mode 100644 index 0000000000..87ad04f014 --- /dev/null +++ b/src/freetype/sfnt/ttcmap.c @@ -0,0 +1,550 @@ +/***************************************************************************/ +/* */ +/* ttcmap.c */ +/* */ +/* TrueType character mapping table (cmap) support (body). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#include +#include + + +#ifdef FT_FLAT_COMPILE + +#include "ttload.h" +#include "ttcmap.h" + +#else + +#include +#include + +#endif + + + /*************************************************************************/ + /* */ + /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ + /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ + /* messages during execution. */ + /* */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_ttcmap + + + static FT_UInt code_to_index0( TT_CMapTable* charmap, + FT_ULong char_code ); + static FT_UInt code_to_index2( TT_CMapTable* charmap, + FT_ULong char_code ); + static FT_UInt code_to_index4( TT_CMapTable* charmap, + FT_ULong char_code ); + static FT_UInt code_to_index6( TT_CMapTable* charmap, + FT_ULong char_code ); + + + /*************************************************************************/ + /* */ + /* */ + /* TT_CharMap_Load */ + /* */ + /* */ + /* Loads a given TrueType character map into memory. */ + /* */ + /* */ + /* face :: A handle to the parent face object. */ + /* stream :: A handle to the current stream object. */ + /* */ + /* */ + /* table :: A pointer to a cmap object. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* The function assumes that the stream is already in use (i.e., */ + /* opened). In case of error, all partially allocated tables are */ + /* released. */ + /* */ + LOCAL_FUNC + FT_Error TT_CharMap_Load( TT_Face face, + TT_CMapTable* cmap, + FT_Stream stream ) + { + FT_Error error; + FT_Memory memory; + FT_UShort num_SH, num_Seg, i; + + FT_UShort u, l; + + TT_CMap0* cmap0; + TT_CMap2* cmap2; + TT_CMap4* cmap4; + TT_CMap6* cmap6; + + TT_CMap2SubHeader* cmap2sub; + TT_CMap4Segment* segments; + + + if ( cmap->loaded ) + return TT_Err_Ok; + + memory = stream->memory; + + if ( FILE_Seek( cmap->offset ) ) + return error; + + switch ( cmap->format ) + { + case 0: + cmap0 = &cmap->c.cmap0; + + if ( ALLOC( cmap0->glyphIdArray, 256L ) || + FILE_Read( cmap0->glyphIdArray, 256L ) ) + goto Fail; + + cmap->get_index = code_to_index0; + break; + + case 2: + num_SH = 0; + cmap2 = &cmap->c.cmap2; + + /* allocate subheader keys */ + + if ( ALLOC_ARRAY( cmap2->subHeaderKeys, 256, FT_UShort ) || + ACCESS_Frame( 512L ) ) + goto Fail; + + for ( i = 0; i < 256; i++ ) + { + u = GET_UShort() / 8; + cmap2->subHeaderKeys[i] = u; + + if ( num_SH < u ) + num_SH = u; + } + + FORGET_Frame(); + + /* load subheaders */ + + cmap2->numGlyphId = l = + ( ( cmap->length - 2L * ( 256 + 3 ) - num_SH * 8L ) & 0xFFFF ) / 2; + + if ( ALLOC_ARRAY( cmap2->subHeaders, + num_SH + 1, + TT_CMap2SubHeader ) || + ACCESS_Frame( ( num_SH + 1 ) * 8L ) ) + goto Fail; + + cmap2sub = cmap2->subHeaders; + + for ( i = 0; i <= num_SH; i++ ) + { + cmap2sub->firstCode = GET_UShort(); + cmap2sub->entryCount = GET_UShort(); + cmap2sub->idDelta = GET_Short(); + /* we apply the location offset immediately */ + cmap2sub->idRangeOffset = GET_UShort() - ( num_SH - i ) * 8 - 2; + + cmap2sub++; + } + + FORGET_Frame(); + + /* load glyph IDs */ + + if ( ALLOC_ARRAY( cmap2->glyphIdArray, l, FT_UShort ) || + ACCESS_Frame( l * 2L ) ) + goto Fail; + + for ( i = 0; i < l; i++ ) + cmap2->glyphIdArray[i] = GET_UShort(); + + FORGET_Frame(); + + cmap->get_index = code_to_index2; + break; + + case 4: + cmap4 = &cmap->c.cmap4; + + /* load header */ + + if ( ACCESS_Frame( 8L ) ) + goto Fail; + + cmap4->segCountX2 = GET_UShort(); + cmap4->searchRange = GET_UShort(); + cmap4->entrySelector = GET_UShort(); + cmap4->rangeShift = GET_UShort(); + + num_Seg = cmap4->segCountX2 / 2; + + FORGET_Frame(); + + /* load segments */ + + if ( ALLOC_ARRAY( cmap4->segments, + num_Seg, + TT_CMap4Segment ) || + ACCESS_Frame( ( num_Seg * 4 + 1 ) * 2L ) ) + goto Fail; + + segments = cmap4->segments; + + for ( i = 0; i < num_Seg; i++ ) + segments[i].endCount = GET_UShort(); + + (void)GET_UShort(); + + for ( i = 0; i < num_Seg; i++ ) + segments[i].startCount = GET_UShort(); + + for ( i = 0; i < num_Seg; i++ ) + segments[i].idDelta = GET_Short(); + + for ( i = 0; i < num_Seg; i++ ) + segments[i].idRangeOffset = GET_UShort(); + + FORGET_Frame(); + + cmap4->numGlyphId = l = + ( ( cmap->length - ( 16L + 8L * num_Seg ) ) & 0xFFFF ) / 2; + + /* load IDs */ + + if ( ALLOC_ARRAY( cmap4->glyphIdArray, l, FT_UShort ) || + ACCESS_Frame( l * 2L ) ) + goto Fail; + + for ( i = 0; i < l; i++ ) + cmap4->glyphIdArray[i] = GET_UShort(); + + FORGET_Frame(); + + cmap->get_index = code_to_index4; + + cmap4->last_segment = cmap4->segments; + break; + + case 6: + cmap6 = &cmap->c.cmap6; + + if ( ACCESS_Frame( 4L ) ) + goto Fail; + + cmap6->firstCode = GET_UShort(); + cmap6->entryCount = GET_UShort(); + + FORGET_Frame(); + + l = cmap6->entryCount; + + if ( ALLOC_ARRAY( cmap6->glyphIdArray, + cmap6->entryCount, + FT_Short ) || + ACCESS_Frame( l * 2L ) ) + goto Fail; + + for ( i = 0; i < l; i++ ) + cmap6->glyphIdArray[i] = GET_UShort(); + + FORGET_Frame(); + cmap->get_index = code_to_index6; + break; + + default: /* corrupt character mapping table */ + return TT_Err_Invalid_CharMap_Format; + + } + + return TT_Err_Ok; + + Fail: + TT_CharMap_Free( face, cmap ); + return error; + } + + + /*************************************************************************/ + /* */ + /* */ + /* TT_CharMap_Free */ + /* */ + /* */ + /* Destroys a character mapping table. */ + /* */ + /* */ + /* face :: A handle to the parent face object. */ + /* cmap :: A handle to a cmap object. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + LOCAL_FUNC + FT_Error TT_CharMap_Free( TT_Face face, + TT_CMapTable* cmap ) + { + FT_Memory memory; + + + if ( !cmap ) + return TT_Err_Ok; + + memory = face->root.driver->root.memory; + + switch ( cmap->format ) + { + case 0: + FREE( cmap->c.cmap0.glyphIdArray ); + break; + + case 2: + FREE( cmap->c.cmap2.subHeaderKeys ); + FREE( cmap->c.cmap2.subHeaders ); + FREE( cmap->c.cmap2.glyphIdArray ); + break; + + case 4: + FREE( cmap->c.cmap4.segments ); + FREE( cmap->c.cmap4.glyphIdArray ); + cmap->c.cmap4.segCountX2 = 0; + break; + + case 6: + FREE( cmap->c.cmap6.glyphIdArray ); + cmap->c.cmap6.entryCount = 0; + break; + + default: + /* invalid table format, do nothing */ + ; + } + + cmap->loaded = FALSE; + return TT_Err_Ok; + } + + + /*************************************************************************/ + /* */ + /* */ + /* code_to_index0 */ + /* */ + /* */ + /* Converts the character code into a glyph index. Uses format 0. */ + /* `charCode' must be in the range 0x00-0xFF (otherwise 0 is */ + /* returned). */ + /* */ + /* */ + /* charCode :: The wanted character code. */ + /* cmap0 :: A pointer to a cmap table in format 0. */ + /* */ + /* */ + /* Glyph index into the glyphs array. 0 if the glyph does not exist. */ + /* */ + static + FT_UInt code_to_index0( TT_CMapTable* cmap, + FT_ULong charCode ) + { + TT_CMap0* cmap0 = &cmap->c.cmap0; + + + return ( charCode <= 0xFF ? cmap0->glyphIdArray[charCode] : 0 ); + } + + + /*************************************************************************/ + /* */ + /* */ + /* code_to_index2 */ + /* */ + /* */ + /* Converts the character code into a glyph index. Uses format 2. */ + /* */ + /* */ + /* charCode :: The wanted character code. */ + /* cmap2 :: A pointer to a cmap table in format 2. */ + /* */ + /* */ + /* Glyph index into the glyphs array. 0 if the glyph does not exist. */ + /* */ + static + FT_UInt code_to_index2( TT_CMapTable* cmap, + FT_ULong charCode ) + { + FT_UInt result, index1, offset; + FT_UInt char_lo; + FT_ULong char_hi; + TT_CMap2SubHeader* sh2; + TT_CMap2* cmap2; + + + cmap2 = &cmap->c.cmap2; + result = 0; + char_lo = (FT_UInt)( charCode & 0xFF ); + char_hi = charCode >> 8; + + if ( char_hi == 0 ) + { + /* an 8-bit character code -- we use the subHeader 0 in this case */ + /* to test whether the character code is in the charmap */ + if ( cmap2->subHeaderKeys[char_lo] == 0 ) + result = cmap2->glyphIdArray[char_lo]; + } + else + { + /* a 16-bit character code */ + index1 = cmap2->subHeaderKeys[char_hi & 0xFF]; + if ( index1 ) + { + sh2 = cmap2->subHeaders + index1; + char_lo -= sh2->firstCode; + + if ( char_lo < sh2->entryCount ) + { + offset = sh2->idRangeOffset / 2 + char_lo; + if ( offset < cmap2->numGlyphId ) + { + result = cmap2->glyphIdArray[offset]; + if ( result ) + result = ( result + sh2->idDelta ) & 0xFFFF; + } + } + } + } + + return result; + } + + + /*************************************************************************/ + /* */ + /* */ + /* code_to_index4 */ + /* */ + /* */ + /* Converts the character code into a glyph index. Uses format 4. */ + /* */ + /* */ + /* charCode :: The wanted character code. */ + /* cmap4 :: A pointer to a cmap table in format 4. */ + /* */ + /* */ + /* Glyph index into the glyphs array. 0 if the glyph does not exist. */ + /* */ + static + FT_UInt code_to_index4( TT_CMapTable* cmap, + FT_ULong charCode ) + { + FT_UInt result, index1, segCount; + TT_CMap4* cmap4; + TT_CMap4Segment *seg4, *limit; + + + cmap4 = &cmap->c.cmap4; + result = 0; + segCount = cmap4->segCountX2 / 2; + seg4 = cmap4->segments; + limit = seg4 + segCount; + + /* check against the last segment */ + seg4 = cmap4->last_segment; + + /* the following is equivalent to performing two tests, as in */ + /* */ + /* if ( charCode >= seg4->startCount && charCode <= seg4->endCount ) */ + /* */ + /* Yes, that's a bit strange, but it's faster, and the idea behind */ + /* the cache is to significantly speed up charcode to glyph index */ + /* conversion. */ + + if ( (FT_ULong)(charCode - seg4->startCount) < + (FT_ULong)(seg4->endCount - seg4->startCount) ) + goto Found; + + for ( seg4 = cmap4->segments; seg4 < limit; seg4++ ) + { + /* the ranges are sorted in increasing order. If we are out of */ + /* the range here, the char code isn't in the charmap, so exit. */ + + if ( charCode > seg4->endCount ) + continue; + + if ( charCode >= seg4->startCount ) + goto Found; + } + return 0; + + Found: + cmap4->last_segment = seg4; + + /* if the idRangeOffset is 0, we can compute the glyph index */ + /* directly */ + + if ( seg4->idRangeOffset == 0 ) + result = ( charCode + seg4->idDelta ) & 0xFFFF; + else + { + /* otherwise, we must use the glyphIdArray to do it */ + index1 = seg4->idRangeOffset / 2 + + ( charCode - seg4->startCount ) + + ( seg4 - cmap4->segments ) + - segCount; + + if ( index1 < cmap4->numGlyphId && + cmap4->glyphIdArray[index1] != 0 ) + result = ( cmap4->glyphIdArray[index1] + seg4->idDelta ) & 0xFFFF; + } + + return result; + } + + + /*************************************************************************/ + /* */ + /* */ + /* code_to_index6 */ + /* */ + /* */ + /* Converts the character code into a glyph index. Uses format 6. */ + /* */ + /* */ + /* charCode :: The wanted character code. */ + /* cmap6 :: A pointer to a cmap table in format 6. */ + /* */ + /* */ + /* Glyph index into the glyphs array. 0 if the glyph does not exist. */ + /* */ + static + FT_UInt code_to_index6( TT_CMapTable* cmap, + FT_ULong charCode ) + { + TT_CMap6* cmap6; + FT_UInt result = 0; + + + cmap6 = &cmap->c.cmap6; + result = 0; + charCode -= cmap6->firstCode; + + if ( charCode < cmap6->entryCount ) + result = cmap6->glyphIdArray[charCode]; + + return result; + } + + +/* END */ diff --git a/src/freetype/sfnt/ttcmap.h b/src/freetype/sfnt/ttcmap.h new file mode 100644 index 0000000000..609972a901 --- /dev/null +++ b/src/freetype/sfnt/ttcmap.h @@ -0,0 +1,45 @@ +/***************************************************************************/ +/* */ +/* ttcmap.h */ +/* */ +/* TrueType character mapping table (cmap) support (specification). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef TTCMAP_H +#define TTCMAP_H + +#include + +#ifdef __cplusplus + extern "C" { +#endif + + + LOCAL_DEF + FT_Error TT_CharMap_Load( TT_Face face, + TT_CMapTable* cmap, + FT_Stream input ); + + LOCAL_DEF + FT_Error TT_CharMap_Free( TT_Face face, + TT_CMapTable* cmap ); + +#ifdef __cplusplus + } +#endif + +#endif /* TTCMAP_H */ + + +/* END */ diff --git a/src/freetype/sfnt/ttload.c b/src/freetype/sfnt/ttload.c new file mode 100644 index 0000000000..e7871874df --- /dev/null +++ b/src/freetype/sfnt/ttload.c @@ -0,0 +1,1676 @@ +/***************************************************************************/ +/* */ +/* ttload.c */ +/* */ +/* Load the basic TrueType tables, i.e., tables that can be either in */ +/* TTF or OTF fonts (body). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#include +#include +#include + + +#ifdef FT_FLAT_COMPILE + +#include "ttload.h" +#include "ttcmap.h" + +#else + +#include +#include + +#endif + + + /*************************************************************************/ + /* */ + /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ + /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ + /* messages during execution. */ + /* */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_ttload + + + /*************************************************************************/ + /* */ + /* */ + /* TT_LookUp_Table */ + /* */ + /* */ + /* Looks for a TrueType table by name. */ + /* */ + /* */ + /* face :: A face object handle. */ + /* tag :: The searched tag. */ + /* */ + /* */ + /* A pointer to the table directory entry. 0 if not found. */ + /* */ + LOCAL_FUNC + TT_Table* TT_LookUp_Table( TT_Face face, + FT_ULong tag ) + { + TT_Table* entry; + TT_Table* limit; + + + FT_TRACE3(( "TT_LookUp_Table: %08p, `%c%c%c%c'\n", + face, + (FT_Char)( tag >> 24 ), + (FT_Char)( tag >> 16 ), + (FT_Char)( tag >> 8 ), + (FT_Char)( tag ) )); + + entry = face->dir_tables; + limit = entry + face->num_tables; + + for ( ; entry < limit; entry++ ) + { + if ( entry->Tag == tag ) + return entry; + } + + FT_TRACE3(( " Could not find table!\n" )); + return 0; + } + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Goto_Table */ + /* */ + /* */ + /* Looks for a TrueType table by name, then seek a stream to it. */ + /* */ + /* */ + /* face :: A face object handle. */ + /* tag :: The searched tag. */ + /* stream :: The stream to seek when the table is found. */ + /* */ + /* */ + /* length :: The length of the table if found, undefined otherwise. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + LOCAL_FUNC + FT_Error TT_Goto_Table( TT_Face face, + FT_ULong tag, + FT_Stream stream, + FT_ULong* length ) + { + TT_Table* table; + FT_Error error; + + + table = TT_LookUp_Table( face, tag ); + if ( table ) + { + if ( length ) + *length = table->Length; + + (void)FILE_Seek( table->Offset ); + } + else + error = TT_Err_Table_Missing; + + return error; + } + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Load_SFNT_Header */ + /* */ + /* */ + /* Loads the header of a SFNT font file. Supports collections. */ + /* */ + /* */ + /* face :: A handle to the target face object. */ + /* stream :: The input stream. */ + /* face_index :: If the font is a collection, the number of the font */ + /* in the collection, ignored otherwise. */ + /* */ + /* */ + /* sfnt :: The SFNT header. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* The stream cursor must be at the font file's origin. */ + /* */ + /* This function recognizes fonts embedded in a `TrueType collection' */ + /* */ + /* The header will be checked whether it is valid by looking at the */ + /* values of `search_range', `entry_selector', and `range_shift'. */ + /* */ + LOCAL_FUNC + FT_Error TT_Load_SFNT_Header( TT_Face face, + FT_Stream stream, + FT_Long face_index, + SFNT_Header* sfnt ) + { + FT_Error error; + FT_ULong format_tag; + FT_Memory memory = stream->memory; + + const FT_Frame_Field sfnt_header_fields[] = + { + FT_FRAME_START( 8 ), + FT_FRAME_USHORT( SFNT_Header, num_tables ), + FT_FRAME_USHORT( SFNT_Header, search_range ), + FT_FRAME_USHORT( SFNT_Header, entry_selector ), + FT_FRAME_USHORT( SFNT_Header, range_shift ), + FT_FRAME_END + }; + + const FT_Frame_Field ttc_header_fields[] = + { + FT_FRAME_START( 8 ), + FT_FRAME_LONG( TTC_Header, version ), + FT_FRAME_LONG( TTC_Header, count ), + FT_FRAME_END }; + + + FT_TRACE2(( "TT_Load_SFNT_Header: %08p, %ld\n", + face, face_index )); + + face->ttc_header.tag = 0; + face->ttc_header.version = 0; + face->ttc_header.count = 0; + + face->num_tables = 0; + + /* first of all, read the first 4 bytes. If it is `ttcf', then the */ + /* file is a TrueType collection, otherwise it can be any other */ + /* kind of font. */ + if ( READ_ULong( format_tag ) ) + goto Exit; + + if ( format_tag == TTAG_ttcf ) + { + FT_Int n; + + + FT_TRACE3(( "TT_Load_SFNT_Header: file is a collection\n" )); + + /* it's a TrueType collection, i.e. a file containing several */ + /* font files. Read the font directory now */ + if ( READ_Fields( ttc_header_fields, &face->ttc_header ) ) + goto Exit; + + /* now read the offsets of each font in the file */ + if ( ALLOC_ARRAY( face->ttc_header.offsets, + face->ttc_header.count, + FT_ULong ) || + ACCESS_Frame( face->ttc_header.count * 4L ) ) + goto Exit; + + for ( n = 0; n < face->ttc_header.count; n++ ) + face->ttc_header.offsets[n] = GET_ULong(); + + FORGET_Frame(); + + /* check face index */ + if ( face_index >= face->ttc_header.count ) + { + error = TT_Err_Bad_Argument; + goto Exit; + } + + /* seek to the appropriate TrueType file, then read tag */ + if ( FILE_Seek( face->ttc_header.offsets[face_index] ) || + READ_Long( format_tag ) ) + goto Exit; + } + + /* the format tag was read, now check the rest of the header */ + sfnt->format_tag = format_tag; + if ( READ_Fields( sfnt_header_fields, sfnt ) ) + goto Exit; + + /* now, check the values of `num_tables', `seach_range', etc. */ + { + FT_UInt num_tables = sfnt->num_tables; + FT_ULong entry_selector = 1L << sfnt->entry_selector; + + + /* IMPORTANT: Many fonts have an incorrect `search_range' value, so */ + /* we only check the `entry_selector' correctness here. */ + /* */ + if ( num_tables == 0 || + entry_selector > num_tables || + entry_selector * 2 <= num_tables ) + { + FT_TRACE2(( "TT_Load_SFNT_Header: file is not SFNT!\n" )); + error = FT_Err_Unknown_File_Format; + } + } + + Exit: + return error; + } + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Load_Directory */ + /* */ + /* */ + /* Loads the table directory into a face object. */ + /* */ + /* */ + /* face :: A handle to the target face object. */ + /* */ + /* */ + /* stream :: The input stream. */ + /* sfnt :: The SFNT directory header. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* The stream cursor must be at the font file's origin. */ + /* */ + LOCAL_FUNC + FT_Error TT_Load_Directory( TT_Face face, + FT_Stream stream, + SFNT_Header* sfnt ) + { + FT_Error error; + FT_Memory memory = stream->memory; + + TT_Table *entry, *limit; + + + FT_TRACE2(( "TT_Load_Directory: %08p\n", face )); + + FT_TRACE2(( "-- Tables count: %12u\n", sfnt->num_tables )); + FT_TRACE2(( "-- Format version: %08lx\n", sfnt->format_tag )); + + face->num_tables = sfnt->num_tables; + + if ( ALLOC_ARRAY( face->dir_tables, + face->num_tables, + TT_Table ) ) + goto Exit; + + if ( ACCESS_Frame( face->num_tables * 16L ) ) + goto Exit; + + entry = face->dir_tables; + limit = entry + face->num_tables; + + for ( ; entry < limit; entry++ ) + { /* loop through the tables and get all entries */ + entry->Tag = GET_Tag4(); + entry->CheckSum = GET_ULong(); + entry->Offset = GET_Long(); + entry->Length = GET_Long(); + + FT_TRACE2(( " %c%c%c%c - %08lx - %08lx\n", + (FT_Char)( entry->Tag >> 24 ), + (FT_Char)( entry->Tag >> 16 ), + (FT_Char)( entry->Tag >> 8 ), + (FT_Char)( entry->Tag ), + entry->Offset, + entry->Length )); + } + + FORGET_Frame(); + + FT_TRACE2(( "Directory loaded\n\n" )); + + Exit: + return error; + } + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Load_Any */ + /* */ + /* */ + /* Loads any font table into client memory. */ + /* */ + /* */ + /* face :: The face object to look for. */ + /* */ + /* tag :: The tag of table to load. Use the value 0 if you want */ + /* to access the whole font file, else set this parameter */ + /* to a valid TrueType table tag that you can forge with */ + /* the MAKE_TT_TAG macro. */ + /* */ + /* offset :: The starting offset in the table (or the file if */ + /* tag == 0). */ + /* */ + /* length :: The address of the decision variable: */ + /* */ + /* If length == NULL: */ + /* Loads the whole table. Returns an error if */ + /* `offset' == 0! */ + /* */ + /* If *length == 0: */ + /* Exits immediately; returning the length of the given */ + /* table or of the font file, depending on the value of */ + /* `tag'. */ + /* */ + /* If *length != 0: */ + /* Loads the next `length' bytes of table or font, */ + /* starting at offset `offset' (in table or font too). */ + /* */ + /* */ + /* buffer :: The address of target buffer. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + LOCAL_FUNC + FT_Error TT_Load_Any( TT_Face face, + FT_ULong tag, + FT_Long offset, + FT_Byte* buffer, + FT_ULong* length ) + { + FT_Error error; + FT_Stream stream; + TT_Table* table; + FT_ULong size; + + + if ( tag != 0 ) + { + /* look for tag in font directory */ + table = TT_LookUp_Table( face, tag ); + if ( !table ) + { + error = TT_Err_Table_Missing; + goto Exit; + } + + offset += table->Offset; + size = table->Length; + } + else + /* tag == 0 -- the user wants to access the font file directly */ + size = face->root.stream->size; + + if ( length && *length == 0 ) + { + *length = size; + + return TT_Err_Ok; + } + + if ( length ) + size = *length; + + stream = face->root.stream; + (void)FILE_Read_At( offset, buffer, size ); + + Exit: + return error; + } + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Load_Header */ + /* */ + /* */ + /* Loads the TrueType font header. */ + /* */ + /* */ + /* face :: A handle to the target face object. */ + /* stream :: The input stream. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + LOCAL_FUNC + FT_Error TT_Load_Header( TT_Face face, + FT_Stream stream ) + { + FT_Error error; + TT_Header* header; + + static const FT_Frame_Field header_fields[] = + { + FT_FRAME_START( 54 ), + FT_FRAME_ULONG( TT_Header, Table_Version ), + FT_FRAME_ULONG( TT_Header, Font_Revision ), + FT_FRAME_LONG( TT_Header, CheckSum_Adjust ), + FT_FRAME_LONG( TT_Header, Magic_Number ), + FT_FRAME_USHORT( TT_Header, Flags ), + FT_FRAME_USHORT( TT_Header, Units_Per_EM ), + FT_FRAME_LONG( TT_Header, Created[0] ), + FT_FRAME_LONG( TT_Header, Created[1] ), + FT_FRAME_LONG( TT_Header, Modified[0] ), + FT_FRAME_LONG( TT_Header, Modified[1] ), + FT_FRAME_SHORT( TT_Header, xMin ), + FT_FRAME_SHORT( TT_Header, yMin ), + FT_FRAME_SHORT( TT_Header, xMax ), + FT_FRAME_SHORT( TT_Header, yMax ), + FT_FRAME_USHORT( TT_Header, Mac_Style ), + FT_FRAME_USHORT( TT_Header, Lowest_Rec_PPEM ), + FT_FRAME_SHORT( TT_Header, Font_Direction ), + FT_FRAME_SHORT( TT_Header, Index_To_Loc_Format ), + FT_FRAME_SHORT( TT_Header, Glyph_Data_Format ), + FT_FRAME_END + }; + + + FT_TRACE2(( "Load_TT_Header: %08p\n", face )); + + error = face->goto_table( face, TTAG_head, stream, 0 ); + if ( error ) + { + FT_TRACE0(( "Font Header is missing!\n" )); + goto Exit; + } + + header = &face->header; + + if ( READ_Fields( header_fields, header ) ) + goto Exit; + + FT_TRACE2(( " Units per EM: %8u\n", header->Units_Per_EM )); + FT_TRACE2(( " IndexToLoc: %8d\n", header->Index_To_Loc_Format )); + FT_TRACE2(( "Font Header Loaded.\n" )); + + Exit: + return error; + } + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Load_MaxProfile */ + /* */ + /* */ + /* Loads the maximum profile into a face object. */ + /* */ + /* */ + /* face :: A handle to the target face object. */ + /* stream :: The input stream. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + LOCAL_FUNC + FT_Error TT_Load_MaxProfile( TT_Face face, + FT_Stream stream ) + { + FT_Error error; + TT_MaxProfile* maxProfile = &face->max_profile; + + const FT_Frame_Field maxp_fields[] = + { + FT_FRAME_START( 32 ), + FT_FRAME_ULONG( TT_MaxProfile, version ), + FT_FRAME_USHORT( TT_MaxProfile, numGlyphs ), + FT_FRAME_USHORT( TT_MaxProfile, maxPoints ), + FT_FRAME_USHORT( TT_MaxProfile, maxContours ), + FT_FRAME_USHORT( TT_MaxProfile, maxCompositePoints ), + FT_FRAME_USHORT( TT_MaxProfile, maxCompositeContours ), + FT_FRAME_USHORT( TT_MaxProfile, maxZones ), + FT_FRAME_USHORT( TT_MaxProfile, maxTwilightPoints ), + FT_FRAME_USHORT( TT_MaxProfile, maxStorage ), + FT_FRAME_USHORT( TT_MaxProfile, maxFunctionDefs ), + FT_FRAME_USHORT( TT_MaxProfile, maxInstructionDefs ), + FT_FRAME_USHORT( TT_MaxProfile, maxStackElements ), + FT_FRAME_USHORT( TT_MaxProfile, maxSizeOfInstructions ), + FT_FRAME_USHORT( TT_MaxProfile, maxComponentElements ), + FT_FRAME_USHORT( TT_MaxProfile, maxComponentDepth ), + FT_FRAME_END }; + + + FT_TRACE2(( "Load_TT_MaxProfile: %08p\n", face )); + + error = face->goto_table( face, TTAG_maxp, stream, 0 ); + if ( error ) + goto Exit; + + if ( READ_Fields( maxp_fields, maxProfile ) ) + goto Exit; + + /* XXX: an adjustment that is necessary to load certain */ + /* broken fonts like `Keystrokes MT' :-( */ + /* */ + /* We allocate 64 function entries by default when */ + /* the maxFunctionDefs field is null. */ + + if ( maxProfile->maxFunctionDefs == 0 ) + maxProfile->maxFunctionDefs = 64; + + face->root.num_glyphs = maxProfile->numGlyphs; + + face->root.max_points = MAX( maxProfile->maxCompositePoints, + maxProfile->maxPoints ); + + face->root.max_contours = MAX( maxProfile->maxCompositeContours, + maxProfile->maxContours ); + + face->max_components = (FT_ULong)maxProfile->maxComponentElements + + maxProfile->maxComponentDepth; + + /* XXX: some fonts have maxComponents set to 0; we will */ + /* then use 16 of them by default. */ + if ( face->max_components == 0 ) + face->max_components = 16; + + /* We also increase maxPoints and maxContours in order to support */ + /* some broken fonts. */ + face->root.max_points += 8; + face->root.max_contours += 4; + + FT_TRACE2(( "MAXP loaded.\n" )); + + Exit: + return error; + } + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Load_Metrics */ + /* */ + /* */ + /* Loads the horizontal or vertical metrics table into a face object. */ + /* */ + /* */ + /* face :: A handle to the target face object. */ + /* stream :: The input stream. */ + /* vertical :: A boolean flag. If set, load vertical metrics. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + static + FT_Error TT_Load_Metrics( TT_Face face, + FT_Stream stream, + FT_Bool vertical ) + { + FT_Error error; + FT_Memory memory = stream->memory; + + FT_ULong table_len; + FT_Long num_shorts, num_longs, num_shorts_checked; + + TT_LongMetrics** longs; + TT_ShortMetrics** shorts; + + + FT_TRACE2(( "TT_Load_%s_Metrics: %08p\n", vertical ? "Vertical" + : "Horizontal", + face )); + + if ( vertical ) + { + /* The table is optional, quit silently if it wasn't found */ + /* XXX: Some fonts have a valid vertical header with a non-null */ + /* `number_of_VMetrics' fields, but no corresponding `vmtx' */ + /* table to get the metrics from (e.g. mingliu). */ + /* */ + /* For safety, we set the field to 0! */ + /* */ + error = face->goto_table( face, TTAG_vmtx, stream, &table_len ); + if ( error ) + { + /* Set number_Of_VMetrics to 0! */ + FT_TRACE2(( " no vertical header in file.\n" )); + face->vertical.number_Of_VMetrics = 0; + error = TT_Err_Ok; + goto Exit; + } + + num_longs = face->vertical.number_Of_VMetrics; + longs = (TT_LongMetrics**)&face->vertical.long_metrics; + shorts = (TT_ShortMetrics**)&face->vertical.short_metrics; + } + else + { + error = face->goto_table( face, TTAG_hmtx, stream, &table_len ); + if ( error ) + { + FT_ERROR(( " no horizontal metrics in file!\n" )); + error = TT_Err_Hmtx_Table_Missing; + goto Exit; + } + + num_longs = face->horizontal.number_Of_HMetrics; + longs = (TT_LongMetrics**)&face->horizontal.long_metrics; + shorts = (TT_ShortMetrics**)&face->horizontal.short_metrics; + } + + /* never trust derived values */ + + num_shorts = face->max_profile.numGlyphs - num_longs; + num_shorts_checked = ( table_len - num_longs * 4L ) / 2; + + if ( num_shorts < 0 ) + { + FT_ERROR(( "TT_Load_%s_Metrics: more metrics than glyphs!\n", + vertical ? "Vertical" + : "Horizontal" )); + + error = vertical ? TT_Err_Invalid_Vert_Metrics + : TT_Err_Invalid_Horiz_Metrics; + goto Exit; + } + + if ( ALLOC_ARRAY( *longs, num_longs, TT_LongMetrics ) || + ALLOC_ARRAY( *shorts, num_shorts, TT_ShortMetrics ) ) + goto Exit; + + if ( ACCESS_Frame( table_len ) ) + goto Exit; + + { + TT_LongMetrics* cur = *longs; + TT_LongMetrics* limit = cur + num_longs; + + + for ( ; cur < limit; cur++ ) + { + cur->advance = GET_UShort(); + cur->bearing = GET_Short(); + } + } + + /* do we have an inconsistent number of metric values? */ + { + TT_ShortMetrics* cur = *shorts; + TT_ShortMetrics* limit = cur + MIN( num_shorts, num_shorts_checked ); + + + for ( ; cur < limit; cur++ ) + *cur = GET_Short(); + + /* we fill up the missing left side bearings with the */ + /* last valid value. Since this will occur for buggy CJK */ + /* fonts usually only, nothing serious will happen */ + if ( num_shorts > num_shorts_checked && num_shorts_checked > 0 ) + { + FT_Short val = *(shorts)[num_shorts_checked - 1]; + + + limit = *shorts + num_shorts; + for ( ; cur < limit; cur++ ) + *cur = val; + } + } + + FORGET_Frame(); + + FT_TRACE2(( "loaded\n" )); + + Exit: + return error; + } + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Load_Metrics_Header */ + /* */ + /* */ + /* Loads the horizontal or vertical header in a face object. */ + /* */ + /* */ + /* face :: A handle to the target face object. */ + /* stream :: The input stream. */ + /* vertical :: A boolean flag. If set, load vertical metrics. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + LOCAL_FUNC + FT_Error TT_Load_Metrics_Header( TT_Face face, + FT_Stream stream, + FT_Bool vertical ) + { + FT_Error error; + TT_HoriHeader* header; + + const FT_Frame_Field metrics_header_fields[] = + { + FT_FRAME_START( 36 ), + FT_FRAME_ULONG( TT_HoriHeader, Version ), + FT_FRAME_SHORT( TT_HoriHeader, Ascender ), + FT_FRAME_SHORT( TT_HoriHeader, Descender ), + FT_FRAME_SHORT( TT_HoriHeader, Line_Gap ), + FT_FRAME_USHORT( TT_HoriHeader, advance_Width_Max ), + FT_FRAME_SHORT( TT_HoriHeader, min_Left_Side_Bearing ), + FT_FRAME_SHORT( TT_HoriHeader, min_Right_Side_Bearing ), + FT_FRAME_SHORT( TT_HoriHeader, xMax_Extent ), + FT_FRAME_SHORT( TT_HoriHeader, caret_Slope_Rise ), + FT_FRAME_SHORT( TT_HoriHeader, caret_Slope_Run ), + FT_FRAME_SHORT( TT_HoriHeader, Reserved[0] ), + FT_FRAME_SHORT( TT_HoriHeader, Reserved[1] ), + FT_FRAME_SHORT( TT_HoriHeader, Reserved[2] ), + FT_FRAME_SHORT( TT_HoriHeader, Reserved[3] ), + FT_FRAME_SHORT( TT_HoriHeader, Reserved[4] ), + FT_FRAME_SHORT( TT_HoriHeader, metric_Data_Format ), + FT_FRAME_USHORT( TT_HoriHeader, number_Of_HMetrics ), + FT_FRAME_END + }; + + + FT_TRACE2(( vertical ? "Vertical header " : "Horizontal header " )); + + if ( vertical ) + { + face->vertical_info = 0; + + /* The vertical header table is optional, so return quietly if */ + /* we don't find it. */ + error = face->goto_table( face, TTAG_vhea, stream, 0 ); + if ( error ) + { + error = TT_Err_Ok; + goto Exit; + } + + face->vertical_info = 1; + header = (TT_HoriHeader*)&face->vertical; + } + else + { + /* The horizontal header is mandatory; return an error if we */ + /* don't find it. */ + error = face->goto_table( face, TTAG_hhea, stream, 0 ); + if ( error ) + { + error = TT_Err_Horiz_Header_Missing; + goto Exit; + } + + header = &face->horizontal; + } + + if ( READ_Fields( metrics_header_fields, header ) ) + goto Exit; + + header->long_metrics = NULL; + header->short_metrics = NULL; + + FT_TRACE2(( "loaded\n" )); + + /* Now try to load the corresponding metrics */ + + error = TT_Load_Metrics( face, stream, vertical ); + + Exit: + return error; + } + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Load_Names */ + /* */ + /* */ + /* Loads the name records. */ + /* */ + /* */ + /* face :: A handle to the target face object. */ + /* stream :: The input stream. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + LOCAL_FUNC + FT_Error TT_Load_Names( TT_Face face, + FT_Stream stream ) + { + FT_Error error; + FT_Memory memory = stream->memory; + + FT_ULong table_pos, table_len; + FT_ULong storageSize; + + TT_NameTable* names; + + const FT_Frame_Field name_table_fields[] = + { + FT_FRAME_START( 6 ), + FT_FRAME_USHORT( TT_NameTable, format ), + FT_FRAME_USHORT( TT_NameTable, numNameRecords ), + FT_FRAME_USHORT( TT_NameTable, storageOffset ), + FT_FRAME_END + }; + + const FT_Frame_Field name_record_fields[] = + { + /* no FT_FRAME_START */ + FT_FRAME_USHORT( TT_NameRec, platformID ), + FT_FRAME_USHORT( TT_NameRec, encodingID ), + FT_FRAME_USHORT( TT_NameRec, languageID ), + FT_FRAME_USHORT( TT_NameRec, nameID ), + FT_FRAME_USHORT( TT_NameRec, stringLength ), + FT_FRAME_USHORT( TT_NameRec, stringOffset ), + FT_FRAME_END + }; + + + FT_TRACE2(( "Names " )); + + error = face->goto_table( face, TTAG_name, stream, &table_len ); + if ( error ) + { + /* The name table is required so indicate failure. */ + FT_TRACE2(( "is missing!\n" )); + error = TT_Err_Name_Table_Missing; + goto Exit; + } + + table_pos = FILE_Pos(); + + names = &face->name_table; + + if ( READ_Fields( name_table_fields, names ) ) + goto Exit; + + /* Allocate the array of name records. */ + if ( ALLOC_ARRAY( names->names, + names->numNameRecords, + TT_NameRec ) || + ACCESS_Frame( names->numNameRecords * 12L ) ) + goto Exit; + + /* Load the name records and determine how much storage is needed */ + /* to hold the strings themselves. */ + { + TT_NameRec* cur = names->names; + TT_NameRec* limit = cur + names->numNameRecords; + + + storageSize = 0; + + for ( ; cur < limit; cur ++ ) + { + FT_ULong upper; + + + (void)READ_Fields( name_record_fields, cur ); + + upper = (FT_ULong)( cur->stringOffset + cur->stringLength ); + if ( upper > storageSize ) + storageSize = upper; + } + } + + FORGET_Frame(); + + if ( storageSize > 0 ) + { + /* allocate the name storage area in memory, then read it */ + if ( ALLOC( names->storage, storageSize ) || + FILE_Read_At( table_pos + names->storageOffset, + names->storage, storageSize ) ) + goto Exit; + + /* Go through and assign the string pointers to the name records. */ + { + TT_NameRec* cur = names->names; + TT_NameRec* limit = cur + names->numNameRecords; + + + for ( ; cur < limit; cur++ ) + cur->string = names->storage + cur->stringOffset; + } + +#ifdef FT_DEBUG_LEVEL_TRACE + + /* Print Name Record Table in case of debugging */ + { + TT_NameRec* cur = names->names; + TT_NameRec* limit = cur + names->numNameRecords; + + + for ( ; cur < limit; cur++ ) + { + FT_UInt j; + + + FT_TRACE3(( "%d %d %x %d\n ", + cur->platformID, + cur->encodingID, + cur->languageID, + cur->nameID )); + + /* I know that M$ encoded strings are Unicode, */ + /* but this works reasonable well for debugging purposes. */ + if ( cur->string ) + for ( j = 0; j < cur->stringLength; j++ ) + { + FT_Char c = *( cur->string + j ); + + + if ( (FT_Byte)c < 128 ) + FT_TRACE3(( "%c", c )); + } + } + } + FT_TRACE3(( "\n" )); + +#endif /* FT_DEBUG_LEVEL_TRACE */ + + } + FT_TRACE2(( "loaded\n" )); + + /* everything went well, update face->num_names */ + face->num_names = names->numNameRecords; + + Exit: + return error; + } + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Free_Names */ + /* */ + /* */ + /* Frees the name records. */ + /* */ + /* */ + /* face :: A handle to the target face object. */ + /* */ + LOCAL_FUNC + void TT_Free_Names( TT_Face face ) + { + FT_Memory memory = face->root.driver->root.memory; + TT_NameTable* names = &face->name_table; + + + /* free strings table */ + FREE( names->names ); + + /* free strings storage */ + FREE( names->storage ); + + names->numNameRecords = 0; + names->format = 0; + names->storageOffset = 0; + } + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Load_CMap */ + /* */ + /* */ + /* Loads the cmap directory in a face object. The cmaps itselves are */ + /* loaded on demand in the `ttcmap.c' module. */ + /* */ + /* */ + /* face :: A handle to the target face object. */ + /* stream :: A handle to the input stream. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + LOCAL_FUNC + FT_Error TT_Load_CMap( TT_Face face, + FT_Stream stream ) + { + FT_Error error; + FT_Memory memory = stream->memory; + FT_Long table_start; + TT_CMapDir cmap_dir; + + const FT_Frame_Field cmap_fields[] = + { + FT_FRAME_START( 4 ), + FT_FRAME_USHORT( TT_CMapDir, tableVersionNumber ), + FT_FRAME_USHORT( TT_CMapDir, numCMaps ), + FT_FRAME_END + }; + + const FT_Frame_Field cmap_rec_fields[] = + { + FT_FRAME_START( 6 ), + FT_FRAME_USHORT( TT_CMapTable, format ), + FT_FRAME_USHORT( TT_CMapTable, length ), + FT_FRAME_USHORT( TT_CMapTable, version ), + FT_FRAME_END + }; + + + FT_TRACE2(( "CMaps " )); + + error = face->goto_table( face, TTAG_cmap, stream, 0 ); + if ( error ) + { + error = TT_Err_CMap_Table_Missing; + goto Exit; + } + + table_start = FILE_Pos(); + + if ( READ_Fields( cmap_fields, &cmap_dir ) ) + goto Exit; + + /* reserve space in face table for cmap tables */ + if ( ALLOC_ARRAY( face->charmaps, + cmap_dir.numCMaps, + TT_CharMapRec ) ) + goto Exit; + + face->num_charmaps = cmap_dir.numCMaps; + { + TT_CharMap charmap = face->charmaps; + TT_CharMap limit = charmap + face->num_charmaps; + + + /* read the header of each charmap first */ + if ( ACCESS_Frame( face->num_charmaps * 8L ) ) + goto Exit; + + for ( ; charmap < limit; charmap++ ) + { + TT_CMapTable* cmap; + + + charmap->root.face = (FT_Face)face; + cmap = &charmap->cmap; + + cmap->loaded = FALSE; + cmap->platformID = GET_UShort(); + cmap->platformEncodingID = GET_UShort(); + cmap->offset = (FT_ULong)GET_Long(); + } + + FORGET_Frame(); + + /* now read the rest of each table */ + for ( charmap = face->charmaps; charmap < limit; charmap++ ) + { + TT_CMapTable* cmap = &charmap->cmap; + + + if ( FILE_Seek( table_start + (FT_Long)cmap->offset ) || + READ_Fields( cmap_rec_fields, cmap ) ) + goto Exit; + + cmap->offset = FILE_Pos(); + } + } + + FT_TRACE2(( "loaded\n" )); + + Exit: + return error; + } + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Load_OS2 */ + /* */ + /* */ + /* Loads the OS2 table. */ + /* */ + /* */ + /* face :: A handle to the target face object. */ + /* stream :: A handle to the input stream. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + LOCAL_FUNC + FT_Error TT_Load_OS2( TT_Face face, + FT_Stream stream ) + { + FT_Error error; + TT_OS2* os2; + + const FT_Frame_Field os2_fields[] = + { + FT_FRAME_START( 78 ), + FT_FRAME_USHORT( TT_OS2, version ), + FT_FRAME_SHORT( TT_OS2, xAvgCharWidth ), + FT_FRAME_USHORT( TT_OS2, usWeightClass ), + FT_FRAME_USHORT( TT_OS2, usWidthClass ), + FT_FRAME_SHORT( TT_OS2, fsType ), + FT_FRAME_SHORT( TT_OS2, ySubscriptXSize ), + FT_FRAME_SHORT( TT_OS2, ySubscriptYSize ), + FT_FRAME_SHORT( TT_OS2, ySubscriptXOffset ), + FT_FRAME_SHORT( TT_OS2, ySubscriptYOffset ), + FT_FRAME_SHORT( TT_OS2, ySuperscriptXSize ), + FT_FRAME_SHORT( TT_OS2, ySuperscriptYSize ), + FT_FRAME_SHORT( TT_OS2, ySuperscriptXOffset ), + FT_FRAME_SHORT( TT_OS2, ySuperscriptYOffset ), + FT_FRAME_SHORT( TT_OS2, yStrikeoutSize ), + FT_FRAME_SHORT( TT_OS2, yStrikeoutPosition ), + FT_FRAME_SHORT( TT_OS2, sFamilyClass ), + FT_FRAME_BYTE( TT_OS2, panose[0] ), + FT_FRAME_BYTE( TT_OS2, panose[1] ), + FT_FRAME_BYTE( TT_OS2, panose[2] ), + FT_FRAME_BYTE( TT_OS2, panose[3] ), + FT_FRAME_BYTE( TT_OS2, panose[4] ), + FT_FRAME_BYTE( TT_OS2, panose[5] ), + FT_FRAME_BYTE( TT_OS2, panose[6] ), + FT_FRAME_BYTE( TT_OS2, panose[7] ), + FT_FRAME_BYTE( TT_OS2, panose[8] ), + FT_FRAME_BYTE( TT_OS2, panose[9] ), + FT_FRAME_ULONG( TT_OS2, ulUnicodeRange1 ), + FT_FRAME_ULONG( TT_OS2, ulUnicodeRange2 ), + FT_FRAME_ULONG( TT_OS2, ulUnicodeRange3 ), + FT_FRAME_ULONG( TT_OS2, ulUnicodeRange4 ), + FT_FRAME_BYTE( TT_OS2, achVendID[0] ), + FT_FRAME_BYTE( TT_OS2, achVendID[1] ), + FT_FRAME_BYTE( TT_OS2, achVendID[2] ), + FT_FRAME_BYTE( TT_OS2, achVendID[3] ), + + FT_FRAME_USHORT( TT_OS2, fsSelection ), + FT_FRAME_USHORT( TT_OS2, usFirstCharIndex ), + FT_FRAME_USHORT( TT_OS2, usLastCharIndex ), + FT_FRAME_SHORT( TT_OS2, sTypoAscender ), + FT_FRAME_SHORT( TT_OS2, sTypoDescender ), + FT_FRAME_SHORT( TT_OS2, sTypoLineGap ), + FT_FRAME_USHORT( TT_OS2, usWinAscent ), + FT_FRAME_USHORT( TT_OS2, usWinDescent ), + FT_FRAME_END + }; + + const FT_Frame_Field os2_fields_extra[] = + { + FT_FRAME_START( 8 ), + FT_FRAME_ULONG( TT_OS2, ulCodePageRange1 ), + FT_FRAME_ULONG( TT_OS2, ulCodePageRange2 ), + FT_FRAME_END + }; + + const FT_Frame_Field os2_fields_extra2[] = + { + FT_FRAME_START( 10 ), + FT_FRAME_SHORT( TT_OS2, sxHeight ), + FT_FRAME_SHORT( TT_OS2, sCapHeight ), + FT_FRAME_USHORT( TT_OS2, usDefaultChar ), + FT_FRAME_USHORT( TT_OS2, usBreakChar ), + FT_FRAME_USHORT( TT_OS2, usMaxContext ), + FT_FRAME_END + }; + + + FT_TRACE2(( "OS/2 Table " )); + + /* We now support old Mac fonts where the OS/2 table doesn't */ + /* exist. Simply put, we set the `version' field to 0xFFFF */ + /* and test this value each time we need to access the table. */ + error = face->goto_table( face, TTAG_OS2, stream, 0 ); + if ( error ) + { + FT_TRACE2(( "is missing!\n" )); + face->os2.version = 0xFFFF; + error = TT_Err_Ok; + goto Exit; + } + + os2 = &face->os2; + + if ( READ_Fields( os2_fields, os2 ) ) + goto Exit; + + os2->ulCodePageRange1 = 0; + os2->ulCodePageRange2 = 0; + + if ( os2->version >= 0x0001 ) + { + /* only version 1 tables */ + if ( READ_Fields( os2_fields_extra, os2 ) ) + goto Exit; + + if ( os2->version >= 0x0002 ) + { + /* only version 2 tables */ + if ( READ_Fields( os2_fields_extra2, os2 ) ) + goto Exit; + } + } + + FT_TRACE2(( "loaded\n" )); + + Exit: + return error; + } + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Load_Postscript */ + /* */ + /* */ + /* Loads the Postscript table. */ + /* */ + /* */ + /* face :: A handle to the target face object. */ + /* stream :: A handle to the input stream. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + LOCAL_FUNC + FT_Error TT_Load_PostScript( TT_Face face, + FT_Stream stream ) + { + FT_Error error; + TT_Postscript* post = &face->postscript; + + static const FT_Frame_Field post_fields[] = + { + FT_FRAME_START( 32 ), + FT_FRAME_ULONG( TT_Postscript, FormatType ), + FT_FRAME_ULONG( TT_Postscript, italicAngle ), + FT_FRAME_SHORT( TT_Postscript, underlinePosition ), + FT_FRAME_SHORT( TT_Postscript, underlineThickness ), + FT_FRAME_ULONG( TT_Postscript, isFixedPitch ), + FT_FRAME_ULONG( TT_Postscript, minMemType42 ), + FT_FRAME_ULONG( TT_Postscript, maxMemType42 ), + FT_FRAME_ULONG( TT_Postscript, minMemType1 ), + FT_FRAME_ULONG( TT_Postscript, maxMemType1 ), + FT_FRAME_END + }; + + + FT_TRACE2(( "PostScript " )); + + error = face->goto_table( face, TTAG_post, stream, 0 ); + if ( error ) + return TT_Err_Post_Table_Missing; + + if ( READ_Fields( post_fields, post ) ) + return error; + + /* we don't load the glyph names, we do that in another */ + /* module (ttpost). */ + FT_TRACE2(( "loaded\n" )); + + return TT_Err_Ok; + } + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Load_PCLT */ + /* */ + /* */ + /* Loads the PCL 5 Table. */ + /* */ + /* */ + /* face :: A handle to the target face object. */ + /* stream :: A handle to the input stream. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + LOCAL_FUNC + FT_Error TT_Load_PCLT( TT_Face face, + FT_Stream stream ) + { + static const FT_Frame_Field pclt_fields[] = + { + FT_FRAME_START( 54 ), + FT_FRAME_ULONG ( TT_PCLT, Version ), + FT_FRAME_ULONG ( TT_PCLT, FontNumber ), + FT_FRAME_USHORT( TT_PCLT, Pitch ), + FT_FRAME_USHORT( TT_PCLT, xHeight ), + FT_FRAME_USHORT( TT_PCLT, Style ), + FT_FRAME_USHORT( TT_PCLT, TypeFamily ), + FT_FRAME_USHORT( TT_PCLT, CapHeight ), + FT_FRAME_BYTES ( TT_PCLT, TypeFace, 16 ), + FT_FRAME_BYTES ( TT_PCLT, CharacterComplement, 8 ), + FT_FRAME_BYTES ( TT_PCLT, FileName, 6 ), + FT_FRAME_CHAR ( TT_PCLT, StrokeWeight ), + FT_FRAME_CHAR ( TT_PCLT, WidthType ), + FT_FRAME_BYTE ( TT_PCLT, SerifStyle ), + FT_FRAME_BYTE ( TT_PCLT, Reserved ), + FT_FRAME_END + }; + + FT_Error error; + TT_PCLT* pclt = &face->pclt; + + + FT_TRACE2(( "PCLT " )); + + /* optional table */ + error = face->goto_table( face, TTAG_PCLT, stream, 0 ); + if ( error ) + { + FT_TRACE2(( "missing (optional)\n" )); + pclt->Version = 0; + return TT_Err_Ok; + } + + if ( READ_Fields( pclt_fields, pclt ) ) + goto Exit; + + FT_TRACE2(( "loaded\n" )); + + Exit: + return error; + } + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Load_Gasp */ + /* */ + /* */ + /* Loads the `gasp' table into a face object. */ + /* */ + /* */ + /* face :: A handle to the target face object. */ + /* stream :: The input stream. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + LOCAL_FUNC + FT_Error TT_Load_Gasp( TT_Face face, + FT_Stream stream ) + { + FT_Error error; + FT_Memory memory = stream->memory; + + FT_UInt j,num_ranges; + TT_GaspRange* gaspranges; + + + FT_TRACE2(( "TT_Load_Gasp: %08p\n", face )); + + /* the gasp table is optional */ + error = face->goto_table( face, TTAG_gasp, stream, 0 ); + if ( error ) + return TT_Err_Ok; + + if ( ACCESS_Frame( 4L ) ) + goto Exit; + + face->gasp.version = GET_UShort(); + face->gasp.numRanges = GET_UShort(); + + FORGET_Frame(); + + num_ranges = face->gasp.numRanges; + FT_TRACE3(( "number of ranges = %d\n", num_ranges )); + + if ( ALLOC_ARRAY( gaspranges, num_ranges, TT_GaspRange ) || + ACCESS_Frame( num_ranges * 4L ) ) + goto Exit; + + face->gasp.gaspRanges = gaspranges; + + for ( j = 0; j < num_ranges; j++ ) + { + gaspranges[j].maxPPEM = GET_UShort(); + gaspranges[j].gaspFlag = GET_UShort(); + + FT_TRACE3(( " [max:%d flag:%d]", + gaspranges[j].maxPPEM, + gaspranges[j].gaspFlag )); + } + FT_TRACE3(( "\n" )); + + FORGET_Frame(); + FT_TRACE2(( "GASP loaded\n" )); + + Exit: + return error; + } + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Load_Kern */ + /* */ + /* */ + /* Loads the first kerning table with format 0 in the font. Only */ + /* accepts the first horizontal kerning table. Developers should use */ + /* the `ftxkern' extension to access other kerning tables in the font */ + /* file, if they really want to. */ + /* */ + /* */ + /* face :: A handle to the target face object. */ + /* stream :: The input stream. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + LOCAL_FUNC + FT_Error TT_Load_Kern( TT_Face face, + FT_Stream stream ) + { + FT_Error error; + FT_Memory memory = stream->memory; + + FT_UInt n, num_tables, version; + + + /* the kern table is optional; exit silently if it is missing */ + error = face->goto_table( face, TTAG_kern, stream, 0 ); + if ( error ) + return TT_Err_Ok; + + if ( ACCESS_Frame( 4L ) ) + goto Exit; + + version = GET_UShort(); + num_tables = GET_UShort(); + + FORGET_Frame(); + + for ( n = 0; n < num_tables; n++ ) + { + FT_UInt coverage; + FT_UInt length; + + + if ( ACCESS_Frame( 6L ) ) + goto Exit; + + version = GET_UShort(); /* version */ + length = GET_UShort() - 6; /* substract header length */ + coverage = GET_UShort(); + + FORGET_Frame(); + + if ( coverage == 0x0001 ) + { + FT_UInt num_pairs; + TT_Kern_0_Pair* pair; + TT_Kern_0_Pair* limit; + + + /* found a horizontal format 0 kerning table! */ + if ( ACCESS_Frame( 8L ) ) + goto Exit; + + num_pairs = GET_UShort(); + + /* skip the rest */ + + FORGET_Frame(); + + /* allocate array of kerning pairs */ + if ( ALLOC_ARRAY( face->kern_pairs, num_pairs, TT_Kern_0_Pair ) || + ACCESS_Frame( 6L * num_pairs ) ) + goto Exit; + + pair = face->kern_pairs; + limit = pair + num_pairs; + for ( ; pair < limit; pair++ ) + { + pair->left = GET_UShort(); + pair->right = GET_UShort(); + pair->value = GET_UShort(); + } + + FORGET_Frame(); + + face->num_kern_pairs = num_pairs; + face->kern_table_index = n; + goto Exit; + } + + if ( FILE_Skip( length ) ) + goto Exit; + } + + /* no kern table found -- doesn't matter */ + face->kern_table_index = -1; + face->num_kern_pairs = 0; + face->kern_pairs = NULL; + + Exit: + return error; + } + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Load_Hdmx */ + /* */ + /* */ + /* Loads the horizontal device metrics table. */ + /* */ + /* */ + /* face :: A handle to the target face object. */ + /* stream :: A handle to the input stream. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + LOCAL_FUNC + FT_Error TT_Load_Hdmx( TT_Face face, + FT_Stream stream ) + { + FT_Error error; + FT_Memory memory = stream->memory; + + TT_Hdmx* hdmx = &face->hdmx; + FT_Long num_glyphs; + FT_Long record_size; + + + hdmx->version = 0; + hdmx->num_records = 0; + hdmx->records = 0; + + /* this table is optional */ + error = face->goto_table( face, TTAG_hdmx, stream, 0 ); + if ( error ) + return TT_Err_Ok; + + if ( ACCESS_Frame( 8L ) ) + goto Exit; + + hdmx->version = GET_UShort(); + hdmx->num_records = GET_Short(); + record_size = GET_Long(); + + FORGET_Frame(); + + /* Only recognize format 0 */ + if ( hdmx->version != 0 ) + goto Exit; + + if ( ALLOC_ARRAY( hdmx->records, hdmx->num_records, TT_HdmxRec ) ) + goto Exit; + + num_glyphs = face->root.num_glyphs; + record_size -= num_glyphs + 2; + + { + TT_HdmxRec* cur = hdmx->records; + TT_HdmxRec* limit = cur + hdmx->num_records; + + + for ( ; cur < limit; cur++ ) + { + /* read record */ + if ( READ_Byte( cur->ppem ) || + READ_Byte( cur->max_width ) ) + goto Exit; + + if ( ALLOC( cur->widths, num_glyphs ) || + FILE_Read( cur->widths, num_glyphs ) ) + goto Exit; + + /* skip padding bytes */ + if ( record_size > 0 && FILE_Skip( record_size ) ) + goto Exit; + } + } + + Exit: + return error; + } + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Free_Hdmx */ + /* */ + /* */ + /* Frees the horizontal device metrics table. */ + /* */ + /* */ + /* face :: A handle to the target face object. */ + /* */ + LOCAL_FUNC + void TT_Free_Hdmx( TT_Face face ) + { + if ( face ) + { + FT_Int n; + FT_Memory memory = face->root.driver->root.memory; + + + for ( n = 0; n < face->hdmx.num_records; n++ ) + FREE( face->hdmx.records[n].widths ); + + FREE( face->hdmx.records ); + face->hdmx.num_records = 0; + } + } + + +/* END */ diff --git a/src/freetype/sfnt/ttload.h b/src/freetype/sfnt/ttload.h new file mode 100644 index 0000000000..dd0de6a4f1 --- /dev/null +++ b/src/freetype/sfnt/ttload.h @@ -0,0 +1,132 @@ +/***************************************************************************/ +/* */ +/* ttload.h */ +/* */ +/* Load the basic TrueType tables, i.e., tables that can be either in */ +/* TTF or OTF fonts (specification). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef TTLOAD_H +#define TTLOAD_H + + +#include +#include + + +#ifdef __cplusplus + extern "C" { +#endif + + + LOCAL_DEF + TT_Table* TT_LookUp_Table( TT_Face face, + FT_ULong tag ); + + LOCAL_DEF + FT_Error TT_Goto_Table( TT_Face face, + FT_ULong tag, + FT_Stream stream, + FT_ULong* length ); + + + LOCAL_DEF + FT_Error TT_Load_SFNT_Header( TT_Face face, + FT_Stream stream, + FT_Long face_index, + SFNT_Header* sfnt ); + LOCAL_DEF + FT_Error TT_Load_Directory( TT_Face face, + FT_Stream stream, + SFNT_Header* sfnt ); + + LOCAL_DEF + FT_Error TT_Load_Any( TT_Face face, + FT_ULong tag, + FT_Long offset, + FT_Byte* buffer, + FT_ULong* length ); + + + LOCAL_DEF + FT_Error TT_Load_Header( TT_Face face, + FT_Stream stream ); + + + LOCAL_DEF + FT_Error TT_Load_Metrics_Header( TT_Face face, + FT_Stream stream, + FT_Bool vertical ); + + + LOCAL_DEF + FT_Error TT_Load_CMap( TT_Face face, + FT_Stream stream ); + + + LOCAL_DEF + FT_Error TT_Load_MaxProfile( TT_Face face, + FT_Stream stream ); + + + LOCAL_DEF + FT_Error TT_Load_Names( TT_Face face, + FT_Stream stream ); + + + LOCAL_DEF + FT_Error TT_Load_OS2( TT_Face face, + FT_Stream stream ); + + + LOCAL_DEF + FT_Error TT_Load_PostScript( TT_Face face, + FT_Stream stream ); + + + LOCAL_DEF + FT_Error TT_Load_Hdmx( TT_Face face, + FT_Stream stream ); + + LOCAL_DEF + FT_Error TT_Load_PCLT( TT_Face face, + FT_Stream stream ); + + LOCAL_DEF + void TT_Free_Names( TT_Face face ); + + + LOCAL_DEF + void TT_Free_Hdmx ( TT_Face face ); + + + LOCAL_DEF + FT_Error TT_Load_Kern( TT_Face face, + FT_Stream stream ); + + + LOCAL_DEF + FT_Error TT_Load_Gasp( TT_Face face, + FT_Stream stream ); + + +#ifdef __cplusplus + } +#endif + + +#endif /* TTLOAD_H */ + + +/* END */ diff --git a/src/freetype/sfnt/ttpost.c b/src/freetype/sfnt/ttpost.c new file mode 100644 index 0000000000..c83205baed --- /dev/null +++ b/src/freetype/sfnt/ttpost.c @@ -0,0 +1,536 @@ +/***************************************************************************/ +/* */ +/* ttpost.c */ +/* */ +/* Postcript name table processing for TrueType and OpenType fonts */ +/* (body). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + /*************************************************************************/ + /* */ + /* The post table is not completely loaded by the core engine. This */ + /* file loads the missing PS glyph names and implements an API to access */ + /* them. */ + /* */ + /*************************************************************************/ + + +#include +#include +#include + + +#ifdef FT_FLAT_COMPILE + +#include "ttpost.h" +#include "ttload.h" + +#else + +#include +#include + +#endif + + + /*************************************************************************/ + /* */ + /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ + /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ + /* messages during execution. */ + /* */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_ttpost + + + /* If this configuration macro is defined, we rely on the `PSNames' */ + /* module to grab the glyph names. */ + +#ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES + + +#include + +#define MAC_NAME( x ) ( (FT_String*)psnames->macintosh_name( x ) ) + + +#else /* FT_CONFIG_OPTION_POSTSCRIPT_NAMES */ + + + /* Otherwise, we ignore the `PSNames' module, and provide our own */ + /* table of Mac names. Thus, it is possible to build a version of */ + /* FreeType without the Type 1 driver & PSNames module. */ + +#define MAC_NAME( x ) TT_Post_Default_Names[x] + + /* the 258 default Mac PS glyph names */ + + FT_String* TT_Post_Default_Names[258] = + { + /* 0 */ + ".notdef", ".null", "CR", "space", "exclam", + "quotedbl", "numbersign", "dollar", "percent", "ampersand", + /* 10 */ + "quotesingle", "parenleft", "parenright", "asterisk", "plus", + "comma", "hyphen", "period", "slash", "zero", + /* 20 */ + "one", "two", "three", "four", "five", + "six", "seven", "eight", "nine", "colon", + /* 30 */ + "semicolon", "less", "equal", "greater", "question", + "at", "A", "B", "C", "D", + /* 40 */ + "E", "F", "G", "H", "I", + "J", "K", "L", "M", "N", + /* 50 */ + "O", "P", "Q", "R", "S", + "T", "U", "V", "W", "X", + /* 60 */ + "Y", "Z", "bracketleft", "backslash", "bracketright", + "asciicircum", "underscore", "grave", "a", "b", + /* 70 */ + "c", "d", "e", "f", "g", + "h", "i", "j", "k", "l", + /* 80 */ + "m", "n", "o", "p", "q", + "r", "s", "t", "u", "v", + /* 90 */ + "w", "x", "y", "z", "braceleft", + "bar", "braceright", "asciitilde", "Adieresis", "Aring", + /* 100 */ + "Ccedilla", "Eacute", "Ntilde", "Odieresis", "Udieresis", + "aacute", "agrave", "acircumflex", "adieresis", "atilde", + /* 110 */ + "aring", "ccedilla", "eacute", "egrave", "ecircumflex", + "edieresis", "iacute", "igrave", "icircumflex", "idieresis", + /* 120 */ + "ntilde", "oacute", "ograve", "ocircumflex", "odieresis", + "otilde", "uacute", "ugrave", "ucircumflex", "udieresis", + /* 130 */ + "dagger", "degree", "cent", "sterling", "section", + "bullet", "paragraph", "germandbls", "registered", "copyright", + /* 140 */ + "trademark", "acute", "dieresis", "notequal", "AE", + "Oslash", "infinity", "plusminus", "lessequal", "greaterequal", + /* 150 */ + "yen", "mu", "partialdiff", "summation", "product", + "pi", "integral", "ordfeminine", "ordmasculine", "Omega", + /* 160 */ + "ae", "oslash", "questiondown", "exclamdown", "logicalnot", + "radical", "florin", "approxequal", "Delta", "guillemotleft", + /* 170 */ + "guillemotright", "ellipsis", "nbspace", "Agrave", "Atilde", + "Otilde", "OE", "oe", "endash", "emdash", + /* 180 */ + "quotedblleft", "quotedblright", "quoteleft", "quoteright", "divide", + "lozenge", "ydieresis", "Ydieresis", "fraction", "currency", + /* 190 */ + "guilsinglleft", "guilsinglright", "fi", "fl", "daggerdbl", + "periodcentered", "quotesinglbase", "quotedblbase", "perthousand", "Acircumflex", + /* 200 */ + "Ecircumflex", "Aacute", "Edieresis", "Egrave", "Iacute", + "Icircumflex", "Idieresis", "Igrave", "Oacute", "Ocircumflex", + /* 210 */ + "apple", "Ograve", "Uacute", "Ucircumflex", "Ugrave", + "dotlessi", "circumflex", "tilde", "macron", "breve", + /* 220 */ + "dotaccent", "ring", "cedilla", "hungarumlaut", "ogonek", + "caron", "Lslash", "lslash", "Scaron", "scaron", + /* 230 */ + "Zcaron", "zcaron", "brokenbar", "Eth", "eth", + "Yacute", "yacute", "Thorn", "thorn", "minus", + /* 240 */ + "multiply", "onesuperior", "twosuperior", "threesuperior", "onehalf", + "onequarter", "threequarters", "franc", "Gbreve", "gbreve", + /* 250 */ + "Idot", "Scedilla", "scedilla", "Cacute", "cacute", + "Ccaron", "ccaron", "dmacron", + }; + + +#endif /* FT_CONFIG_OPTION_POSTSCRIPT_NAMES */ + + + static + FT_Error Load_Format_20( TT_Face face, + FT_Stream stream ) + { + FT_Memory memory = stream->memory; + FT_Error error; + + FT_Int num_glyphs; + FT_Int num_names; + + FT_UShort* glyph_indices = 0; + FT_Char** name_strings = 0; + + + if ( READ_UShort( num_glyphs ) ) + goto Exit; + + /* UNDOCUMENTED! The number of glyphs in this table can be smaller */ + /* than the value in the maxp table (cf. cyberbit.ttf). */ + + /* There already exist fonts which have more than 32768 glyph names */ + /* in this table, so the test for this threshold has been dropped. */ + + if ( num_glyphs > face->root.num_glyphs ) + { + error = TT_Err_Invalid_File_Format; + goto Exit; + } + + /* load the indices */ + { + FT_Int n; + + + if ( ALLOC_ARRAY ( glyph_indices, num_glyphs, FT_UShort ) || + ACCESS_Frame( num_glyphs * 2L ) ) + goto Fail; + + for ( n = 0; n < num_glyphs; n++ ) + glyph_indices[n] = GET_UShort(); + + FORGET_Frame(); + } + + /* compute number of names stored in table */ + { + FT_Int n; + + + num_names = 0; + + for ( n = 0; n < num_glyphs; n++ ) + { + FT_Int index; + + + index = glyph_indices[n]; + if ( index >= 258 ) + { + index -= 257; + if ( index > num_names ) + num_names = index; + } + } + } + + /* now load the name strings */ + { + FT_Int n; + + + if ( ALLOC_ARRAY( name_strings, num_names, FT_Char* ) ) + goto Fail; + + for ( n = 0; n < num_names; n++ ) + { + FT_UInt len; + + + if ( READ_Byte ( len ) || + ALLOC_ARRAY( name_strings[n], len + 1, FT_Char ) || + FILE_Read ( name_strings[n], len ) ) + goto Fail1; + + name_strings[n][len] = '\0'; + } + } + + /* all right, set table fields and exit successfuly */ + { + TT_Post_20* table = &face->postscript_names.names.format_20; + + + table->num_glyphs = num_glyphs; + table->num_names = num_names; + table->glyph_indices = glyph_indices; + table->glyph_names = name_strings; + } + return TT_Err_Ok; + + + Fail1: + { + FT_Int n; + + + for ( n = 0; n < num_names; n++ ) + FREE( name_strings[n] ); + } + + Fail: + FREE( name_strings ); + FREE( glyph_indices ); + + Exit: + return error; + } + + + static + FT_Error Load_Format_25( TT_Face face, + FT_Stream stream ) + { + FT_Memory memory = stream->memory; + FT_Error error; + + FT_Int num_glyphs; + FT_Char* offset_table = 0; + + + /* UNDOCUMENTED! This value appears only in the Apple TT specs. */ + if ( READ_UShort( num_glyphs ) ) + goto Exit; + + /* check the number of glyphs */ + if ( num_glyphs > face->root.num_glyphs || num_glyphs > 258 ) + { + error = TT_Err_Invalid_File_Format; + goto Exit; + } + + if ( ALLOC ( offset_table, num_glyphs ) || + FILE_Read( offset_table, num_glyphs ) ) + goto Fail; + + /* now check the offset table */ + { + FT_Int n; + + + for ( n = 0; n < num_glyphs; n++ ) + { + FT_Long index = (FT_Long)n + offset_table[n]; + + + if ( index < 0 || index > num_glyphs ) + { + error = TT_Err_Invalid_File_Format; + goto Fail; + } + } + } + + /* OK, set table fields and exit successfuly */ + { + TT_Post_25* table = &face->postscript_names.names.format_25; + + + table->num_glyphs = num_glyphs; + table->offsets = offset_table; + } + + return TT_Err_Ok; + + Fail: + FREE( offset_table ); + + Exit: + return error; + } + + + static + FT_Error Load_Post_Names( TT_Face face ) + { + FT_Stream stream; + FT_Error error; + + /* get a stream for the face's resource */ + stream = face->root.stream; + + /* seek to the beginning of the PS names table */ + error = face->goto_table( face, TTAG_post, stream, 0 ); + if ( error ) + goto Exit; + + /* now read postscript table */ + switch ( face->postscript.FormatType ) + { + case 0x00020000L: + error = Load_Format_20( face, stream ); + break; + + case 0x00028000L: + error = Load_Format_25( face, stream ); + break; + + default: + error = TT_Err_Invalid_File_Format; + } + + face->postscript_names.loaded = 1; + + Exit: + return error; + } + + + LOCAL_FUNC + void TT_Free_Post_Names( TT_Face face ) + { + FT_Memory memory = face->root.memory; + TT_Post_Names* names = &face->postscript_names; + + + if ( names->loaded ) + { + switch ( face->postscript.FormatType ) + { + case 0x00020000L: + { + TT_Post_20* table = &names->names.format_20; + FT_UInt n; + + + FREE( table->glyph_indices ); + table->num_glyphs = 0; + + for ( n = 0; n < table->num_names; n++ ) + FREE( table->glyph_names[n] ); + + FREE( table->glyph_names ); + table->num_names = 0; + } + break; + + case 0x00028000L: + { + TT_Post_25* table = &names->names.format_25; + + + FREE( table->offsets ); + table->num_glyphs = 0; + } + break; + } + } + names->loaded = 0; + } + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Get_PS_Name */ + /* */ + /* */ + /* Gets the PostScript glyph name of a glyph. */ + /* */ + /* */ + /* face :: A handle to the parent face. */ + /* */ + /* index :: The glyph index. */ + /* */ + /* PSname :: The address of a string pointer. Will be NULL in case */ + /* of error, otherwise it is a pointer to the glyph name. */ + /* */ + /* You must not modify the returned string! */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + LOCAL_FUNC + FT_Error TT_Get_PS_Name( TT_Face face, + FT_UInt index, + FT_String** PSname ) + { + FT_Error error; + TT_Post_Names* names; + +#ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES + PSNames_Interface* psnames; +#endif + + + if ( !face ) + return TT_Err_Invalid_Face_Handle; + + if ( index >= (FT_UInt)face->root.num_glyphs ) + return TT_Err_Invalid_Glyph_Index; + +#ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES + psnames = (PSNames_Interface*)face->psnames; + if ( !psnames ) + return TT_Err_Unimplemented_Feature; +#endif + + names = &face->postscript_names; + + /* `.notdef' by default */ + *PSname = MAC_NAME( 0 ); + + switch ( face->postscript.FormatType ) + { + case 0x00010000L: + if ( index < 258 ) /* paranoid checking */ + *PSname = MAC_NAME( index ); + break; + + case 0x00020000L: + { + TT_Post_20* table = &names->names.format_20; + + + if ( !names->loaded ) + { + error = Load_Post_Names( face ); + if ( error ) + break; + } + + if ( index < table->num_glyphs ) + { + FT_UShort name_index = table->glyph_indices[index]; + + + if ( name_index < 258 ) + *PSname = MAC_NAME( name_index ); + else + *PSname = (FT_String*)table->glyph_names[name_index - 258]; + } + } + break; + + case 0x00028000L: + { + TT_Post_25* table = &names->names.format_25; + + + if ( !names->loaded ) + { + error = Load_Post_Names( face ); + if ( error ) + break; + } + + if ( index < table->num_glyphs ) /* paranoid checking */ + { + index += table->offsets[index]; + *PSname = MAC_NAME( index ); + } + } + break; + + case 0x00030000L: + break; /* nothing to do */ + } + + return TT_Err_Ok; + } + + +/* END */ diff --git a/src/freetype/sfnt/ttpost.h b/src/freetype/sfnt/ttpost.h new file mode 100644 index 0000000000..e3da83606d --- /dev/null +++ b/src/freetype/sfnt/ttpost.h @@ -0,0 +1,52 @@ +/***************************************************************************/ +/* */ +/* ttpost.h */ +/* */ +/* Postcript name table processing for TrueType and OpenType fonts */ +/* (specification). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef TTPOST_H +#define TTPOST_H + +#include +#include + +#ifdef __cplusplus + extern "C" { +#endif + + +#define TT_Err_Invalid_Post_Table_Format 0x0B00 +#define TT_Err_Invalid_Post_Table 0x0B01 + + + LOCAL_DEF + FT_Error TT_Get_PS_Name( TT_Face face, + FT_UInt index, + FT_String** PSname ); + + LOCAL_DEF + void TT_Free_Post_Names( TT_Face face ); + + +#ifdef __cplusplus + } +#endif + + +#endif /* TTPOST_H */ + + +/* END */ diff --git a/src/freetype/sfnt/ttsbit.c b/src/freetype/sfnt/ttsbit.c new file mode 100644 index 0000000000..9a5455afb8 --- /dev/null +++ b/src/freetype/sfnt/ttsbit.c @@ -0,0 +1,1444 @@ +/***************************************************************************/ +/* */ +/* ttsbit.c */ +/* */ +/* TrueType and OpenType embedded bitmap support (body). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#include +#include +#include + + +#ifdef FT_FLAT_COMPILE + +#include "ttsbit.h" + +#else + +#include + +#endif + + + /*************************************************************************/ + /* */ + /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ + /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ + /* messages during execution. */ + /* */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_ttsbit + + + /*************************************************************************/ + /* */ + /* */ + /* blit_sbit */ + /* */ + /* */ + /* Blits a bitmap from an input stream into a given target. Supports */ + /* x and y offsets as well as byte padded lines. */ + /* */ + /* */ + /* target :: The target bitmap/pixmap. */ + /* */ + /* source :: The input packed bitmap data. */ + /* */ + /* line_bits :: The number of bits per line. */ + /* */ + /* byte_padded :: A flag which is true if lines are byte-padded. */ + /* */ + /* x_offset :: The horizontal offset. */ + /* */ + /* y_offset :: The vertical offset. */ + /* */ + /* */ + /* IMPORTANT: The x and y offsets are relative to the top corner of */ + /* the target bitmap (unlike the normal TrueType */ + /* convention). A positive y offset indicates a downwards */ + /* direction! */ + /* */ + static + void blit_sbit( FT_Bitmap* target, + FT_Byte* source, + FT_Int line_bits, + FT_Bool byte_padded, + FT_Int x_offset, + FT_Int y_offset ) + { + FT_Byte* line_buff; + FT_Int line_incr; + FT_Int height; + + FT_UShort acc; + FT_Byte loaded; + + + /* first of all, compute starting write position */ + line_incr = target->pitch; + line_buff = target->buffer; + + if ( line_incr < 0 ) + line_buff -= line_incr * ( target->rows - 1 ); + + line_buff += ( x_offset >> 3 ) + y_offset * line_incr; + + /***********************************************************************/ + /* */ + /* We use the extra-classic `accumulator' trick to extract the bits */ + /* from the source byte stream. */ + /* */ + /* Namely, the variable `acc' is a 16-bit accumulator containing the */ + /* last `loaded' bits from the input stream. The bits are shifted to */ + /* the upmost position in `acc'. */ + /* */ + /***********************************************************************/ + + acc = 0; /* clear accumulator */ + loaded = 0; /* no bits were loaded */ + + for ( height = target->rows; height > 0; height-- ) + { + FT_Byte* cur = line_buff; /* current write cursor */ + FT_Int count = line_bits; /* # of bits to extract per line */ + FT_Byte shift = x_offset & 7; /* current write shift */ + FT_Byte space = 8 - shift; + + + /* first of all, read individual source bytes */ + if ( count >= 8 ) + { + count -= 8; + { + do + { + FT_Byte val; + + + /* ensure that there are at least 8 bits in the accumulator */ + if ( loaded < 8 ) + { + acc |= (FT_UShort)*source++ << ( 8 - loaded ); + loaded += 8; + } + + /* now write one byte */ + val = (FT_Byte)( acc >> 8 ); + if ( shift ) + { + cur[0] |= val >> shift; + cur[1] |= val << space; + } + else + cur[0] |= val; + + cur++; + acc <<= 8; /* remove bits from accumulator */ + loaded -= 8; + count -= 8; + + } while ( count >= 0 ); + } + + /* restore `count' to correct value */ + count += 8; + } + + /* now write remaining bits (count < 8) */ + if ( count > 0 ) + { + FT_Byte val; + + + /* ensure that there are at least `count' bits in the accumulator */ + if ( loaded < count ) + { + acc |= (FT_UShort)*source++ << ( 8 - loaded ); + loaded += 8; + } + + /* now write remaining bits */ + val = ( (FT_Byte)( acc >> 8 ) ) & ~( 0xFF >> count ); + cur[0] |= val >> shift; + + if ( count > space ) + cur[1] |= val << space; + + acc <<= count; + loaded -= count; + } + + /* now, skip to next line */ + if ( byte_padded ) + acc = loaded = 0; /* clear accumulator on byte-padded lines */ + + line_buff += line_incr; + } + } + + + const FT_Frame_Field sbit_metrics_fields[] = + { + FT_FRAME_START( 8 ), + FT_FRAME_BYTE( TT_SBit_Metrics, height ), + FT_FRAME_BYTE( TT_SBit_Metrics, width ), + + FT_FRAME_CHAR( TT_SBit_Metrics, horiBearingX ), + FT_FRAME_CHAR( TT_SBit_Metrics, horiBearingY ), + FT_FRAME_BYTE( TT_SBit_Metrics, horiAdvance ), + + FT_FRAME_CHAR( TT_SBit_Metrics, vertBearingX ), + FT_FRAME_CHAR( TT_SBit_Metrics, vertBearingY ), + FT_FRAME_BYTE( TT_SBit_Metrics, vertAdvance ), + FT_FRAME_END + }; + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Load_SBit_Const_Metrics */ + /* */ + /* */ + /* Loads the metrics for `EBLC' index tables format 2 and 5. */ + /* */ + /* */ + /* range :: The target range. */ + /* */ + /* stream :: The input stream. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + static + FT_Error Load_SBit_Const_Metrics( TT_SBit_Range* range, + FT_Stream stream ) + { + FT_Error error; + + + if ( READ_ULong( range->image_size ) ) + return error; + + return READ_Fields( sbit_metrics_fields, &range->metrics ); + } + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Load_SBit_Range_Codes */ + /* */ + /* */ + /* Loads the range codes for `EBLC' index tables format 4 and 5. */ + /* */ + /* */ + /* range :: The target range. */ + /* */ + /* stream :: The input stream. */ + /* */ + /* load_offsets :: A flag whether to load the glyph offset table. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + static + FT_Error Load_SBit_Range_Codes( TT_SBit_Range* range, + FT_Stream stream, + FT_Bool load_offsets ) + { + FT_Error error; + FT_ULong count, n, size; + FT_Memory memory = stream->memory; + + + if ( READ_ULong( count ) ) + goto Exit; + + range->num_glyphs = count; + + /* Allocate glyph offsets table if needed */ + if ( load_offsets ) + { + if ( ALLOC_ARRAY( range->glyph_offsets, count, FT_ULong ) ) + goto Exit; + + size = count * 4L; + } + else + size = count * 2L; + + /* Allocate glyph codes table and access frame */ + if ( ALLOC_ARRAY ( range->glyph_codes, count, FT_UShort ) || + ACCESS_Frame( size ) ) + goto Exit; + + for ( n = 0; n < count; n++ ) + { + range->glyph_codes[n] = GET_UShort(); + + if ( load_offsets ) + range->glyph_offsets[n] = (FT_ULong)range->image_offset + + GET_UShort(); + } + + FORGET_Frame(); + + Exit: + return error; + } + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Load_SBit_Range */ + /* */ + /* */ + /* Loads a given `EBLC' index/range table. */ + /* */ + /* */ + /* range :: The target range. */ + /* */ + /* stream :: The input stream. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + static + FT_Error Load_SBit_Range( TT_SBit_Range* range, + FT_Stream stream ) + { + FT_Error error; + FT_Memory memory = stream->memory; + + + switch( range->index_format ) + { + case 1: /* variable metrics with 4-byte offsets */ + case 3: /* variable metrics with 2-byte offsets */ + { + FT_ULong num_glyphs, n; + FT_Int size_elem; + FT_Bool large = ( range->index_format == 1 ); + + + num_glyphs = range->last_glyph - range->first_glyph + 1L; + range->num_glyphs = num_glyphs; + num_glyphs++; /* XXX: BEWARE - see spec */ + + size_elem = large ? 4 : 2; + + if ( ALLOC_ARRAY( range->glyph_offsets, + num_glyphs, FT_ULong ) || + ACCESS_Frame( num_glyphs * size_elem ) ) + goto Exit; + + for ( n = 0; n < num_glyphs; n++ ) + range->glyph_offsets[n] = (FT_ULong)( range->image_offset + + ( large ? GET_ULong() + : GET_UShort() ) ); + FORGET_Frame(); + } + break; + + case 2: /* all glyphs have identical metrics */ + error = Load_SBit_Const_Metrics( range, stream ); + break; + + case 4: + error = Load_SBit_Range_Codes( range, stream, 1 ); + break; + + case 5: + error = Load_SBit_Const_Metrics( range, stream ) || + Load_SBit_Range_Codes( range, stream, 0 ); + break; + + default: + error = TT_Err_Invalid_File_Format; + } + + Exit: + return error; + } + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Load_SBit_Strikes */ + /* */ + /* */ + /* Loads the table of embedded bitmap sizes for this face. */ + /* */ + /* */ + /* face :: The target face object. */ + /* */ + /* stream :: The input stream. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + LOCAL_FUNC + FT_Error TT_Load_SBit_Strikes( TT_Face face, + FT_Stream stream ) + { + FT_Error error = 0; + FT_Memory memory = stream->memory; + FT_Fixed version; + FT_ULong num_strikes; + FT_ULong table_base; + + const FT_Frame_Field sbit_line_metrics_fields[] = + { + /* no FT_FRAME_START */ + FT_FRAME_CHAR( TT_SBit_Line_Metrics, ascender ), + FT_FRAME_CHAR( TT_SBit_Line_Metrics, descender ), + FT_FRAME_BYTE( TT_SBit_Line_Metrics, max_width ), + + FT_FRAME_CHAR( TT_SBit_Line_Metrics, caret_slope_numerator ), + FT_FRAME_CHAR( TT_SBit_Line_Metrics, caret_slope_denominator ), + FT_FRAME_CHAR( TT_SBit_Line_Metrics, caret_offset ), + + FT_FRAME_CHAR( TT_SBit_Line_Metrics, min_origin_SB ), + FT_FRAME_CHAR( TT_SBit_Line_Metrics, min_advance_SB ), + FT_FRAME_CHAR( TT_SBit_Line_Metrics, max_before_BL ), + FT_FRAME_CHAR( TT_SBit_Line_Metrics, min_after_BL ), + FT_FRAME_CHAR( TT_SBit_Line_Metrics, pads[0] ), + FT_FRAME_CHAR( TT_SBit_Line_Metrics, pads[1] ), + FT_FRAME_END + }; + + const FT_Frame_Field strike_start_fields[] = + { + /* no FT_FRAME_START */ + FT_FRAME_ULONG( TT_SBit_Strike, ranges_offset ), + FT_FRAME_SKIP_LONG, + FT_FRAME_ULONG( TT_SBit_Strike, num_ranges ), + FT_FRAME_ULONG( TT_SBit_Strike, color_ref ), + FT_FRAME_END + }; + + const FT_Frame_Field strike_end_fields[] = + { + /* no FT_FRAME_START */ + FT_FRAME_USHORT( TT_SBit_Strike, start_glyph ), + FT_FRAME_USHORT( TT_SBit_Strike, end_glyph ), + FT_FRAME_BYTE ( TT_SBit_Strike, x_ppem ), + FT_FRAME_BYTE ( TT_SBit_Strike, y_ppem ), + FT_FRAME_BYTE ( TT_SBit_Strike, bit_depth ), + FT_FRAME_CHAR ( TT_SBit_Strike, flags ), + FT_FRAME_END + }; + + + face->num_sbit_strikes = 0; + + /* this table is optional */ + error = face->goto_table( face, TTAG_EBLC, stream, 0 ); + if (error) + error = face->goto_table( face, TTAG_bloc, stream, 0 ); + if ( error ) + { + error = 0; + goto Exit; + } + + table_base = FILE_Pos(); + if ( ACCESS_Frame( 8L ) ) + goto Exit; + + version = GET_Long(); + num_strikes = GET_ULong(); + + FORGET_Frame(); + + /* check version number and strike count */ + if ( version != 0x00020000L || + num_strikes >= 0x10000L ) + { + FT_ERROR(( "TT_Load_SBit_Strikes: invalid table version!\n" )); + error = TT_Err_Invalid_File_Format; + + goto Exit; + } + + /* allocate the strikes table */ + if ( ALLOC_ARRAY( face->sbit_strikes, num_strikes, TT_SBit_Strike ) ) + goto Exit; + + face->num_sbit_strikes = num_strikes; + + /* now read each strike table separately */ + { + TT_SBit_Strike* strike = face->sbit_strikes; + FT_ULong count = num_strikes; + + + if ( ACCESS_Frame( 48L * num_strikes ) ) + goto Exit; + + while ( count > 0 ) + { + (void)READ_Fields( strike_start_fields, strike ); + + (void)READ_Fields( sbit_line_metrics_fields, &strike->hori ); + (void)READ_Fields( sbit_line_metrics_fields, &strike->vert ); + + (void)READ_Fields( strike_end_fields, strike ); + + count--; + strike++; + } + + FORGET_Frame(); + } + + /* allocate the index ranges for each strike table */ + { + TT_SBit_Strike* strike = face->sbit_strikes; + FT_ULong count = num_strikes; + + + while ( count > 0 ) + { + TT_SBit_Range* range; + FT_ULong count2 = strike->num_ranges; + + + if ( ALLOC_ARRAY( strike->sbit_ranges, + strike->num_ranges, + TT_SBit_Range ) ) + goto Exit; + + /* read each range */ + if ( FILE_Seek( table_base + strike->ranges_offset ) || + ACCESS_Frame( strike->num_ranges * 8L ) ) + goto Exit; + + range = strike->sbit_ranges; + while ( count2 > 0 ) + { + range->first_glyph = GET_UShort(); + range->last_glyph = GET_UShort(); + range->table_offset = table_base + strike->ranges_offset + + GET_ULong(); + count2--; + range++; + } + + FORGET_Frame(); + + /* Now, read each index table */ + count2 = strike->num_ranges; + range = strike->sbit_ranges; + while ( count2 > 0 ) + { + /* Read the header */ + if ( FILE_Seek( range->table_offset ) || + ACCESS_Frame( 8L ) ) + goto Exit; + + range->index_format = GET_UShort(); + range->image_format = GET_UShort(); + range->image_offset = GET_ULong(); + + FORGET_Frame(); + + error = Load_SBit_Range( range, stream ); + if ( error ) + goto Exit; + + count2--; + range++; + } + + count--; + strike++; + } + } + + Exit: + return error; + } + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Free_SBit_Strikes */ + /* */ + /* */ + /* Releases the embedded bitmap tables. */ + /* */ + /* */ + /* face :: The target face object. */ + /* */ + LOCAL_FUNC + void TT_Free_SBit_Strikes( TT_Face face ) + { + FT_Memory memory = face->root.memory; + TT_SBit_Strike* strike = face->sbit_strikes; + TT_SBit_Strike* strike_limit = strike + face->num_sbit_strikes; + + + if ( strike ) + { + for ( ; strike < strike_limit; strike++ ) + { + TT_SBit_Range* range = strike->sbit_ranges; + TT_SBit_Range* range_limit = range + strike->num_ranges; + + + if ( range ) + { + for ( ; range < range_limit; range++ ) + { + /* release the glyph offsets and codes tables */ + /* where appropriate */ + FREE( range->glyph_offsets ); + FREE( range->glyph_codes ); + } + } + FREE( strike->sbit_ranges ); + strike->num_ranges = 0; + } + FREE( face->sbit_strikes ); + } + face->num_sbit_strikes = 0; + } + + + /*************************************************************************/ + /* */ + /* */ + /* Find_SBit_Range */ + /* */ + /* */ + /* Scans a given strike's ranges and return, for a given glyph */ + /* index, the corresponding sbit range, and `EBDT' offset. */ + /* */ + /* */ + /* glyph_index :: The glyph index. */ + /* strike :: The source/current sbit strike. */ + /* */ + /* */ + /* arange :: The sbit range containing the glyph index. */ + /* aglyph_offset :: The offset of the glyph data in `EBDT' table. */ + /* */ + /* */ + /* FreeType error code. 0 means the glyph index was found. */ + /* */ + static + FT_Error Find_SBit_Range( FT_UInt glyph_index, + TT_SBit_Strike* strike, + TT_SBit_Range** arange, + FT_ULong* aglyph_offset ) + { + TT_SBit_Range *range, *range_limit; + + + /* check whether the glyph index is within this strike's */ + /* glyph range */ + if ( glyph_index < strike->start_glyph || + glyph_index > strike->end_glyph ) + goto Fail; + + /* scan all ranges in strike */ + range = strike->sbit_ranges; + range_limit = range + strike->num_ranges; + if ( !range ) + goto Fail; + + for ( ; range < range_limit; range++ ) + { + if ( glyph_index >= range->first_glyph && + glyph_index <= range->last_glyph ) + { + FT_UShort delta = glyph_index - range->first_glyph; + + + switch ( range->index_format ) + { + case 1: + case 3: + *aglyph_offset = range->glyph_offsets[delta]; + break; + + case 2: + *aglyph_offset = range->image_offset + + range->image_size * delta; + break; + + case 4: + case 5: + { + FT_ULong n; + + + for ( n = 0; n < range->num_glyphs; n++ ) + { + if ( range->glyph_codes[n] == glyph_index ) + { + if ( range->index_format == 4 ) + *aglyph_offset = range->glyph_offsets[n]; + else + *aglyph_offset = range->image_offset + + n * range->image_size; + goto Found; + } + } + } + + /* fall-through */ + default: + goto Fail; + } + + Found: + /* return successfully! */ + *arange = range; + return 0; + } + } + + Fail: + *arange = 0; + *aglyph_offset = 0; + + return TT_Err_Invalid_Argument; + } + + + /*************************************************************************/ + /* */ + /* */ + /* Find_SBit_Image */ + /* */ + /* */ + /* Checks whether an embedded bitmap (an `sbit') exists for a given */ + /* glyph, at given x and y ppems. */ + /* */ + /* */ + /* face :: The target face object. */ + /* glyph_index :: The glyph index. */ + /* x_ppem :: The horizontal resolution in points per EM. */ + /* y_ppem :: The vertical resolution in points per EM. */ + /* */ + /* */ + /* arange :: The SBit range containing the glyph index. */ + /* astrike :: The SBit strike containing the glyph index. */ + /* aglyph_offset :: The offset of the glyph data in `EBDT' table. */ + /* */ + /* */ + /* FreeType error code. 0 means success. Returns */ + /* TT_Err_Invalid_Argument if no sbit exists for the requested glyph. */ + /* */ + static + FT_Error Find_SBit_Image( TT_Face face, + FT_UInt glyph_index, + FT_Int x_ppem, + FT_Int y_ppem, + + TT_SBit_Range** arange, + TT_SBit_Strike** astrike, + FT_ULong* aglyph_offset ) + { + TT_SBit_Strike* strike = face->sbit_strikes; + TT_SBit_Strike* strike_limit = strike + face->num_sbit_strikes; + + + if ( !strike ) + goto Fail; + + for ( ; strike < strike_limit; strike++ ) + { + if ( strike->x_ppem == x_ppem && strike->y_ppem == y_ppem ) + { + FT_Error error; + + + error = Find_SBit_Range( glyph_index, strike, + arange, aglyph_offset ); + if ( error ) + goto Fail; + + *astrike = strike; + + return TT_Err_Ok; + } + } + + Fail: + /* no embedded bitmap for this glyph in face */ + *arange = 0; + *astrike = 0; + *aglyph_offset = 0; + + return TT_Err_Invalid_Argument; + } + + + /*************************************************************************/ + /* */ + /* */ + /* Load_SBit_Metrics */ + /* */ + /* */ + /* Gets the big metrics for a given SBit. */ + /* */ + /* */ + /* stream :: The input stream. */ + /* */ + /* range :: The SBit range containing the glyph. */ + /* */ + /* */ + /* big_metrics :: A big SBit metrics structure for the glyph. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* The stream cursor must be positioned at the glyph's offset within */ + /* the `EBDT' table before the call. */ + /* */ + /* If the image format uses variable metrics, the stream cursor is */ + /* positioned just after the metrics header in the `EBDT' table on */ + /* function exit. */ + /* */ + static + FT_Error Load_SBit_Metrics( FT_Stream stream, + TT_SBit_Range* range, + TT_SBit_Metrics* metrics ) + { + FT_Error error = TT_Err_Ok; + + + switch ( range->image_format ) + { + case 1: + case 2: + case 8: + /* variable small metrics */ + { + TT_SBit_Small_Metrics smetrics; + + const FT_Frame_Field sbit_small_metrics_fields[] = + { + FT_FRAME_START( 5 ), + FT_FRAME_BYTE( TT_SBit_Small_Metrics, height ), + FT_FRAME_BYTE( TT_SBit_Small_Metrics, width ), + FT_FRAME_CHAR( TT_SBit_Small_Metrics, bearingX ), + FT_FRAME_CHAR( TT_SBit_Small_Metrics, bearingY ), + FT_FRAME_BYTE( TT_SBit_Small_Metrics, advance ), + FT_FRAME_END + }; + + + /* read small metrics */ + if ( READ_Fields( sbit_small_metrics_fields, &smetrics ) ) + goto Exit; + + /* convert it to a big metrics */ + metrics->height = smetrics.height; + metrics->width = smetrics.width; + metrics->horiBearingX = smetrics.bearingX; + metrics->horiBearingY = smetrics.bearingY; + metrics->horiAdvance = smetrics.advance; + + /* these metrics are made up at a higher level when */ + /* needed. */ + metrics->vertBearingX = 0; + metrics->vertBearingY = 0; + metrics->vertAdvance = 0; + } + break; + + case 6: + case 7: + case 9: + /* variable big metrics */ + (void)READ_Fields( sbit_metrics_fields, metrics ); + break; + + case 5: + default: /* constant metrics */ + if ( range->index_format == 2 || range->index_format == 5 ) + *metrics = range->metrics; + else + return TT_Err_Invalid_File_Format; + } + + Exit: + return error; + } + + + /*************************************************************************/ + /* */ + /* */ + /* Crop_Bitmap */ + /* */ + /* */ + /* Crops a bitmap to its tightest bounding box, and adjusts its */ + /* metrics. */ + /* */ + /* */ + /* image :: The input glyph slot. */ + /* */ + /* metrics :: The corresponding metrics structure. */ + /* */ + static + void Crop_Bitmap( FT_Bitmap* map, + TT_SBit_Metrics* metrics ) + { + /***********************************************************************/ + /* */ + /* In this situation, some bounding boxes of embedded bitmaps are too */ + /* large. We need to crop it to a reasonable size. */ + /* */ + /* --------- */ + /* | | ----- */ + /* | *** | |***| */ + /* | * | | * | */ + /* | * | ------> | * | */ + /* | * | | * | */ + /* | * | | * | */ + /* | *** | |***| */ + /* --------- ----- */ + /* */ + /***********************************************************************/ + + FT_Int rows, count; + FT_Long line_len; + FT_Byte* line; + + + /***********************************************************************/ + /* */ + /* first of all, check the top-most lines of the bitmap, and remove */ + /* them if they're empty. */ + /* */ + { + line = (FT_Byte*)map->buffer; + rows = map->rows; + line_len = map->pitch; + + + for ( count = 0; count < rows; count++ ) + { + FT_Byte* cur = line; + FT_Byte* limit = line + line_len; + + + for ( ; cur < limit; cur++ ) + if ( cur[0] ) + goto Found_Top; + + /* the current line was empty - skip to next one */ + line = limit; + } + + Found_Top: + /* check that we have at least one filled line */ + if ( count >= rows ) + goto Empty_Bitmap; + + /* now, crop the empty upper lines */ + if ( count > 0 ) + { + line = (FT_Byte*)map->buffer; + + MEM_Move( line, line + count * line_len, + ( rows - count ) * line_len ); + + metrics->height -= count; + metrics->horiBearingY -= count; + metrics->vertBearingY -= count; + + map->rows -= count; + rows -= count; + } + } + + /***********************************************************************/ + /* */ + /* second, crop the lower lines */ + /* */ + { + line = (FT_Byte*)map->buffer + ( rows - 1 ) * line_len; + + for ( count = 0; count < rows; count++ ) + { + FT_Byte* cur = line; + FT_Byte* limit = line + line_len; + + + for ( ; cur < limit; cur++ ) + if ( cur[0] ) + goto Found_Bottom; + + /* the current line was empty - skip to previous one */ + line -= line_len; + } + + Found_Bottom: + if ( count > 0 ) + { + metrics->height -= count; + rows -= count; + map->rows -= count; + } + } + + /***********************************************************************/ + /* */ + /* third, get rid of the space on the left side of the glyph */ + /* */ + do + { + FT_Byte* limit; + + + line = (FT_Byte*)map->buffer; + limit = line + rows * line_len; + + for ( ; line < limit; line += line_len ) + if ( line[0] & 0x80 ) + goto Found_Left; + + /* shift the whole glyph one pixel to the left */ + line = (FT_Byte*)map->buffer; + limit = line + rows * line_len; + + for ( ; line < limit; line += line_len ) + { + FT_Int n, width = map->width; + FT_Byte old; + FT_Byte* cur = line; + + + old = cur[0] << 1; + for ( n = 8; n < width; n += 8 ) + { + FT_Byte val; + + + val = cur[1]; + cur[0] = old | ( val >> 7 ); + old = val << 1; + cur++; + } + cur[0] = old; + } + + map->width--; + metrics->horiBearingX++; + metrics->vertBearingX++; + metrics->width--; + + } while ( map->width > 0 ); + + Found_Left: + + /***********************************************************************/ + /* */ + /* finally, crop the bitmap width to get rid of the space on the right */ + /* side of the glyph. */ + /* */ + do + { + FT_Int right = map->width - 1; + FT_Byte* limit; + FT_Byte mask; + + + line = (FT_Byte*)map->buffer + ( right >> 3 ); + limit = line + rows * line_len; + mask = 0x80 >> ( right & 7 ); + + for ( ; line < limit; line += line_len ) + if ( line[0] & mask ) + goto Found_Right; + + /* crop the whole glyph to the right */ + map->width--; + metrics->width--; + + } while ( map->width > 0 ); + + Found_Right: + /* all right, the bitmap was cropped */ + return; + + Empty_Bitmap: + map->width = 0; + map->rows = 0; + map->pitch = 0; + map->pixel_mode = ft_pixel_mode_mono; + } + + + static + FT_Error Load_SBit_Single( FT_Bitmap* map, + FT_Int x_offset, + FT_Int y_offset, + FT_Int pix_bits, + FT_UShort image_format, + TT_SBit_Metrics* metrics, + FT_Stream stream ) + { + FT_Error error; + + + /* check that the source bitmap fits into the target pixmap */ + if ( x_offset < 0 || x_offset + metrics->width > map->width || + y_offset < 0 || y_offset + metrics->height > map->rows ) + { + error = TT_Err_Invalid_Argument; + + goto Exit; + } + + { + FT_Int glyph_width = metrics->width; + FT_Int glyph_height = metrics->height; + FT_Int glyph_size; + FT_Int line_bits = pix_bits * glyph_width; + FT_Bool pad_bytes = 0; + + + /* compute size of glyph image */ + switch ( image_format ) + { + case 1: /* byte-padded formats */ + case 6: + { + FT_Int line_length; + + + switch ( pix_bits ) + { + case 1: line_length = ( glyph_width + 7 ) >> 3; break; + case 2: line_length = ( glyph_width + 3 ) >> 2; break; + case 4: line_length = ( glyph_width + 1 ) >> 1; break; + default: line_length = glyph_width; + } + + glyph_size = glyph_height * line_length; + pad_bytes = 1; + } + break; + + case 2: + case 5: + case 7: + line_bits = glyph_width * pix_bits; + glyph_size = ( glyph_height * line_bits + 7 ) >> 3; + break; + + default: /* invalid format */ + return TT_Err_Invalid_File_Format; + } + + /* Now read data and draw glyph into target pixmap */ + if ( ACCESS_Frame( glyph_size ) ) + goto Exit; + + /* don't forget to multiply `x_offset' by `map->pix_bits' as */ + /* the sbit blitter doesn't make a difference between pixmap */ + /* depths. */ + blit_sbit( map, (FT_Byte*)stream->cursor, line_bits, pad_bytes, + x_offset * pix_bits, y_offset ); + + FORGET_Frame(); + } + + Exit: + return error; + } + + + static + FT_Error Load_SBit_Image( TT_SBit_Strike* strike, + TT_SBit_Range* range, + FT_ULong ebdt_pos, + FT_ULong glyph_offset, + FT_Bitmap* map, + FT_Int x_offset, + FT_Int y_offset, + FT_Stream stream, + TT_SBit_Metrics* metrics ) + { + FT_Memory memory = stream->memory; + FT_Error error; + + + /* place stream at beginning of glyph data and read metrics */ + if ( FILE_Seek( ebdt_pos + glyph_offset ) ) + goto Exit; + + error = Load_SBit_Metrics( stream, range, metrics ); + if ( error ) + goto Exit; + + /* this function is recursive. At the top-level call, the */ + /* field map.buffer is NULL. We thus begin by finding the */ + /* dimensions of the higher-level glyph to allocate the */ + /* final pixmap buffer */ + if ( map->buffer == 0 ) + { + FT_Long size; + + + map->width = metrics->width; + map->rows = metrics->height; + + switch ( strike->bit_depth ) + { + case 1: + map->pixel_mode = ft_pixel_mode_mono; + map->pitch = ( map->width + 7 ) >> 3; + break; + + case 2: + map->pixel_mode = ft_pixel_mode_pal2; + map->pitch = ( map->width + 3 ) >> 2; + break; + + case 4: + map->pixel_mode = ft_pixel_mode_pal4; + map->pitch = ( map->width + 1 ) >> 1; + break; + + case 8: + map->pixel_mode = ft_pixel_mode_grays; + map->pitch = map->width; + break; + + default: + return TT_Err_Invalid_File_Format; + } + + size = map->rows * map->pitch; + + /* check that there is no empty image */ + if ( size == 0 ) + goto Exit; /* exit successfully! */ + + if ( ALLOC( map->buffer, size ) ) + goto Exit; + } + + switch ( range->image_format ) + { + case 1: /* single sbit image - load it */ + case 2: + case 5: + case 6: + case 7: + return Load_SBit_Single( map, x_offset, y_offset, strike->bit_depth, + range->image_format, metrics, stream ); + + case 8: /* compound format */ + FT_Skip_Stream( stream, 1L ); + /* fallthrough */ + + case 9: + break; + + default: /* invalid image format */ + return TT_Err_Invalid_File_Format; + } + + /* All right, we have a compound format. First of all, read */ + /* the array of elements. */ + { + TT_SBit_Component* components; + TT_SBit_Component* comp; + FT_UShort num_components, count; + + + if ( READ_UShort( num_components ) || + ALLOC_ARRAY( components, num_components, TT_SBit_Component ) ) + goto Exit; + + count = num_components; + + if ( ACCESS_Frame( 4L * num_components ) ) + goto Fail_Memory; + + for ( comp = components; count > 0; count--, comp++ ) + { + comp->glyph_code = GET_UShort(); + comp->x_offset = GET_Char(); + comp->y_offset = GET_Char(); + } + + FORGET_Frame(); + + /* Now recursively load each element glyph */ + count = num_components; + comp = components; + for ( ; count > 0; count--, comp++ ) + { + TT_SBit_Range* elem_range; + TT_SBit_Metrics elem_metrics; + FT_ULong elem_offset; + + + /* find the range for this element */ + error = Find_SBit_Range( comp->glyph_code, + strike, + &elem_range, + &elem_offset ); + if ( error ) + goto Fail_Memory; + + /* now load the element, recursively */ + error = Load_SBit_Image( strike, + elem_range, + ebdt_pos, + elem_offset, + map, + x_offset + comp->x_offset, + y_offset + comp->y_offset, + stream, + &elem_metrics ); + if ( error ) + goto Fail_Memory; + } + + Fail_Memory: + FREE( components ); + } + + Exit: + return error; + } + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Load_SBit_Image */ + /* */ + /* */ + /* Loads a given glyph sbit image from the font resource. This also */ + /* returns its metrics. */ + /* */ + /* */ + /* face :: The target face object. */ + /* */ + /* x_ppem :: The horizontal resolution in points per EM. */ + /* */ + /* y_ppem :: The vertical resolution in points per EM. */ + /* */ + /* glyph_index :: The current glyph index. */ + /* */ + /* load_flags :: The glyph load flags (the code checks for the flag */ + /* FT_LOAD_CROP_BITMAP */ + /* */ + /* stream :: The input stream. */ + /* */ + /* */ + /* map :: The target pixmap. */ + /* */ + /* metrics :: A big sbit metrics structure for the glyph image. */ + /* */ + /* */ + /* FreeType error code. 0 means success. Returns an error if no */ + /* glyph sbit exists for the index. */ + /* */ + /* */ + /* The `map.buffer' field is always freed before the glyph is loaded. */ + /* */ + LOCAL_FUNC + FT_Error TT_Load_SBit_Image( TT_Face face, + FT_Int x_ppem, + FT_Int y_ppem, + FT_UInt glyph_index, + FT_UInt load_flags, + FT_Stream stream, + FT_Bitmap* map, + TT_SBit_Metrics* metrics ) + { + FT_Error error; + FT_Memory memory = stream->memory; + FT_ULong ebdt_pos, glyph_offset; + + TT_SBit_Strike* strike; + TT_SBit_Range* range; + + + /* Check whether there is a glyph sbit for the current index */ + error = Find_SBit_Image( face, glyph_index, x_ppem, y_ppem, + &range, &strike, &glyph_offset ); + if ( error ) + goto Exit; + + /* now, find the location of the `EBDT' table in */ + /* the font file */ + error = face->goto_table( face, TTAG_EBDT, stream, 0 ); + if ( error ) + error = face->goto_table( face, TTAG_bdat, stream, 0 ); + if (error) + goto Exit; + + ebdt_pos = FILE_Pos(); + + /* clear the bitmap & load the bitmap */ + if ( face->root.glyph->flags & ft_glyph_own_bitmap ) + FREE( map->buffer ); + + map->rows = map->pitch = map->width = 0; + + error = Load_SBit_Image( strike, range, ebdt_pos, glyph_offset, + map, 0, 0, stream, metrics ); + if ( error ) + goto Exit; + + /* the glyph slot owns this bitmap buffer */ + face->root.glyph->flags |= ft_glyph_own_bitmap; + + /* setup vertical metrics if needed */ + if ( strike->flags & 1 ) + { + /* in case of a horizontal strike only */ + FT_Int advance; + FT_Int top; + + + advance = strike->hori.ascender - strike->hori.descender; + top = advance / 10; + + /* some heuristic values */ + + metrics->vertBearingX = -metrics->width / 2; + metrics->vertBearingY = advance / 10; + metrics->vertAdvance = advance * 12 / 10; + } + + /* Crop the bitmap now, unless specified otherwise */ + if ( load_flags & FT_LOAD_CROP_BITMAP ) + Crop_Bitmap( map, metrics ); + + Exit: + return error; + } + + +/* END */ diff --git a/src/freetype/sfnt/ttsbit.h b/src/freetype/sfnt/ttsbit.h new file mode 100644 index 0000000000..e77de53872 --- /dev/null +++ b/src/freetype/sfnt/ttsbit.h @@ -0,0 +1,65 @@ +/***************************************************************************/ +/* */ +/* ttsbit.h */ +/* */ +/* TrueType and OpenType embedded bitmap support (specification). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef TTSBIT_H +#define TTSBIT_H + + +#ifdef FT_FLAT_COMPILE + +#include "ttload.h" + +#else + +#include + +#endif + + +#ifdef __cplusplus + extern "C" { +#endif + + + LOCAL_DEF + FT_Error TT_Load_SBit_Strikes( TT_Face face, + FT_Stream stream ); + + LOCAL_DEF + void TT_Free_SBit_Strikes( TT_Face face ); + + LOCAL_DEF + FT_Error TT_Load_SBit_Image( TT_Face face, + FT_Int x_ppem, + FT_Int y_ppem, + FT_UInt glyph_index, + FT_UInt load_flags, + FT_Stream stream, + FT_Bitmap* map, + TT_SBit_Metrics* metrics ); + + +#ifdef __cplusplus + } +#endif + + +#endif /* TTSBIT_H */ + + +/* END */ diff --git a/src/freetype/smooth/ftgrays.c b/src/freetype/smooth/ftgrays.c new file mode 100644 index 0000000000..7ed0838850 --- /dev/null +++ b/src/freetype/smooth/ftgrays.c @@ -0,0 +1,1969 @@ +/***************************************************************************/ +/* */ +/* ftgrays.c */ +/* */ +/* A new `perfect' anti-aliasing renderer (body). */ +/* */ +/* Copyright 2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + /*************************************************************************/ + /* */ + /* This file can be compiled without the rest of the FreeType engine, */ + /* by defining the _STANDALONE_ macro when compiling it. You also need */ + /* to put the files `ftgrays.h' and `ftimage.h' into the current */ + /* compilation directory. Typically, you could do something like */ + /* */ + /* - copy `src/base/ftgrays.c' to your current directory */ + /* */ + /* - copy `include/freetype/ftimage.h' and */ + /* `include/freetype/ftgrays.h' to the same directory */ + /* */ + /* - compile `ftgrays' with the _STANDALONE_ macro defined, as in */ + /* */ + /* cc -c -D_STANDALONE_ ftgrays.c */ + /* */ + /* The renderer can be initialized with a call to */ + /* `ft_grays_raster.grays_raster_new'; an anti-aliased bitmap can be */ + /* generated with a call to `ft_grays_raster.grays_raster_render'. */ + /* */ + /* See the comments and documentation in the file `ftimage.h' for */ + /* more details on how the raster works. */ + /* */ + /*************************************************************************/ + + /*************************************************************************/ + /* */ + /* This is a new anti-aliasing scan-converter for FreeType 2. The */ + /* algorithm used here is _very_ different from the one in the standard */ + /* `ftraster' module. Actually, `ftgrays' computes the _exact_ */ + /* coverage of the outline on each pixel cell. */ + /* */ + /* It is based on ideas that I initially found in Raph Levien's */ + /* excellent LibArt graphics library (see http://www.levien.com/libart */ + /* for more information, though the web pages do not tell anything */ + /* about the renderer; you'll have to dive into the source code to */ + /* understand how it works). */ + /* */ + /* Note, however, that this is a _very_ different implementation */ + /* compared to Raph's. Coverage information is stored in a very */ + /* different way, and I don't use sorted vector paths. Also, it */ + /* doesn't use floating point values. */ + /* */ + /* This renderer has the following advantages: */ + /* */ + /* - It doesn't need an intermediate bitmap. Instead, one can supply */ + /* a callback function that will be called by the renderer to draw */ + /* gray spans on any target surface. You can thus do direct */ + /* composition on any kind of bitmap, provided that you give the */ + /* renderer the right callback. */ + /* */ + /* - A perfect anti-aliaser, i.e., it computes the _exact_ coverage on */ + /* each pixel cell */ + /* */ + /* - It performs a single pass on the outline (the `standard' FT2 */ + /* renderer makes two passes). */ + /* */ + /* - It can easily be modified to render to _any_ number of gray levels */ + /* cheaply. */ + /* */ + /* - For small (< 20) pixel sizes, it is faster than the standard */ + /* renderer. */ + /* */ + /*************************************************************************/ + + +#include /* for memcpy() */ + + + /*************************************************************************/ + /* */ + /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ + /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ + /* messages during execution. */ + /* */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_aaraster + + +#ifdef _STANDALONE_ + + +#define ErrRaster_Invalid_Mode -2 +#define ErrRaster_Invalid_Outline -1 + +#include "ftimage.h" +#include "ftgrays.h" + + /* This macro is used to indicate that a function parameter is unused. */ + /* Its purpose is simply to reduce compiler warnings. Note also that */ + /* simply defining it as `(void)x' doesn't avoid warnings with certain */ + /* ANSI compilers (e.g. LCC). */ +#define FT_UNUSED( x ) (x) = (x) + + /* Disable the tracing mechanism for simplicity -- developers can */ + /* activate it easily by redefining these two macros. */ +#ifndef FT_ERROR +#define FT_ERROR( x ) do ; while ( 0 ) /* nothing */ +#endif + +#ifndef FT_TRACE +#define FT_TRACE( x ) do ; while ( 0 ) /* nothing */ +#endif + + +#else /* _STANDALONE_ */ + + +#ifdef FT_FLAT_COMPILE + +#include "ftgrays.h" + +#else + +#include + +#endif + + +#include /* for FT_UNUSED() */ +#include /* for FT_TRACE() and FT_ERROR() */ +#include /* for FT_Outline_Decompose() */ + +#define ErrRaster_Invalid_Mode FT_Err_Cannot_Render_Glyph +#define ErrRaster_Invalid_Outline FT_Err_Invalid_Outline + + +#endif /* _STANDALONE_ */ + + + /* define this to dump debugging information */ +#define xxxDEBUG_GRAYS + + /* as usual, for the speed hungry :-) */ + +#ifndef FT_STATIC_RASTER + + +#define RAS_ARG PRaster raster +#define RAS_ARG_ PRaster raster, + +#define RAS_VAR raster +#define RAS_VAR_ raster, + +#define ras (*raster) + + +#else /* FT_STATIC_RASTER */ + + +#define RAS_ARG /* empty */ +#define RAS_ARG_ /* empty */ +#define RAS_VAR /* empty */ +#define RAS_VAR_ /* empty */ + + static TRaster ras; + + +#endif /* FT_STATIC_RASTER */ + + + /* must be at least 6 bits! */ +#define PIXEL_BITS 8 + +#define ONE_PIXEL ( 1L << PIXEL_BITS ) +#define PIXEL_MASK ( -1L << PIXEL_BITS ) +#define TRUNC( x ) ( (x) >> PIXEL_BITS ) +#define SUBPIXELS( x ) ( (x) << PIXEL_BITS ) +#define FLOOR( x ) ( (x) & -ONE_PIXEL ) +#define CEILING( x ) ( ( (x) + ONE_PIXEL - 1 ) & -ONE_PIXEL ) +#define ROUND( x ) ( ( (x) + ONE_PIXEL / 2 ) & -ONE_PIXEL ) + +#if PIXEL_BITS >= 6 +#define UPSCALE( x ) ( (x) << ( PIXEL_BITS - 6 ) ) +#define DOWNSCALE( x ) ( (x) >> ( PIXEL_BITS - 6 ) ) +#else +#define UPSCALE( x ) ( (x) >> ( 6 - PIXEL_BITS ) ) +#define DOWNSCALE( x ) ( (x) << ( 6 - PIXEL_BITS ) ) +#endif + + /* Define this if you want to use a more compact storage scheme. This */ + /* increases the number of cells available in the render pool but slows */ + /* down the rendering a bit. It is useful if you have a really tiny */ + /* render pool. */ +#define xxxGRAYS_COMPACT + + + /*************************************************************************/ + /* */ + /* TYPE DEFINITIONS */ + /* */ + typedef int TScan; /* integer scanline/pixel coordinate */ + typedef long TPos; /* sub-pixel coordinate */ + + /* maximal number of gray spans in a call to the span callback */ +#define FT_MAX_GRAY_SPANS 32 + + +#ifdef GRAYS_COMPACT + + typedef struct TCell_ + { + short x : 14; + short y : 14; + int cover : PIXEL_BITS + 2; + int area : PIXEL_BITS * 2 + 2; + + } TCell, *PCell; + +#else /* GRAYS_COMPACT */ + + typedef struct TCell_ + { + TScan x; + TScan y; + int cover; + int area; + + } TCell, *PCell; + +#endif /* GRAYS_COMPACT */ + + + typedef struct TRaster_ + { + PCell cells; + int max_cells; + int num_cells; + + TScan min_ex, max_ex; + TScan min_ey, max_ey; + + int area; + int cover; + int invalid; + + TScan ex, ey; + TScan cx, cy; + TPos x, y; + + TScan last_ey; + + FT_Vector bez_stack[32 * 3]; + int lev_stack[32]; + + FT_Outline outline; + FT_Bitmap target; + + FT_Span gray_spans[FT_MAX_GRAY_SPANS]; + int num_gray_spans; + + FT_Raster_Span_Func render_span; + void* render_span_data; + int span_y; + + int band_size; + int band_shoot; + int conic_level; + int cubic_level; + + void* memory; + + } TRaster, *PRaster; + + + /*************************************************************************/ + /* */ + /* Initialize the cells table. */ + /* */ + static + void init_cells( RAS_ARG_ void* buffer, + long byte_size ) + { + ras.cells = (PCell)buffer; + ras.max_cells = byte_size / sizeof ( TCell ); + ras.num_cells = 0; + ras.area = 0; + ras.cover = 0; + ras.invalid = 1; + } + + + /*************************************************************************/ + /* */ + /* Compute the outline bounding box. */ + /* */ + static + void compute_cbox( RAS_ARG_ FT_Outline* outline ) + { + FT_Vector* vec = outline->points; + FT_Vector* limit = vec + outline->n_points; + + + if ( outline->n_points <= 0 ) + { + ras.min_ex = ras.max_ex = 0; + ras.min_ey = ras.max_ey = 0; + return; + } + + ras.min_ex = ras.max_ex = vec->x; + ras.min_ey = ras.max_ey = vec->y; + + vec++; + + for ( ; vec < limit; vec++ ) + { + TPos x = vec->x; + TPos y = vec->y; + + + if ( x < ras.min_ex ) ras.min_ex = x; + if ( x > ras.max_ex ) ras.max_ex = x; + if ( y < ras.min_ey ) ras.min_ey = y; + if ( y > ras.max_ey ) ras.max_ey = y; + } + + /* truncate the bounding box to integer pixels */ + ras.min_ex = ras.min_ex >> 6; + ras.min_ey = ras.min_ey >> 6; + ras.max_ex = ( ras.max_ex + 63 ) >> 6; + ras.max_ey = ( ras.max_ey + 63 ) >> 6; + } + + + /*************************************************************************/ + /* */ + /* Record the current cell in the table. */ + /* */ + static + int record_cell( RAS_ARG ) + { + PCell cell; + + + if ( !ras.invalid && ( ras.area | ras.cover ) ) + { + if ( ras.num_cells >= ras.max_cells ) + return 1; + + cell = ras.cells + ras.num_cells++; + cell->x = ras.ex - ras.min_ex; + cell->y = ras.ey - ras.min_ey; + cell->area = ras.area; + cell->cover = ras.cover; + } + + return 0; + } + + + /*************************************************************************/ + /* */ + /* Set the current cell to a new position. */ + /* */ + static + int set_cell( RAS_ARG_ TScan ex, + TScan ey ) + { + int invalid, record, clean; + + + /* Move the cell pointer to a new position. We set the `invalid' */ + /* flag to indicate that the cell isn't part of those we're interested */ + /* in during the render phase. This means that: */ + /* */ + /* . the new vertical position must be within min_ey..max_ey-1. */ + /* . the new horizontal position must be strictly less than max_ex */ + /* */ + /* Note that if a cell is to the left of the clipping region, it is */ + /* actually set to the (min_ex-1) horizontal position. */ + + record = 0; + clean = 1; + + invalid = ( ey < ras.min_ey || ey >= ras.max_ey || ex >= ras.max_ex ); + if ( !invalid ) + { + /* All cells that are on the left of the clipping region go to the */ + /* min_ex - 1 horizontal position. */ + if ( ex < ras.min_ex ) + ex = ras.min_ex - 1; + + /* if our position is new, then record the previous cell */ + if ( ex != ras.ex || ey != ras.ey ) + record = 1; + else + clean = ras.invalid; /* do not clean if we didn't move from */ + /* a valid cell */ + } + + /* record the previous cell if needed (i.e., if we changed the cell */ + /* position, of changed the `invalid' flag) */ + if ( ( ras.invalid != invalid || record ) && record_cell( RAS_VAR ) ) + return 1; + + if ( clean ) + { + ras.area = 0; + ras.cover = 0; + } + + ras.invalid = invalid; + ras.ex = ex; + ras.ey = ey; + return 0; + } + + + /*************************************************************************/ + /* */ + /* Start a new contour at a given cell. */ + /* */ + static + void start_cell( RAS_ARG_ TScan ex, + TScan ey ) + { + if ( ex < ras.min_ex ) + ex = ras.min_ex - 1; + + ras.area = 0; + ras.cover = 0; + ras.ex = ex; + ras.ey = ey; + ras.last_ey = SUBPIXELS( ey ); + ras.invalid = 0; + + (void)set_cell( RAS_VAR_ ex, ey ); + } + + + /*************************************************************************/ + /* */ + /* Render a scanline as one or more cells. */ + /* */ + static + int render_scanline( RAS_ARG_ TScan ey, + TPos x1, + TScan y1, + TPos x2, + TScan y2 ) + { + TScan ex1, ex2, fx1, fx2, delta; + long p, first, dx; + int incr, lift, mod, rem; + + + dx = x2 - x1; + + ex1 = TRUNC( x1 ); /* if (ex1 >= ras.max_ex) ex1 = ras.max_ex-1; */ + ex2 = TRUNC( x2 ); /* if (ex2 >= ras.max_ex) ex2 = ras.max_ex-1; */ + fx1 = x1 - SUBPIXELS( ex1 ); + fx2 = x2 - SUBPIXELS( ex2 ); + + /* trivial case. Happens often */ + if ( y1 == y2 ) + return set_cell( RAS_VAR_ ex2, ey ); + + /* everything is located in a single cell. That is easy! */ + /* */ + if ( ex1 == ex2 ) + { + delta = y2 - y1; + ras.area += ( fx1 + fx2 ) * delta; + ras.cover += delta; + return 0; + } + + /* ok, we'll have to render a run of adjacent cells on the same */ + /* scanline... */ + /* */ + p = ( ONE_PIXEL - fx1 ) * ( y2 - y1 ); + first = ONE_PIXEL; + incr = 1; + + if ( dx < 0 ) + { + p = fx1 * ( y2 - y1 ); + first = 0; + incr = -1; + dx = -dx; + } + + delta = p / dx; + mod = p % dx; + if ( mod < 0 ) + { + delta--; + mod += dx; + } + + ras.area += ( fx1 + first ) * delta; + ras.cover += delta; + + ex1 += incr; + if ( set_cell( RAS_VAR_ ex1, ey ) ) + goto Error; + y1 += delta; + + if ( ex1 != ex2 ) + { + p = ONE_PIXEL * ( y2 - y1 ); + lift = p / dx; + rem = p % dx; + if ( rem < 0 ) + { + lift--; + rem += dx; + } + + mod -= dx; + + while ( ex1 != ex2 ) + { + delta = lift; + mod += rem; + if ( mod >= 0 ) + { + mod -= dx; + delta++; + } + + ras.area += ONE_PIXEL * delta; + ras.cover += delta; + y1 += delta; + ex1 += incr; + if ( set_cell( RAS_VAR_ ex1, ey ) ) + goto Error; + } + } + + delta = y2 - y1; + ras.area += ( fx2 + ONE_PIXEL - first ) * delta; + ras.cover += delta; + + return 0; + + Error: + return 1; + } + + + /*************************************************************************/ + /* */ + /* Render a given line as a series of scanlines. */ + /* */ + static + int render_line( RAS_ARG_ TPos to_x, + TPos to_y ) + { + TScan ey1, ey2, fy1, fy2; + TPos dx, dy, x, x2; + int p, rem, mod, lift, delta, first, incr; + + + ey1 = TRUNC( ras.last_ey ); + ey2 = TRUNC( to_y ); /* if (ey2 >= ras.max_ey) ey2 = ras.max_ey-1; */ + fy1 = ras.y - ras.last_ey; + fy2 = to_y - SUBPIXELS( ey2 ); + + dx = to_x - ras.x; + dy = to_y - ras.y; + + /* XXX: we should do something about the trivial case where dx == 0, */ + /* as it happens very often! */ + + /* perform vertical clipping */ + { + TScan min, max; + + + min = ey1; + max = ey2; + if ( ey1 > ey2 ) + { + min = ey2; + max = ey1; + } + if ( min >= ras.max_ey || max < ras.min_ey ) + goto End; + } + + /* everything is on a single scanline */ + if ( ey1 == ey2 ) + { + if ( render_scanline( RAS_VAR_ ey1, ras.x, fy1, to_x, fy2 ) ) + goto Error; + goto End; + } + + /* ok, we have to render several scanlines */ + p = ( ONE_PIXEL - fy1 ) * dx; + first = ONE_PIXEL; + incr = 1; + + if ( dy < 0 ) + { + p = fy1 * dx; + first = 0; + incr = -1; + dy = -dy; + } + + delta = p / dy; + mod = p % dy; + if ( mod < 0 ) + { + delta--; + mod += dy; + } + + x = ras.x + delta; + if ( render_scanline( RAS_VAR_ ey1, ras.x, fy1, x, first ) ) + goto Error; + + ey1 += incr; + if ( set_cell( RAS_VAR_ TRUNC( x ), ey1 ) ) + goto Error; + + if ( ey1 != ey2 ) + { + p = ONE_PIXEL * dx; + lift = p / dy; + rem = p % dy; + if ( rem < 0 ) + { + lift--; + rem += dy; + } + mod -= dy; + + while ( ey1 != ey2 ) + { + delta = lift; + mod += rem; + if ( mod >= 0 ) + { + mod -= dy; + delta++; + } + + x2 = x + delta; + if ( render_scanline( RAS_VAR_ ey1, + x, ONE_PIXEL - first, x2, first ) ) + goto Error; + x = x2; + ey1 += incr; + if ( set_cell( RAS_VAR_ TRUNC( x ), ey1 ) ) + goto Error; + } + } + + if ( render_scanline( RAS_VAR_ ey1, + x, ONE_PIXEL - first, to_x, fy2 ) ) + goto Error; + + End: + ras.x = to_x; + ras.y = to_y; + ras.last_ey = SUBPIXELS( ey2 ); + + return 0; + + Error: + return 1; + } + + + static + void split_conic( FT_Vector* base ) + { + TPos a, b; + + + base[4].x = base[2].x; + b = base[1].x; + a = base[3].x = ( base[2].x + b ) / 2; + b = base[1].x = ( base[0].x + b ) / 2; + base[2].x = ( a + b ) / 2; + + base[4].y = base[2].y; + b = base[1].y; + a = base[3].y = ( base[2].y + b ) / 2; + b = base[1].y = ( base[0].y + b ) / 2; + base[2].y = ( a + b ) / 2; + } + + + static + int render_conic( RAS_ARG_ FT_Vector* control, + FT_Vector* to ) + { + TPos dx, dy; + int top, level; + int* levels; + FT_Vector* arc; + + + dx = DOWNSCALE( ras.x ) + to->x - ( control->x << 1 ); + if ( dx < 0 ) + dx = -dx; + dy = DOWNSCALE( ras.y ) + to->y - ( control->y << 1 ); + if ( dy < 0 ) + dy = -dy; + if ( dx < dy ) + dx = dy; + + level = 1; + dx = dx / ras.conic_level; + while ( dx > 0 ) + { + dx >>= 1; + level++; + } + + /* a shortcut to speed things up */ + if ( level <= 1 ) + { + /* we compute the mid-point directly in order to avoid */ + /* calling split_conic() */ + TPos to_x, to_y, mid_x, mid_y; + + + to_x = UPSCALE( to->x ); + to_y = UPSCALE( to->y ); + mid_x = ( ras.x + to_x + 2 * UPSCALE( control->x ) ) / 4; + mid_y = ( ras.y + to_y + 2 * UPSCALE( control->y ) ) / 4; + + return render_line( RAS_VAR_ mid_x, mid_y ) || + render_line( RAS_VAR_ to_x, to_y ); + } + + arc = ras.bez_stack; + levels = ras.lev_stack; + top = 0; + levels[0] = level; + + arc[0].x = UPSCALE( to->x ); + arc[0].y = UPSCALE( to->y ); + arc[1].x = UPSCALE( control->x ); + arc[1].y = UPSCALE( control->y ); + arc[2].x = ras.x; + arc[2].y = ras.y; + + while ( top >= 0 ) + { + level = levels[top]; + if ( level > 1 ) + { + /* check that the arc crosses the current band */ + TPos min, max, y; + + + min = max = arc[0].y; + + y = arc[1].y; + if ( y < min ) min = y; + if ( y > max ) max = y; + + y = arc[2].y; + if ( y < min ) min = y; + if ( y > max ) max = y; + + if ( TRUNC( min ) >= ras.max_ey || TRUNC( max ) < 0 ) + goto Draw; + + split_conic( arc ); + arc += 2; + top++; + levels[top] = levels[top - 1] = level - 1; + continue; + } + + Draw: + { + TPos to_x, to_y, mid_x, mid_y; + + + to_x = arc[0].x; + to_y = arc[0].y; + mid_x = ( ras.x + to_x + 2 * arc[1].x ) / 4; + mid_y = ( ras.y + to_y + 2 * arc[1].y ) / 4; + + if ( render_line( RAS_VAR_ mid_x, mid_y ) || + render_line( RAS_VAR_ to_x, to_y ) ) + return 1; + + top--; + arc -= 2; + } + } + return 0; + } + + + static + void split_cubic( FT_Vector* base ) + { + TPos a, b, c, d; + + + base[6].x = base[3].x; + c = base[1].x; + d = base[2].x; + base[1].x = a = ( base[0].x + c ) / 2; + base[5].x = b = ( base[3].x + d ) / 2; + c = ( c + d ) / 2; + base[2].x = a = ( a + c ) / 2; + base[4].x = b = ( b + c ) / 2; + base[3].x = ( a + b ) / 2; + + base[6].y = base[3].y; + c = base[1].y; + d = base[2].y; + base[1].y = a = ( base[0].y + c ) / 2; + base[5].y = b = ( base[3].y + d ) / 2; + c = ( c + d ) / 2; + base[2].y = a = ( a + c ) / 2; + base[4].y = b = ( b + c ) / 2; + base[3].y = ( a + b ) / 2; + } + + + static + int render_cubic( RAS_ARG_ FT_Vector* control1, + FT_Vector* control2, + FT_Vector* to ) + { + TPos dx, dy, da, db; + int top, level; + int* levels; + FT_Vector* arc; + + + dx = DOWNSCALE( ras.x ) + to->x - ( control1->x << 1 ); + if ( dx < 0 ) + dx = -dx; + dy = DOWNSCALE( ras.y ) + to->y - ( control1->y << 1 ); + if ( dy < 0 ) + dy = -dy; + if ( dx < dy ) + dx = dy; + da = dx; + + dx = DOWNSCALE( ras.x ) + to->x - 3 * ( control1->x + control2->x ); + if ( dx < 0 ) + dx = -dx; + dy = DOWNSCALE( ras.y ) + to->y - 3 * ( control1->x + control2->y ); + if ( dy < 0 ) + dy = -dy; + if ( dx < dy ) + dx = dy; + db = dx; + + level = 1; + da = da / ras.cubic_level; + db = db / ras.conic_level; + while ( da > 0 || db > 0 ) + { + da >>= 1; + db >>= 2; + level++; + } + + if ( level <= 1 ) + { + TPos to_x, to_y, mid_x, mid_y; + + + to_x = UPSCALE( to->x ); + to_y = UPSCALE( to->y ); + mid_x = ( ras.x + to_x + + 3 * UPSCALE( control1->x + control2->x ) ) / 8; + mid_y = ( ras.y + to_y + + 3 * UPSCALE( control1->y + control2->y ) ) / 8; + + return render_line( RAS_VAR_ mid_x, mid_y ) || + render_line( RAS_VAR_ to_x, to_y ); + } + + arc = ras.bez_stack; + arc[0].x = UPSCALE( to->x ); + arc[0].y = UPSCALE( to->y ); + arc[1].x = UPSCALE( control2->x ); + arc[1].y = UPSCALE( control2->y ); + arc[2].x = UPSCALE( control1->x ); + arc[2].y = UPSCALE( control1->y ); + arc[3].x = ras.x; + arc[3].y = ras.y; + + levels = ras.lev_stack; + top = 0; + levels[0] = level; + + while ( top >= 0 ) + { + level = levels[top]; + if ( level > 1 ) + { + /* check that the arc crosses the current band */ + TPos min, max, y; + + + min = max = arc[0].y; + y = arc[1].y; + if ( y < min ) min = y; + if ( y > max ) max = y; + y = arc[2].y; + if ( y < min ) min = y; + if ( y > max ) max = y; + y = arc[3].y; + if ( y < min ) min = y; + if ( y > max ) max = y; + if ( TRUNC( min ) >= ras.max_ey || TRUNC( max ) < 0 ) + goto Draw; + split_cubic( arc ); + arc += 3; + top ++; + levels[top] = levels[top - 1] = level - 1; + continue; + } + + Draw: + { + TPos to_x, to_y, mid_x, mid_y; + + + to_x = arc[0].x; + to_y = arc[0].y; + mid_x = ( ras.x + to_x + 3 * ( arc[1].x + arc[2].x ) ) / 8; + mid_y = ( ras.y + to_y + 3 * ( arc[1].y + arc[2].y ) ) / 8; + + if ( render_line( RAS_VAR_ mid_x, mid_y ) || + render_line( RAS_VAR_ to_x, to_y ) ) + return 1; + top --; + arc -= 3; + } + } + return 0; + } + + + /* a macro comparing two cell pointers. Returns true if a <= b. */ +#if 1 + +#define PACK( a ) ( ( (long)(a)->y << 16 ) + (a)->x ) +#define LESS_THAN( a, b ) ( PACK( a ) < PACK( b ) ) + +#else /* 1 */ + +#define LESS_THAN( a, b ) ( (a)->y < (b)->y || \ + ( (a)->y == (b)->y && (a)->x < (b)->x ) ) + +#endif /* 1 */ + +#define SWAP_CELLS( a, b, temp ) do \ + { \ + temp = *(a); \ + *(a) = *(b); \ + *(b) = temp; \ + } while ( 0 ) +#define DEBUG_SORT +#define QUICK_SORT + +#ifdef SHELL_SORT + + /* a simple shell sort algorithm that works directly on our */ + /* cells table */ + static + void shell_sort ( PCell cells, + int count ) + { + PCell i, j, limit = cells + count; + TCell temp; + int gap; + + + /* compute initial gap */ + for ( gap = 0; ++gap < count; gap *= 3 ) + ; + + while ( gap /= 3 ) + { + for ( i = cells + gap; i < limit; i++ ) + { + for ( j = i - gap; ; j -= gap ) + { + PCell k = j + gap; + + + if ( LESS_THAN( j, k ) ) + break; + + SWAP_CELLS( j, k, temp ); + + if ( j < cells + gap ) + break; + } + } + } + } + +#endif /* SHELL_SORT */ + + +#ifdef QUICK_SORT + + /* This is a non-recursive quicksort that directly process our cells */ + /* array. It should be faster than calling the stdlib qsort(), and we */ + /* can even tailor our insertion threshold... */ + +#define QSORT_THRESHOLD 9 /* below this size, a sub-array will be sorted */ + /* through a normal insertion sort */ + + static + void quick_sort( PCell cells, + int count ) + { + PCell stack[40]; /* should be enough ;-) */ + PCell* top; /* top of stack */ + PCell base, limit; + TCell temp; + + + limit = cells + count; + base = cells; + top = stack; + + for (;;) + { + int len = limit - base; + PCell i, j, pivot; + + + if ( len > QSORT_THRESHOLD ) + { + /* we use base + len/2 as the pivot */ + pivot = base + len / 2; + SWAP_CELLS( base, pivot, temp ); + + i = base + 1; + j = limit - 1; + + /* now ensure that *i <= *base <= *j */ + if ( LESS_THAN( j, i ) ) + SWAP_CELLS( i, j, temp ); + + if ( LESS_THAN( base, i ) ) + SWAP_CELLS( base, i, temp ); + + if ( LESS_THAN( j, base ) ) + SWAP_CELLS( base, j, temp ); + + for (;;) + { + do i++; while ( LESS_THAN( i, base ) ); + do j--; while ( LESS_THAN( base, j ) ); + + if ( i > j ) + break; + + SWAP_CELLS( i, j, temp ); + } + + SWAP_CELLS( base, j, temp ); + + /* now, push the largest sub-array */ + if ( j - base > limit - i ) + { + top[0] = base; + top[1] = j; + base = i; + } + else + { + top[0] = i; + top[1] = limit; + limit = j; + } + top += 2; + } + else + { + /* the sub-array is small, perform insertion sort */ + j = base; + i = j + 1; + + for ( ; i < limit; j = i, i++ ) + { + for ( ; LESS_THAN( j + 1, j ); j-- ) + { + SWAP_CELLS( j + 1, j, temp ); + if ( j == base ) + break; + } + } + if ( top > stack ) + { + top -= 2; + base = top[0]; + limit = top[1]; + } + else + break; + } + } + } + +#endif /* QUICK_SORT */ + + +#ifdef DEBUG_GRAYS +#ifdef DEBUG_SORT + + static + int check_sort( PCell cells, + int count ) + { + PCell p, q; + + + for ( p = cells + count - 2; p >= cells; p-- ) + { + q = p + 1; + if ( !LESS_THAN( p, q ) ) + return 0; + } + return 1; + } + +#endif /* DEBUG_SORT */ +#endif /* DEBUG_GRAYS */ + + + static + int Move_To( FT_Vector* to, + FT_Raster raster ) + { + TPos x, y; + + + /* record current cell, if any */ + record_cell( (PRaster)raster ); + + /* start to a new position */ + x = UPSCALE( to->x ); + y = UPSCALE( to->y ); + start_cell( (PRaster)raster, TRUNC( x ), TRUNC( y ) ); + ((PRaster)raster)->x = x; + ((PRaster)raster)->y = y; + return 0; + } + + + static + int Line_To( FT_Vector* to, + FT_Raster raster ) + { + return render_line( (PRaster)raster, + UPSCALE( to->x ), UPSCALE( to->y ) ); + } + + + static + int Conic_To( FT_Vector* control, + FT_Vector* to, + FT_Raster raster ) + { + return render_conic( (PRaster)raster, control, to ); + } + + + static + int Cubic_To( FT_Vector* control1, + FT_Vector* control2, + FT_Vector* to, + FT_Raster raster ) + { + return render_cubic( (PRaster)raster, control1, control2, to ); + } + + + static + void grays_render_span( int y, + int count, + FT_Span* spans, + PRaster raster ) + { + unsigned char* p; + FT_Bitmap* map = &raster->target; + + + /* first of all, compute the scanline offset */ + p = (unsigned char*)map->buffer - y * map->pitch; + if ( map->pitch >= 0 ) + p += ( map->rows - 1 ) * map->pitch; + + for ( ; count > 0; count--, spans++ ) + { + if ( spans->coverage ) +#if 1 + memset( p + spans->x, (unsigned char)spans->coverage, spans->len ); +#else /* 1 */ + { + q = p + spans->x; + limit = q + spans->len; + for ( ; q < limit; q++ ) + q[0] = (unsigned char)spans->coverage; + } +#endif /* 1 */ + } + } + + +#ifdef DEBUG_GRAYS + +#include + + static + void dump_cells( RAS_ARG ) + { + PCell cell, limit; + int y = -1; + + + cell = ras.cells; + limit = cell + ras.num_cells; + + for ( ; cell < limit; cell++ ) + { + if ( cell->y != y ) + { + fprintf( stderr, "\n%2d: ", cell->y ); + y = cell->y; + } + fprintf( stderr, "[%d %d %d]", + cell->x, cell->area, cell->cover ); + } + fprintf(stderr, "\n" ); + } + +#endif /* DEBUG_GRAYS */ + + + static + void grays_hline( RAS_ARG_ TScan x, + TScan y, + TPos area, + int acount ) + { + FT_Span* span; + int count; + int coverage; + + + /* compute the coverage line's coverage, depending on the */ + /* outline fill rule */ + /* */ + /* the coverage percentage is area/(PIXEL_BITS*PIXEL_BITS*2) */ + /* */ + coverage = area >> ( PIXEL_BITS * 2 + 1 - 8); /* use range 0..256 */ + + if ( ras.outline.flags & ft_outline_even_odd_fill ) + { + if ( coverage < 0 ) + coverage = -coverage; + + while ( coverage >= 512 ) + coverage -= 512; + + if ( coverage > 256 ) + coverage = 512 - coverage; + else if ( coverage == 256 ) + coverage = 255; + } + else + { + /* normal non-zero winding rule */ + if ( coverage < 0 ) + coverage = -coverage; + + if ( coverage >= 256 ) + coverage = 255; + } + + y += ras.min_ey; + x += ras.min_ex; + + if ( coverage ) + { + /* see if we can add this span to the current list */ + count = ras.num_gray_spans; + span = ras.gray_spans + count - 1; + if ( count > 0 && + ras.span_y == y && + (int)span->x + span->len == (int)x && + span->coverage == coverage ) + { + span->len += acount; + return; + } + + if ( ras.span_y != y || count >= FT_MAX_GRAY_SPANS ) + { + if ( ras.render_span ) + ras.render_span( ras.span_y, count, ras.gray_spans, + ras.render_span_data ); + /* ras.render_span( span->y, ras.gray_spans, count ); */ + +#ifdef DEBUG_GRAYS + + if ( ras.span_y >= 0 ) + { + int n; + + + fprintf( stderr, "y=%3d ", ras.span_y ); + span = ras.gray_spans; + for ( n = 0; n < count; n++, span++ ) + fprintf( stderr, "[%d..%d]:%02x ", + span->x, span->x + span->len - 1, span->coverage ); + fprintf( stderr, "\n" ); + } + +#endif /* DEBUG_GRAYS */ + + ras.num_gray_spans = 0; + ras.span_y = y; + + count = 0; + span = ras.gray_spans; + } + else + span++; + + /* add a gray span to the current list */ + span->x = (short)x; + span->len = (unsigned short)acount; + span->coverage = (unsigned char)coverage; + ras.num_gray_spans++; + } + } + + + static + void grays_sweep( RAS_ARG_ FT_Bitmap* target ) + { + TScan x, y, cover, area; + PCell start, cur, limit; + + FT_UNUSED( target ); + + + cur = ras.cells; + limit = cur + ras.num_cells; + + cover = 0; + ras.span_y = -1; + ras.num_gray_spans = 0; + + for (;;) + { + start = cur; + y = start->y; + x = start->x; + + area = start->area; + cover += start->cover; + + /* accumulate all start cells */ + for (;;) + { + ++cur; + if ( cur >= limit || cur->y != start->y || cur->x != start->x ) + break; + + area += cur->area; + cover += cur->cover; + } + + /* if the start cell has a non-null area, we must draw an */ + /* individual gray pixel there */ + if ( area && x >= 0 ) + { + grays_hline( RAS_VAR_ x, y, cover * ( ONE_PIXEL * 2 ) - area, 1 ); + x++; + } + + if ( x < 0 ) + x = 0; + + if ( cur < limit && start->y == cur->y ) + { + /* draw a gray span between the start cell and the current one */ + if ( cur->x > x ) + grays_hline( RAS_VAR_ x, y, + cover * ( ONE_PIXEL * 2 ), cur->x - x ); + } + else + { + /* draw a gray span until the end of the clipping region */ + if ( cover && x < ras.max_ex - ras.min_ex ) + grays_hline( RAS_VAR_ x, y, + cover * ( ONE_PIXEL * 2 ), + ras.max_ex - x - ras.min_ex ); + cover = 0; + } + + if ( cur >= limit ) + break; + } + + if ( ras.render_span && ras.num_gray_spans > 0 ) + ras.render_span( ras.span_y, ras.num_gray_spans, + ras.gray_spans, ras.render_span_data ); + +#ifdef DEBUG_GRAYS + + { + int n; + FT_Span* span; + + + fprintf( stderr, "y=%3d ", ras.span_y ); + span = ras.gray_spans; + for ( n = 0; n < ras.num_gray_spans; n++, span++ ) + fprintf( stderr, "[%d..%d]:%02x ", + span->x, span->x + span->len - 1, span->coverage ); + fprintf( stderr, "\n" ); + } + +#endif /* DEBUG_GRAYS */ + + } + + +#ifdef _STANDALONE_ + + /*************************************************************************/ + /* */ + /* The following function should only compile in stand_alone mode, */ + /* i.e., when building this component without the rest of FreeType. */ + /* */ + /*************************************************************************/ + + /*************************************************************************/ + /* */ + /* */ + /* FT_Outline_Decompose */ + /* */ + /* */ + /* Walks over an outline's structure to decompose it into individual */ + /* segments and Bezier arcs. This function is also able to emit */ + /* `move to' and `close to' operations to indicate the start and end */ + /* of new contours in the outline. */ + /* */ + /* */ + /* outline :: A pointer to the source target. */ + /* */ + /* interface :: A table of `emitters', i.e,. function pointers called */ + /* during decomposition to indicate path operations. */ + /* */ + /* user :: A typeless pointer which is passed to each emitter */ + /* during the decomposition. It can be used to store */ + /* the state during the decomposition. */ + /* */ + /* */ + /* Error code. 0 means sucess. */ + /* */ + static + int FT_Outline_Decompose( FT_Outline* outline, + FT_Outline_Funcs* interface, + void* user ) + { +#undef SCALED +#define SCALED( x ) ( ( (x) << shift ) - delta ) + + FT_Vector v_last; + FT_Vector v_control; + FT_Vector v_start; + + FT_Vector* point; + FT_Vector* limit; + char* tags; + + int n; /* index of contour in outline */ + int first; /* index of first point in contour */ + int error; + char tag; /* current point's state */ + + int shift = interface->shift; + FT_Pos delta = interface->delta; + + + first = 0; + + for ( n = 0; n < outline->n_contours; n++ ) + { + int last; /* index of last point in contour */ + + + last = outline->contours[n]; + limit = outline->points + last; + + v_start = outline->points[first]; + v_last = outline->points[last]; + + v_start.x = SCALED( v_start.x ); v_start.y = SCALED( v_start.y ); + v_last.x = SCALED( v_last.x ); v_last.y = SCALED( v_last.y ); + + v_control = v_start; + + point = outline->points + first; + tags = outline->tags + first; + tag = FT_CURVE_TAG( tags[0] ); + + /* A contour cannot start with a cubic control point! */ + if ( tag == FT_Curve_Tag_Cubic ) + goto Invalid_Outline; + + /* check first point to determine origin */ + if ( tag == FT_Curve_Tag_Conic ) + { + /* first point is conic control. Yes, this happens. */ + if ( FT_CURVE_TAG( outline->tags[last] ) == FT_Curve_Tag_On ) + { + /* start at last point if it is on the curve */ + v_start = v_last; + limit--; + } + else + { + /* if both first and last points are conic, */ + /* start at their middle and record its position */ + /* for closure */ + v_start.x = ( v_start.x + v_last.x ) / 2; + v_start.y = ( v_start.y + v_last.y ) / 2; + + v_last = v_start; + } + point--; + tags--; + } + + error = interface->move_to( &v_start, user ); + if ( error ) + goto Exit; + + while ( point < limit ) + { + point++; + tags++; + + tag = FT_CURVE_TAG( tags[0] ); + switch ( tag ) + { + case FT_Curve_Tag_On: /* emit a single line_to */ + { + FT_Vector vec; + + + vec.x = SCALED( point->x ); + vec.y = SCALED( point->y ); + + error = interface->line_to( &vec, user ); + if ( error ) + goto Exit; + continue; + } + + case FT_Curve_Tag_Conic: /* consume conic arcs */ + { + v_control.x = SCALED( point->x ); + v_control.y = SCALED( point->y ); + + Do_Conic: + if ( point < limit ) + { + FT_Vector vec; + FT_Vector v_middle; + + + point++; + tags++; + tag = FT_CURVE_TAG( tags[0] ); + + vec.x = SCALED( point->x ); + vec.y = SCALED( point->y ); + + if ( tag == FT_Curve_Tag_On ) + { + error = interface->conic_to( &v_control, &vec, user ); + if ( error ) + goto Exit; + continue; + } + + if ( tag != FT_Curve_Tag_Conic ) + goto Invalid_Outline; + + v_middle.x = ( v_control.x + vec.x ) / 2; + v_middle.y = ( v_control.y + vec.y ) / 2; + + error = interface->conic_to( &v_control, &v_middle, user ); + if ( error ) + goto Exit; + + v_control = vec; + goto Do_Conic; + } + + error = interface->conic_to( &v_control, &v_start, user ); + goto Close; + } + + default: /* FT_Curve_Tag_Cubic */ + { + FT_Vector vec1, vec2; + + + if ( point + 1 > limit || + FT_CURVE_TAG( tags[1] ) != FT_Curve_Tag_Cubic ) + goto Invalid_Outline; + + point += 2; + tags += 2; + + vec1.x = SCALED( point[-2].x ); vec1.y = SCALED( point[-2].y ); + vec2.x = SCALED( point[-1].x ); vec2.y = SCALED( point[-1].y ); + + if ( point <= limit ) + { + FT_Vector vec; + + + vec.x = SCALED( point->x ); + vec.y = SCALED( point->y ); + + error = interface->cubic_to( &vec1, &vec2, &vec, user ); + if ( error ) + goto Exit; + continue; + } + + error = interface->cubic_to( &vec1, &vec2, &v_start, user ); + goto Close; + } + } + } + + /* close the contour with a line segment */ + error = interface->line_to( &v_start, user ); + + Close: + if ( error ) + goto Exit; + + first = last + 1; + } + + return 0; + + Exit: + return error; + + Invalid_Outline: + return ErrRaster_Invalid_Outline; + } + +#endif /* _STANDALONE_ */ + + + typedef struct TBand_ + { + FT_Pos min, max; + + } TBand; + + + static + int grays_convert_glyph( RAS_ARG_ FT_Outline* outline ) + { + static + FT_Outline_Funcs interface = + { + (FT_Outline_MoveTo_Func) Move_To, + (FT_Outline_LineTo_Func) Line_To, + (FT_Outline_ConicTo_Func)Conic_To, + (FT_Outline_CubicTo_Func)Cubic_To, + 0, + 0 + }; + + TBand bands[40], *band; + int n, num_bands; + TPos min, max, max_y; + + + /* Set up state in the raster object */ + compute_cbox( RAS_VAR_ outline ); + + /* clip to target bitmap, exit if nothing to do */ + if ( ras.max_ex <= 0 || ras.min_ex >= ras.target.width || + ras.max_ey <= 0 || ras.min_ey >= ras.target.rows ) + return 0; + + if ( ras.min_ex < 0 ) ras.min_ex = 0; + if ( ras.min_ey < 0 ) ras.min_ey = 0; + + if ( ras.max_ex > ras.target.width ) ras.max_ex = ras.target.width; + if ( ras.max_ey > ras.target.rows ) ras.max_ey = ras.target.rows; + + /* simple heuristic used to speed-up the bezier decomposition -- see */ + /* the code in render_conic() and render_cubic() for more details */ + ras.conic_level = 32; + ras.cubic_level = 16; + + { + int level = 0; + + + if ( ras.max_ex > 24 || ras.max_ey > 24 ) + level++; + if ( ras.max_ex > 120 || ras.max_ey > 120 ) + level += 2; + + ras.conic_level <<= level; + ras.cubic_level <<= level; + } + + /* setup vertical bands */ + num_bands = ( ras.max_ey - ras.min_ey ) / ras.band_size; + if ( num_bands == 0 ) num_bands = 1; + if ( num_bands >= 39 ) num_bands = 39; + + ras.band_shoot = 0; + + min = ras.min_ey; + max_y = ras.max_ey; + + for ( n = 0; n < num_bands; n++, min = max ) + { + max = min + ras.band_size; + if ( n == num_bands - 1 || max > max_y ) + max = max_y; + + bands[0].min = min; + bands[0].max = max; + band = bands; + + while ( band >= bands ) + { + FT_Pos bottom, top, middle; + int error; + + + ras.num_cells = 0; + ras.invalid = 1; + ras.min_ey = band->min; + ras.max_ey = band->max; + + error = FT_Outline_Decompose( outline, &interface, &ras ) || + record_cell( RAS_VAR ); + + if ( !error ) + { +#ifdef SHELL_SORT + shell_sort( ras.cells, ras.num_cells ); +#else + quick_sort( ras.cells, ras.num_cells ); +#endif + +#ifdef DEBUG_GRAYS + check_sort( ras.cells, ras.num_cells ); + dump_cells( RAS_VAR ); +#endif + + grays_sweep( RAS_VAR_ &ras.target ); + band--; + continue; + } + + /* render pool overflow, we will reduce the render band by half */ + bottom = band->min; + top = band->max; + middle = bottom + ( ( top - bottom ) >> 1 ); + + /* waoow! This is too complex for a single scanline, something */ + /* must be really rotten here! */ + if ( middle == bottom ) + { +#ifdef DEBUG_GRAYS + fprintf( stderr, "Rotten glyph!\n" ); +#endif + return 1; + } + + if ( bottom-top >= ras.band_size ) + ras.band_shoot++; + + band[1].min = bottom; + band[1].max = middle; + band[0].min = middle; + band[0].max = top; + band++; + } + } + + if ( ras.band_shoot > 8 && ras.band_size > 16 ) + ras.band_size = ras.band_size / 2; + + return 0; + } + + + extern + int grays_raster_render( PRaster raster, + FT_Raster_Params* params ) + { + FT_Outline* outline = (FT_Outline*)params->source; + FT_Bitmap* target_map = params->target; + + + if ( !raster || !raster->cells || !raster->max_cells ) + return -1; + + /* return immediately if the outline is empty */ + if ( outline->n_points == 0 || outline->n_contours <= 0 ) + return 0; + + if ( !outline || !outline->contours || !outline->points ) + return ErrRaster_Invalid_Outline; + + if ( outline->n_points != + outline->contours[outline->n_contours - 1] + 1 ) + return ErrRaster_Invalid_Outline; + + if ( !target_map || !target_map->buffer ) + return -1; + + /* XXX: this version does not support monochrome rendering yet! */ + if ( !(params->flags & ft_raster_flag_aa) ) + return ErrRaster_Invalid_Mode; + + ras.outline = *outline; + ras.target = *target_map; + ras.num_cells = 0; + ras.invalid = 1; + + ras.render_span = (FT_Raster_Span_Func)grays_render_span; + ras.render_span_data = &ras; + + if ( params->flags & ft_raster_flag_direct ) + { + ras.render_span = (FT_Raster_Span_Func)params->gray_spans; + ras.render_span_data = params->user; + } + + return grays_convert_glyph( (PRaster)raster, outline ); + } + + + /**** RASTER OBJECT CREATION: In standalone mode, we simply use *****/ + /**** a static object. *****/ + +#ifdef _STANDALONE_ + + static + int grays_raster_new( void* memory, + FT_Raster* araster ) + { + static TRaster the_raster; + + FT_UNUSED( memory ); + + + *araster = (FT_Raster)&the_raster; + memset( &the_raster, 0, sizeof ( the_raster ) ); + + return 0; + } + + + static + void grays_raster_done( FT_Raster raster ) + { + /* nothing */ + FT_UNUSED( raster ); + } + +#else /* _STANDALONE_ */ + + static + int grays_raster_new( FT_Memory memory, + FT_Raster* araster ) + { + FT_Error error; + PRaster raster; + + + *araster = 0; + if ( !ALLOC( raster, sizeof ( TRaster ) ) ) + { + raster->memory = memory; + *araster = (FT_Raster)raster; + } + + return error; + } + + + static + void grays_raster_done( FT_Raster raster ) + { + FT_Memory memory = (FT_Memory)((PRaster)raster)->memory; + + + FREE( raster ); + } + +#endif /* _STANDALONE_ */ + + + static + void grays_raster_reset( FT_Raster raster, + const char* pool_base, + long pool_size ) + { + PRaster rast = (PRaster)raster; + + + if ( raster && pool_base && pool_size >= 4096 ) + init_cells( rast, (char*)pool_base, pool_size ); + + rast->band_size = ( pool_size / sizeof ( TCell ) ) / 8; + } + + + FT_Raster_Funcs ft_grays_raster = + { + ft_glyph_format_outline, + + (FT_Raster_New_Func) grays_raster_new, + (FT_Raster_Reset_Func) grays_raster_reset, + (FT_Raster_Set_Mode_Func)0, + (FT_Raster_Render_Func) grays_raster_render, + (FT_Raster_Done_Func) grays_raster_done + }; + + +/* END */ diff --git a/src/freetype/smooth/ftgrays.h b/src/freetype/smooth/ftgrays.h new file mode 100644 index 0000000000..2423a0e45e --- /dev/null +++ b/src/freetype/smooth/ftgrays.h @@ -0,0 +1,52 @@ +/***************************************************************************/ +/* */ +/* ftgrays.h */ +/* */ +/* FreeType smooth renderer declaration */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + +#ifndef FTGRAYS_H +#define FTGRAYS_H + +#ifdef __cplusplus + extern "C" { +#endif + +#ifdef _STANDALONE_ +#include "ftimage.h" +#else +#include +#endif + + /*************************************************************************/ + /* */ + /* To make ftgrays.h independent from configuration files we check */ + /* whether FT_EXPORT_DEF has been defined already. */ + /* */ + /* On some systems and compilers (Win32 mostly), an extra keyword is */ + /* necessary to compile the library as a DLL. */ + /* */ +#ifndef FT_EXPORT_VAR +#define FT_EXPORT_VAR( x ) extern x +#endif + + FT_EXPORT_VAR( FT_Raster_Funcs ) ft_grays_raster; + +#ifdef __cplusplus + } +#endif + +#endif /* FTGRAYS_H */ + + +/* END */ diff --git a/src/freetype/smooth/ftsmooth.c b/src/freetype/smooth/ftsmooth.c new file mode 100644 index 0000000000..6f399acf59 --- /dev/null +++ b/src/freetype/smooth/ftsmooth.c @@ -0,0 +1,220 @@ +/***************************************************************************/ +/* */ +/* ftsmooth.c */ +/* */ +/* Anti-aliasing renderer interface (body). */ +/* */ +/* Copyright 2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#include +#include + + +#ifdef FT_FLAT_COMPILE + +#include "ftsmooth.h" +#include "ftgrays.h" + +#else + +#include +#include + +#endif + + + /* initialize renderer -- init its raster */ + static + FT_Error ft_smooth_init( FT_Renderer render ) + { + FT_Library library = FT_MODULE_LIBRARY( render ); + + + render->clazz->raster_class->raster_reset( render->raster, + library->raster_pool, + library->raster_pool_size ); + + return 0; + } + + + /* sets render-specific mode */ + static + FT_Error ft_smooth_set_mode( FT_Renderer render, + FT_ULong mode_tag, + FT_Pointer data ) + { + /* we simply pass it to the raster */ + return render->clazz->raster_class->raster_set_mode( render->raster, + mode_tag, + data ); + } + + /* transform a given glyph image */ + static + FT_Error ft_smooth_transform( FT_Renderer render, + FT_GlyphSlot slot, + FT_Matrix* matrix, + FT_Vector* delta ) + { + FT_Error error = FT_Err_Ok; + + + if ( slot->format != render->glyph_format ) + { + error = FT_Err_Invalid_Argument; + goto Exit; + } + + if ( matrix ) + FT_Outline_Transform( &slot->outline, matrix ); + + if ( delta ) + FT_Outline_Translate( &slot->outline, delta->x, delta->y ); + + Exit: + return error; + } + + + /* return the glyph's control box */ + static + void ft_smooth_get_cbox( FT_Renderer render, + FT_GlyphSlot slot, + FT_BBox* cbox ) + { + MEM_Set( cbox, 0, sizeof ( *cbox ) ); + + if ( slot->format == render->glyph_format ) + FT_Outline_Get_CBox( &slot->outline, cbox ); + } + + + /* convert a slot's glyph image into a bitmap */ + static + FT_Error ft_smooth_render( FT_Renderer render, + FT_GlyphSlot slot, + FT_UInt mode, + FT_Vector* origin ) + { + FT_Error error; + FT_Outline* outline; + FT_BBox cbox; + FT_UInt width, height, pitch; + FT_Bitmap* bitmap; + FT_Memory memory; + + FT_Raster_Params params; + + + /* check glyph image format */ + if ( slot->format != render->glyph_format ) + { + error = FT_Err_Invalid_Argument; + goto Exit; + } + + /* check mode */ + if ( mode != ft_render_mode_normal ) + return FT_Err_Cannot_Render_Glyph; + + outline = &slot->outline; + + /* translate the outline to the new origin if needed */ + if ( origin ) + FT_Outline_Translate( outline, origin->x, origin->y ); + + /* compute the control box, and grid fit it */ + FT_Outline_Get_CBox( outline, &cbox ); + + cbox.xMin &= -64; + cbox.yMin &= -64; + cbox.xMax = ( cbox.xMax + 63 ) & -64; + cbox.yMax = ( cbox.yMax + 63 ) & -64; + + width = ( cbox.xMax - cbox.xMin ) >> 6; + height = ( cbox.yMax - cbox.yMin ) >> 6; + bitmap = &slot->bitmap; + memory = render->root.memory; + + /* release old bitmap buffer */ + if ( slot->flags & ft_glyph_own_bitmap ) + { + FREE( bitmap->buffer ); + slot->flags &= ~ft_glyph_own_bitmap; + } + + /* allocate new one, depends on pixel format */ + pitch = width; + bitmap->pixel_mode = ft_pixel_mode_grays; + bitmap->num_grays = 256; + bitmap->width = width; + bitmap->rows = height; + bitmap->pitch = pitch; + + if ( ALLOC( bitmap->buffer, (FT_ULong)pitch * height ) ) + goto Exit; + + slot->flags |= ft_glyph_own_bitmap; + + /* translate outline to render it into the bitmap */ + FT_Outline_Translate( outline, -cbox.xMin, -cbox.yMin ); + + /* set up parameters */ + params.target = bitmap; + params.source = outline; + params.flags = ft_raster_flag_aa; + + /* render outline into the bitmap */ + error = render->raster_render( render->raster, ¶ms ); + if ( error ) + goto Exit; + + slot->format = ft_glyph_format_bitmap; + slot->bitmap_left = cbox.xMin >> 6; + slot->bitmap_top = cbox.yMax >> 6; + + Exit: + return error; + } + + + const FT_Renderer_Class ft_smooth_renderer_class = + { + { + ft_module_renderer, + sizeof( FT_RendererRec ), + + "smooth", + 0x10000L, + 0x20000L, + + 0, /* module specific interface */ + + (FT_Module_Constructor)ft_smooth_init, + (FT_Module_Destructor) 0, + (FT_Module_Requester) 0 + }, + + ft_glyph_format_outline, + + (FTRenderer_render) ft_smooth_render, + (FTRenderer_transform)ft_smooth_transform, + (FTRenderer_getCBox) ft_smooth_get_cbox, + (FTRenderer_setMode) ft_smooth_set_mode, + + (FT_Raster_Funcs*) &ft_grays_raster + }; + + +/* END */ diff --git a/src/freetype/smooth/ftsmooth.h b/src/freetype/smooth/ftsmooth.h new file mode 100644 index 0000000000..4b8a533437 --- /dev/null +++ b/src/freetype/smooth/ftsmooth.h @@ -0,0 +1,35 @@ +/***************************************************************************/ +/* */ +/* ftsmooth.h */ +/* */ +/* Anti-aliasing renderer interface (specification). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef FTSMOOTH_H +#define FTSMOOTH_H + +#include + +#ifndef FT_CONFIG_OPTION_NO_STD_RASTER + FT_EXPORT_VAR( const FT_Renderer_Class ) ft_std_renderer_class; +#endif + +#ifndef FT_CONFIG_OPTION_NO_SMOOTH_RASTER + FT_EXPORT_VAR( const FT_Renderer_Class ) ft_smooth_renderer_class; +#endif + +#endif /* FTSMOOTH_H */ + + +/* END */ diff --git a/src/freetype/smooth/module.mk b/src/freetype/smooth/module.mk new file mode 100644 index 0000000000..b93bc4d3dd --- /dev/null +++ b/src/freetype/smooth/module.mk @@ -0,0 +1,7 @@ +make_module_list: add_smooth_renderer + +add_smooth_renderer: + $(OPEN_DRIVER)ft_smooth_renderer_class$(CLOSE_DRIVER) + $(ECHO_DRIVER)smooth $(ECHO_DRIVER_DESC)anti-aliased bitmap renderer$(ECHO_DRIVER_DONE) + +# EOF diff --git a/src/freetype/smooth/rules.mk b/src/freetype/smooth/rules.mk new file mode 100644 index 0000000000..a81d60ae86 --- /dev/null +++ b/src/freetype/smooth/rules.mk @@ -0,0 +1,69 @@ +# +# FreeType 2 renderer module build rules +# + + +# Copyright 1996-2000 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +# smooth driver directory +# +SMOOTH_DIR := $(SRC_)smooth +SMOOTH_DIR_ := $(SMOOTH_DIR)$(SEP) + +# compilation flags for the driver +# +SMOOTH_COMPILE := $(FT_COMPILE) + + +# smooth driver sources (i.e., C files) +# +SMOOTH_DRV_SRC := $(SMOOTH_DIR_)ftgrays.c \ + $(SMOOTH_DIR_)ftsmooth.c + + +# smooth driver headers +# +SMOOTH_DRV_H := $(SMOOTH_DRV_SRC:%c=%h) + + +# smooth driver object(s) +# +# SMOOTH_DRV_OBJ_M is used during `multi' builds. +# SMOOTH_DRV_OBJ_S is used during `single' builds. +# +SMOOTH_DRV_OBJ_M := $(SMOOTH_DRV_SRC:$(SMOOTH_DIR_)%.c=$(OBJ_)%.$O) +SMOOTH_DRV_OBJ_S := $(OBJ_)smooth.$O + +# smooth driver source file for single build +# +SMOOTH_DRV_SRC_S := $(SMOOTH_DIR_)smooth.c + + +# smooth driver - single object +# +$(SMOOTH_DRV_OBJ_S): $(SMOOTH_DRV_SRC_S) $(SMOOTH_DRV_SRC) \ + $(FREETYPE_H) $(SMOOTH_DRV_H) + $(SMOOTH_COMPILE) $T$@ $(SMOOTH_DRV_SRC_S) + + +# smooth driver - multiple objects +# +$(OBJ_)%.$O: $(SMOOTH_DIR_)%.c $(FREETYPE_H) $(SMOOTH_DRV_H) + $(SMOOTH_COMPILE) $T$@ $< + + +# update main driver object lists +# +DRV_OBJS_S += $(SMOOTH_DRV_OBJ_S) +DRV_OBJS_M += $(SMOOTH_DRV_OBJ_M) + + +# EOF diff --git a/src/freetype/smooth/smooth.c b/src/freetype/smooth/smooth.c new file mode 100644 index 0000000000..41cc4aea52 --- /dev/null +++ b/src/freetype/smooth/smooth.c @@ -0,0 +1,35 @@ +/***************************************************************************/ +/* */ +/* smooth.c */ +/* */ +/* FreeType anti-aliasing rasterer module component (body only). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#define FT_MAKE_OPTION_SINGLE_OBJECT + + +#ifdef FT_FLAT_COMPILE + +#include "ftgrays.c" +#include "ftsmooth.c" + +#else + +#include +#include + +#endif + + +/* END */ diff --git a/src/freetype/truetype/module.mk b/src/freetype/truetype/module.mk new file mode 100644 index 0000000000..79072bb54b --- /dev/null +++ b/src/freetype/truetype/module.mk @@ -0,0 +1,7 @@ +make_module_list: add_truetype_driver + +add_truetype_driver: + $(OPEN_DRIVER)tt_driver_class$(CLOSE_DRIVER) + $(ECHO_DRIVER)truetype $(ECHO_DRIVER_DESC)Windows/Mac font files with extension *.ttf or *.ttc$(ECHO_DRIVER_DONE) + +# EOF diff --git a/src/freetype/truetype/rules.mk b/src/freetype/truetype/rules.mk new file mode 100644 index 0000000000..9289378cb5 --- /dev/null +++ b/src/freetype/truetype/rules.mk @@ -0,0 +1,70 @@ +# +# FreeType 2 TrueType driver configuration rules +# + + +# Copyright 1996-2000 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +# TrueType driver directory +# +TT_DIR := $(SRC_)truetype +TT_DIR_ := $(TT_DIR)$(SEP) + + +# compilation flags for the driver +# +TT_COMPILE := $(FT_COMPILE) + + +# TrueType driver sources (i.e., C files) +# +TT_DRV_SRC := $(TT_DIR_)ttobjs.c \ + $(TT_DIR_)ttpload.c \ + $(TT_DIR_)ttgload.c \ + $(TT_DIR_)ttinterp.c \ + $(TT_DIR_)ttdriver.c + +# TrueType driver headers +# +TT_DRV_H := $(TT_DRV_SRC:%.c=%.h) + + +# TrueType driver object(s) +# +# TT_DRV_OBJ_M is used during `multi' builds +# TT_DRV_OBJ_S is used during `single' builds +# +TT_DRV_OBJ_M := $(TT_DRV_SRC:$(TT_DIR_)%.c=$(OBJ_)%.$O) +TT_DRV_OBJ_S := $(OBJ_)truetype.$O + +# TrueType driver source file for single build +# +TT_DRV_SRC_S := $(TT_DIR_)truetype.c + + +# TrueType driver - single object +# +$(TT_DRV_OBJ_S): $(TT_DRV_SRC_S) $(TT_DRV_SRC) $(FREETYPE_H) $(TT_DRV_H) + $(TT_COMPILE) $T$@ $(TT_DRV_SRC_S) + + +# driver - multiple objects +# +$(OBJ_)%.$O: $(TT_DIR_)%.c $(FREETYPE_H) $(TT_DRV_H) + $(TT_COMPILE) $T$@ $< + + +# update main driver object lists +# +DRV_OBJS_S += $(TT_DRV_OBJ_S) +DRV_OBJS_M += $(TT_DRV_OBJ_M) + +# EOF diff --git a/src/freetype/truetype/truetype.c b/src/freetype/truetype/truetype.c new file mode 100644 index 0000000000..55ba0c9d41 --- /dev/null +++ b/src/freetype/truetype/truetype.c @@ -0,0 +1,47 @@ +/***************************************************************************/ +/* */ +/* truetype.c */ +/* */ +/* FreeType TrueType driver component (body only). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#define FT_MAKE_OPTION_SINGLE_OBJECT + + +#ifdef FT_FLAT_COMPILE + +#include "ttdriver.c" /* driver interface */ +#include "ttpload.c" /* tables loader */ +#include "ttgload.c" /* glyph loader */ +#include "ttobjs.c" /* object manager */ + +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER +#include "ttinterp.c" /* bytecode interpreter */ +#endif + +#else /* FT_FLAT_COMPILE */ + +#include /* driver interface */ +#include /* tables loader */ +#include /* glyph loader */ +#include /* object manager */ + +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER +#include /* bytecode interpreter */ +#endif + +#endif /* FT_FLAT_COMPILE */ + + +/* END */ diff --git a/src/freetype/truetype/ttdriver.c b/src/freetype/truetype/ttdriver.c new file mode 100644 index 0000000000..0b3cb480c5 --- /dev/null +++ b/src/freetype/truetype/ttdriver.c @@ -0,0 +1,511 @@ +/***************************************************************************/ +/* */ +/* ttdriver.c */ +/* */ +/* TrueType font driver implementation (body). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#include +#include +#include +#include + + +#ifdef FT_FLAT_COMPILE + +#include "ttdriver.h" +#include "ttgload.h" + +#else + +#include +#include + +#endif + + + /*************************************************************************/ + /* */ + /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ + /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ + /* messages during execution. */ + /* */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_ttdriver + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** F A C E S ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + +#undef PAIR_TAG +#define PAIR_TAG( left, right ) ( ( (FT_ULong)left << 16 ) | \ + (FT_ULong)right ) + + + /*************************************************************************/ + /* */ + /* */ + /* Get_Kerning */ + /* */ + /* */ + /* A driver method used to return the kerning vector between two */ + /* glyphs of the same face. */ + /* */ + /* */ + /* face :: A handle to the source face object. */ + /* */ + /* left_glyph :: The index of the left glyph in the kern pair. */ + /* */ + /* right_glyph :: The index of the right glyph in the kern pair. */ + /* */ + /* */ + /* kerning :: The kerning vector. This is in font units for */ + /* scalable formats, and in pixels for fixed-sizes */ + /* formats. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* Only horizontal layouts (left-to-right & right-to-left) are */ + /* supported by this function. Other layouts, or more sophisticated */ + /* kernings, are out of scope of this method (the basic driver */ + /* interface is meant to be simple). */ + /* */ + /* They can be implemented by format-specific interfaces. */ + /* */ + static + FT_Error Get_Kerning( TT_Face face, + FT_UInt left_glyph, + FT_UInt right_glyph, + FT_Vector* kerning ) + { + TT_Kern_0_Pair* pair; + + + if ( !face ) + return TT_Err_Invalid_Face_Handle; + + kerning->x = 0; + kerning->y = 0; + + if ( face->kern_pairs ) + { + /* there are some kerning pairs in this font file! */ + FT_ULong search_tag = PAIR_TAG( left_glyph, right_glyph ); + FT_Long left, right; + + + left = 0; + right = face->num_kern_pairs - 1; + + while ( left <= right ) + { + FT_Int middle = left + ( ( right - left ) >> 1 ); + FT_ULong cur_pair; + + + pair = face->kern_pairs + middle; + cur_pair = PAIR_TAG( pair->left, pair->right ); + + if ( cur_pair == search_tag ) + goto Found; + + if ( cur_pair < search_tag ) + left = middle + 1; + else + right = middle - 1; + } + } + + Exit: + return TT_Err_Ok; + + Found: + kerning->x = pair->value; + goto Exit; + } + + +#undef PAIR_TAG + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** S I Z E S ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* */ + /* Set_Char_Sizes */ + /* */ + /* */ + /* A driver method used to reset a size's character sizes (horizontal */ + /* and vertical) expressed in fractional points. */ + /* */ + /* */ + /* char_width :: The character width expressed in 26.6 */ + /* fractional points. */ + /* */ + /* char_height :: The character height expressed in 26.6 */ + /* fractional points. */ + /* */ + /* horz_resolution :: The horizontal resolution of the output device. */ + /* */ + /* vert_resolution :: The vertical resolution of the output device. */ + /* */ + /* */ + /* size :: A handle to the target size object. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + static + FT_Error Set_Char_Sizes( TT_Size size, + FT_F26Dot6 char_width, + FT_F26Dot6 char_height, + FT_UInt horz_resolution, + FT_UInt vert_resolution ) + { + FT_Size_Metrics* metrics = &size->root.metrics; + TT_Face face = (TT_Face)size->root.face; + FT_Long dim_x, dim_y; + + + /* This bit flag, when set, indicates that the pixel size must be */ + /* truncated to an integer. Nearly all TrueType fonts have this */ + /* bit set, as hinting won't work really well otherwise. */ + /* */ + /* However, for those rare fonts who do not set it, we override */ + /* the default computations performed by the base layer. I */ + /* really don't know whether this is useful, but hey, that's the */ + /* spec :-) */ + /* */ + if ( ( face->header.Flags & 8 ) == 0 ) + { + /* Compute pixel sizes in 26.6 units */ + dim_x = ( char_width * horz_resolution ) / 72; + dim_y = ( char_height * vert_resolution ) / 72; + + metrics->x_scale = FT_DivFix( dim_x, face->root.units_per_EM ); + metrics->y_scale = FT_DivFix( dim_y, face->root.units_per_EM ); + + metrics->x_ppem = (FT_UShort)( dim_x >> 6 ); + metrics->y_ppem = (FT_UShort)( dim_y >> 6 ); + } + + size->ttmetrics.valid = FALSE; + + return TT_Reset_Size( size ); + } + + + /*************************************************************************/ + /* */ + /* */ + /* Set_Pixel_Sizes */ + /* */ + /* */ + /* A driver method used to reset a size's character sizes (horizontal */ + /* and vertical) expressed in integer pixels. */ + /* */ + /* */ + /* pixel_width :: The character width expressed in integer pixels. */ + /* */ + /* pixel_height :: The character height expressed in integer pixels. */ + /* */ + /* */ + /* size :: A handle to the target size object. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + static + FT_Error Set_Pixel_Sizes( TT_Size size, + FT_UInt pixel_width, + FT_UInt pixel_height ) + { + FT_UNUSED( pixel_width ); + FT_UNUSED( pixel_height ); + + /* many things have been pre-computed by the base layer */ + + size->ttmetrics.valid = FALSE; + + return TT_Reset_Size( size ); + } + + + /*************************************************************************/ + /* */ + /* */ + /* Load_Glyph */ + /* */ + /* */ + /* A driver method used to load a glyph within a given glyph slot. */ + /* */ + /* */ + /* slot :: A handle to the target slot object where the glyph */ + /* will be loaded. */ + /* */ + /* size :: A handle to the source face size at which the glyph */ + /* must be scaled, loaded, etc. */ + /* */ + /* glyph_index :: The index of the glyph in the font file. */ + /* */ + /* load_flags :: A flag indicating what to load for this glyph. The */ + /* FTLOAD_??? constants can be used to control the */ + /* glyph loading process (e.g., whether the outline */ + /* should be scaled, whether to load bitmaps or not, */ + /* whether to hint the outline, etc). */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + static + FT_Error Load_Glyph( TT_GlyphSlot slot, + TT_Size size, + FT_UShort glyph_index, + FT_UInt load_flags ) + { + FT_Error error; + + + if ( !slot ) + return TT_Err_Invalid_Glyph_Handle; + + /* check whether we want a scaled outline or bitmap */ + if ( !size ) + load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING; + + if ( load_flags & FT_LOAD_NO_SCALE ) + size = NULL; + + /* reset the size object if necessary */ + if ( size ) + { + /* these two object must have the same parent */ + if ( size->root.face != slot->face ) + return TT_Err_Invalid_Face_Handle; + + if ( !size->ttmetrics.valid ) + { + if ( FT_SET_ERROR( TT_Reset_Size( size ) ) ) + return error; + } + } + + /* now load the glyph outline if necessary */ + error = TT_Load_Glyph( size, slot, glyph_index, load_flags ); + + /* force drop-out mode to 2 - irrelevant now */ + /* slot->outline.dropout_mode = 2; */ + + return error; + } + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** C H A R A C T E R M A P P I N G S ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + /*************************************************************************/ + /* */ + /* */ + /* Get_Char_Index */ + /* */ + /* */ + /* Uses a charmap to return a given character code's glyph index. */ + /* */ + /* */ + /* charmap :: A handle to the source charmap object. */ + /* charcode :: The character code. */ + /* */ + /* */ + /* Glyph index. 0 means `undefined character code'. */ + /* */ + static + FT_UInt Get_Char_Index( TT_CharMap charmap, + FT_Long charcode ) + { + FT_Error error; + TT_Face face; + TT_CMapTable* cmap; + + + cmap = &charmap->cmap; + face = (TT_Face)charmap->root.face; + + /* Load table if needed */ + if ( !cmap->loaded ) + { + SFNT_Interface* sfnt = (SFNT_Interface*)face->sfnt; + + + error = sfnt->load_charmap( face, cmap, face->root.stream ); + if ( error ) + return 0; + + cmap->loaded = TRUE; + } + + if ( cmap->get_index ) + return cmap->get_index( cmap, charcode ); + else + return 0; + } + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** D R I V E R I N T E R F A C E ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + static + FT_Module_Interface tt_get_interface( TT_Driver driver, + const char* interface ) + { + FT_Module sfntd = FT_Get_Module( driver->root.root.library, + "sfnt" ); + SFNT_Interface* sfnt; + + + /* only return the default interface from the SFNT module */ + if ( sfntd ) + { + sfnt = (SFNT_Interface*)( sfntd->clazz->module_interface ); + if ( sfnt ) + return sfnt->get_interface( FT_MODULE( driver ), interface ); + } + + return 0; + } + + + /* The FT_DriverInterface structure is defined in ftdriver.h. */ + + const FT_Driver_Class tt_driver_class = + { + { + ft_module_font_driver | + ft_module_driver_scalable | +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER + ft_module_driver_has_hinter, +#else + 0, +#endif + + sizeof ( TT_DriverRec ), + + "truetype", /* driver name */ + 0x10000L, /* driver version == 1.0 */ + 0x20000L, /* driver requires FreeType 2.0 or above */ + + (void*)0, /* driver specific interface */ + + (FT_Module_Constructor)TT_Init_Driver, + (FT_Module_Destructor) TT_Done_Driver, + (FT_Module_Requester) tt_get_interface, + }, + + sizeof ( TT_FaceRec ), + sizeof ( TT_SizeRec ), + sizeof ( FT_GlyphSlotRec ), + + + (FTDriver_initFace) TT_Init_Face, + (FTDriver_doneFace) TT_Done_Face, + (FTDriver_initSize) TT_Init_Size, + (FTDriver_doneSize) TT_Done_Size, + (FTDriver_initGlyphSlot)0, + (FTDriver_doneGlyphSlot)0, + + (FTDriver_setCharSizes) Set_Char_Sizes, + (FTDriver_setPixelSizes)Set_Pixel_Sizes, + (FTDriver_loadGlyph) Load_Glyph, + (FTDriver_getCharIndex) Get_Char_Index, + + (FTDriver_getKerning) Get_Kerning, + (FTDriver_attachFile) 0, + (FTDriver_getAdvances) 0 + }; + + +#ifdef FT_CONFIG_OPTION_DYNAMIC_DRIVERS + + + /*************************************************************************/ + /* */ + /* */ + /* getDriverInterface */ + /* */ + /* */ + /* This function is used when compiling the TrueType driver as a */ + /* shared library (`.DLL' or `.so'). It will be used by the */ + /* high-level library of FreeType to retrieve the address of the */ + /* driver's generic interface. */ + /* */ + /* It shouldn't be implemented in a static build, as each driver must */ + /* have the same function as an exported entry point. */ + /* */ + /* */ + /* The address of the TrueType's driver generic interface. The */ + /* format-specific interface can then be retrieved through the method */ + /* interface->get_format_interface. */ + /* */ + EXPORT_FUNC( const FT_Driver_Class* ) getDriverClass( void ) + { + return &tt_driver_class; + } + + +#endif /* CONFIG_OPTION_DYNAMIC_DRIVERS */ + + +/* END */ diff --git a/src/freetype/truetype/ttdriver.h b/src/freetype/truetype/ttdriver.h new file mode 100644 index 0000000000..9867fbc309 --- /dev/null +++ b/src/freetype/truetype/ttdriver.h @@ -0,0 +1,31 @@ +/***************************************************************************/ +/* */ +/* ttdriver.h */ +/* */ +/* High-level TrueType driver interface (specification). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef TTDRIVER_H +#define TTDRIVER_H + +#include + + + FT_EXPORT_VAR( const FT_Driver_Class ) tt_driver_class; + + +#endif /* TTDRIVER_H */ + + +/* END */ diff --git a/src/freetype/truetype/ttgload.c b/src/freetype/truetype/ttgload.c new file mode 100644 index 0000000000..e9b87fa67e --- /dev/null +++ b/src/freetype/truetype/ttgload.c @@ -0,0 +1,1477 @@ +/***************************************************************************/ +/* */ +/* ttgload.c */ +/* */ +/* TrueType Glyph Loader (body). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#include +#include +#include +#include +#include +#include + + +#ifdef FT_FLAT_COMPILE + +#include "ttgload.h" + +#else + +#include + +#endif + + + /*************************************************************************/ + /* */ + /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ + /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ + /* messages during execution. */ + /* */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_ttgload + + + /*************************************************************************/ + /* */ + /* Composite font flags. */ + /* */ +#define ARGS_ARE_WORDS 0x001 +#define ARGS_ARE_XY_VALUES 0x002 +#define ROUND_XY_TO_GRID 0x004 +#define WE_HAVE_A_SCALE 0x008 +/* reserved 0x010 */ +#define MORE_COMPONENTS 0x020 +#define WE_HAVE_AN_XY_SCALE 0x040 +#define WE_HAVE_A_2X2 0x080 +#define WE_HAVE_INSTR 0x100 +#define USE_MY_METRICS 0x200 + + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Get_Metrics */ + /* */ + /* */ + /* Returns the horizontal or vertical metrics in font units for a */ + /* given glyph. The metrics are the left side bearing (resp. top */ + /* side bearing) and advance width (resp. advance height). */ + /* */ + /* */ + /* header :: A pointer to either the horizontal or vertical metrics */ + /* structure. */ + /* */ + /* index :: The glyph index. */ + /* */ + /* */ + /* bearing :: The bearing, either left side or top side. */ + /* */ + /* advance :: The advance width resp. advance height. */ + /* */ + /* */ + /* This function will much probably move to another component in the */ + /* near future, but I haven't decided which yet. */ + /* */ + LOCAL_FUNC + void TT_Get_Metrics( TT_HoriHeader* header, + FT_UInt index, + FT_Short* bearing, + FT_UShort* advance ) + { + TT_LongMetrics* longs_m; + FT_UShort k = header->number_Of_HMetrics; + + + if ( index < k ) + { + longs_m = (TT_LongMetrics*)header->long_metrics + index; + *bearing = longs_m->bearing; + *advance = longs_m->advance; + } + else + { + *bearing = ((TT_ShortMetrics*)header->short_metrics)[index - k]; + *advance = ((TT_LongMetrics*)header->long_metrics)[k - 1].advance; + } + } + + + /*************************************************************************/ + /* */ + /* Returns the horizontal metrics in font units for a given glyph. If */ + /* `check' is true, take care of monospaced fonts by returning the */ + /* advance width maximum. */ + /* */ + static + void Get_HMetrics( TT_Face face, + FT_UInt index, + FT_Bool check, + FT_Short* lsb, + FT_UShort* aw ) + { + TT_Get_Metrics( &face->horizontal, index, lsb, aw ); + + if ( check && face->postscript.isFixedPitch ) + *aw = face->horizontal.advance_Width_Max; + } + + + /*************************************************************************/ + /* */ + /* Returns the advance width table for a given pixel size if it is */ + /* found in the font's `hdmx' table (if any). */ + /* */ + static + FT_Byte* Get_Advance_Widths( TT_Face face, + FT_UShort ppem ) + { + FT_UShort n; + + for ( n = 0; n < face->hdmx.num_records; n++ ) + if ( face->hdmx.records[n].ppem == ppem ) + return face->hdmx.records[n].widths; + + return NULL; + } + + +#define cur_to_org( n, zone ) \ + MEM_Copy( (zone)->org, (zone)->cur, n * sizeof ( FT_Vector ) ) + +#define org_to_cur( n, zone ) \ + MEM_Copy( (zone)->cur, (zone)->org, n * sizeof ( FT_Vector ) ) + + + /*************************************************************************/ + /* */ + /* Translates an array of coordinates. */ + /* */ + static + void translate_array( FT_UInt n, + FT_Vector* coords, + FT_Pos delta_x, + FT_Pos delta_y ) + { + FT_UInt k; + + + if ( delta_x ) + for ( k = 0; k < n; k++ ) + coords[k].x += delta_x; + + if ( delta_y ) + for ( k = 0; k < n; k++ ) + coords[k].y += delta_y; + } + + + static + void tt_prepare_zone( TT_GlyphZone* zone, + FT_GlyphLoad* load, + FT_UInt start_point, + FT_UInt start_contour ) + { + zone->n_points = load->outline.n_points - start_point; + zone->n_contours = load->outline.n_contours - start_contour; + zone->org = load->extra_points + start_point; + zone->cur = load->outline.points + start_point; + zone->tags = (FT_Byte*)load->outline.tags + start_point; + zone->contours = (FT_UShort*)load->outline.contours + start_contour; + } + + +#undef IS_HINTED +#define IS_HINTED( flags ) ( ( flags & FT_LOAD_NO_HINTING ) == 0 ) + + + /*************************************************************************/ + /* */ + /* The following functions are used by default with TrueType fonts. */ + /* However, they can be replaced by alternatives if we need to support */ + /* TrueType-compressed formats (like MicroType) in the future. */ + /* */ + /*************************************************************************/ + + static + FT_Error TT_Access_Glyph_Frame( TT_Loader* loader, + FT_UInt glyph_index, + FT_ULong offset, + FT_UInt byte_count ) + { + FT_Error error; + FT_Stream stream = loader->stream; + + + /* the following line sets the `error' variable through macros! */ + (void)( FILE_Seek( offset ) || ACCESS_Frame( byte_count ) ); + + FT_TRACE5(( "Glyph %ld\n", glyph_index )); + return error; + } + + + static + void TT_Forget_Glyph_Frame( TT_Loader* loader ) + { + FT_Stream stream = loader->stream; + + + FORGET_Frame(); + } + + + static + FT_Error TT_Load_Glyph_Header( TT_Loader* loader ) + { + FT_Stream stream = loader->stream; + + + loader->n_contours = GET_Short(); + + loader->bbox.xMin = GET_Short(); + loader->bbox.yMin = GET_Short(); + loader->bbox.xMax = GET_Short(); + loader->bbox.yMax = GET_Short(); + + 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 )); + + return FT_Err_Ok; + } + + + static + FT_Error TT_Load_Simple_Glyph( TT_Loader* load ) + { + FT_Error error; + FT_Stream stream = load->stream; + FT_GlyphLoader* gloader = load->gloader; + FT_Int n_contours = load->n_contours; + FT_Outline* outline; + TT_Face face = (TT_Face)load->face; + TT_GlyphSlot slot = (TT_GlyphSlot)load->glyph; + FT_UShort n_ins; + FT_Int n, n_points; + + + /* reading the contours endpoints & number of points */ + { + short* cur = gloader->current.outline.contours; + short* limit = cur + n_contours; + + + for ( ; cur < limit; cur++ ) + cur[0] = GET_UShort(); + + n_points = 0; + if ( n_contours > 0 ) + n_points = cur[-1] + 1; + + error = FT_GlyphLoader_Check_Points( gloader, n_points + 2, 0 ); + if ( error ) + goto Fail; + + outline = &gloader->current.outline; + } + + /* reading the bytecode instructions */ + slot->control_len = 0; + slot->control_data = 0; + + n_ins = GET_UShort(); + + FT_TRACE5(( " Instructions size: %d\n", n_ins )); + + if ( n_ins > face->max_profile.maxSizeOfInstructions ) + { + FT_TRACE0(( "ERROR: Too many instructions!\n" )); + error = TT_Err_Too_Many_Ins; + goto Fail; + } + + if ( stream->cursor + n_ins > stream->limit ) + { + FT_TRACE0(( "ERROR: Instruction count mismatch!\n" )); + error = TT_Err_Too_Many_Ins; + goto Fail; + } + +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER + + if ( ( load->load_flags & + ( FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING ) ) == 0 && + load->instructions ) + { + slot->control_len = n_ins; + slot->control_data = load->instructions; + + MEM_Copy( load->instructions, stream->cursor, n_ins ); + } + +#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */ + + stream->cursor += n_ins; + + /* reading the point tags */ + + { + FT_Byte* flag = (FT_Byte*)outline->tags; + FT_Byte* limit = flag + n_points; + FT_Byte c, count; + + + for ( ; flag < limit; flag++ ) + { + *flag = c = GET_Byte(); + if ( c & 8 ) + { + for ( count = GET_Byte(); count > 0; count-- ) + *++flag = c; + } + } + } + + /* reading the X coordinates */ + + { + FT_Vector* vec = outline->points; + FT_Vector* limit = vec + n_points; + FT_Byte* flag = (FT_Byte*)outline->tags; + FT_Pos x = 0; + + + for ( ; vec < limit; vec++, flag++ ) + { + FT_Pos y = 0; + + + if ( *flag & 2 ) + { + y = GET_Byte(); + if ( ( *flag & 16 ) == 0 ) + y = -y; + } + else if ( ( *flag & 16 ) == 0 ) + y = GET_Short(); + + x += y; + vec->x = x; + } + } + + /* reading the Y coordinates */ + + { + FT_Vector* vec = gloader->current.outline.points; + FT_Vector* limit = vec + n_points; + FT_Byte* flag = (FT_Byte*)outline->tags; + FT_Pos x = 0; + + + for ( ; vec < limit; vec++, flag++ ) + { + FT_Pos y = 0; + + + if ( *flag & 4 ) + { + y = GET_Byte(); + if ( ( *flag & 32 ) == 0 ) + y = -y; + } + else if ( ( *flag & 32 ) == 0 ) + y = GET_Short(); + + x += y; + vec->y = x; + } + } + + /* clear the touch tags */ + for ( n = 0; n < n_points; n++ ) + outline->tags[n] &= FT_Curve_Tag_On; + + outline->n_points = n_points; + outline->n_contours = n_contours; + + Fail: + return error; + } + + + static + FT_Error TT_Load_Composite_Glyph( TT_Loader* loader ) + { + FT_Error error; + FT_Stream stream = loader->stream; + FT_GlyphLoader* gloader = loader->gloader; + FT_SubGlyph* subglyph; + FT_UInt num_subglyphs; + + + num_subglyphs = 0; + + do + { + FT_Fixed xx, xy, yy, yx; + + + /* check that we can load a new subglyph */ + error = FT_GlyphLoader_Check_Subglyphs( gloader, num_subglyphs + 1 ); + if ( error ) + goto Fail; + + subglyph = gloader->current.subglyphs + num_subglyphs; + + subglyph->arg1 = subglyph->arg2 = 0; + + subglyph->flags = GET_UShort(); + subglyph->index = GET_UShort(); + + /* read arguments */ + if ( subglyph->flags & ARGS_ARE_WORDS ) + { + subglyph->arg1 = GET_Short(); + subglyph->arg2 = GET_Short(); + } + else + { + subglyph->arg1 = GET_Char(); + subglyph->arg2 = GET_Char(); + } + + /* read transform */ + xx = yy = 0x10000L; + xy = yx = 0; + + if ( subglyph->flags & WE_HAVE_A_SCALE ) + { + xx = (FT_Fixed)GET_Short() << 2; + yy = xx; + } + else if ( subglyph->flags & WE_HAVE_AN_XY_SCALE ) + { + xx = (FT_Fixed)GET_Short() << 2; + yy = (FT_Fixed)GET_Short() << 2; + } + else if ( subglyph->flags & WE_HAVE_A_2X2 ) + { + xx = (FT_Fixed)GET_Short() << 2; + xy = (FT_Fixed)GET_Short() << 2; + yx = (FT_Fixed)GET_Short() << 2; + yy = (FT_Fixed)GET_Short() << 2; + } + + subglyph->transform.xx = xx; + subglyph->transform.xy = xy; + subglyph->transform.yx = yx; + subglyph->transform.yy = yy; + + num_subglyphs++; + + } while ( subglyph->flags & MORE_COMPONENTS ); + + gloader->current.num_subglyphs = num_subglyphs; + +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER + { + /* we must undo the ACCESS_Frame in order to point to the */ + /* composite instructions, if we find some. */ + /* we will process them later... */ + /* */ + loader->ins_pos = FILE_Pos() + stream->cursor - stream->limit; + } +#endif + + Fail: + return error; + } + + + LOCAL_FUNC + void TT_Init_Glyph_Loading( TT_Face face ) + { + face->access_glyph_frame = TT_Access_Glyph_Frame; + face->read_glyph_header = TT_Load_Glyph_Header; + face->read_simple_glyph = TT_Load_Simple_Glyph; + face->read_composite_glyph = TT_Load_Composite_Glyph; + face->forget_glyph_frame = TT_Forget_Glyph_Frame; + } + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Process_Simple_Glyph */ + /* */ + /* */ + /* Once a simple glyph has been loaded, it needs to be processed. */ + /* Usually, this means scaling and hinting through bytecode */ + /* interpretation. */ + /* */ + static + FT_Error TT_Process_Simple_Glyph( TT_Loader* load, + FT_Bool debug ) + { + FT_GlyphLoader* gloader = load->gloader; + FT_Outline* outline = &gloader->current.outline; + FT_UInt n_points = outline->n_points; + FT_UInt n_ins; + TT_GlyphZone* zone = &load->zone; + FT_Error error = FT_Err_Ok; + + + n_ins = load->glyph->control_len; + + /* add shadow points */ + + /* Now add the two shadow points at n and n + 1. */ + /* We need the left side bearing and advance width. */ + + { + FT_Vector* pp1; + FT_Vector* pp2; + + + /* pp1 = xMin - lsb */ + pp1 = outline->points + n_points; + pp1->x = load->bbox.xMin - load->left_bearing; + pp1->y = 0; + + /* pp2 = pp1 + aw */ + pp2 = pp1 + 1; + pp2->x = pp1->x + load->advance; + pp2->y = 0; + + outline->tags[n_points ] = 0; + outline->tags[n_points + 1] = 0; + } + + /* Note that we return two more points that are not */ + /* part of the glyph outline. */ + + n_points += 2; + + /* set up zone for hinting */ + tt_prepare_zone( zone, &gloader->current, 0, 0 ); + + /* eventually scale the glyph */ + if ( !( load->load_flags & FT_LOAD_NO_SCALE ) ) + { + FT_Vector* vec = zone->cur; + FT_Vector* limit = vec + n_points; + FT_Fixed x_scale = load->size->metrics.x_scale; + FT_Fixed y_scale = load->size->metrics.y_scale; + + + /* first scale the glyph points */ + for ( ; vec < limit; vec++ ) + { + vec->x = FT_MulFix( vec->x, x_scale ); + vec->y = FT_MulFix( vec->y, y_scale ); + } + } + + cur_to_org( n_points, zone ); + + /* eventually hint the glyph */ + if ( IS_HINTED( load->load_flags ) ) + { + FT_Pos x = zone->org[n_points-2].x; + + + x = ( ( x + 32 ) & -64 ) - x; + translate_array( n_points, zone->org, x, 0 ); + + org_to_cur( n_points, zone ); + + zone->cur[n_points - 1].x = ( zone->cur[n_points - 1].x + 32 ) & -64; + +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER + + /* now consider hinting */ + if ( n_ins > 0 ) + { + error = TT_Set_CodeRange( load->exec, tt_coderange_glyph, + load->exec->glyphIns, n_ins ); + if ( error ) + goto Exit; + + load->exec->is_composite = FALSE; + load->exec->pedantic_hinting = (FT_Bool)( load->load_flags & + FT_LOAD_PEDANTIC ); + load->exec->pts = *zone; + load->exec->pts.n_points += 2; + + error = TT_Run_Context( load->exec, debug ); + if ( error && load->exec->pedantic_hinting ) + goto Exit; + + error = FT_Err_Ok; /* ignore bytecode errors in non-pedantic mode */ + } + +#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */ + + } + + /* save glyph phantom points */ + if ( !load->preserve_pps ) + { + load->pp1 = zone->cur[n_points - 2]; + load->pp2 = zone->cur[n_points - 1]; + } + +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER + Exit: +#endif + return error; + } + + + /*************************************************************************/ + /* */ + /* */ + /* load_truetype_glyph */ + /* */ + /* */ + /* Loads a given truetype glyph. Handles composites and uses a */ + /* TT_Loader object. */ + /* */ + static + FT_Error load_truetype_glyph( TT_Loader* loader, + FT_UInt glyph_index ) + { + FT_Stream stream = loader->stream; + FT_Error error; + TT_Face face = (TT_Face)loader->face; + FT_ULong offset; + FT_Int contours_count; + FT_UInt index, num_points, num_contours, count; + FT_Fixed x_scale, y_scale; + FT_ULong ins_offset; + FT_GlyphLoader* gloader = loader->gloader; + FT_Bool opened_frame = 0; + + + /* check glyph index */ + index = glyph_index; + if ( index >= (FT_UInt)face->root.num_glyphs ) + { + error = TT_Err_Invalid_Glyph_Index; + goto Exit; + } + + loader->glyph_index = glyph_index; + num_contours = 0; + num_points = 0; + ins_offset = 0; + + x_scale = 0x10000L; + y_scale = 0x10000L; + if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 ) + { + x_scale = loader->size->metrics.x_scale; + y_scale = loader->size->metrics.y_scale; + } + + /* get horizontal metrics */ + { + FT_Short left_bearing; + FT_UShort advance_width; + + + Get_HMetrics( face, index, + (FT_Bool)!(loader->load_flags & + FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH), + &left_bearing, + &advance_width ); + + loader->left_bearing = left_bearing; + loader->advance = advance_width; + } + + offset = face->glyph_locations[index]; + count = 0; + + if ( index < (FT_UInt)face->num_locations - 1 ) + count = face->glyph_locations[index + 1] - offset; + + if ( count == 0 ) + { + /* as described by Frederic Loyer, these are spaces, and */ + /* not the unknown glyph. */ + loader->bbox.xMin = 0; + loader->bbox.xMax = 0; + loader->bbox.yMin = 0; + loader->bbox.yMax = 0; + + loader->pp1.x = 0; + loader->pp2.x = loader->advance; + + if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 ) + loader->pp2.x = FT_MulFix( loader->pp2.x, x_scale ); + +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER + + if ( loader->exec ) + loader->exec->glyphSize = 0; + +#endif + + error = FT_Err_Ok; + goto Exit; + } + + offset = loader->glyf_offset + offset; + + /* access glyph frame */ + error = face->access_glyph_frame( loader, glyph_index, offset, count ); + if ( error ) + goto Exit; + + opened_frame = 1; + + /* read first glyph header */ + error = face->read_glyph_header( loader ); + if ( error ) + goto Fail; + + contours_count = loader->n_contours; + + count -= 10; + + loader->pp1.x = loader->bbox.xMin - loader->left_bearing; + loader->pp1.y = 0; + loader->pp2.x = loader->pp1.x + loader->advance; + loader->pp2.y = 0; + + if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 ) + { + loader->pp1.x = FT_MulFix( loader->pp1.x, x_scale ); + loader->pp2.x = FT_MulFix( loader->pp2.x, x_scale ); + } + + /***********************************************************************/ + /***********************************************************************/ + /***********************************************************************/ + + /* if it is a simple glyph, load it */ + + if ( contours_count >= 0 ) + { + /* check that we can add the contours to the glyph */ + error = FT_GlyphLoader_Check_Points( gloader, 0, contours_count ); + if ( error ) + goto Fail; + + error = face->read_simple_glyph( loader ); + if ( error ) + goto Fail; + +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER + + { + TT_Size size = (TT_Size)loader->size; + + + error = TT_Process_Simple_Glyph( loader, + (FT_Bool)( size && size->debug ) ); + } + +#else + + error = TT_Process_Simple_Glyph( loader, 0 ); + +#endif + + if ( error ) + goto Fail; + + FT_GlyphLoader_Add( gloader ); + + /* Note: We could have put the simple loader source there */ + /* but the code is fat enough already :-) */ + } + + /***********************************************************************/ + /***********************************************************************/ + /***********************************************************************/ + + /* otherwise, load a composite! */ + else + { + TT_GlyphSlot glyph = (TT_GlyphSlot)loader->glyph; + FT_UInt start_point, start_contour; + FT_ULong ins_pos; /* position of composite instructions, if any */ + + + /* for each subglyph, read composite header */ + start_point = gloader->base.outline.n_points; + start_contour = gloader->base.outline.n_contours; + + error = face->read_composite_glyph( loader ); + if ( error ) + goto Fail; + + ins_pos = loader->ins_pos; + face->forget_glyph_frame( loader ); + opened_frame = 0; + + /* if the flag FT_LOAD_NO_RECURSE is set, we return the subglyph */ + /* `as is' in the glyph slot (the client application will be */ + /* responsible for interpreting this data)... */ + /* */ + if ( loader->load_flags & FT_LOAD_NO_RECURSE ) + { + /* set up remaining glyph fields */ + FT_GlyphLoader_Add( gloader ); + + glyph->num_subglyphs = gloader->base.num_subglyphs; + glyph->format = ft_glyph_format_composite; + glyph->subglyphs = gloader->base.subglyphs; + + goto Exit; + } + + /*********************************************************************/ + /*********************************************************************/ + /*********************************************************************/ + + /* Now, read each subglyph independently. */ + { + FT_Int n, num_base_points, num_new_points; + FT_SubGlyph* subglyph = 0; + + FT_UInt num_subglyphs = gloader->current.num_subglyphs; + FT_UInt num_base_subgs = gloader->base.num_subglyphs; + + + FT_GlyphLoader_Add( gloader ); + + for ( n = 0; n < (FT_Int)num_subglyphs; n++ ) + { + FT_Vector pp1, pp2; + FT_Pos x, y; + + + /* Each time we call load_truetype_glyph in this loop, the */ + /* value of `gloader.base.subglyphs' can change due to table */ + /* reallocations. We thus need to recompute the subglyph */ + /* pointer on each iteration. */ + subglyph = gloader->base.subglyphs + num_base_subgs + n; + + pp1 = loader->pp1; + pp2 = loader->pp2; + + num_base_points = gloader->base.outline.n_points; + + error = load_truetype_glyph( loader, subglyph->index ); + if ( error ) + goto Fail; + + subglyph = gloader->base.subglyphs + num_base_subgs + n; + + if ( subglyph->flags & USE_MY_METRICS ) + { + pp1 = loader->pp1; + pp2 = loader->pp2; + } + else + { + loader->pp1 = pp1; + loader->pp2 = pp2; + } + + num_points = gloader->base.outline.n_points; + + num_new_points = num_points - num_base_points; + + /* now perform the transform required for this subglyph */ + + if ( subglyph->flags & ( WE_HAVE_A_SCALE | + WE_HAVE_AN_XY_SCALE | + WE_HAVE_A_2X2 ) ) + { + FT_Vector* cur = gloader->base.outline.points + + num_base_points; + FT_Vector* org = gloader->base.extra_points + + num_base_points; + FT_Vector* limit = cur + num_new_points; + + + for ( ; cur < limit; cur++, org++ ) + { + FT_Vector_Transform( cur, &subglyph->transform ); + FT_Vector_Transform( org, &subglyph->transform ); + } + } + + /* apply offset */ + + if ( !( subglyph->flags & ARGS_ARE_XY_VALUES ) ) + { + FT_UInt k = subglyph->arg1; + FT_UInt l = subglyph->arg2; + FT_Vector* p1; + FT_Vector* p2; + + + if ( start_point + k >= (FT_UInt)num_base_points || + l >= (FT_UInt)num_new_points ) + { + error = TT_Err_Invalid_Composite; + goto Fail; + } + + l += num_base_points; + + p1 = gloader->base.outline.points + start_point + k; + p2 = gloader->base.outline.points + start_point + l; + + x = p1->x - p2->x; + y = p1->y - p2->y; + } + else + { + x = subglyph->arg1; + y = subglyph->arg2; + + if ( !( loader->load_flags & FT_LOAD_NO_SCALE ) ) + { + x = FT_MulFix( x, x_scale ); + y = FT_MulFix( y, y_scale ); + + if ( subglyph->flags & ROUND_XY_TO_GRID ) + { + x = ( x + 32 ) & -64; + y = ( y + 32 ) & -64; + } + } + } + + translate_array( num_new_points, loader->zone.cur, x, y ); + cur_to_org( num_new_points, &loader->zone ); + } + + /*******************************************************************/ + /*******************************************************************/ + /*******************************************************************/ + + /* we have finished loading all sub-glyphs; now, look for */ + /* instructions for this composite! */ + +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER + + if ( num_subglyphs > 0 && + loader->exec && + ins_pos > 0 && + subglyph->flags & WE_HAVE_INSTR ) + { + FT_UShort n_ins; + TT_ExecContext exec = loader->exec; + TT_GlyphZone* pts; + FT_Vector* pp1; + + + /* read size of instructions */ + if ( FILE_Seek( ins_pos ) || + READ_UShort( n_ins ) ) + goto Fail; + FT_TRACE5(( " Instructions size = %d\n", n_ins )); + + /* in some fonts? */ + if ( n_ins == 0xFFFF ) + n_ins = 0; + + /* check it */ + if ( n_ins > face->max_profile.maxSizeOfInstructions ) + { + FT_TRACE0(( "Too many instructions (%d) in composite glyph %ld\n", + n_ins, subglyph->index )); + return TT_Err_Too_Many_Ins; + } + + /* read the instructions */ + if ( FILE_Read( exec->glyphIns, n_ins ) ) + goto Fail; + + glyph->control_data = exec->glyphIns; + glyph->control_len = n_ins; + + error = TT_Set_CodeRange( exec, + tt_coderange_glyph, + exec->glyphIns, + n_ins ); + if ( error ) + goto Fail; + + /* prepare the execution context */ + tt_prepare_zone( &exec->pts, &gloader->base, + start_point, start_contour ); + pts = &exec->pts; + + pts->n_points = num_points + 2; + pts->n_contours = gloader->base.outline.n_contours; + + /* add phantom points */ + pp1 = pts->cur + num_points; + pp1[0] = loader->pp1; + pp1[1] = loader->pp2; + + pts->tags[num_points ] = 0; + pts->tags[num_points + 1] = 0; + + /* if hinting, round the phantom points */ + if ( IS_HINTED( loader->load_flags ) ) + { + pp1[0].x = ( ( loader->pp1.x + 32 ) & -64 ); + pp1[1].x = ( ( loader->pp2.x + 32 ) & -64 ); + } + + { + FT_UInt k; + + + for ( k = 0; k < num_points; k++ ) + pts->tags[k] &= FT_Curve_Tag_On; + } + + cur_to_org( num_points + 2, pts ); + + /* now consider hinting */ + if ( IS_HINTED( loader->load_flags ) && n_ins > 0 ) + { + exec->is_composite = TRUE; + exec->pedantic_hinting = + (FT_Bool)( loader->load_flags & FT_LOAD_PEDANTIC ); + + error = TT_Run_Context( exec, ((TT_Size)loader->size)->debug ); + if ( error && exec->pedantic_hinting ) + goto Fail; + } + + /* save glyph origin and advance points */ + loader->pp1 = pp1[0]; + loader->pp2 = pp1[1]; + } + +#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */ + + } + /* end of composite loading */ + } + + /***********************************************************************/ + /***********************************************************************/ + /***********************************************************************/ + + Fail: + if ( opened_frame ) + face->forget_glyph_frame( loader ); + + Exit: + return error; + } + + + static + void compute_glyph_metrics( TT_Loader* loader, + FT_UInt glyph_index ) + { + FT_BBox bbox; + TT_Face face = (TT_Face)loader->face; + FT_Fixed x_scale, y_scale; + TT_GlyphSlot glyph = loader->glyph; + TT_Size size = (TT_Size)loader->size; + + + x_scale = 0x10000L; + y_scale = 0x10000L; + if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 ) + { + x_scale = size->root.metrics.x_scale; + y_scale = size->root.metrics.y_scale; + } + + if ( glyph->format != ft_glyph_format_composite ) + { + glyph->outline.flags &= ~ft_outline_single_pass; + + /* copy outline to our glyph slot */ + FT_GlyphLoader_Copy_Points( glyph->loader, loader->gloader ); + glyph->outline = glyph->loader->base.outline; + + /* translate array so that (0,0) is the glyph's origin */ + FT_Outline_Translate( &glyph->outline, -loader->pp1.x, 0 ); + + FT_Outline_Get_CBox( &glyph->outline, &bbox ); + + if ( IS_HINTED( loader->load_flags ) ) + { + /* grid-fit the bounding box */ + bbox.xMin &= -64; + bbox.yMin &= -64; + bbox.xMax = ( bbox.xMax + 63 ) & -64; + bbox.yMax = ( bbox.yMax + 63 ) & -64; + } + } + else + bbox = loader->bbox; + + /* get the device-independent horizontal advance. It is scaled later */ + /* by the base layer. */ + { + FT_Pos advance = loader->advance; + + + /* the flag FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH was introduced to */ + /* correctly support DynaLab fonts, which have an incorrect */ + /* `advance_Width_Max' field! It is used, to my knowledge, */ + /* exclusively in the X-TrueType font server. */ + /* */ + if ( face->postscript.isFixedPitch && + ( loader->load_flags & FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH ) == 0 ) + advance = face->horizontal.advance_Width_Max; + + /* we need to return the advance in font units in linearHoriAdvance, */ + /* it will be scaled later by the base layer. */ + glyph->linearHoriAdvance = advance; + } + + glyph->metrics.horiBearingX = bbox.xMin; + glyph->metrics.horiBearingY = bbox.yMax; + glyph->metrics.horiAdvance = loader->pp2.x - loader->pp1.x; + + /* Now take care of vertical metrics. In the case where there is */ + /* no vertical information within the font (relatively common), make */ + /* up some metrics by `hand'... */ + + { + FT_Short top_bearing; /* vertical top side bearing (EM units) */ + FT_UShort advance_height; /* vertical advance height (EM units) */ + + FT_Pos left; /* scaled vertical left side bearing */ + FT_Pos Top; /* scaled original vertical top side bearing */ + FT_Pos top; /* scaled vertical top side bearing */ + FT_Pos advance; /* scaled vertical advance height */ + + + /* Get the unscaled `tsb' and `ah' */ + if ( face->vertical_info && + face->vertical.number_Of_VMetrics > 0 ) + { + /* Don't assume that both the vertical header and vertical */ + /* metrics are present in the same font :-) */ + + TT_Get_Metrics( (TT_HoriHeader*)&face->vertical, + glyph_index, + &top_bearing, + &advance_height ); + } + else + { + /* Make up the distances from the horizontal header. */ + + /* NOTE: The OS/2 values are the only `portable' ones, */ + /* which is why we use them, if there is an OS/2 */ + /* table in the font. Otherwise, we use the */ + /* values defined in the horizontal header. */ + /* */ + /* NOTE2: The sTypoDescender is negative, which is why */ + /* we compute the baseline-to-baseline distance */ + /* here with: */ + /* ascender - descender + linegap */ + /* */ + if ( face->os2.version != 0xFFFF ) + { + top_bearing = face->os2.sTypoLineGap / 2; + advance_height = (FT_UShort)( face->os2.sTypoAscender - + face->os2.sTypoDescender + + face->os2.sTypoLineGap ); + } + else + { + top_bearing = face->horizontal.Line_Gap / 2; + advance_height = (FT_UShort)( face->horizontal.Ascender + + face->horizontal.Descender + + face->horizontal.Line_Gap ); + } + } + + /* We must adjust the top_bearing value from the bounding box given */ + /* in the glyph header to te bounding box calculated with */ + /* FT_Get_Outline_CBox(). */ + + /* scale the metrics */ + if ( !( loader->load_flags & FT_LOAD_NO_SCALE ) ) + { + Top = FT_MulFix( top_bearing, y_scale ); + top = FT_MulFix( top_bearing + loader->bbox.yMax, y_scale ) + - bbox.yMax; + advance = FT_MulFix( advance_height, y_scale ); + } + else + { + Top = top_bearing; + top = top_bearing + loader->bbox.yMax - bbox.yMax; + advance = advance_height; + } + + /* set the advance height in design units. It is scaled later by */ + /* the base layer. */ + glyph->linearVertAdvance = advance_height; + + /* XXX: for now, we have no better algorithm for the lsb, but it */ + /* should work fine. */ + /* */ + left = ( bbox.xMin - bbox.xMax ) / 2; + + /* grid-fit them if necessary */ + if ( IS_HINTED( loader->load_flags ) ) + { + left &= -64; + top = ( top + 63 ) & -64; + advance = ( advance + 32 ) & -64; + } + + glyph->metrics.vertBearingX = left; + glyph->metrics.vertBearingY = top; + glyph->metrics.vertAdvance = advance; + } + + /* adjust advance width to the value contained in the hdmx table */ + if ( !face->postscript.isFixedPitch && size && + IS_HINTED( loader->load_flags ) ) + { + FT_Byte* widths = Get_Advance_Widths( face, + size->root.metrics.x_ppem ); + + + if ( widths ) + glyph->metrics.horiAdvance = widths[glyph_index] << 6; + } + + /* set glyph dimensions */ + glyph->metrics.width = bbox.xMax - bbox.xMin; + glyph->metrics.height = bbox.yMax - bbox.yMin; + } + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Load_Glyph */ + /* */ + /* */ + /* A function used to load a single glyph within a given glyph slot, */ + /* for a given size. */ + /* */ + /* */ + /* glyph :: A handle to a target slot object where the glyph */ + /* will be loaded. */ + /* */ + /* size :: A handle to the source face size at which the glyph */ + /* must be scaled/loaded. */ + /* */ + /* glyph_index :: The index of the glyph in the font file. */ + /* */ + /* load_flags :: A flag indicating what to load for this glyph. The */ + /* FT_LOAD_XXX constants can be used to control the */ + /* glyph loading process (e.g., whether the outline */ + /* should be scaled, whether to load bitmaps or not, */ + /* whether to hint the outline, etc). */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + LOCAL_FUNC + FT_Error TT_Load_Glyph( TT_Size size, + TT_GlyphSlot glyph, + FT_UShort glyph_index, + FT_UInt load_flags ) + { + SFNT_Interface* sfnt; + TT_Face face; + FT_Stream stream; + FT_Memory memory; + FT_Error error; + TT_Loader loader; + + + face = (TT_Face)glyph->face; + sfnt = (SFNT_Interface*)face->sfnt; + stream = face->root.stream; + memory = face->root.memory; + error = 0; + + if ( !size || ( load_flags & FT_LOAD_NO_SCALE ) || + ( load_flags & FT_LOAD_NO_RECURSE ) ) + { + size = NULL; + load_flags |= FT_LOAD_NO_SCALE | + FT_LOAD_NO_HINTING | + FT_LOAD_NO_BITMAP; + } + + glyph->num_subglyphs = 0; + +#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS + + /* try to load embedded bitmap if any */ + if ( size && + ( load_flags & FT_LOAD_NO_BITMAP ) == 0 && + sfnt->load_sbits ) + { + TT_SBit_Metrics metrics; + + + error = sfnt->load_sbit_image( face, + size->root.metrics.x_ppem, + size->root.metrics.y_ppem, + glyph_index, + load_flags, + stream, + &glyph->bitmap, + &metrics ); + if ( !error ) + { + glyph->outline.n_points = 0; + glyph->outline.n_contours = 0; + + glyph->metrics.width = (FT_Pos)metrics.width << 6; + glyph->metrics.height = (FT_Pos)metrics.height << 6; + + glyph->metrics.horiBearingX = (FT_Pos)metrics.horiBearingX << 6; + glyph->metrics.horiBearingY = (FT_Pos)metrics.horiBearingY << 6; + glyph->metrics.horiAdvance = (FT_Pos)metrics.horiAdvance << 6; + + glyph->metrics.vertBearingX = (FT_Pos)metrics.vertBearingX << 6; + glyph->metrics.vertBearingY = (FT_Pos)metrics.vertBearingY << 6; + glyph->metrics.vertAdvance = (FT_Pos)metrics.vertAdvance << 6; + + glyph->format = ft_glyph_format_bitmap; + if ( load_flags & FT_LOAD_VERTICAL_LAYOUT ) + { + glyph->bitmap_left = metrics.vertBearingX; + glyph->bitmap_top = metrics.vertBearingY; + } + else + { + glyph->bitmap_left = metrics.horiBearingX; + glyph->bitmap_top = metrics.horiBearingY; + } + return error; + } + } + +#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ + + /* seek to the beginning of the glyph table. For Type 42 fonts */ + /* the table might be accessed from a Postscript stream or something */ + /* else... */ + + error = face->goto_table( face, TTAG_glyf, stream, 0 ); + if ( error ) + { + FT_ERROR(( "TT_Load_Glyph: could not access glyph table\n" )); + goto Exit; + } + + MEM_Set( &loader, 0, sizeof ( loader ) ); + + /* update the glyph zone bounds */ + { + FT_GlyphLoader* gloader = FT_FACE_DRIVER(face)->glyph_loader; + + + loader.gloader = gloader; + + FT_GlyphLoader_Rewind( gloader ); + + tt_prepare_zone( &loader.zone, &gloader->base, 0, 0 ); + tt_prepare_zone( &loader.base, &gloader->base, 0, 0 ); + } + +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER + + if ( size ) + { + /* query new execution context */ + loader.exec = size->debug ? size->context : TT_New_Context( face ); + if ( !loader.exec ) + return TT_Err_Could_Not_Find_Context; + + TT_Load_Context( loader.exec, face, size ); + loader.instructions = loader.exec->glyphIns; + + /* load default graphics state - if needed */ + if ( size->GS.instruct_control & 2 ) + loader.exec->GS = tt_default_graphics_state; + } + +#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */ + + /* clear all outline flags, except the `owner' one */ + glyph->outline.flags = 0; + + if ( size && size->root.metrics.y_ppem < 24 ) + glyph->outline.flags |= ft_outline_high_precision; + + /* let's initialize the rest of our loader now */ + + loader.load_flags = load_flags; + + loader.face = (FT_Face)face; + loader.size = (FT_Size)size; + loader.glyph = (FT_GlyphSlot)glyph; + loader.stream = stream; + + loader.glyf_offset = FILE_Pos(); + +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER + + /* if the cvt program has disabled hinting, the argument */ + /* is ignored. */ + if ( size && ( size->GS.instruct_control & 1 ) ) + loader.load_flags |= FT_LOAD_NO_HINTING; + +#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */ + + /* Main loading loop */ + glyph->format = ft_glyph_format_outline; + glyph->num_subglyphs = 0; + error = load_truetype_glyph( &loader, glyph_index ); + if ( !error ) + compute_glyph_metrics( &loader, glyph_index ); + +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER + + if ( !size || !size->debug ) + TT_Done_Context( loader.exec ); + +#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */ + + Exit: + return error; + } + + +/* END */ diff --git a/src/freetype/truetype/ttgload.h b/src/freetype/truetype/ttgload.h new file mode 100644 index 0000000000..2f3e96b7b0 --- /dev/null +++ b/src/freetype/truetype/ttgload.h @@ -0,0 +1,69 @@ +/***************************************************************************/ +/* */ +/* ttgload.h */ +/* */ +/* TrueType Glyph Loader (specification). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef TTGLOAD_H +#define TTGLOAD_H + + +#ifdef FT_FLAT_COMPILE + +#include "ttobjs.h" + +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER +#include "ttinterp.h" +#endif + +#else /* FT_FLAT_COMPILE */ + +#include + +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER +#include +#endif + +#endif /* FT_FLAT_COMPILE */ + + +#ifdef __cplusplus + extern "C" { +#endif + + + LOCAL_DEF + void TT_Get_Metrics( TT_HoriHeader* header, + FT_UInt index, + FT_Short* bearing, + FT_UShort* advance ); + + LOCAL_DEF + void TT_Init_Glyph_Loading( TT_Face face ); + + LOCAL_DEF + FT_Error TT_Load_Glyph( TT_Size size, + TT_GlyphSlot glyph, + FT_UShort glyph_index, + FT_UInt load_flags ); + +#ifdef __cplusplus + } +#endif + +#endif /* TTGLOAD_H */ + + +/* END */ diff --git a/src/freetype/truetype/ttinterp.c b/src/freetype/truetype/ttinterp.c new file mode 100644 index 0000000000..9dc0c190a7 --- /dev/null +++ b/src/freetype/truetype/ttinterp.c @@ -0,0 +1,7544 @@ +/***************************************************************************/ +/* */ +/* ttinterp.c */ +/* */ +/* TrueType bytecode interpreter (body). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#include +#include +#include + + +#ifdef FT_FLAT_COMPILE + +#include "ttinterp.h" + +#else + +#include + +#endif + + +#include + + +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER + + +#define TT_MULFIX FT_MulFix +#define TT_MULDIV FT_MulDiv + +#define TT_INT64 FT_Int64 + + + /*************************************************************************/ + /* */ + /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ + /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ + /* messages during execution. */ + /* */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_ttinterp + +#undef NO_APPLE_PATENT +#define APPLE_THRESHOLD 0x4000000L + + /*************************************************************************/ + /* */ + /* In order to detect infinite loops in the code, we set up a counter */ + /* within the run loop. A single stroke of interpretation is now */ + /* limitet to a maximal number of opcodes defined below. */ + /* */ +#define MAX_RUNNABLE_OPCODES 1000000L + + + /*************************************************************************/ + /* */ + /* There are two kinds of implementations: */ + /* */ + /* a. static implementation */ + /* */ + /* The current execution context is a static variable, which fields */ + /* are accessed directly by the interpreter during execution. The */ + /* context is named `cur'. */ + /* */ + /* This version is non-reentrant, of course. */ + /* */ + /* b. indirect implementation */ + /* */ + /* The current execution context is passed to _each_ function as its */ + /* first argument, and each field is thus accessed indirectly. */ + /* */ + /* This version is fully re-entrant. */ + /* */ + /* The idea is that an indirect implementation may be slower to execute */ + /* on low-end processors that are used in some systems (like 386s or */ + /* even 486s). */ + /* */ + /* As a consequence, the indirect implementation is now the default, as */ + /* its performance costs can be considered negligible in our context. */ + /* Note, however, that we kept the same source with macros because: */ + /* */ + /* - The code is kept very close in design to the Pascal code used for */ + /* development. */ + /* */ + /* - It's much more readable that way! */ + /* */ + /* - It's still open to experimentation and tuning. */ + /* */ + /*************************************************************************/ + + +#ifndef TT_CONFIG_OPTION_STATIC_INTERPRETER /* indirect implementation */ + +#define CUR (*exc) /* see ttobjs.h */ + +#else /* static implementation */ + +#define CUR cur + + static + TT_ExecContextRec cur; /* static exec. context variable */ + + /* apparently, we have a _lot_ of direct indexing when accessing */ + /* the static `cur', which makes the code bigger (due to all the */ + /* four bytes addresses). */ + +#endif /* TT_CONFIG_OPTION_STATIC_INTERPRETER */ + + + /*************************************************************************/ + /* */ + /* The instruction argument stack. */ + /* */ +#define INS_ARG EXEC_OP_ FT_Long* args /* see ttobjs.h for EXEC_OP_ */ + + + /*************************************************************************/ + /* */ + /* This macro is used whenever `exec' is unused in a function, to avoid */ + /* stupid warnings from pedantic compilers. */ + /* */ +#define FT_UNUSED_EXEC FT_UNUSED( CUR ) + + + /*************************************************************************/ + /* */ + /* This macro is used whenever `args' is unused in a function, to avoid */ + /* stupid warnings from pedantic compilers. */ + /* */ +#define FT_UNUSED_ARG FT_UNUSED_EXEC; FT_UNUSED( args ) + + + /*************************************************************************/ + /* */ + /* The following macros hide the use of EXEC_ARG and EXEC_ARG_ to */ + /* increase readabilty of the code. */ + /* */ + /*************************************************************************/ + + +#define SKIP_Code() \ + SkipCode( EXEC_ARG ) + +#define GET_ShortIns() \ + GetShortIns( EXEC_ARG ) + +#define NORMalize( x, y, v ) \ + Normalize( EXEC_ARG_ x, y, v ) + +#define SET_SuperRound( scale, flags ) \ + SetSuperRound( EXEC_ARG_ scale, flags ) + +#define ROUND_None( d, c ) \ + Round_None( EXEC_ARG_ d, c ) + +#define INS_Goto_CodeRange( range, ip ) \ + Ins_Goto_CodeRange( EXEC_ARG_ range, ip ) + +#define CUR_Func_project( x, y ) \ + CUR.func_project( EXEC_ARG_ x, y ) + +#define CUR_Func_move( z, p, d ) \ + CUR.func_move( EXEC_ARG_ z, p, d ) + +#define CUR_Func_dualproj( x, y ) \ + CUR.func_dualproj( EXEC_ARG_ x, y ) + +#define CUR_Func_freeProj( x, y ) \ + CUR.func_freeProj( EXEC_ARG_ x, y ) + +#define CUR_Func_round( d, c ) \ + CUR.func_round( EXEC_ARG_ d, c ) + +#define CUR_Func_read_cvt( index ) \ + CUR.func_read_cvt( EXEC_ARG_ index ) + +#define CUR_Func_write_cvt( index, val ) \ + CUR.func_write_cvt( EXEC_ARG_ index, val ) + +#define CUR_Func_move_cvt( index, val ) \ + CUR.func_move_cvt( EXEC_ARG_ index, val ) + +#define CURRENT_Ratio() \ + Current_Ratio( EXEC_ARG ) + +#define CURRENT_Ppem() \ + Current_Ppem( EXEC_ARG ) + +#define CUR_Ppem() \ + Cur_PPEM( EXEC_ARG ) + +#define CALC_Length() \ + Calc_Length( EXEC_ARG ) + +#define INS_SxVTL( a, b, c, d ) \ + Ins_SxVTL( EXEC_ARG_ a, b, c, d ) + +#define COMPUTE_Funcs() \ + Compute_Funcs( EXEC_ARG ) + +#define COMPUTE_Round( a ) \ + Compute_Round( EXEC_ARG_ a ) + +#define COMPUTE_Point_Displacement( a, b, c, d ) \ + Compute_Point_Displacement( EXEC_ARG_ a, b, c, d ) + +#define MOVE_Zp2_Point( a, b, c, t ) \ + Move_Zp2_Point( EXEC_ARG_ a, b, c, t ) + + + /*************************************************************************/ + /* */ + /* Instruction dispatch function, as used by the interpreter. */ + /* */ + typedef void (*TInstruction_Function)( INS_ARG ); + + + /*************************************************************************/ + /* */ + /* A simple bounds-checking macro. */ + /* */ +#define BOUNDS( x, n ) ( (FT_UInt)(x) >= (FT_UInt)(n) ) + + +#undef SUCCESS +#define SUCCESS 0 + +#undef FAILURE +#define FAILURE 1 + + + /*************************************************************************/ + /* */ + /* CODERANGE FUNCTIONS */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Goto_CodeRange */ + /* */ + /* */ + /* Switches to a new code range (updates the code related elements in */ + /* `exec', and `IP'). */ + /* */ + /* */ + /* range :: The new execution code range. */ + /* */ + /* IP :: The new IP in the new code range. */ + /* */ + /* */ + /* exec :: The target execution context. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + LOCAL_FUNC + FT_Error TT_Goto_CodeRange( TT_ExecContext exec, + FT_Int range, + FT_Long IP ) + { + TT_CodeRange* coderange; + + + FT_Assert( range >= 1 && range <= 3 ); + + coderange = &exec->codeRangeTable[range - 1]; + + FT_Assert( coderange->base != NULL ); + + /* NOTE: Because the last instruction of a program may be a CALL */ + /* which will return to the first byte *after* the code */ + /* range, we test for IP <= Size instead of IP < Size. */ + /* */ + FT_Assert( (FT_ULong)IP <= coderange->size ); + + exec->code = coderange->base; + exec->codeSize = coderange->size; + exec->IP = IP; + exec->curRange = range; + + return TT_Err_Ok; + } + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Set_CodeRange */ + /* */ + /* */ + /* Sets a code range. */ + /* */ + /* */ + /* range :: The code range index. */ + /* */ + /* base :: The new code base. */ + /* */ + /* length :: The range size in bytes. */ + /* */ + /* */ + /* exec :: The target execution context. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + LOCAL_FUNC + FT_Error TT_Set_CodeRange( TT_ExecContext exec, + FT_Int range, + void* base, + FT_Long length ) + { + FT_Assert( range >= 1 && range <= 3 ); + + exec->codeRangeTable[range - 1].base = (FT_Byte*)base; + exec->codeRangeTable[range - 1].size = length; + + return TT_Err_Ok; + } + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Clear_CodeRange */ + /* */ + /* */ + /* Clears a code range. */ + /* */ + /* */ + /* range :: The code range index. */ + /* */ + /* */ + /* exec :: The target execution context. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* Does not set the Error variable. */ + /* */ + LOCAL_FUNC + FT_Error TT_Clear_CodeRange( TT_ExecContext exec, + FT_Int range ) + { + FT_Assert( range >= 1 && range <= 3 ); + + exec->codeRangeTable[range - 1].base = NULL; + exec->codeRangeTable[range - 1].size = 0; + + return TT_Err_Ok; + } + + + /*************************************************************************/ + /* */ + /* EXECUTION CONTEXT ROUTINES */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Destroy_Context */ + /* */ + /* */ + /* Destroys a given context. */ + /* */ + /* */ + /* exec :: A handle to the target execution context. */ + /* */ + /* memory :: A handle to the parent memory object. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* Only the glyph loader and debugger should call this function. */ + /* */ + LOCAL_FUNC + FT_Error TT_Destroy_Context( TT_ExecContext exec, + FT_Memory memory ) + { + /* free composite load stack */ + FREE( exec->loadStack ); + exec->loadSize = 0; + + /* points zone */ + exec->maxPoints = 0; + exec->maxContours = 0; + + /* free stack */ + FREE( exec->stack ); + exec->stackSize = 0; + + /* free call stack */ + FREE( exec->callStack ); + exec->callSize = 0; + exec->callTop = 0; + + /* free glyph code range */ + FREE( exec->glyphIns ); + exec->glyphSize = 0; + + exec->size = NULL; + exec->face = NULL; + + FREE( exec ); + return TT_Err_Ok; + } + + + /*************************************************************************/ + /* */ + /* */ + /* Init_Context */ + /* */ + /* */ + /* Initializes a context object. */ + /* */ + /* */ + /* memory :: A handle to the parent memory object. */ + /* */ + /* face :: A handle to the source TrueType face object. */ + /* */ + /* */ + /* exec :: A handle to the target execution context. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + static + FT_Error Init_Context( TT_ExecContext exec, + TT_Face face, + FT_Memory memory ) + { + FT_Error error; + + + FT_TRACE1(( "Init_Context: new object at 0x%08p, parent = 0x%08p\n", + exec, face )); + + exec->memory = memory; + exec->callSize = 32; + + if ( ALLOC_ARRAY( exec->callStack, exec->callSize, TT_CallRec ) ) + goto Fail_Memory; + + /* all values in the context are set to 0 already, but this is */ + /* here as a remainder */ + exec->maxPoints = 0; + exec->maxContours = 0; + + exec->stackSize = 0; + exec->loadSize = 0; + exec->glyphSize = 0; + + exec->stack = NULL; + exec->loadStack = NULL; + exec->glyphIns = NULL; + + exec->face = face; + exec->size = NULL; + + return TT_Err_Ok; + + Fail_Memory: + FT_ERROR(( "Init_Context: not enough memory for 0x%08lx\n", + (FT_Long)exec )); + TT_Destroy_Context( exec, memory ); + + return error; + } + + + /*************************************************************************/ + /* */ + /* */ + /* Update_Max */ + /* */ + /* */ + /* Checks the size of a buffer and reallocates it if necessary. */ + /* */ + /* */ + /* memory :: A handle to the parent memory object. */ + /* */ + /* multiplier :: The size in bytes of each element in the buffer. */ + /* */ + /* new_max :: The new capacity (size) of the buffer. */ + /* */ + /* */ + /* size :: The address of the buffer's current size expressed */ + /* in elements. */ + /* */ + /* buff :: The address of the buffer base pointer. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + static + FT_Error Update_Max( FT_Memory memory, + FT_ULong* size, + FT_Long multiplier, + void** buff, + FT_ULong new_max ) + { + FT_Error error; + + + if ( *size < new_max ) + { + FREE( *buff ); + if ( ALLOC( *buff, new_max * multiplier ) ) + return error; + *size = new_max; + } + + return TT_Err_Ok; + } + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Load_Context */ + /* */ + /* */ + /* Prepare an execution context for glyph hinting. */ + /* */ + /* */ + /* face :: A handle to the source face object. */ + /* */ + /* size :: A handle to the source size object. */ + /* */ + /* */ + /* exec :: A handle to the target execution context. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* Only the glyph loader and debugger should call this function. */ + /* */ + LOCAL_FUNC + FT_Error TT_Load_Context( TT_ExecContext exec, + TT_Face face, + TT_Size size ) + { + FT_Int i; + FT_ULong tmp; + TT_MaxProfile* maxp; + FT_Error error; + + + exec->face = face; + maxp = &face->max_profile; + exec->size = size; + + if ( size ) + { + exec->numFDefs = size->num_function_defs; + exec->maxFDefs = size->max_function_defs; + exec->numIDefs = size->num_instruction_defs; + exec->maxIDefs = size->max_instruction_defs; + exec->FDefs = size->function_defs; + exec->IDefs = size->instruction_defs; + exec->tt_metrics = size->ttmetrics; + exec->metrics = size->root.metrics; + + exec->maxFunc = size->max_func; + exec->maxIns = size->max_ins; + + for ( i = 0; i < TT_MAX_CODE_RANGES; i++ ) + exec->codeRangeTable[i] = size->codeRangeTable[i]; + + /* set graphics state */ + exec->GS = size->GS; + + exec->cvtSize = size->cvt_size; + exec->cvt = size->cvt; + + exec->storeSize = size->storage_size; + exec->storage = size->storage; + + exec->twilight = size->twilight; + } + + error = Update_Max( exec->memory, + &exec->loadSize, + sizeof ( TT_SubGlyphRec ), + (void**)&exec->loadStack, + exec->face->max_components + 1 ); + if ( error ) + return error; + + /* XXX: We reserve a little more elements on the stack to deal safely */ + /* with broken fonts like arialbs, courbs, timesbs, etc. */ + tmp = exec->stackSize; + error = Update_Max( exec->memory, + &tmp, + sizeof ( FT_F26Dot6 ), + (void**)&exec->stack, + maxp->maxStackElements + 32 ); + exec->stackSize = (FT_UInt)tmp; + if ( error ) + return error; + + tmp = exec->glyphSize; + error = Update_Max( exec->memory, + &tmp, + sizeof ( FT_Byte ), + (void**)&exec->glyphIns, + maxp->maxSizeOfInstructions ); + exec->glyphSize = (FT_UShort)tmp; + if ( error ) + return error; + + exec->pts.n_points = 0; + exec->pts.n_contours = 0; + + exec->instruction_trap = FALSE; + + return TT_Err_Ok; + } + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Save_Context */ + /* */ + /* */ + /* Saves the code ranges in a `size' object. */ + /* */ + /* */ + /* exec :: A handle to the source execution context. */ + /* */ + /* */ + /* size :: A handle to the target size object. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* Only the glyph loader and debugger should call this function. */ + /* */ + LOCAL_FUNC + FT_Error TT_Save_Context( TT_ExecContext exec, + TT_Size size ) + { + FT_Int i; + + + /* XXXX: Will probably disappear soon with all the code range */ + /* management, which is now rather obsolete. */ + /* */ + size->num_function_defs = exec->numFDefs; + size->num_instruction_defs = exec->numIDefs; + + size->max_func = exec->maxFunc; + size->max_ins = exec->maxIns; + + for ( i = 0; i < TT_MAX_CODE_RANGES; i++ ) + size->codeRangeTable[i] = exec->codeRangeTable[i]; + + return TT_Err_Ok; + } + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Run_Context */ + /* */ + /* */ + /* Executes one or more instructions in the execution context. */ + /* */ + /* */ + /* debug :: A Boolean flag. If set, the function sets some internal */ + /* variables and returns immediately, otherwise TT_RunIns() */ + /* is called. */ + /* */ + /* This is commented out currently. */ + /* */ + /* */ + /* exec :: A handle to the target execution context. */ + /* */ + /* */ + /* TrueTyoe error code. 0 means success. */ + /* */ + /* */ + /* Only the glyph loader and debugger should call this function. */ + /* */ + LOCAL_FUNC + FT_Error TT_Run_Context( TT_ExecContext exec, + FT_Bool debug ) + { + FT_Error error; + + + if ( ( error = TT_Goto_CodeRange( exec, tt_coderange_glyph, 0 ) ) + != TT_Err_Ok ) + return error; + + exec->zp0 = exec->pts; + exec->zp1 = exec->pts; + exec->zp2 = exec->pts; + + exec->GS.gep0 = 1; + exec->GS.gep1 = 1; + exec->GS.gep2 = 1; + + exec->GS.projVector.x = 0x4000; + exec->GS.projVector.y = 0x0000; + + exec->GS.freeVector = exec->GS.projVector; + exec->GS.dualVector = exec->GS.projVector; + + exec->GS.round_state = 1; + exec->GS.loop = 1; + + /* some glyphs leave something on the stack. so we clean it */ + /* before a new execution. */ + exec->top = 0; + exec->callTop = 0; + +#if 1 + FT_UNUSED( debug ); + + return exec->face->interpreter( exec ); +#else + if ( !debug ) + return TT_RunIns( exec ); + else + return TT_Err_Ok; +#endif + } + + + const TT_GraphicsState tt_default_graphics_state = + { + 0, 0, 0, + { 0x4000, 0 }, + { 0x4000, 0 }, + { 0x4000, 0 }, + 1, 64, 1, + TRUE, 68, 0, 0, 9, 3, + 0, FALSE, 2, 1, 1, 1 + }; + + + /*************************************************************************/ + /* */ + /* */ + /* TT_New_Context */ + /* */ + /* */ + /* Queries the face context for a given font. Note that there is */ + /* now a _single_ execution context in the TrueType driver which is */ + /* shared among faces. */ + /* */ + /* */ + /* face :: A handle to the source face object. */ + /* */ + /* */ + /* A handle to the execution context. Initialized for `face'. */ + /* */ + /* */ + /* Only the glyph loader and debugger should call this function. */ + /* */ + FT_EXPORT_FUNC( TT_ExecContext ) TT_New_Context( TT_Face face ) + { + TT_Driver driver; + TT_ExecContext exec; + FT_Memory memory; + + + if ( !face ) + return 0; + + driver = (TT_Driver)face->root.driver; + + memory = driver->root.root.memory; + exec = driver->context; + + if ( !driver->context ) + { + FT_Error error; + + + /* allocate object */ + if ( ALLOC( exec, sizeof ( *exec ) ) ) + goto Exit; + + /* initialize it */ + error = Init_Context( exec, face, memory ); + if ( error ) + goto Fail; + + /* store it into the driver */ + driver->context = exec; + } + + Exit: + return driver->context; + + Fail: + FREE( exec ); + + return 0; + } + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Done_Context */ + /* */ + /* */ + /* Discards an execution context. */ + /* */ + /* */ + /* exec :: A handle to the target execution context. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* Only the glyph loader and debugger should call this function. */ + /* */ + LOCAL_FUNC + FT_Error TT_Done_Context( TT_ExecContext exec ) + { + /* Nothing at all for now */ + FT_UNUSED( exec ); + + return TT_Err_Ok; + } + + +#ifdef FT_CONFIG_OPTION_OLD_CALCS + + static FT_F26Dot6 Norm( FT_F26Dot6 X, + FT_F26Dot6 Y ) + { + TT_INT64 T1, T2; + + + MUL_64( X, X, T1 ); + MUL_64( Y, Y, T2 ); + + ADD_64( T1, T2, T1 ); + + return (FT_F26Dot6)SQRT_64( T1 ); + } + +#endif /* FT_CONFIG_OPTION_OLD_CALCS */ + + + /*************************************************************************/ + /* */ + /* Before an opcode is executed, the interpreter verifies that there are */ + /* enough arguments on the stack, with the help of the Pop_Push_Count */ + /* table. */ + /* */ + /* For each opcode, the first column gives the number of arguments that */ + /* are popped from the stack; the second one gives the number of those */ + /* that are pushed in result. */ + /* */ + /* Note that for opcodes with a varying number of parameters, either 0 */ + /* or 1 arg is verified before execution, depending on the nature of the */ + /* instruction: */ + /* */ + /* - if the number of arguments is given by the bytecode stream or the */ + /* loop variable, 0 is chosen. */ + /* */ + /* - if the first argument is a count n that is followed by arguments */ + /* a1 .. an, then 1 is chosen. */ + /* */ + /*************************************************************************/ + + +#undef PACK +#define PACK( x, y ) ( ( x << 4 ) | y ) + + + static + const FT_Byte Pop_Push_Count[256] = + { + /* opcodes are gathered in groups of 16 */ + /* please keep the spaces as they are */ + + /* SVTCA y */ PACK( 0, 0 ), + /* SVTCA x */ PACK( 0, 0 ), + /* SPvTCA y */ PACK( 0, 0 ), + /* SPvTCA x */ PACK( 0, 0 ), + /* SFvTCA y */ PACK( 0, 0 ), + /* SFvTCA x */ PACK( 0, 0 ), + /* SPvTL // */ PACK( 2, 0 ), + /* SPvTL + */ PACK( 2, 0 ), + /* SFvTL // */ PACK( 2, 0 ), + /* SFvTL + */ PACK( 2, 0 ), + /* SPvFS */ PACK( 2, 0 ), + /* SFvFS */ PACK( 2, 0 ), + /* GPV */ PACK( 0, 2 ), + /* GFV */ PACK( 0, 2 ), + /* SFvTPv */ PACK( 0, 0 ), + /* ISECT */ PACK( 5, 0 ), + + /* SRP0 */ PACK( 1, 0 ), + /* SRP1 */ PACK( 1, 0 ), + /* SRP2 */ PACK( 1, 0 ), + /* SZP0 */ PACK( 1, 0 ), + /* SZP1 */ PACK( 1, 0 ), + /* SZP2 */ PACK( 1, 0 ), + /* SZPS */ PACK( 1, 0 ), + /* SLOOP */ PACK( 1, 0 ), + /* RTG */ PACK( 0, 0 ), + /* RTHG */ PACK( 0, 0 ), + /* SMD */ PACK( 1, 0 ), + /* ELSE */ PACK( 0, 0 ), + /* JMPR */ PACK( 1, 0 ), + /* SCvTCi */ PACK( 1, 0 ), + /* SSwCi */ PACK( 1, 0 ), + /* SSW */ PACK( 1, 0 ), + + /* DUP */ PACK( 1, 2 ), + /* POP */ PACK( 1, 0 ), + /* CLEAR */ PACK( 0, 0 ), + /* SWAP */ PACK( 2, 2 ), + /* DEPTH */ PACK( 0, 1 ), + /* CINDEX */ PACK( 1, 1 ), + /* MINDEX */ PACK( 1, 0 ), + /* AlignPTS */ PACK( 2, 0 ), + /* INS_$28 */ PACK( 0, 0 ), + /* UTP */ PACK( 1, 0 ), + /* LOOPCALL */ PACK( 2, 0 ), + /* CALL */ PACK( 1, 0 ), + /* FDEF */ PACK( 1, 0 ), + /* ENDF */ PACK( 0, 0 ), + /* MDAP[0] */ PACK( 1, 0 ), + /* MDAP[1] */ PACK( 1, 0 ), + + /* IUP[0] */ PACK( 0, 0 ), + /* IUP[1] */ PACK( 0, 0 ), + /* SHP[0] */ PACK( 0, 0 ), + /* SHP[1] */ PACK( 0, 0 ), + /* SHC[0] */ PACK( 1, 0 ), + /* SHC[1] */ PACK( 1, 0 ), + /* SHZ[0] */ PACK( 1, 0 ), + /* SHZ[1] */ PACK( 1, 0 ), + /* SHPIX */ PACK( 1, 0 ), + /* IP */ PACK( 0, 0 ), + /* MSIRP[0] */ PACK( 2, 0 ), + /* MSIRP[1] */ PACK( 2, 0 ), + /* AlignRP */ PACK( 0, 0 ), + /* RTDG */ PACK( 0, 0 ), + /* MIAP[0] */ PACK( 2, 0 ), + /* MIAP[1] */ PACK( 2, 0 ), + + /* NPushB */ PACK( 0, 0 ), + /* NPushW */ PACK( 0, 0 ), + /* WS */ PACK( 2, 0 ), + /* RS */ PACK( 1, 1 ), + /* WCvtP */ PACK( 2, 0 ), + /* RCvt */ PACK( 1, 1 ), + /* GC[0] */ PACK( 1, 1 ), + /* GC[1] */ PACK( 1, 1 ), + /* SCFS */ PACK( 2, 0 ), + /* MD[0] */ PACK( 2, 1 ), + /* MD[1] */ PACK( 2, 1 ), + /* MPPEM */ PACK( 0, 1 ), + /* MPS */ PACK( 0, 1 ), + /* FlipON */ PACK( 0, 0 ), + /* FlipOFF */ PACK( 0, 0 ), + /* DEBUG */ PACK( 1, 0 ), + + /* LT */ PACK( 2, 1 ), + /* LTEQ */ PACK( 2, 1 ), + /* GT */ PACK( 2, 1 ), + /* GTEQ */ PACK( 2, 1 ), + /* EQ */ PACK( 2, 1 ), + /* NEQ */ PACK( 2, 1 ), + /* ODD */ PACK( 1, 1 ), + /* EVEN */ PACK( 1, 1 ), + /* IF */ PACK( 1, 0 ), + /* EIF */ PACK( 0, 0 ), + /* AND */ PACK( 2, 1 ), + /* OR */ PACK( 2, 1 ), + /* NOT */ PACK( 1, 1 ), + /* DeltaP1 */ PACK( 1, 0 ), + /* SDB */ PACK( 1, 0 ), + /* SDS */ PACK( 1, 0 ), + + /* ADD */ PACK( 2, 1 ), + /* SUB */ PACK( 2, 1 ), + /* DIV */ PACK( 2, 1 ), + /* MUL */ PACK( 2, 1 ), + /* ABS */ PACK( 1, 1 ), + /* NEG */ PACK( 1, 1 ), + /* FLOOR */ PACK( 1, 1 ), + /* CEILING */ PACK( 1, 1 ), + /* ROUND[0] */ PACK( 1, 1 ), + /* ROUND[1] */ PACK( 1, 1 ), + /* ROUND[2] */ PACK( 1, 1 ), + /* ROUND[3] */ PACK( 1, 1 ), + /* NROUND[0] */ PACK( 1, 1 ), + /* NROUND[1] */ PACK( 1, 1 ), + /* NROUND[2] */ PACK( 1, 1 ), + /* NROUND[3] */ PACK( 1, 1 ), + + /* WCvtF */ PACK( 2, 0 ), + /* DeltaP2 */ PACK( 1, 0 ), + /* DeltaP3 */ PACK( 1, 0 ), + /* DeltaCn[0] */ PACK( 1, 0 ), + /* DeltaCn[1] */ PACK( 1, 0 ), + /* DeltaCn[2] */ PACK( 1, 0 ), + /* SROUND */ PACK( 1, 0 ), + /* S45Round */ PACK( 1, 0 ), + /* JROT */ PACK( 2, 0 ), + /* JROF */ PACK( 2, 0 ), + /* ROFF */ PACK( 0, 0 ), + /* INS_$7B */ PACK( 0, 0 ), + /* RUTG */ PACK( 0, 0 ), + /* RDTG */ PACK( 0, 0 ), + /* SANGW */ PACK( 1, 0 ), + /* AA */ PACK( 1, 0 ), + + /* FlipPT */ PACK( 0, 0 ), + /* FlipRgON */ PACK( 2, 0 ), + /* FlipRgOFF */ PACK( 2, 0 ), + /* INS_$83 */ PACK( 0, 0 ), + /* INS_$84 */ PACK( 0, 0 ), + /* ScanCTRL */ PACK( 1, 0 ), + /* SDVPTL[0] */ PACK( 2, 0 ), + /* SDVPTL[1] */ PACK( 2, 0 ), + /* GetINFO */ PACK( 1, 1 ), + /* IDEF */ PACK( 1, 0 ), + /* ROLL */ PACK( 3, 3 ), + /* MAX */ PACK( 2, 1 ), + /* MIN */ PACK( 2, 1 ), + /* ScanTYPE */ PACK( 1, 0 ), + /* InstCTRL */ PACK( 2, 0 ), + /* INS_$8F */ PACK( 0, 0 ), + + /* INS_$90 */ PACK( 0, 0 ), + /* INS_$91 */ PACK( 0, 0 ), + /* INS_$92 */ PACK( 0, 0 ), + /* INS_$93 */ PACK( 0, 0 ), + /* INS_$94 */ PACK( 0, 0 ), + /* INS_$95 */ PACK( 0, 0 ), + /* INS_$96 */ PACK( 0, 0 ), + /* INS_$97 */ PACK( 0, 0 ), + /* INS_$98 */ PACK( 0, 0 ), + /* INS_$99 */ PACK( 0, 0 ), + /* INS_$9A */ PACK( 0, 0 ), + /* INS_$9B */ PACK( 0, 0 ), + /* INS_$9C */ PACK( 0, 0 ), + /* INS_$9D */ PACK( 0, 0 ), + /* INS_$9E */ PACK( 0, 0 ), + /* INS_$9F */ PACK( 0, 0 ), + + /* INS_$A0 */ PACK( 0, 0 ), + /* INS_$A1 */ PACK( 0, 0 ), + /* INS_$A2 */ PACK( 0, 0 ), + /* INS_$A3 */ PACK( 0, 0 ), + /* INS_$A4 */ PACK( 0, 0 ), + /* INS_$A5 */ PACK( 0, 0 ), + /* INS_$A6 */ PACK( 0, 0 ), + /* INS_$A7 */ PACK( 0, 0 ), + /* INS_$A8 */ PACK( 0, 0 ), + /* INS_$A9 */ PACK( 0, 0 ), + /* INS_$AA */ PACK( 0, 0 ), + /* INS_$AB */ PACK( 0, 0 ), + /* INS_$AC */ PACK( 0, 0 ), + /* INS_$AD */ PACK( 0, 0 ), + /* INS_$AE */ PACK( 0, 0 ), + /* INS_$AF */ PACK( 0, 0 ), + + /* PushB[0] */ PACK( 0, 1 ), + /* PushB[1] */ PACK( 0, 2 ), + /* PushB[2] */ PACK( 0, 3 ), + /* PushB[3] */ PACK( 0, 4 ), + /* PushB[4] */ PACK( 0, 5 ), + /* PushB[5] */ PACK( 0, 6 ), + /* PushB[6] */ PACK( 0, 7 ), + /* PushB[7] */ PACK( 0, 8 ), + /* PushW[0] */ PACK( 0, 1 ), + /* PushW[1] */ PACK( 0, 2 ), + /* PushW[2] */ PACK( 0, 3 ), + /* PushW[3] */ PACK( 0, 4 ), + /* PushW[4] */ PACK( 0, 5 ), + /* PushW[5] */ PACK( 0, 6 ), + /* PushW[6] */ PACK( 0, 7 ), + /* PushW[7] */ PACK( 0, 8 ), + + /* MDRP[00] */ PACK( 1, 0 ), + /* MDRP[01] */ PACK( 1, 0 ), + /* MDRP[02] */ PACK( 1, 0 ), + /* MDRP[03] */ PACK( 1, 0 ), + /* MDRP[04] */ PACK( 1, 0 ), + /* MDRP[05] */ PACK( 1, 0 ), + /* MDRP[06] */ PACK( 1, 0 ), + /* MDRP[07] */ PACK( 1, 0 ), + /* MDRP[08] */ PACK( 1, 0 ), + /* MDRP[09] */ PACK( 1, 0 ), + /* MDRP[10] */ PACK( 1, 0 ), + /* MDRP[11] */ PACK( 1, 0 ), + /* MDRP[12] */ PACK( 1, 0 ), + /* MDRP[13] */ PACK( 1, 0 ), + /* MDRP[14] */ PACK( 1, 0 ), + /* MDRP[15] */ PACK( 1, 0 ), + + /* MDRP[16] */ PACK( 1, 0 ), + /* MDRP[17] */ PACK( 1, 0 ), + /* MDRP[18] */ PACK( 1, 0 ), + /* MDRP[19] */ PACK( 1, 0 ), + /* MDRP[20] */ PACK( 1, 0 ), + /* MDRP[21] */ PACK( 1, 0 ), + /* MDRP[22] */ PACK( 1, 0 ), + /* MDRP[23] */ PACK( 1, 0 ), + /* MDRP[24] */ PACK( 1, 0 ), + /* MDRP[25] */ PACK( 1, 0 ), + /* MDRP[26] */ PACK( 1, 0 ), + /* MDRP[27] */ PACK( 1, 0 ), + /* MDRP[28] */ PACK( 1, 0 ), + /* MDRP[29] */ PACK( 1, 0 ), + /* MDRP[30] */ PACK( 1, 0 ), + /* MDRP[31] */ PACK( 1, 0 ), + + /* MIRP[00] */ PACK( 2, 0 ), + /* MIRP[01] */ PACK( 2, 0 ), + /* MIRP[02] */ PACK( 2, 0 ), + /* MIRP[03] */ PACK( 2, 0 ), + /* MIRP[04] */ PACK( 2, 0 ), + /* MIRP[05] */ PACK( 2, 0 ), + /* MIRP[06] */ PACK( 2, 0 ), + /* MIRP[07] */ PACK( 2, 0 ), + /* MIRP[08] */ PACK( 2, 0 ), + /* MIRP[09] */ PACK( 2, 0 ), + /* MIRP[10] */ PACK( 2, 0 ), + /* MIRP[11] */ PACK( 2, 0 ), + /* MIRP[12] */ PACK( 2, 0 ), + /* MIRP[13] */ PACK( 2, 0 ), + /* MIRP[14] */ PACK( 2, 0 ), + /* MIRP[15] */ PACK( 2, 0 ), + + /* MIRP[16] */ PACK( 2, 0 ), + /* MIRP[17] */ PACK( 2, 0 ), + /* MIRP[18] */ PACK( 2, 0 ), + /* MIRP[19] */ PACK( 2, 0 ), + /* MIRP[20] */ PACK( 2, 0 ), + /* MIRP[21] */ PACK( 2, 0 ), + /* MIRP[22] */ PACK( 2, 0 ), + /* MIRP[23] */ PACK( 2, 0 ), + /* MIRP[24] */ PACK( 2, 0 ), + /* MIRP[25] */ PACK( 2, 0 ), + /* MIRP[26] */ PACK( 2, 0 ), + /* MIRP[27] */ PACK( 2, 0 ), + /* MIRP[28] */ PACK( 2, 0 ), + /* MIRP[29] */ PACK( 2, 0 ), + /* MIRP[30] */ PACK( 2, 0 ), + /* MIRP[31] */ PACK( 2, 0 ) + }; + + + static + const FT_Char opcode_length[256] = + { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + -1,-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 3, 4, 5, 6, 7, 8, 9, 3, 5, 7, 9, 11,13,15,17, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 + }; + + static + const FT_Vector Null_Vector = {0,0}; + + +#undef PACK + + +#undef NULL_Vector +#define NULL_Vector (FT_Vector*)&Null_Vector + + + /*************************************************************************/ + /* */ + /* */ + /* Current_Ratio */ + /* */ + /* */ + /* Returns the current aspect ratio scaling factor depending on the */ + /* projection vector's state and device resolutions. */ + /* */ + /* */ + /* The aspect ratio in 16.16 format, always <= 1.0 . */ + /* */ + static + FT_Long Current_Ratio( EXEC_OP ) + { + if ( CUR.tt_metrics.ratio ) + return CUR.tt_metrics.ratio; + + if ( CUR.GS.projVector.y == 0 ) + CUR.tt_metrics.ratio = CUR.tt_metrics.x_ratio; + + else if ( CUR.GS.projVector.x == 0 ) + CUR.tt_metrics.ratio = CUR.tt_metrics.y_ratio; + + else + { + FT_Long x, y; + + +#ifdef FT_CONFIG_OPTION_OLD_CALCS + + x = TT_MULDIV( CUR.GS.projVector.x, CUR.tt_metrics.x_ratio, 0x4000 ); + y = TT_MULDIV( CUR.GS.projVector.y, CUR.tt_metrics.y_ratio, 0x4000 ); + CUR.tt_metrics.ratio = Norm( x, y ); + +#else + + x = TT_MULDIV( CUR.GS.projVector.x, CUR.tt_metrics.x_ratio, 0x8000 ); + y = TT_MULDIV( CUR.GS.projVector.y, CUR.tt_metrics.y_ratio, 0x8000 ); + CUR.tt_metrics.ratio = FT_Sqrt32( x * x + y * y ) << 1; + +#endif /* FT_CONFIG_OPTION_OLD_CALCS */ + + } + + return CUR.tt_metrics.ratio; + } + + + static + FT_Long Current_Ppem( EXEC_OP ) + { + return TT_MULFIX( CUR.tt_metrics.ppem, CURRENT_Ratio() ); + } + + + /*************************************************************************/ + /* */ + /* Functions related to the control value table (CVT). */ + /* */ + /*************************************************************************/ + + + static + FT_F26Dot6 Read_CVT( EXEC_OP_ FT_ULong index ) + { + return CUR.cvt[index]; + } + + + static + FT_F26Dot6 Read_CVT_Stretched( EXEC_OP_ FT_ULong index ) + { + return TT_MULFIX( CUR.cvt[index], CURRENT_Ratio() ); + } + + + static + void Write_CVT( EXEC_OP_ FT_ULong index, + FT_F26Dot6 value ) + { + CUR.cvt[index] = value; + } + + + static + void Write_CVT_Stretched( EXEC_OP_ FT_ULong index, + FT_F26Dot6 value ) + { + CUR.cvt[index] = FT_DivFix( value, CURRENT_Ratio() ); + } + + + static + void Move_CVT( EXEC_OP_ FT_ULong index, + FT_F26Dot6 value ) + { + CUR.cvt[index] += value; + } + + + static + void Move_CVT_Stretched( EXEC_OP_ FT_ULong index, + FT_F26Dot6 value ) + { + CUR.cvt[index] += FT_DivFix( value, CURRENT_Ratio() ); + } + + + /*************************************************************************/ + /* */ + /* */ + /* GetShortIns */ + /* */ + /* */ + /* Returns a short integer taken from the instruction stream at */ + /* address IP. */ + /* */ + /* */ + /* Short read at code[IP]. */ + /* */ + /* */ + /* This one could become a macro. */ + /* */ + static FT_Short GetShortIns( EXEC_OP ) + { + /* Reading a byte stream so there is no endianess (DaveP) */ + CUR.IP += 2; + return (FT_Short)( ( CUR.code[CUR.IP - 2] << 8 ) + + CUR.code[CUR.IP - 1] ); + } + + + /*************************************************************************/ + /* */ + /* */ + /* Ins_Goto_CodeRange */ + /* */ + /* */ + /* Goes to a certain code range in the instruction stream. */ + /* */ + /* */ + /* aRange :: The index of the code range. */ + /* */ + /* aIP :: The new IP address in the code range. */ + /* */ + /* */ + /* SUCCESS or FAILURE. */ + /* */ + static + FT_Bool Ins_Goto_CodeRange( EXEC_OP_ FT_Int aRange, + FT_ULong aIP ) + { + TT_CodeRange* range; + + + if ( aRange < 1 || aRange > 3 ) + { + CUR.error = TT_Err_Bad_Argument; + return FAILURE; + } + + range = &CUR.codeRangeTable[aRange - 1]; + + if ( range->base == NULL ) /* invalid coderange */ + { + CUR.error = TT_Err_Invalid_CodeRange; + return FAILURE; + } + + /* NOTE: Because the last instruction of a program may be a CALL */ + /* which will return to the first byte *after* the code */ + /* range, we test for AIP <= Size, instead of AIP < Size. */ + + if ( aIP > range->size ) + { + CUR.error = TT_Err_Code_Overflow; + return FAILURE; + } + + CUR.code = range->base; + CUR.codeSize = range->size; + CUR.IP = aIP; + CUR.curRange = aRange; + + return SUCCESS; + } + + + /*************************************************************************/ + /* */ + /* */ + /* Direct_Move */ + /* */ + /* */ + /* Moves a point by a given distance along the freedom vector. The */ + /* point will be `touched'. */ + /* */ + /* */ + /* point :: The index of the point to move. */ + /* */ + /* distance :: The distance to apply. */ + /* */ + /* */ + /* zone :: The affected glyph zone. */ + /* */ + static + void Direct_Move( EXEC_OP_ TT_GlyphZone* zone, + FT_UShort point, + FT_F26Dot6 distance ) + { + FT_F26Dot6 v; + + + v = CUR.GS.freeVector.x; + + if ( v != 0 ) + { + +#ifdef NO_APPLE_PATENT + + if ( ABS( CUR.F_dot_P ) > APPLE_THRESHOLD ) + zone->cur[point].x += distance; + +#else + + zone->cur[point].x += TT_MULDIV( distance, + v * 0x10000L, + CUR.F_dot_P ); + +#endif + + zone->tags[point] |= FT_Curve_Tag_Touch_X; + } + + v = CUR.GS.freeVector.y; + + if ( v != 0 ) + { + +#ifdef NO_APPLE_PATENT + + if ( ABS( CUR.F_dot_P ) > APPLE_THRESHOLD ) + zone->cur[point].y += distance; + +#else + + zone->cur[point].y += TT_MULDIV( distance, + v * 0x10000L, + CUR.F_dot_P ); + +#endif + + zone->tags[point] |= FT_Curve_Tag_Touch_Y; + } + } + + + /*************************************************************************/ + /* */ + /* Special versions of Direct_Move() */ + /* */ + /* The following versions are used whenever both vectors are both */ + /* along one of the coordinate unit vectors, i.e. in 90% of the cases. */ + /* */ + /*************************************************************************/ + + + static + void Direct_Move_X( EXEC_OP_ TT_GlyphZone* zone, + FT_UShort point, + FT_F26Dot6 distance ) + { + FT_UNUSED_EXEC; + + zone->cur[point].x += distance; + zone->tags[point] |= FT_Curve_Tag_Touch_X; + } + + + static + void Direct_Move_Y( EXEC_OP_ TT_GlyphZone* zone, + FT_UShort point, + FT_F26Dot6 distance ) + { + FT_UNUSED_EXEC; + + zone->cur[point].y += distance; + zone->tags[point] |= FT_Curve_Tag_Touch_Y; + } + + + /*************************************************************************/ + /* */ + /* */ + /* Round_None */ + /* */ + /* */ + /* Does not round, but adds engine compensation. */ + /* */ + /* */ + /* distance :: The distance (not) to round. */ + /* */ + /* compensation :: The engine compensation. */ + /* */ + /* */ + /* The compensated distance. */ + /* */ + /* */ + /* The TrueType specification says very few about the relationship */ + /* between rounding and engine compensation. However, it seems from */ + /* the description of super round that we should add the compensation */ + /* before rounding. */ + /* */ + static + FT_F26Dot6 Round_None( EXEC_OP_ FT_F26Dot6 distance, + FT_F26Dot6 compensation ) + { + FT_F26Dot6 val; + + FT_UNUSED_EXEC; + + + if ( distance >= 0 ) + { + val = distance + compensation; + if ( val < 0 ) + val = 0; + } + else { + val = distance - compensation; + if ( val > 0 ) + val = 0; + } + return val; + } + + + /*************************************************************************/ + /* */ + /* */ + /* Round_To_Grid */ + /* */ + /* */ + /* Rounds value to grid after adding engine compensation. */ + /* */ + /* */ + /* distance :: The distance to round. */ + /* */ + /* compensation :: The engine compensation. */ + /* */ + /* */ + /* Rounded distance. */ + /* */ + static + FT_F26Dot6 Round_To_Grid( EXEC_OP_ FT_F26Dot6 distance, + FT_F26Dot6 compensation ) + { + FT_F26Dot6 val; + + FT_UNUSED_EXEC; + + + if ( distance >= 0 ) + { + val = distance + compensation + 32; + if ( val > 0 ) + val &= ~63; + else + val = 0; + } + else + { + val = -( ( compensation - distance + 32 ) & -64 ); + if ( val > 0 ) + val = 0; + } + + return val; + } + + + /*************************************************************************/ + /* */ + /* */ + /* Round_To_Half_Grid */ + /* */ + /* */ + /* Rounds value to half grid after adding engine compensation. */ + /* */ + /* */ + /* distance :: The distance to round. */ + /* */ + /* compensation :: The engine compensation. */ + /* */ + /* */ + /* Rounded distance. */ + /* */ + static + FT_F26Dot6 Round_To_Half_Grid( EXEC_OP_ FT_F26Dot6 distance, + FT_F26Dot6 compensation ) + { + FT_F26Dot6 val; + + FT_UNUSED_EXEC; + + + if ( distance >= 0 ) + { + val = ( ( distance + compensation ) & -64 ) + 32; + if ( val < 0 ) + val = 0; + } + else + { + val = -( ( (compensation - distance) & -64 ) + 32 ); + if ( val > 0 ) + val = 0; + } + + return val; + } + + + /*************************************************************************/ + /* */ + /* */ + /* Round_Down_To_Grid */ + /* */ + /* */ + /* Rounds value down to grid after adding engine compensation. */ + /* */ + /* */ + /* distance :: The distance to round. */ + /* */ + /* compensation :: The engine compensation. */ + /* */ + /* */ + /* Rounded distance. */ + /* */ + static + FT_F26Dot6 Round_Down_To_Grid( EXEC_OP_ FT_F26Dot6 distance, + FT_F26Dot6 compensation ) + { + FT_F26Dot6 val; + + FT_UNUSED_EXEC; + + + if ( distance >= 0 ) + { + val = distance + compensation; + if ( val > 0 ) + val &= ~63; + else + val = 0; + } + else + { + val = -( ( compensation - distance ) & -64 ); + if ( val > 0 ) + val = 0; + } + + return val; + } + + + /*************************************************************************/ + /* */ + /* */ + /* Round_Up_To_Grid */ + /* */ + /* */ + /* Rounds value up to grid after adding engine compensation. */ + /* */ + /* */ + /* distance :: The distance to round. */ + /* */ + /* compensation :: The engine compensation. */ + /* */ + /* */ + /* Rounded distance. */ + /* */ + static + FT_F26Dot6 Round_Up_To_Grid( EXEC_OP_ FT_F26Dot6 distance, + FT_F26Dot6 compensation ) + { + FT_F26Dot6 val; + + + FT_UNUSED_EXEC; + + if ( distance >= 0 ) + { + val = distance + compensation + 63; + if ( val > 0 ) + val &= ~63; + else + val = 0; + } + else + { + val = -( ( compensation - distance + 63 ) & -64 ); + if ( val > 0 ) + val = 0; + } + + return val; + } + + + /*************************************************************************/ + /* */ + /* */ + /* Round_To_Double_Grid */ + /* */ + /* */ + /* Rounds value to double grid after adding engine compensation. */ + /* */ + /* */ + /* distance :: The distance to round. */ + /* */ + /* compensation :: The engine compensation. */ + /* */ + /* */ + /* Rounded distance. */ + /* */ + static + FT_F26Dot6 Round_To_Double_Grid( EXEC_OP_ FT_F26Dot6 distance, + FT_F26Dot6 compensation ) + { + FT_F26Dot6 val; + + FT_UNUSED_EXEC; + + + if ( distance >= 0 ) + { + val = distance + compensation + 16; + if ( val > 0 ) + val &= ~31; + else + val = 0; + } + else + { + val = -( ( compensation - distance + 16 ) & -32 ); + if ( val > 0 ) + val = 0; + } + + return val; + } + + + /*************************************************************************/ + /* */ + /* */ + /* Round_Super */ + /* */ + /* */ + /* Super-rounds value to grid after adding engine compensation. */ + /* */ + /* */ + /* distance :: The distance to round. */ + /* */ + /* compensation :: The engine compensation. */ + /* */ + /* */ + /* Rounded distance. */ + /* */ + /* */ + /* The TrueType specification says very few about the relationship */ + /* between rounding and engine compensation. However, it seems from */ + /* the description of super round that we should add the compensation */ + /* before rounding. */ + /* */ + static + FT_F26Dot6 Round_Super( EXEC_OP_ FT_F26Dot6 distance, + FT_F26Dot6 compensation ) + { + FT_F26Dot6 val; + + + if ( distance >= 0 ) + { + val = ( distance - CUR.phase + CUR.threshold + compensation ) & + -CUR.period; + if ( val < 0 ) + val = 0; + val += CUR.phase; + } + else + { + val = -( ( CUR.threshold - CUR.phase - distance + compensation ) & + -CUR.period ); + if ( val > 0 ) + val = 0; + val -= CUR.phase; + } + + return val; + } + + + /*************************************************************************/ + /* */ + /* */ + /* Round_Super_45 */ + /* */ + /* */ + /* Super-rounds value to grid after adding engine compensation. */ + /* */ + /* */ + /* distance :: The distance to round. */ + /* */ + /* compensation :: The engine compensation. */ + /* */ + /* */ + /* Rounded distance. */ + /* */ + /* */ + /* There is a separate function for Round_Super_45() as we may need */ + /* greater precision. */ + /* */ + static + FT_F26Dot6 Round_Super_45( EXEC_OP_ FT_F26Dot6 distance, + FT_F26Dot6 compensation ) + { + FT_F26Dot6 val; + + + if ( distance >= 0 ) + { + val = ( ( distance - CUR.phase + CUR.threshold + compensation ) / + CUR.period ) * CUR.period; + if ( val < 0 ) + val = 0; + val += CUR.phase; + } + else + { + val = -( ( ( CUR.threshold - CUR.phase - distance + compensation ) / + CUR.period ) * CUR.period ); + if ( val > 0 ) + val = 0; + val -= CUR.phase; + } + + return val; + } + + + /*************************************************************************/ + /* */ + /* */ + /* Compute_Round */ + /* */ + /* */ + /* Sets the rounding mode. */ + /* */ + /* */ + /* round_mode :: The rounding mode to be used. */ + /* */ + static + void Compute_Round( EXEC_OP_ FT_Byte round_mode ) + { + switch ( round_mode ) + { + case TT_Round_Off: + CUR.func_round = (TT_Round_Func)Round_None; + break; + + case TT_Round_To_Grid: + CUR.func_round = (TT_Round_Func)Round_To_Grid; + break; + + case TT_Round_Up_To_Grid: + CUR.func_round = (TT_Round_Func)Round_Up_To_Grid; + break; + + case TT_Round_Down_To_Grid: + CUR.func_round = (TT_Round_Func)Round_Down_To_Grid; + break; + + case TT_Round_To_Half_Grid: + CUR.func_round = (TT_Round_Func)Round_To_Half_Grid; + break; + + case TT_Round_To_Double_Grid: + CUR.func_round = (TT_Round_Func)Round_To_Double_Grid; + break; + + case TT_Round_Super: + CUR.func_round = (TT_Round_Func)Round_Super; + break; + + case TT_Round_Super_45: + CUR.func_round = (TT_Round_Func)Round_Super_45; + break; + } + } + + + /*************************************************************************/ + /* */ + /* */ + /* SetSuperRound */ + /* */ + /* */ + /* Sets Super Round parameters. */ + /* */ + /* */ + /* GridPeriod :: Grid period */ + /* selector :: SROUND opcode */ + /* */ + static + void SetSuperRound( EXEC_OP_ FT_F26Dot6 GridPeriod, + FT_Long selector ) + { + switch ( (FT_Int)( selector & 0xC0 ) ) + { + case 0: + CUR.period = GridPeriod / 2; + break; + + case 0x40: + CUR.period = GridPeriod; + break; + + case 0x80: + CUR.period = GridPeriod * 2; + break; + + /* This opcode is reserved, but... */ + + case 0xC0: + CUR.period = GridPeriod; + break; + } + + switch ( (FT_Int)( selector & 0x30 ) ) + { + case 0: + CUR.phase = 0; + break; + + case 0x10: + CUR.phase = CUR.period / 4; + break; + + case 0x20: + CUR.phase = CUR.period / 2; + break; + + case 0x30: + CUR.phase = GridPeriod * 3 / 4; + break; + } + + if ( (selector & 0x0F) == 0 ) + CUR.threshold = CUR.period - 1; + else + CUR.threshold = ( (FT_Int)( selector & 0x0F ) - 4 ) * CUR.period / 8; + + CUR.period /= 256; + CUR.phase /= 256; + CUR.threshold /= 256; + } + + + /*************************************************************************/ + /* */ + /* */ + /* Project */ + /* */ + /* */ + /* Computes the projection of vector given by (v2-v1) along the */ + /* current projection vector. */ + /* */ + /* */ + /* v1 :: First input vector. */ + /* v2 :: Second input vector. */ + /* */ + /* */ + /* The distance in F26dot6 format. */ + /* */ + static + FT_F26Dot6 Project( EXEC_OP_ FT_Vector* v1, + FT_Vector* v2 ) + { + return TT_MULDIV( v1->x - v2->x, CUR.GS.projVector.x, 0x4000 ) + + TT_MULDIV( v1->y - v2->y, CUR.GS.projVector.y, 0x4000 ); + } + + + /*************************************************************************/ + /* */ + /* */ + /* Dual_Project */ + /* */ + /* */ + /* Computes the projection of the vector given by (v2-v1) along the */ + /* current dual vector. */ + /* */ + /* */ + /* v1 :: First input vector. */ + /* v2 :: Second input vector. */ + /* */ + /* */ + /* The distance in F26dot6 format. */ + /* */ + static + FT_F26Dot6 Dual_Project( EXEC_OP_ FT_Vector* v1, + FT_Vector* v2 ) + { + return TT_MULDIV( v1->x - v2->x, CUR.GS.dualVector.x, 0x4000 ) + + TT_MULDIV( v1->y - v2->y, CUR.GS.dualVector.y, 0x4000 ); + } + + + /*************************************************************************/ + /* */ + /* */ + /* Free_Project */ + /* */ + /* */ + /* Computes the projection of the vector given by (v2-v1) along the */ + /* current freedom vector. */ + /* */ + /* */ + /* v1 :: First input vector. */ + /* v2 :: Second input vector. */ + /* */ + /* */ + /* The distance in F26dot6 format. */ + /* */ + static + FT_F26Dot6 Free_Project( EXEC_OP_ FT_Vector* v1, + FT_Vector* v2 ) + { + return TT_MULDIV( v1->x - v2->x, CUR.GS.freeVector.x, 0x4000 ) + + TT_MULDIV( v1->y - v2->y, CUR.GS.freeVector.y, 0x4000 ); + } + + + /*************************************************************************/ + /* */ + /* */ + /* Project_x */ + /* */ + /* */ + /* Computes the projection of the vector given by (v2-v1) along the */ + /* horizontal axis. */ + /* */ + /* */ + /* v1 :: First input vector. */ + /* v2 :: Second input vector. */ + /* */ + /* */ + /* The distance in F26dot6 format. */ + /* */ + static + FT_F26Dot6 Project_x( EXEC_OP_ FT_Vector* v1, + FT_Vector* v2 ) + { + FT_UNUSED_EXEC; + + return ( v1->x - v2->x ); + } + + + /*************************************************************************/ + /* */ + /* */ + /* Project_y */ + /* */ + /* */ + /* Computes the projection of the vector given by (v2-v1) along the */ + /* vertical axis. */ + /* */ + /* */ + /* v1 :: First input vector. */ + /* v2 :: Second input vector. */ + /* */ + /* */ + /* The distance in F26dot6 format. */ + /* */ + static + FT_F26Dot6 Project_y( EXEC_OP_ FT_Vector* v1, + FT_Vector* v2 ) + { + FT_UNUSED_EXEC; + + return ( v1->y - v2->y ); + } + + + /*************************************************************************/ + /* */ + /* */ + /* Compute_Funcs */ + /* */ + /* */ + /* Computes the projection and movement function pointers according */ + /* to the current graphics state. */ + /* */ + static + void Compute_Funcs( EXEC_OP ) + { + if ( CUR.GS.freeVector.x == 0x4000 ) + { + CUR.func_freeProj = (TT_Project_Func)Project_x; + CUR.F_dot_P = CUR.GS.projVector.x * 0x10000L; + } + else + { + if ( CUR.GS.freeVector.y == 0x4000 ) + { + CUR.func_freeProj = (TT_Project_Func)Project_y; + CUR.F_dot_P = CUR.GS.projVector.y * 0x10000L; + } + else + { + CUR.func_freeProj = (TT_Project_Func)Free_Project; + CUR.F_dot_P = (FT_Long)CUR.GS.projVector.x * CUR.GS.freeVector.x * 4 + + (FT_Long)CUR.GS.projVector.y * CUR.GS.freeVector.y * 4; + } + } + + if ( CUR.GS.projVector.x == 0x4000 ) + CUR.func_project = (TT_Project_Func)Project_x; + else + { + if ( CUR.GS.projVector.y == 0x4000 ) + CUR.func_project = (TT_Project_Func)Project_y; + else + CUR.func_project = (TT_Project_Func)Project; + } + + if ( CUR.GS.dualVector.x == 0x4000 ) + CUR.func_dualproj = (TT_Project_Func)Project_x; + else + { + if ( CUR.GS.dualVector.y == 0x4000 ) + CUR.func_dualproj = (TT_Project_Func)Project_y; + else + CUR.func_dualproj = (TT_Project_Func)Dual_Project; + } + + CUR.func_move = (TT_Move_Func)Direct_Move; + + if ( CUR.F_dot_P == 0x40000000L ) + { + if ( CUR.GS.freeVector.x == 0x4000 ) + CUR.func_move = (TT_Move_Func)Direct_Move_X; + else + { + if ( CUR.GS.freeVector.y == 0x4000 ) + CUR.func_move = (TT_Move_Func)Direct_Move_Y; + } + } + + /* at small sizes, F_dot_P can become too small, resulting */ + /* in overflows and `spikes' in a number of glyphs like `w'. */ + + if ( ABS( CUR.F_dot_P ) < 0x4000000L ) + CUR.F_dot_P = 0x40000000L; + + /* Disable cached aspect ratio */ + CUR.tt_metrics.ratio = 0; + } + + + /*************************************************************************/ + /* */ + /* */ + /* Normalize */ + /* */ + /* */ + /* Norms a vector. */ + /* */ + /* */ + /* Vx :: The horizontal input vector coordinate. */ + /* Vy :: The vertical input vector coordinate. */ + /* */ + /* */ + /* R :: The normed unit vector. */ + /* */ + /* */ + /* Returns FAILURE if a vector parameter is zero. */ + /* */ + /* */ + /* In case Vx and Vy are both zero, Normalize() returns SUCCESS, and */ + /* R is undefined. */ + /* */ + +#ifdef FT_CONFIG_OPTION_OLD_CALCS + + static + FT_Bool Normalize( EXEC_OP_ FT_F26Dot6 Vx, + FT_F26Dot6 Vy, + FT_UnitVector* R ) + { + FT_F26Dot6 W; + FT_Bool S1, S2; + + FT_UNUSED_EXEC; + + + if ( ABS( Vx ) < 0x10000L && ABS( Vy ) < 0x10000L ) + { + Vx *= 0x100; + Vy *= 0x100; + + W = Norm( Vx, Vy ); + + if ( W == 0 ) + { + /* XXX: UNDOCUMENTED! It seems that it is possible to try */ + /* to normalize the vector (0,0). Return immediately. */ + return SUCCESS; + } + + R->x = (FT_F2Dot14)FT_MulDiv( Vx, 0x4000L, W ); + R->y = (FT_F2Dot14)FT_MulDiv( Vy, 0x4000L, W ); + + return SUCCESS; + } + + W = Norm( Vx, Vy ); + + Vx = FT_MulDiv( Vx, 0x4000L, W ); + Vy = FT_MulDiv( Vy, 0x4000L, W ); + + W = Vx * Vx + Vy * Vy; + + /* Now, we want that Sqrt( W ) = 0x4000 */ + /* Or 0x1000000 <= W < 0x1004000 */ + + if ( Vx < 0 ) + { + Vx = -Vx; + S1 = TRUE; + } + else + S1 = FALSE; + + if ( Vy < 0 ) + { + Vy = -Vy; + S2 = TRUE; + } + else + S2 = FALSE; + + while ( W < 0x1000000L ) + { + /* We need to increase W by a minimal amount */ + if ( Vx < Vy ) + Vx++; + else + Vy++; + + W = Vx * Vx + Vy * Vy; + } + + while ( W >= 0x1004000L ) + { + /* We need to decrease W by a minimal amount */ + if ( Vx < Vy ) + Vx--; + else + Vy--; + + W = Vx * Vx + Vy * Vy; + } + + /* Note that in various cases, we can only */ + /* compute a Sqrt(W) of 0x3FFF, eg. Vx = Vy */ + + if ( S1 ) + Vx = -Vx; + + if ( S2 ) + Vy = -Vy; + + R->x = (FT_F2Dot14)Vx; /* Type conversion */ + R->y = (FT_F2Dot14)Vy; /* Type conversion */ + + return SUCCESS; + } + +#else + + static + FT_Bool Normalize( EXEC_OP_ FT_F26Dot6 Vx, + FT_F26Dot6 Vy, + FT_UnitVector* R ) + { + FT_F26Dot6 u, v, d; + FT_Int shift; + FT_ULong H, L, L2, hi, lo, med; + + + u = ABS( Vx ); + v = ABS( Vy ); + + if ( u < v ) + { + d = u; + u = v; + v = d; + } + + R->x = 0; + R->y = 0; + + /* check that we are not trying to normalise zero! */ + if ( u == 0 ) + return SUCCESS; + + /* 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 */ + if ( H == 0 ) + { + shift = 0; + while ( ( L & 0xC0000000L ) == 0 ) + { + L <<= 2; + shift++; + } + + d = FT_Sqrt32( L ); + R->x = (FT_F2Dot14)TT_MULDIV( Vx << shift, 0x4000, d ); + R->y = (FT_F2Dot14)TT_MULDIV( Vy << shift, 0x4000, d ); + } + /* if the value is greater than 64-bits */ + else + { + shift = 0; + while ( H ) + { + L = ( L >> 2 ) | ( H << 30 ); + H >>= 2; + shift++; + } + + d = FT_Sqrt32( L ); + R->x = (FT_F2Dot14)TT_MULDIV( Vx >> shift, 0x4000, d ); + R->y = (FT_F2Dot14)TT_MULDIV( Vy >> shift, 0x4000, d ); + } + + { + FT_ULong x, y, w; + FT_Int sx, sy; + + + sx = R->x >= 0 ? 1 : -1; + sy = R->y >= 0 ? 1 : -1; + x = (FT_ULong)sx * R->x; + y = (FT_ULong)sy * R->y; + + w = x * x + y * y; + + /* we now want to adjust (x,y) in order to have sqrt(w) == 0x4000 */ + /* which means 0x1000000 <= w < 0x1004000 */ + while ( w <= 0x10000000L ) + { + /* increment the smallest coordinate */ + if ( x < y ) + x++; + else + y++; + + w = x * x + y * y; + } + + while ( w >= 0x10040000L ) + { + /* decrement the smallest coordinate */ + if ( x < y ) + x--; + else + y--; + + w = x * x + y * y; + } + + R->x = sx * x; + R->y = sy * y; + } + + return SUCCESS; + } + +#endif /* FT_CONFIG_OPTION_OLD_CALCS */ + + + /*************************************************************************/ + /* */ + /* Here we start with the implementation of the various opcodes. */ + /* */ + /*************************************************************************/ + + + static + FT_Bool Ins_SxVTL( EXEC_OP_ FT_UShort aIdx1, + FT_UShort aIdx2, + FT_Int aOpc, + FT_UnitVector* Vec ) + { + FT_Long A, B, C; + FT_Vector* p1; + FT_Vector* p2; + + + if ( BOUNDS( aIdx1, CUR.zp2.n_points ) || + BOUNDS( aIdx2, CUR.zp1.n_points ) ) + { + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + return FAILURE; + } + + p1 = CUR.zp1.cur + aIdx2; + p2 = CUR.zp2.cur + aIdx1; + + A = p1->x - p2->x; + B = p1->y - p2->y; + + if ( ( aOpc & 1 ) != 0 ) + { + C = B; /* counter clockwise rotation */ + B = A; + A = -C; + } + + NORMalize( A, B, Vec ); + + return SUCCESS; + } + + + /* When not using the big switch statements, the interpreter uses a */ + /* call table defined later below in this source. Each opcode must */ + /* thus have a corresponding function, even trivial ones. */ + /* */ + /* They are all defined there. */ + +#define DO_SVTCA \ + { \ + FT_Short A, B; \ + \ + \ + A = (FT_Short)( CUR.opcode & 1 ) << 14; \ + B = A ^ (FT_Short)0x4000; \ + \ + CUR.GS.freeVector.x = A; \ + CUR.GS.projVector.x = A; \ + CUR.GS.dualVector.x = A; \ + \ + CUR.GS.freeVector.y = B; \ + CUR.GS.projVector.y = B; \ + CUR.GS.dualVector.y = B; \ + \ + COMPUTE_Funcs(); \ + } + + +#define DO_SPVTCA \ + { \ + FT_Short A, B; \ + \ + \ + A = (FT_Short)( CUR.opcode & 1 ) << 14; \ + B = A ^ (FT_Short)0x4000; \ + \ + CUR.GS.projVector.x = A; \ + CUR.GS.dualVector.x = A; \ + \ + CUR.GS.projVector.y = B; \ + CUR.GS.dualVector.y = B; \ + \ + COMPUTE_Funcs(); \ + } + + +#define DO_SFVTCA \ + { \ + FT_Short A, B; \ + \ + \ + A = (FT_Short)( CUR.opcode & 1 ) << 14; \ + B = A ^ (FT_Short)0x4000; \ + \ + CUR.GS.freeVector.x = A; \ + CUR.GS.freeVector.y = B; \ + \ + COMPUTE_Funcs(); \ + } + + +#define DO_SPVTL \ + if ( INS_SxVTL( (FT_UShort)args[1], \ + (FT_UShort)args[0], \ + CUR.opcode, \ + &CUR.GS.projVector ) == SUCCESS ) \ + { \ + CUR.GS.dualVector = CUR.GS.projVector; \ + COMPUTE_Funcs(); \ + } + + +#define DO_SFVTL \ + if ( INS_SxVTL( (FT_UShort)args[1], \ + (FT_UShort)args[0], \ + CUR.opcode, \ + &CUR.GS.freeVector ) == SUCCESS ) \ + COMPUTE_Funcs(); + + +#define DO_SFVTPV \ + CUR.GS.freeVector = CUR.GS.projVector; \ + COMPUTE_Funcs(); + + +#define DO_SPVFS \ + { \ + FT_Short S; \ + FT_Long X, Y; \ + \ + \ + /* Only use low 16bits, then sign extend */ \ + S = (FT_Short)args[1]; \ + Y = (FT_Long)S; \ + S = (FT_Short)args[0]; \ + X = (FT_Long)S; \ + \ + NORMalize( X, Y, &CUR.GS.projVector ); \ + \ + CUR.GS.dualVector = CUR.GS.projVector; \ + COMPUTE_Funcs(); \ + } + + +#define DO_SFVFS \ + { \ + FT_Short S; \ + FT_Long X, Y; \ + \ + \ + /* Only use low 16bits, then sign extend */ \ + S = (FT_Short)args[1]; \ + Y = (FT_Long)S; \ + S = (FT_Short)args[0]; \ + X = S; \ + \ + NORMalize( X, Y, &CUR.GS.freeVector ); \ + COMPUTE_Funcs(); \ + } + + +#define DO_GPV \ + args[0] = CUR.GS.projVector.x; \ + args[1] = CUR.GS.projVector.y; + + +#define DO_GFV \ + args[0] = CUR.GS.freeVector.x; \ + args[1] = CUR.GS.freeVector.y; + + +#define DO_SRP0 \ + CUR.GS.rp0 = (FT_UShort)args[0]; + + +#define DO_SRP1 \ + CUR.GS.rp1 = (FT_UShort)args[0]; + + +#define DO_SRP2 \ + CUR.GS.rp2 = (FT_UShort)args[0]; + + +#define DO_RTHG \ + CUR.GS.round_state = TT_Round_To_Half_Grid; \ + CUR.func_round = (TT_Round_Func)Round_To_Half_Grid; + + +#define DO_RTG \ + CUR.GS.round_state = TT_Round_To_Grid; \ + CUR.func_round = (TT_Round_Func)Round_To_Grid; + + +#define DO_RTDG \ + CUR.GS.round_state = TT_Round_To_Double_Grid; \ + CUR.func_round = (TT_Round_Func)Round_To_Double_Grid; + + +#define DO_RUTG \ + CUR.GS.round_state = TT_Round_Up_To_Grid; \ + CUR.func_round = (TT_Round_Func)Round_Up_To_Grid; + + +#define DO_RDTG \ + CUR.GS.round_state = TT_Round_Down_To_Grid; \ + CUR.func_round = (TT_Round_Func)Round_Down_To_Grid; + + +#define DO_ROFF \ + CUR.GS.round_state = TT_Round_Off; \ + CUR.func_round = (TT_Round_Func)Round_None; + + +#define DO_SROUND \ + SET_SuperRound( 0x4000, args[0] ); \ + CUR.GS.round_state = TT_Round_Super; \ + CUR.func_round = (TT_Round_Func)Round_Super; + + +#define DO_S45ROUND \ + SET_SuperRound( 0x2D41, args[0] ); \ + CUR.GS.round_state = TT_Round_Super_45; \ + CUR.func_round = (TT_Round_Func)Round_Super_45; + + +#define DO_SLOOP \ + if ( args[0] < 0 ) \ + CUR.error = TT_Err_Bad_Argument; \ + else \ + CUR.GS.loop = args[0]; + + +#define DO_SMD \ + CUR.GS.minimum_distance = args[0]; + + +#define DO_SCVTCI \ + CUR.GS.control_value_cutin = (FT_F26Dot6)args[0]; + + +#define DO_SSWCI \ + CUR.GS.single_width_cutin = (FT_F26Dot6)args[0]; + + + /* XXX: UNDOCUMENTED! or bug in the Windows engine? */ + /* */ + /* It seems that the value that is read here is */ + /* expressed in 16.16 format rather than in font */ + /* units. */ + /* */ +#define DO_SSW \ + CUR.GS.single_width_value = (FT_F26Dot6)( args[0] >> 10 ); + + +#define DO_FLIPON \ + CUR.GS.auto_flip = TRUE; + + +#define DO_FLIPOFF \ + CUR.GS.auto_flip = FALSE; + + +#define DO_SDB \ + CUR.GS.delta_base = (FT_Short)args[0]; + + +#define DO_SDS \ + CUR.GS.delta_shift = (FT_Short)args[0]; + + +#define DO_MD /* nothing */ + + +#define DO_MPPEM \ + args[0] = CURRENT_Ppem(); + + + /* Note: The pointSize should be irrelevant in a given font program; */ + /* we thus decide to return only the ppem. */ +#if 0 + +#define DO_MPS \ + args[0] = CUR.metrics.pointSize; + +#else + +#define DO_MPS \ + args[0] = CURRENT_Ppem(); + +#endif /* 0 */ + + +#define DO_DUP \ + args[1] = args[0]; + + +#define DO_CLEAR \ + CUR.new_top = 0; + + +#define DO_SWAP \ + { \ + FT_Long L; \ + \ + \ + L = args[0]; \ + args[0] = args[1]; \ + args[1] = L; \ + } + + +#define DO_DEPTH \ + args[0] = CUR.top; + + +#define DO_CINDEX \ + { \ + FT_Long L; \ + \ + \ + L = args[0]; \ + \ + if ( L <= 0 || L > CUR.args ) \ + CUR.error = TT_Err_Invalid_Reference; \ + else \ + args[0] = CUR.stack[CUR.args - L]; \ + } + + +#define DO_JROT \ + if ( args[1] != 0 ) \ + { \ + CUR.IP += args[0]; \ + CUR.step_ins = FALSE; \ + } + + +#define DO_JMPR \ + CUR.IP += args[0]; \ + CUR.step_ins = FALSE; + + +#define DO_JROF \ + if ( args[1] == 0 ) \ + { \ + CUR.IP += args[0]; \ + CUR.step_ins = FALSE; \ + } + + +#define DO_LT \ + args[0] = ( args[0] < args[1] ); + + +#define DO_LTEQ \ + args[0] = ( args[0] <= args[1] ); + + +#define DO_GT \ + args[0] = ( args[0] > args[1] ); + + +#define DO_GTEQ \ + args[0] = ( args[0] >= args[1] ); + + +#define DO_EQ \ + args[0] = ( args[0] == args[1] ); + + +#define DO_NEQ \ + args[0] = ( args[0] != args[1] ); + + +#define DO_ODD \ + args[0] = ( ( CUR_Func_round( args[0], 0 ) & 127 ) == 64 ); + + +#define DO_EVEN \ + args[0] = ( ( CUR_Func_round( args[0], 0 ) & 127 ) == 0 ); + + +#define DO_AND \ + args[0] = ( args[0] && args[1] ); + + +#define DO_OR \ + args[0] = ( args[0] || args[1] ); + + +#define DO_NOT \ + args[0] = !args[0]; + + +#define DO_ADD \ + args[0] += args[1]; + + +#define DO_SUB \ + args[0] -= args[1]; + + +#define DO_DIV \ + if ( args[1] == 0 ) \ + CUR.error = TT_Err_Divide_By_Zero; \ + else \ + args[0] = TT_MULDIV( args[0], 64L, args[1] ); + + +#define DO_MUL \ + args[0] = TT_MULDIV( args[0], args[1], 64L ); + + +#define DO_ABS \ + args[0] = ABS( args[0] ); + + +#define DO_NEG \ + args[0] = -args[0]; + + +#define DO_FLOOR \ + args[0] &= -64; + + +#define DO_CEILING \ + args[0] = ( args[0] + 63 ) & -64; + + +#define DO_RS \ + { \ + FT_ULong I = (FT_ULong)args[0]; \ + \ + \ + if ( BOUNDS( I, CUR.storeSize ) ) \ + { \ + if ( CUR.pedantic_hinting ) \ + { \ + ARRAY_BOUND_ERROR; \ + } \ + else \ + args[0] = 0; \ + } \ + else \ + args[0] = CUR.storage[I]; \ + } + + +#define DO_WS \ + { \ + FT_ULong I = (FT_ULong)args[0]; \ + \ + \ + if ( BOUNDS( I, CUR.storeSize ) ) \ + { \ + if ( CUR.pedantic_hinting ) \ + { \ + ARRAY_BOUND_ERROR; \ + } \ + } \ + else \ + CUR.storage[I] = args[1]; \ + } + + +#define DO_RCVT \ + { \ + FT_ULong I = (FT_ULong)args[0]; \ + \ + \ + if ( BOUNDS( I, CUR.cvtSize ) ) \ + { \ + if ( CUR.pedantic_hinting ) \ + { \ + ARRAY_BOUND_ERROR; \ + } \ + else \ + args[0] = 0; \ + } \ + else \ + args[0] = CUR_Func_read_cvt( I ); \ + } + + +#define DO_WCVTP \ + { \ + FT_ULong I = (FT_ULong)args[0]; \ + \ + \ + if ( BOUNDS( I, CUR.cvtSize ) ) \ + { \ + if ( CUR.pedantic_hinting ) \ + { \ + ARRAY_BOUND_ERROR; \ + } \ + } \ + else \ + CUR_Func_write_cvt( I, args[1] ); \ + } + + +#define DO_WCVTF \ + { \ + FT_ULong I = (FT_ULong)args[0]; \ + \ + \ + if ( BOUNDS( I, CUR.cvtSize ) ) \ + { \ + if ( CUR.pedantic_hinting ) \ + { \ + ARRAY_BOUND_ERROR; \ + } \ + } \ + else \ + CUR.cvt[I] = TT_MULFIX( args[1], CUR.tt_metrics.scale ); \ + } + + +#define DO_DEBUG \ + CUR.error = TT_Err_Debug_OpCode; + + +#define DO_ROUND \ + args[0] = CUR_Func_round( \ + args[0], \ + CUR.tt_metrics.compensations[CUR.opcode - 0x68] ); + + +#define DO_NROUND \ + args[0] = ROUND_None( args[0], \ + CUR.tt_metrics.compensations[CUR.opcode - 0x6C] ); + + +#define DO_MAX \ + if ( args[1] > args[0] ) \ + args[0] = args[1]; + + +#define DO_MIN \ + if ( args[1] < args[0] ) \ + args[0] = args[1]; + + +#ifndef TT_CONFIG_OPTION_INTERPRETER_SWITCH + + +#undef ARRAY_BOUND_ERROR +#define ARRAY_BOUND_ERROR \ + { \ + CUR.error = TT_Err_Invalid_Reference; \ + return; \ + } + + + /*************************************************************************/ + /* */ + /* SVTCA[a]: Set (F and P) Vectors to Coordinate Axis */ + /* Opcode range: 0x00-0x01 */ + /* Stack: --> */ + /* */ + static + void Ins_SVTCA( INS_ARG ) + { + DO_SVTCA + } + + + /*************************************************************************/ + /* */ + /* SPVTCA[a]: Set PVector to Coordinate Axis */ + /* Opcode range: 0x02-0x03 */ + /* Stack: --> */ + /* */ + static + void Ins_SPVTCA( INS_ARG ) + { + DO_SPVTCA + } + + + /*************************************************************************/ + /* */ + /* SFVTCA[a]: Set FVector to Coordinate Axis */ + /* Opcode range: 0x04-0x05 */ + /* Stack: --> */ + /* */ + static + void Ins_SFVTCA( INS_ARG ) + { + DO_SFVTCA + } + + + /*************************************************************************/ + /* */ + /* SPVTL[a]: Set PVector To Line */ + /* Opcode range: 0x06-0x07 */ + /* Stack: uint32 uint32 --> */ + /* */ + static + void Ins_SPVTL( INS_ARG ) + { + DO_SPVTL + } + + + /*************************************************************************/ + /* */ + /* SFVTL[a]: Set FVector To Line */ + /* Opcode range: 0x08-0x09 */ + /* Stack: uint32 uint32 --> */ + /* */ + static + void Ins_SFVTL( INS_ARG ) + { + DO_SFVTL + } + + + /*************************************************************************/ + /* */ + /* SFVTPV[]: Set FVector To PVector */ + /* Opcode range: 0x0E */ + /* Stack: --> */ + /* */ + static + void Ins_SFVTPV( INS_ARG ) + { + DO_SFVTPV + } + + + /*************************************************************************/ + /* */ + /* SPVFS[]: Set PVector From Stack */ + /* Opcode range: 0x0A */ + /* Stack: f2.14 f2.14 --> */ + /* */ + static + void Ins_SPVFS( INS_ARG ) + { + DO_SPVFS + } + + + /*************************************************************************/ + /* */ + /* SFVFS[]: Set FVector From Stack */ + /* Opcode range: 0x0B */ + /* Stack: f2.14 f2.14 --> */ + /* */ + static + void Ins_SFVFS( INS_ARG ) + { + DO_SFVFS + } + + + /*************************************************************************/ + /* */ + /* GPV[]: Get Projection Vector */ + /* Opcode range: 0x0C */ + /* Stack: ef2.14 --> ef2.14 */ + /* */ + static + void Ins_GPV( INS_ARG ) + { + DO_GPV + } + + + /*************************************************************************/ + /* GFV[]: Get Freedom Vector */ + /* Opcode range: 0x0D */ + /* Stack: ef2.14 --> ef2.14 */ + /* */ + static + void Ins_GFV( INS_ARG ) + { + DO_GFV + } + + + /*************************************************************************/ + /* */ + /* SRP0[]: Set Reference Point 0 */ + /* Opcode range: 0x10 */ + /* Stack: uint32 --> */ + /* */ + static + void Ins_SRP0( INS_ARG ) + { + DO_SRP0 + } + + + /*************************************************************************/ + /* */ + /* SRP1[]: Set Reference Point 1 */ + /* Opcode range: 0x11 */ + /* Stack: uint32 --> */ + /* */ + static + void Ins_SRP1( INS_ARG ) + { + DO_SRP1 + } + + + /*************************************************************************/ + /* */ + /* SRP2[]: Set Reference Point 2 */ + /* Opcode range: 0x12 */ + /* Stack: uint32 --> */ + /* */ + static + void Ins_SRP2( INS_ARG ) + { + DO_SRP2 + } + + + /*************************************************************************/ + /* */ + /* RTHG[]: Round To Half Grid */ + /* Opcode range: 0x19 */ + /* Stack: --> */ + /* */ + static + void Ins_RTHG( INS_ARG ) + { + DO_RTHG + } + + + /*************************************************************************/ + /* */ + /* RTG[]: Round To Grid */ + /* Opcode range: 0x18 */ + /* Stack: --> */ + /* */ + static + void Ins_RTG( INS_ARG ) + { + DO_RTG + } + + + /*************************************************************************/ + /* RTDG[]: Round To Double Grid */ + /* Opcode range: 0x3D */ + /* Stack: --> */ + /* */ + static + void Ins_RTDG( INS_ARG ) + { + DO_RTDG + } + + + /*************************************************************************/ + /* RUTG[]: Round Up To Grid */ + /* Opcode range: 0x7C */ + /* Stack: --> */ + /* */ + static + void Ins_RUTG( INS_ARG ) + { + DO_RUTG + } + + + /*************************************************************************/ + /* */ + /* RDTG[]: Round Down To Grid */ + /* Opcode range: 0x7D */ + /* Stack: --> */ + /* */ + static + void Ins_RDTG( INS_ARG ) + { + DO_RDTG + } + + + /*************************************************************************/ + /* */ + /* ROFF[]: Round OFF */ + /* Opcode range: 0x7A */ + /* Stack: --> */ + /* */ + static + void Ins_ROFF( INS_ARG ) + { + DO_ROFF + } + + + /*************************************************************************/ + /* */ + /* SROUND[]: Super ROUND */ + /* Opcode range: 0x76 */ + /* Stack: Eint8 --> */ + /* */ + static + void Ins_SROUND( INS_ARG ) + { + DO_SROUND + } + + + /*************************************************************************/ + /* */ + /* S45ROUND[]: Super ROUND 45 degrees */ + /* Opcode range: 0x77 */ + /* Stack: uint32 --> */ + /* */ + static + void Ins_S45ROUND( INS_ARG ) + { + DO_S45ROUND + } + + + /*************************************************************************/ + /* */ + /* SLOOP[]: Set LOOP variable */ + /* Opcode range: 0x17 */ + /* Stack: int32? --> */ + /* */ + static + void Ins_SLOOP( INS_ARG ) + { + DO_SLOOP + } + + + /*************************************************************************/ + /* */ + /* SMD[]: Set Minimum Distance */ + /* Opcode range: 0x1A */ + /* Stack: f26.6 --> */ + /* */ + static + void Ins_SMD( INS_ARG ) + { + DO_SMD + } + + + /*************************************************************************/ + /* */ + /* SCVTCI[]: Set Control Value Table Cut In */ + /* Opcode range: 0x1D */ + /* Stack: f26.6 --> */ + /* */ + static + void Ins_SCVTCI( INS_ARG ) + { + DO_SCVTCI + } + + + /*************************************************************************/ + /* */ + /* SSWCI[]: Set Single Width Cut In */ + /* Opcode range: 0x1E */ + /* Stack: f26.6 --> */ + /* */ + static + void Ins_SSWCI( INS_ARG ) + { + DO_SSWCI + } + + + /*************************************************************************/ + /* */ + /* SSW[]: Set Single Width */ + /* Opcode range: 0x1F */ + /* Stack: int32? --> */ + /* */ + static + void Ins_SSW( INS_ARG ) + { + DO_SSW + } + + + /*************************************************************************/ + /* */ + /* FLIPON[]: Set auto-FLIP to ON */ + /* Opcode range: 0x4D */ + /* Stack: --> */ + /* */ + static + void Ins_FLIPON( INS_ARG ) + { + DO_FLIPON + } + + + /*************************************************************************/ + /* */ + /* FLIPOFF[]: Set auto-FLIP to OFF */ + /* Opcode range: 0x4E */ + /* Stack: --> */ + /* */ + static + void Ins_FLIPOFF( INS_ARG ) + { + DO_FLIPOFF + } + + + /*************************************************************************/ + /* */ + /* SANGW[]: Set ANGle Weight */ + /* Opcode range: 0x7E */ + /* Stack: uint32 --> */ + /* */ + static + void Ins_SANGW( INS_ARG ) + { + /* instruction not supported anymore */ + } + + + /*************************************************************************/ + /* */ + /* SDB[]: Set Delta Base */ + /* Opcode range: 0x5E */ + /* Stack: uint32 --> */ + /* */ + static + void Ins_SDB( INS_ARG ) + { + DO_SDB + } + + + /*************************************************************************/ + /* */ + /* SDS[]: Set Delta Shift */ + /* Opcode range: 0x5F */ + /* Stack: uint32 --> */ + /* */ + static + void Ins_SDS( INS_ARG ) + { + DO_SDS + } + + + /*************************************************************************/ + /* */ + /* MPPEM[]: Measure Pixel Per EM */ + /* Opcode range: 0x4B */ + /* Stack: --> Euint16 */ + /* */ + static + void Ins_MPPEM( INS_ARG ) + { + DO_MPPEM + } + + + /*************************************************************************/ + /* */ + /* MPS[]: Measure Point Size */ + /* Opcode range: 0x4C */ + /* Stack: --> Euint16 */ + /* */ + static + void Ins_MPS( INS_ARG ) + { + DO_MPS + } + + + /*************************************************************************/ + /* */ + /* DUP[]: DUPlicate the top stack's element */ + /* Opcode range: 0x20 */ + /* Stack: StkElt --> StkElt StkElt */ + /* */ + static + void Ins_DUP( INS_ARG ) + { + DO_DUP + } + + + /*************************************************************************/ + /* */ + /* POP[]: POP the stack's top element */ + /* Opcode range: 0x21 */ + /* Stack: StkElt --> */ + /* */ + static + void Ins_POP( INS_ARG ) + { + /* nothing to do */ + } + + + /*************************************************************************/ + /* */ + /* CLEAR[]: CLEAR the entire stack */ + /* Opcode range: 0x22 */ + /* Stack: StkElt... --> */ + /* */ + static + void Ins_CLEAR( INS_ARG ) + { + DO_CLEAR + } + + + /*************************************************************************/ + /* */ + /* SWAP[]: SWAP the stack's top two elements */ + /* Opcode range: 0x23 */ + /* Stack: 2 * StkElt --> 2 * StkElt */ + /* */ + static + void Ins_SWAP( INS_ARG ) + { + DO_SWAP + } + + + /*************************************************************************/ + /* */ + /* DEPTH[]: return the stack DEPTH */ + /* Opcode range: 0x24 */ + /* Stack: --> uint32 */ + /* */ + static + void Ins_DEPTH( INS_ARG ) + { + DO_DEPTH + } + + + /*************************************************************************/ + /* */ + /* CINDEX[]: Copy INDEXed element */ + /* Opcode range: 0x25 */ + /* Stack: int32 --> StkElt */ + /* */ + static + void Ins_CINDEX( INS_ARG ) + { + DO_CINDEX + } + + + /*************************************************************************/ + /* */ + /* EIF[]: End IF */ + /* Opcode range: 0x59 */ + /* Stack: --> */ + /* */ + static + void Ins_EIF( INS_ARG ) + { + /* nothing to do */ + } + + + /*************************************************************************/ + /* */ + /* JROT[]: Jump Relative On True */ + /* Opcode range: 0x78 */ + /* Stack: StkElt int32 --> */ + /* */ + static + void Ins_JROT( INS_ARG ) + { + DO_JROT + } + + + /*************************************************************************/ + /* */ + /* JMPR[]: JuMP Relative */ + /* Opcode range: 0x1C */ + /* Stack: int32 --> */ + /* */ + static + void Ins_JMPR( INS_ARG ) + { + DO_JMPR + } + + + /*************************************************************************/ + /* */ + /* JROF[]: Jump Relative On False */ + /* Opcode range: 0x79 */ + /* Stack: StkElt int32 --> */ + /* */ + static + void Ins_JROF( INS_ARG ) + { + DO_JROF + } + + + /*************************************************************************/ + /* */ + /* LT[]: Less Than */ + /* Opcode range: 0x50 */ + /* Stack: int32? int32? --> bool */ + /* */ + static + void Ins_LT( INS_ARG ) + { + DO_LT + } + + + /*************************************************************************/ + /* */ + /* LTEQ[]: Less Than or EQual */ + /* Opcode range: 0x51 */ + /* Stack: int32? int32? --> bool */ + /* */ + static + void Ins_LTEQ( INS_ARG ) + { + DO_LTEQ + } + + + /*************************************************************************/ + /* */ + /* GT[]: Greater Than */ + /* Opcode range: 0x52 */ + /* Stack: int32? int32? --> bool */ + /* */ + static + void Ins_GT( INS_ARG ) + { + DO_GT + } + + + /*************************************************************************/ + /* */ + /* GTEQ[]: Greater Than or EQual */ + /* Opcode range: 0x53 */ + /* Stack: int32? int32? --> bool */ + /* */ + static + void Ins_GTEQ( INS_ARG ) + { + DO_GTEQ + } + + + /*************************************************************************/ + /* */ + /* EQ[]: EQual */ + /* Opcode range: 0x54 */ + /* Stack: StkElt StkElt --> bool */ + /* */ + static + void Ins_EQ( INS_ARG ) + { + DO_EQ + } + + + /*************************************************************************/ + /* */ + /* NEQ[]: Not EQual */ + /* Opcode range: 0x55 */ + /* Stack: StkElt StkElt --> bool */ + /* */ + static + void Ins_NEQ( INS_ARG ) + { + DO_NEQ + } + + + /*************************************************************************/ + /* */ + /* ODD[]: Is ODD */ + /* Opcode range: 0x56 */ + /* Stack: f26.6 --> bool */ + /* */ + static + void Ins_ODD( INS_ARG ) + { + DO_ODD + } + + + /*************************************************************************/ + /* */ + /* EVEN[]: Is EVEN */ + /* Opcode range: 0x57 */ + /* Stack: f26.6 --> bool */ + /* */ + static + void Ins_EVEN( INS_ARG ) + { + DO_EVEN + } + + + /*************************************************************************/ + /* */ + /* AND[]: logical AND */ + /* Opcode range: 0x5A */ + /* Stack: uint32 uint32 --> uint32 */ + /* */ + static + void Ins_AND( INS_ARG ) + { + DO_AND + } + + + /*************************************************************************/ + /* */ + /* OR[]: logical OR */ + /* Opcode range: 0x5B */ + /* Stack: uint32 uint32 --> uint32 */ + /* */ + static + void Ins_OR( INS_ARG ) + { + DO_OR + } + + + /*************************************************************************/ + /* */ + /* NOT[]: logical NOT */ + /* Opcode range: 0x5C */ + /* Stack: StkElt --> uint32 */ + /* */ + static + void Ins_NOT( INS_ARG ) + { + DO_NOT + } + + + /*************************************************************************/ + /* */ + /* ADD[]: ADD */ + /* Opcode range: 0x60 */ + /* Stack: f26.6 f26.6 --> f26.6 */ + /* */ + static + void Ins_ADD( INS_ARG ) + { + DO_ADD + } + + + /*************************************************************************/ + /* */ + /* SUB[]: SUBtract */ + /* Opcode range: 0x61 */ + /* Stack: f26.6 f26.6 --> f26.6 */ + /* */ + static + void Ins_SUB( INS_ARG ) + { + DO_SUB + } + + + /*************************************************************************/ + /* */ + /* DIV[]: DIVide */ + /* Opcode range: 0x62 */ + /* Stack: f26.6 f26.6 --> f26.6 */ + /* */ + static + void Ins_DIV( INS_ARG ) + { + DO_DIV + } + + + /*************************************************************************/ + /* */ + /* MUL[]: MULtiply */ + /* Opcode range: 0x63 */ + /* Stack: f26.6 f26.6 --> f26.6 */ + /* */ + static + void Ins_MUL( INS_ARG ) + { + DO_MUL + } + + + /*************************************************************************/ + /* */ + /* ABS[]: ABSolute value */ + /* Opcode range: 0x64 */ + /* Stack: f26.6 --> f26.6 */ + /* */ + static + void Ins_ABS( INS_ARG ) + { + DO_ABS + } + + + /*************************************************************************/ + /* */ + /* NEG[]: NEGate */ + /* Opcode range: 0x65 */ + /* Stack: f26.6 --> f26.6 */ + /* */ + static + void Ins_NEG( INS_ARG ) + { + DO_NEG + } + + + /*************************************************************************/ + /* */ + /* FLOOR[]: FLOOR */ + /* Opcode range: 0x66 */ + /* Stack: f26.6 --> f26.6 */ + /* */ + static + void Ins_FLOOR( INS_ARG ) + { + DO_FLOOR + } + + + /*************************************************************************/ + /* */ + /* CEILING[]: CEILING */ + /* Opcode range: 0x67 */ + /* Stack: f26.6 --> f26.6 */ + /* */ + static + void Ins_CEILING( INS_ARG ) + { + DO_CEILING + } + + + /*************************************************************************/ + /* */ + /* RS[]: Read Store */ + /* Opcode range: 0x43 */ + /* Stack: uint32 --> uint32 */ + /* */ + static + void Ins_RS( INS_ARG ) + { + DO_RS + } + + + /*************************************************************************/ + /* */ + /* WS[]: Write Store */ + /* Opcode range: 0x42 */ + /* Stack: uint32 uint32 --> */ + /* */ + static + void Ins_WS( INS_ARG ) + { + DO_WS + } + + + /*************************************************************************/ + /* */ + /* WCVTP[]: Write CVT in Pixel units */ + /* Opcode range: 0x44 */ + /* Stack: f26.6 uint32 --> */ + /* */ + static + void Ins_WCVTP( INS_ARG ) + { + DO_WCVTP + } + + + /*************************************************************************/ + /* */ + /* WCVTF[]: Write CVT in Funits */ + /* Opcode range: 0x70 */ + /* Stack: uint32 uint32 --> */ + /* */ + static + void Ins_WCVTF( INS_ARG ) + { + DO_WCVTF + } + + + /*************************************************************************/ + /* */ + /* RCVT[]: Read CVT */ + /* Opcode range: 0x45 */ + /* Stack: uint32 --> f26.6 */ + /* */ + static + void Ins_RCVT( INS_ARG ) + { + DO_RCVT + } + + + /*************************************************************************/ + /* */ + /* AA[]: Adjust Angle */ + /* Opcode range: 0x7F */ + /* Stack: uint32 --> */ + /* */ + static + void Ins_AA( INS_ARG ) + { + /* intentionally no longer supported */ + } + + + /*************************************************************************/ + /* */ + /* DEBUG[]: DEBUG. Unsupported. */ + /* Opcode range: 0x4F */ + /* Stack: uint32 --> */ + /* */ + /* Note: The original instruction pops a value from the stack. */ + /* */ + static + void Ins_DEBUG( INS_ARG ) + { + DO_DEBUG + } + + + /*************************************************************************/ + /* */ + /* ROUND[ab]: ROUND value */ + /* Opcode range: 0x68-0x6B */ + /* Stack: f26.6 --> f26.6 */ + /* */ + static + void Ins_ROUND( INS_ARG ) + { + DO_ROUND + } + + + /*************************************************************************/ + /* */ + /* NROUND[ab]: No ROUNDing of value */ + /* Opcode range: 0x6C-0x6F */ + /* Stack: f26.6 --> f26.6 */ + /* */ + static + void Ins_NROUND( INS_ARG ) + { + DO_NROUND + } + + + /*************************************************************************/ + /* */ + /* MAX[]: MAXimum */ + /* Opcode range: 0x68 */ + /* Stack: int32? int32? --> int32 */ + /* */ + static + void Ins_MAX( INS_ARG ) + { + DO_MAX + } + + + /*************************************************************************/ + /* */ + /* MIN[]: MINimum */ + /* Opcode range: 0x69 */ + /* Stack: int32? int32? --> int32 */ + /* */ + static + void Ins_MIN( INS_ARG ) + { + DO_MIN + } + + +#endif /* !TT_CONFIG_OPTION_INTERPRETER_SWITCH */ + + + /*************************************************************************/ + /* */ + /* The following functions are called as is within the switch statement. */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* MINDEX[]: Move INDEXed element */ + /* Opcode range: 0x26 */ + /* Stack: int32? --> StkElt */ + /* */ + static + void Ins_MINDEX( INS_ARG ) + { + FT_Long L, K; + + + L = args[0]; + + if ( L <= 0 || L > CUR.args ) + { + CUR.error = TT_Err_Invalid_Reference; + return; + } + + K = CUR.stack[CUR.args - L]; + + MEM_Move( &CUR.stack[CUR.args - L ], + &CUR.stack[CUR.args - L + 1], + ( L - 1 ) * sizeof ( FT_Long ) ); + + CUR.stack[CUR.args - 1] = K; + } + + + /*************************************************************************/ + /* */ + /* ROLL[]: ROLL top three elements */ + /* Opcode range: 0x8A */ + /* Stack: 3 * StkElt --> 3 * StkElt */ + /* */ + static + void Ins_ROLL( INS_ARG ) + { + FT_Long A, B, C; + + FT_UNUSED_EXEC; + + + A = args[2]; + B = args[1]; + C = args[0]; + + args[2] = C; + args[1] = A; + args[0] = B; + } + + + /*************************************************************************/ + /* */ + /* MANAGING THE FLOW OF CONTROL */ + /* */ + /* Instructions appear in the specification's order. */ + /* */ + /*************************************************************************/ + + + static + FT_Bool SkipCode( EXEC_OP ) + { + CUR.IP += CUR.length; + + if ( CUR.IP < CUR.codeSize ) + { + CUR.opcode = CUR.code[CUR.IP]; + + CUR.length = opcode_length[CUR.opcode]; + if ( CUR.length < 0 ) + { + if ( CUR.IP + 1 > CUR.codeSize ) + goto Fail_Overflow; + CUR.length = CUR.code[CUR.IP + 1] + 2; + } + + if ( CUR.IP + CUR.length <= CUR.codeSize ) + return SUCCESS; + } + + Fail_Overflow: + CUR.error = TT_Err_Code_Overflow; + return FAILURE; + } + + + /*************************************************************************/ + /* */ + /* IF[]: IF test */ + /* Opcode range: 0x58 */ + /* Stack: StkElt --> */ + /* */ + static + void Ins_IF( INS_ARG ) + { + FT_Int nIfs; + FT_Bool Out; + + + if ( args[0] != 0 ) + return; + + nIfs = 1; + Out = 0; + + do + { + if ( SKIP_Code() == FAILURE ) + return; + + switch ( CUR.opcode ) + { + case 0x58: /* IF */ + nIfs++; + break; + + case 0x1B: /* ELSE */ + Out = ( nIfs == 1 ); + break; + + case 0x59: /* EIF */ + nIfs--; + Out = ( nIfs == 0 ); + break; + } + } while ( Out == 0 ); + } + + + /*************************************************************************/ + /* */ + /* ELSE[]: ELSE */ + /* Opcode range: 0x1B */ + /* Stack: --> */ + /* */ + static + void Ins_ELSE( INS_ARG ) + { + FT_Int nIfs; + + FT_UNUSED_ARG; + + + nIfs = 1; + + do + { + if ( SKIP_Code() == FAILURE ) + return; + + switch ( CUR.opcode ) + { + case 0x58: /* IF */ + nIfs++; + break; + + case 0x59: /* EIF */ + nIfs--; + break; + } + } while ( nIfs != 0 ); + } + + + /*************************************************************************/ + /* */ + /* DEFINING AND USING FUNCTIONS AND INSTRUCTIONS */ + /* */ + /* Instructions appear in the specification's order. */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* FDEF[]: Function DEFinition */ + /* Opcode range: 0x2C */ + /* Stack: uint32 --> */ + /* */ + static + void Ins_FDEF( INS_ARG ) + { + FT_ULong n; + TT_DefRecord* rec; + TT_DefRecord* limit; + + + /* some font programs are broken enough to redefine functions! */ + /* We will then parse the current table. */ + + rec = CUR.FDefs; + limit = rec + CUR.numFDefs; + n = args[0]; + + for ( ; rec < limit; rec++ ) + { + if ( rec->opc == n ) + break; + } + + if ( rec == limit ) + { + /* check that there is enough room for new functions */ + if ( CUR.numFDefs >= CUR.maxFDefs ) + { + CUR.error = TT_Err_Too_Many_Function_Defs; + return; + } + CUR.numFDefs++; + } + + rec->range = CUR.curRange; + rec->opc = n; + rec->start = CUR.IP + 1; + rec->active = TRUE; + + if ( n > CUR.maxFunc ) + CUR.maxFunc = n; + + /* Now skip the whole function definition. */ + /* We don't allow nested IDEFS & FDEFs. */ + + while ( SKIP_Code() == SUCCESS ) + { + switch ( CUR.opcode ) + { + case 0x89: /* IDEF */ + case 0x2C: /* FDEF */ + CUR.error = TT_Err_Nested_DEFS; + return; + + case 0x2D: /* ENDF */ + return; + } + } + } + + + /*************************************************************************/ + /* */ + /* ENDF[]: END Function definition */ + /* Opcode range: 0x2D */ + /* Stack: --> */ + /* */ + static + void Ins_ENDF( INS_ARG ) + { + TT_CallRec* pRec; + + FT_UNUSED_ARG; + + + if ( CUR.callTop <= 0 ) /* We encountered an ENDF without a call */ + { + CUR.error = TT_Err_ENDF_In_Exec_Stream; + return; + } + + CUR.callTop--; + + pRec = &CUR.callStack[CUR.callTop]; + + pRec->Cur_Count--; + + CUR.step_ins = FALSE; + + if ( pRec->Cur_Count > 0 ) + { + CUR.callTop++; + CUR.IP = pRec->Cur_Restart; + } + else + /* Loop through the current function */ + INS_Goto_CodeRange( pRec->Caller_Range, + pRec->Caller_IP ); + + /* Exit the current call frame. */ + + /* NOTE: If the last intruction of a program is a */ + /* CALL or LOOPCALL, the return address is */ + /* always out of the code range. This is a */ + /* valid address, and it is why we do not test */ + /* the result of Ins_Goto_CodeRange() here! */ + } + + + /*************************************************************************/ + /* */ + /* CALL[]: CALL function */ + /* Opcode range: 0x2B */ + /* Stack: uint32? --> */ + /* */ + static + void Ins_CALL( INS_ARG ) + { + FT_ULong F; + TT_CallRec* pCrec; + TT_DefRecord* def; + + + /* first of all, check the index */ + + F = args[0]; + if ( BOUNDS( F, CUR.maxFunc + 1 ) ) + goto Fail; + + /* Except for some old Apple fonts, all functions in a TrueType */ + /* font are defined in increasing order, starting from 0. This */ + /* means that we normally have */ + /* */ + /* CUR.maxFunc+1 == CUR.numFDefs */ + /* CUR.FDefs[n].opc == n for n in 0..CUR.maxFunc */ + /* */ + /* If this isn't true, we need to look up the function table. */ + + def = CUR.FDefs + F; + if ( CUR.maxFunc + 1 != CUR.numFDefs || def->opc != F ) + { + /* look up the FDefs table */ + TT_DefRecord* limit; + + + def = CUR.FDefs; + limit = def + CUR.numFDefs; + + while ( def < limit && def->opc != F ) + def++; + + if ( def == limit ) + goto Fail; + } + + /* check that the function is active */ + if ( !def->active ) + goto Fail; + + /* check the call stack */ + if ( CUR.callTop >= CUR.callSize ) + { + CUR.error = TT_Err_Stack_Overflow; + return; + } + + pCrec = CUR.callStack + CUR.callTop; + + pCrec->Caller_Range = CUR.curRange; + pCrec->Caller_IP = CUR.IP + 1; + pCrec->Cur_Count = 1; + pCrec->Cur_Restart = def->start; + + CUR.callTop++; + + INS_Goto_CodeRange( def->range, + def->start ); + + CUR.step_ins = FALSE; + return; + + Fail: + CUR.error = TT_Err_Invalid_Reference; + } + + + /*************************************************************************/ + /* */ + /* LOOPCALL[]: LOOP and CALL function */ + /* Opcode range: 0x2A */ + /* Stack: uint32? Eint16? --> */ + /* */ + static + void Ins_LOOPCALL( INS_ARG ) + { + FT_ULong F; + TT_CallRec* pCrec; + TT_DefRecord* def; + + + /* first of all, check the index */ + F = args[1]; + if ( BOUNDS( F, CUR.maxFunc + 1 ) ) + goto Fail; + + /* Except for some old Apple fonts, all functions in a TrueType */ + /* font are defined in increasing order, starting from 0. This */ + /* means that we normally have */ + /* */ + /* CUR.maxFunc+1 == CUR.numFDefs */ + /* CUR.FDefs[n].opc == n for n in 0..CUR.maxFunc */ + /* */ + /* If this isn't true, we need to look up the function table. */ + + def = CUR.FDefs + F; + if ( CUR.maxFunc + 1 != CUR.numFDefs || def->opc != F ) + { + /* look up the FDefs table */ + TT_DefRecord* limit; + + + def = CUR.FDefs; + limit = def + CUR.numFDefs; + + while ( def < limit && def->opc != F ) + def++; + + if ( def == limit ) + goto Fail; + } + + /* check that the function is active */ + if ( !def->active ) + goto Fail; + + /* check stack */ + if ( CUR.callTop >= CUR.callSize ) + { + CUR.error = TT_Err_Stack_Overflow; + return; + } + + if ( args[0] > 0 ) + { + pCrec = CUR.callStack + CUR.callTop; + + pCrec->Caller_Range = CUR.curRange; + pCrec->Caller_IP = CUR.IP + 1; + pCrec->Cur_Count = (FT_Int)args[0]; + pCrec->Cur_Restart = def->start; + + CUR.callTop++; + + INS_Goto_CodeRange( def->range, def->start ); + + CUR.step_ins = FALSE; + } + return; + + Fail: + CUR.error = TT_Err_Invalid_Reference; + } + + + /*************************************************************************/ + /* */ + /* IDEF[]: Instruction DEFinition */ + /* Opcode range: 0x89 */ + /* Stack: Eint8 --> */ + /* */ + static + void Ins_IDEF( INS_ARG ) + { + TT_DefRecord* def; + TT_DefRecord* limit; + + + /* First of all, look for the same function in our table */ + + def = CUR.IDefs; + limit = def + CUR.numIDefs; + + for ( ; def < limit; def++ ) + if ( def->opc == (FT_ULong)args[0] ) + break; + + if ( def == limit ) + { + /* check that there is enough room for a new instruction */ + if ( CUR.numIDefs >= CUR.maxIDefs ) + { + CUR.error = TT_Err_Too_Many_Instruction_Defs; + return; + } + CUR.numIDefs++; + } + + def->opc = args[0]; + def->start = CUR.IP+1; + def->range = CUR.curRange; + def->active = TRUE; + + if ( (FT_ULong)args[0] > CUR.maxIns ) + CUR.maxIns = args[0]; + + /* Now skip the whole function definition. */ + /* We don't allow nested IDEFs & FDEFs. */ + + while ( SKIP_Code() == SUCCESS ) + { + switch ( CUR.opcode ) + { + case 0x89: /* IDEF */ + case 0x2C: /* FDEF */ + CUR.error = TT_Err_Nested_DEFS; + return; + case 0x2D: /* ENDF */ + return; + } + } + } + + + /*************************************************************************/ + /* */ + /* PUSHING DATA ONTO THE INTERPRETER STACK */ + /* */ + /* Instructions appear in the specification's order. */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* NPUSHB[]: PUSH N Bytes */ + /* Opcode range: 0x40 */ + /* Stack: --> uint32... */ + /* */ + static + void Ins_NPUSHB( INS_ARG ) + { + FT_UShort L, K; + + + L = (FT_UShort)CUR.code[CUR.IP + 1]; + + if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) ) + { + CUR.error = TT_Err_Stack_Overflow; + return; + } + + for ( K = 1; K <= L; K++ ) + args[K - 1] = CUR.code[CUR.IP + K + 1]; + + CUR.new_top += L; + } + + + /*************************************************************************/ + /* */ + /* NPUSHW[]: PUSH N Words */ + /* Opcode range: 0x41 */ + /* Stack: --> int32... */ + /* */ + static + void Ins_NPUSHW( INS_ARG ) + { + FT_UShort L, K; + + + L = (FT_UShort)CUR.code[CUR.IP + 1]; + + if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) ) + { + CUR.error = TT_Err_Stack_Overflow; + return; + } + + CUR.IP += 2; + + for ( K = 0; K < L; K++ ) + args[K] = GET_ShortIns(); + + CUR.step_ins = FALSE; + CUR.new_top += L; + } + + + /*************************************************************************/ + /* */ + /* PUSHB[abc]: PUSH Bytes */ + /* Opcode range: 0xB0-0xB7 */ + /* Stack: --> uint32... */ + /* */ + static + void Ins_PUSHB( INS_ARG ) + { + FT_UShort L, K; + + + L = (FT_UShort)CUR.opcode - 0xB0 + 1; + + if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) ) + { + CUR.error = TT_Err_Stack_Overflow; + return; + } + + for ( K = 1; K <= L; K++ ) + args[K - 1] = CUR.code[CUR.IP + K]; + } + + + /*************************************************************************/ + /* */ + /* PUSHW[abc]: PUSH Words */ + /* Opcode range: 0xB8-0xBF */ + /* Stack: --> int32... */ + /* */ + static + void Ins_PUSHW( INS_ARG ) + { + FT_UShort L, K; + + + L = (FT_UShort)CUR.opcode - 0xB8 + 1; + + if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) ) + { + CUR.error = TT_Err_Stack_Overflow; + return; + } + + CUR.IP++; + + for ( K = 0; K < L; K++ ) + args[K] = GET_ShortIns(); + + CUR.step_ins = FALSE; + } + + + /*************************************************************************/ + /* */ + /* MANAGING THE GRAPHICS STATE */ + /* */ + /* Instructions appear in the specs' order. */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* GC[a]: Get Coordinate projected onto */ + /* Opcode range: 0x46-0x47 */ + /* Stack: uint32 --> f26.6 */ + /* */ + /* BULLSHIT: Measures from the original glyph must be taken along the */ + /* dual projection vector! */ + /* */ + static void Ins_GC( INS_ARG ) + { + FT_ULong L; + FT_F26Dot6 R; + + + L = (FT_ULong)args[0]; + + if ( BOUNDS( L, CUR.zp2.n_points ) ) + { + if ( CUR.pedantic_hinting ) + { + CUR.error = TT_Err_Invalid_Reference; + return; + } + else + R = 0; + } + else + { + if ( CUR.opcode & 1 ) + R = CUR_Func_dualproj( CUR.zp2.org + L, NULL_Vector ); + else + R = CUR_Func_project( CUR.zp2.cur + L, NULL_Vector ); + } + + args[0] = R; + } + + + /*************************************************************************/ + /* */ + /* SCFS[]: Set Coordinate From Stack */ + /* Opcode range: 0x48 */ + /* Stack: f26.6 uint32 --> */ + /* */ + /* Formula: */ + /* */ + /* OA := OA + ( value - OA.p )/( f.p ) * f */ + /* */ + static + void Ins_SCFS( INS_ARG ) + { + FT_Long K; + FT_UShort L; + + + L = (FT_UShort)args[0]; + + if ( BOUNDS( L, CUR.zp2.n_points ) ) + { + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + return; + } + + K = CUR_Func_project( CUR.zp2.cur + L, NULL_Vector ); + + CUR_Func_move( &CUR.zp2, L, args[1] - K ); + + /* not part of the specs, but here for safety */ + + if ( CUR.GS.gep2 == 0 ) + CUR.zp2.org[L] = CUR.zp2.cur[L]; + } + + + /*************************************************************************/ + /* */ + /* MD[a]: Measure Distance */ + /* Opcode range: 0x49-0x4A */ + /* Stack: uint32 uint32 --> f26.6 */ + /* */ + /* BULLSHIT: Measure taken in the original glyph must be along the dual */ + /* projection vector. */ + /* */ + /* Second BULLSHIT: Flag attributes are inverted! */ + /* 0 => measure distance in original outline */ + /* 1 => measure distance in grid-fitted outline */ + /* */ + /* Third one: `zp0 - zp1', and not `zp2 - zp1! */ + /* */ + static + void Ins_MD( INS_ARG ) + { + FT_UShort K, L; + FT_F26Dot6 D; + + + K = (FT_UShort)args[1]; + L = (FT_UShort)args[0]; + + if( BOUNDS( L, CUR.zp0.n_points ) || + BOUNDS( K, CUR.zp1.n_points ) ) + { + if ( CUR.pedantic_hinting ) + { + CUR.error = TT_Err_Invalid_Reference; + return; + } + D = 0; + } + else + { + if ( CUR.opcode & 1 ) + D = CUR_Func_project( CUR.zp0.cur + L, CUR.zp1.cur + K ); + else + D = CUR_Func_dualproj( CUR.zp0.org + L, CUR.zp1.org + K ); + } + + args[0] = D; + } + + + /*************************************************************************/ + /* */ + /* SDPVTL[a]: Set Dual PVector to Line */ + /* Opcode range: 0x86-0x87 */ + /* Stack: uint32 uint32 --> */ + /* */ + static + void Ins_SDPVTL( INS_ARG ) + { + FT_Long A, B, C; + FT_UShort p1, p2; /* was FT_Int in pas type ERROR */ + + + p1 = (FT_UShort)args[1]; + p2 = (FT_UShort)args[0]; + + if ( BOUNDS( p2, CUR.zp1.n_points ) || + BOUNDS( p1, CUR.zp2.n_points ) ) + { + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + return; + } + + { + FT_Vector* v1 = CUR.zp1.org + p2; + FT_Vector* v2 = CUR.zp2.org + p1; + + + A = v1->x - v2->x; + B = v1->y - v2->y; + } + + if ( ( CUR.opcode & 1 ) != 0 ) + { + C = B; /* counter clockwise rotation */ + B = A; + A = -C; + } + + NORMalize( A, B, &CUR.GS.dualVector ); + + { + FT_Vector* v1 = CUR.zp1.cur + p2; + FT_Vector* v2 = CUR.zp2.cur + p1; + + + A = v1->x - v2->x; + B = v1->y - v2->y; + } + + if ( ( CUR.opcode & 1 ) != 0 ) + { + C = B; /* counter clockwise rotation */ + B = A; + A = -C; + } + + NORMalize( A, B, &CUR.GS.projVector ); + + COMPUTE_Funcs(); + } + + + /*************************************************************************/ + /* */ + /* SZP0[]: Set Zone Pointer 0 */ + /* Opcode range: 0x13 */ + /* Stack: uint32 --> */ + /* */ + static + void Ins_SZP0( INS_ARG ) + { + switch ( (FT_Int)args[0] ) + { + case 0: + CUR.zp0 = CUR.twilight; + break; + + case 1: + CUR.zp0 = CUR.pts; + break; + + default: + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + return; + } + + CUR.GS.gep0 = (FT_UShort)args[0]; + } + + + /*************************************************************************/ + /* */ + /* SZP1[]: Set Zone Pointer 1 */ + /* Opcode range: 0x14 */ + /* Stack: uint32 --> */ + /* */ + static + void Ins_SZP1( INS_ARG ) + { + switch ( (FT_Int)args[0] ) + { + case 0: + CUR.zp1 = CUR.twilight; + break; + + case 1: + CUR.zp1 = CUR.pts; + break; + + default: + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + return; + } + + CUR.GS.gep1 = (FT_UShort)args[0]; + } + + + /*************************************************************************/ + /* */ + /* SZP2[]: Set Zone Pointer 2 */ + /* Opcode range: 0x15 */ + /* Stack: uint32 --> */ + /* */ + static + void Ins_SZP2( INS_ARG ) + { + switch ( (FT_Int)args[0] ) + { + case 0: + CUR.zp2 = CUR.twilight; + break; + + case 1: + CUR.zp2 = CUR.pts; + break; + + default: + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + return; + } + + CUR.GS.gep2 = (FT_UShort)args[0]; + } + + + /*************************************************************************/ + /* */ + /* SZPS[]: Set Zone PointerS */ + /* Opcode range: 0x16 */ + /* Stack: uint32 --> */ + /* */ + static + void Ins_SZPS( INS_ARG ) + { + switch ( (FT_Int)args[0] ) + { + case 0: + CUR.zp0 = CUR.twilight; + break; + + case 1: + CUR.zp0 = CUR.pts; + break; + + default: + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + return; + } + + CUR.zp1 = CUR.zp0; + CUR.zp2 = CUR.zp0; + + CUR.GS.gep0 = (FT_UShort)args[0]; + CUR.GS.gep1 = (FT_UShort)args[0]; + CUR.GS.gep2 = (FT_UShort)args[0]; + } + + + /*************************************************************************/ + /* */ + /* INSTCTRL[]: INSTruction ConTRoL */ + /* Opcode range: 0x8e */ + /* Stack: int32 int32 --> */ + /* */ + static + void Ins_INSTCTRL( INS_ARG ) + { + FT_Long K, L; + + + K = args[1]; + L = args[0]; + + if ( K < 1 || K > 2 ) + { + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + return; + } + + if ( L != 0 ) + L = K; + + CUR.GS.instruct_control = + (FT_Byte)( CUR.GS.instruct_control & ~(FT_Byte)K ) | (FT_Byte)L; + } + + + /*************************************************************************/ + /* */ + /* SCANCTRL[]: SCAN ConTRoL */ + /* Opcode range: 0x85 */ + /* Stack: uint32? --> */ + /* */ + static + void Ins_SCANCTRL( INS_ARG ) + { + FT_Int A; + + + /* Get Threshold */ + A = (FT_Int)( args[0] & 0xFF ); + + if ( A == 0xFF ) + { + CUR.GS.scan_control = TRUE; + return; + } + else if ( A == 0 ) + { + CUR.GS.scan_control = FALSE; + return; + } + + A *= 64; + +#if 0 + if ( (args[0] & 0x100) != 0 && CUR.metrics.pointSize <= A ) + CUR.GS.scan_control = TRUE; +#endif + + if ( (args[0] & 0x200) != 0 && CUR.tt_metrics.rotated ) + CUR.GS.scan_control = TRUE; + + if ( (args[0] & 0x400) != 0 && CUR.tt_metrics.stretched ) + CUR.GS.scan_control = TRUE; + +#if 0 + if ( (args[0] & 0x800) != 0 && CUR.metrics.pointSize > A ) + CUR.GS.scan_control = FALSE; +#endif + + if ( (args[0] & 0x1000) != 0 && CUR.tt_metrics.rotated ) + CUR.GS.scan_control = FALSE; + + if ( (args[0] & 0x2000) != 0 && CUR.tt_metrics.stretched ) + CUR.GS.scan_control = FALSE; +} + + + /*************************************************************************/ + /* */ + /* SCANTYPE[]: SCAN TYPE */ + /* Opcode range: 0x8D */ + /* Stack: uint32? --> */ + /* */ + static + void Ins_SCANTYPE( INS_ARG ) + { + /* for compatibility with future enhancements, */ + /* we must ignore new modes */ + + if ( args[0] >= 0 && args[0] <= 5 ) + { + if ( args[0] == 3 ) + args[0] = 2; + + CUR.GS.scan_type = (FT_Int)args[0]; + } + } + + + /*************************************************************************/ + /* */ + /* MANAGING OUTLINES */ + /* */ + /* Instructions appear in the specification's order. */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* FLIPPT[]: FLIP PoinT */ + /* Opcode range: 0x80 */ + /* Stack: uint32... --> */ + /* */ + static + void Ins_FLIPPT( INS_ARG ) + { + FT_UShort point; + + FT_UNUSED_ARG; + + + if ( CUR.top < CUR.GS.loop ) + { + CUR.error = TT_Err_Too_Few_Arguments; + return; + } + + while ( CUR.GS.loop > 0 ) + { + CUR.args--; + + point = (FT_UShort)CUR.stack[CUR.args]; + + if ( BOUNDS( point, CUR.pts.n_points ) ) + { + if ( CUR.pedantic_hinting ) + { + CUR.error = TT_Err_Invalid_Reference; + return; + } + } + else + CUR.pts.tags[point] ^= FT_Curve_Tag_On; + + CUR.GS.loop--; + } + + CUR.GS.loop = 1; + CUR.new_top = CUR.args; + } + + + /*************************************************************************/ + /* */ + /* FLIPRGON[]: FLIP RanGe ON */ + /* Opcode range: 0x81 */ + /* Stack: uint32 uint32 --> */ + /* */ + static + void Ins_FLIPRGON( INS_ARG ) + { + FT_UShort I, K, L; + + + K = (FT_UShort)args[1]; + L = (FT_UShort)args[0]; + + if ( BOUNDS( K, CUR.pts.n_points ) || + BOUNDS( L, CUR.pts.n_points ) ) + { + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + return; + } + + for ( I = L; I <= K; I++ ) + CUR.pts.tags[I] |= FT_Curve_Tag_On; + } + + + /*************************************************************************/ + /* */ + /* FLIPRGOFF: FLIP RanGe OFF */ + /* Opcode range: 0x82 */ + /* Stack: uint32 uint32 --> */ + /* */ + static + void Ins_FLIPRGOFF( INS_ARG ) + { + FT_UShort I, K, L; + + + K = (FT_UShort)args[1]; + L = (FT_UShort)args[0]; + + if ( BOUNDS( K, CUR.pts.n_points ) || + BOUNDS( L, CUR.pts.n_points ) ) + { + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + return; + } + + for ( I = L; I <= K; I++ ) + CUR.pts.tags[I] &= ~FT_Curve_Tag_On; + } + + + static + FT_Bool Compute_Point_Displacement( EXEC_OP_ FT_F26Dot6* x, + FT_F26Dot6* y, + TT_GlyphZone* zone, + FT_UShort* refp ) + { + TT_GlyphZone zp; + FT_UShort p; + FT_F26Dot6 d; + + + if ( CUR.opcode & 1 ) + { + zp = CUR.zp0; + p = CUR.GS.rp1; + } + else + { + zp = CUR.zp1; + p = CUR.GS.rp2; + } + + if ( BOUNDS( p, zp.n_points ) ) + { + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + return FAILURE; + } + + *zone = zp; + *refp = p; + + d = CUR_Func_project( zp.cur + p, zp.org + p ); + +#ifdef NO_APPLE_PATENT + + *x = TT_MULDIV( d, CUR.GS.freeVector.x, 0x4000 ); + *y = TT_MULDIV( d, CUR.GS.freeVector.y, 0x4000 ); + +#else + + *x = TT_MULDIV( d, + (FT_Long)CUR.GS.freeVector.x * 0x10000L, + CUR.F_dot_P ); + *y = TT_MULDIV( d, + (FT_Long)CUR.GS.freeVector.y * 0x10000L, + CUR.F_dot_P ); + +#endif /* NO_APPLE_PATENT */ + + return SUCCESS; + } + + + static + void Move_Zp2_Point( EXEC_OP_ FT_UShort point, + FT_F26Dot6 dx, + FT_F26Dot6 dy, + FT_Bool touch ) + { + if ( CUR.GS.freeVector.x != 0 ) + { + CUR.zp2.cur[point].x += dx; + if ( touch ) + CUR.zp2.tags[point] |= FT_Curve_Tag_Touch_X; + } + + if ( CUR.GS.freeVector.y != 0 ) + { + CUR.zp2.cur[point].y += dy; + if ( touch ) + CUR.zp2.tags[point] |= FT_Curve_Tag_Touch_Y; + } + } + + + /*************************************************************************/ + /* */ + /* SHP[a]: SHift Point by the last point */ + /* Opcode range: 0x32-0x33 */ + /* Stack: uint32... --> */ + /* */ + static + void Ins_SHP( INS_ARG ) + { + TT_GlyphZone zp; + FT_UShort refp; + + FT_F26Dot6 dx, + dy; + FT_UShort point; + + FT_UNUSED_ARG; + + + if ( CUR.top < CUR.GS.loop ) + { + CUR.error = TT_Err_Invalid_Reference; + return; + } + + if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) ) + return; + + while ( CUR.GS.loop > 0 ) + { + CUR.args--; + point = (FT_UShort)CUR.stack[CUR.args]; + + if ( BOUNDS( point, CUR.zp2.n_points ) ) + { + if ( CUR.pedantic_hinting ) + { + CUR.error = TT_Err_Invalid_Reference; + return; + } + } + else + /* XXX: UNDOCUMENTED! SHP touches the points */ + MOVE_Zp2_Point( point, dx, dy, TRUE ); + + CUR.GS.loop--; + } + + CUR.GS.loop = 1; + CUR.new_top = CUR.args; + } + + + /*************************************************************************/ + /* */ + /* SHC[a]: SHift Contour */ + /* Opcode range: 0x34-35 */ + /* Stack: uint32 --> */ + /* */ + static + void Ins_SHC( INS_ARG ) + { + TT_GlyphZone zp; + FT_UShort refp; + FT_F26Dot6 dx, + dy; + + FT_Short contour; + FT_UShort first_point, last_point, i; + + + contour = (FT_UShort)args[0]; + + if ( BOUNDS( contour, CUR.pts.n_contours ) ) + { + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + return; + } + + if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) ) + return; + + if ( contour == 0 ) + first_point = 0; + else + first_point = CUR.pts.contours[contour - 1] + 1; + + last_point = CUR.pts.contours[contour]; + + /* XXX: this is probably wrong... at least it prevents memory */ + /* corruption when zp2 is the twilight zone */ + if ( last_point > CUR.zp2.n_points ) + { + if ( CUR.zp2.n_points > 0 ) + last_point = CUR.zp2.n_points - 1; + else + last_point = 0; + } + + /* XXX: UNDOCUMENTED! SHC doesn't touch the points */ + for ( i = first_point; i <= last_point; i++ ) + { + if ( zp.cur != CUR.zp2.cur || refp != i ) + MOVE_Zp2_Point( i, dx, dy, FALSE ); + } + } + + + /*************************************************************************/ + /* */ + /* SHZ[a]: SHift Zone */ + /* Opcode range: 0x36-37 */ + /* Stack: uint32 --> */ + /* */ + static + void Ins_SHZ( INS_ARG ) + { + TT_GlyphZone zp; + FT_UShort refp; + FT_F26Dot6 dx, + dy; + + FT_UShort last_point, i; + + + if ( BOUNDS( args[0], 2 ) ) + { + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + return; + } + + if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) ) + return; + + if ( CUR.zp2.n_points > 0 ) + last_point = CUR.zp2.n_points - 1; + else + last_point = 0; + + /* XXX: UNDOCUMENTED! SHZ doesn't touch the points */ + for ( i = 0; i <= last_point; i++ ) + { + if ( zp.cur != CUR.zp2.cur || refp != i ) + MOVE_Zp2_Point( i, dx, dy, FALSE ); + } + } + + + /*************************************************************************/ + /* */ + /* SHPIX[]: SHift points by a PIXel amount */ + /* Opcode range: 0x38 */ + /* Stack: f26.6 uint32... --> */ + /* */ + static + void Ins_SHPIX( INS_ARG ) + { + FT_F26Dot6 dx, dy; + FT_UShort point; + + + if ( CUR.top < CUR.GS.loop + 1 ) + { + CUR.error = TT_Err_Invalid_Reference; + return; + } + + dx = TT_MULDIV( args[0], + (FT_Long)CUR.GS.freeVector.x, + 0x4000 ); + dy = TT_MULDIV( args[0], + (FT_Long)CUR.GS.freeVector.y, + 0x4000 ); + + while ( CUR.GS.loop > 0 ) + { + CUR.args--; + + point = (FT_UShort)CUR.stack[CUR.args]; + + if ( BOUNDS( point, CUR.zp2.n_points ) ) + { + if ( CUR.pedantic_hinting ) + { + CUR.error = TT_Err_Invalid_Reference; + return; + } + } + else + MOVE_Zp2_Point( point, dx, dy, TRUE ); + + CUR.GS.loop--; + } + + CUR.GS.loop = 1; + CUR.new_top = CUR.args; + } + + + /*************************************************************************/ + /* */ + /* MSIRP[a]: Move Stack Indirect Relative Position */ + /* Opcode range: 0x3A-0x3B */ + /* Stack: f26.6 uint32 --> */ + /* */ + static + void Ins_MSIRP( INS_ARG ) + { + FT_UShort point; + FT_F26Dot6 distance; + + + point = (FT_UShort)args[0]; + + if ( BOUNDS( point, CUR.zp1.n_points ) || + BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) ) + { + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + return; + } + + /* XXX: UNDOCUMENTED! behaviour */ + if ( CUR.GS.gep0 == 0 ) /* if in twilight zone */ + { + CUR.zp1.org[point] = CUR.zp0.org[CUR.GS.rp0]; + CUR.zp1.cur[point] = CUR.zp1.org[point]; + } + + distance = CUR_Func_project( CUR.zp1.cur + point, + CUR.zp0.cur + CUR.GS.rp0 ); + + CUR_Func_move( &CUR.zp1, point, args[1] - distance ); + + CUR.GS.rp1 = CUR.GS.rp0; + CUR.GS.rp2 = point; + + if ( (CUR.opcode & 1) != 0 ) + CUR.GS.rp0 = point; + } + + + /*************************************************************************/ + /* */ + /* MDAP[a]: Move Direct Absolute Point */ + /* Opcode range: 0x2E-0x2F */ + /* Stack: uint32 --> */ + /* */ + static + void Ins_MDAP( INS_ARG ) + { + FT_UShort point; + FT_F26Dot6 cur_dist, + distance; + + + point = (FT_UShort)args[0]; + + if ( BOUNDS( point, CUR.zp0.n_points ) ) + { + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + return; + } + + /* XXX: Is there some undocumented feature while in the */ + /* twilight zone? ? */ + if ( ( CUR.opcode & 1 ) != 0 ) + { + cur_dist = CUR_Func_project( CUR.zp0.cur + point, NULL_Vector ); + distance = CUR_Func_round( cur_dist, + CUR.tt_metrics.compensations[0] ) - cur_dist; + } + else + distance = 0; + + CUR_Func_move( &CUR.zp0, point, distance ); + + CUR.GS.rp0 = point; + CUR.GS.rp1 = point; + } + + + /*************************************************************************/ + /* */ + /* MIAP[a]: Move Indirect Absolute Point */ + /* Opcode range: 0x3E-0x3F */ + /* Stack: uint32 uint32 --> */ + /* */ + static + void Ins_MIAP( INS_ARG ) + { + FT_ULong cvtEntry; + FT_UShort point; + FT_F26Dot6 distance, + org_dist; + + + cvtEntry = (FT_ULong)args[1]; + point = (FT_UShort)args[0]; + + if ( BOUNDS( point, CUR.zp0.n_points ) || + BOUNDS( cvtEntry, CUR.cvtSize ) ) + { + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + return; + } + + /* UNDOCUMENTED! */ + /* */ + /* The behaviour of an MIAP instruction is quite */ + /* different when used in the twilight zone. */ + /* */ + /* First, no control value cutin test is performed */ + /* as it would fail anyway. Second, the original */ + /* point, i.e. (org_x,org_y) of zp0.point, is set */ + /* to the absolute, unrounded distance found in */ + /* the CVT. */ + /* */ + /* This is used in the CVT programs of the Microsoft */ + /* fonts Arial, Times, etc., in order to re-adjust */ + /* some key font heights. It allows the use of the */ + /* IP instruction in the twilight zone, which */ + /* otherwise would be `illegal' according to the */ + /* specification. */ + /* */ + /* We implement it with a special sequence for the */ + /* twilight zone. This is a bad hack, but it seems */ + /* to work. */ + + distance = CUR_Func_read_cvt( cvtEntry ); + + if ( CUR.GS.gep0 == 0 ) /* If in twilight zone */ + { + CUR.zp0.org[point].x = TT_MULDIV( CUR.GS.freeVector.x, + distance, 0x4000 ); + CUR.zp0.org[point].y = TT_MULDIV( CUR.GS.freeVector.y, + distance, 0x4000 ); + CUR.zp0.cur[point] = CUR.zp0.org[point]; + } + + org_dist = CUR_Func_project( CUR.zp0.cur + point, NULL_Vector ); + + if ( ( CUR.opcode & 1 ) != 0 ) /* rounding and control cutin flag */ + { + if ( ABS( distance - org_dist ) > CUR.GS.control_value_cutin ) + distance = org_dist; + + distance = CUR_Func_round( distance, CUR.tt_metrics.compensations[0] ); + } + + CUR_Func_move( &CUR.zp0, point, distance - org_dist ); + + CUR.GS.rp0 = point; + CUR.GS.rp1 = point; + } + + + /*************************************************************************/ + /* */ + /* MDRP[abcde]: Move Direct Relative Point */ + /* Opcode range: 0xC0-0xDF */ + /* Stack: uint32 --> */ + /* */ + static + void Ins_MDRP( INS_ARG ) + { + FT_UShort point; + FT_F26Dot6 org_dist, distance; + + + point = (FT_UShort)args[0]; + + if ( BOUNDS( point, CUR.zp1.n_points ) || + BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) ) + { + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + return; + } + + /* XXX: Is there some undocumented feature while in the */ + /* twilight zone? */ + + org_dist = CUR_Func_dualproj( CUR.zp1.org + point, + CUR.zp0.org + CUR.GS.rp0 ); + + /* single width cutin test */ + + if ( ABS( org_dist ) < CUR.GS.single_width_cutin ) + { + if ( org_dist >= 0 ) + org_dist = CUR.GS.single_width_value; + else + org_dist = -CUR.GS.single_width_value; + } + + /* round flag */ + + if ( ( CUR.opcode & 4 ) != 0 ) + distance = CUR_Func_round( + org_dist, + CUR.tt_metrics.compensations[CUR.opcode & 3] ); + else + distance = ROUND_None( + org_dist, + CUR.tt_metrics.compensations[CUR.opcode & 3] ); + + /* minimum distance flag */ + + if ( ( CUR.opcode & 8 ) != 0 ) + { + if ( org_dist >= 0 ) + { + if ( distance < CUR.GS.minimum_distance ) + distance = CUR.GS.minimum_distance; + } + else + { + if ( distance > -CUR.GS.minimum_distance ) + distance = -CUR.GS.minimum_distance; + } + } + + /* now move the point */ + + org_dist = CUR_Func_project( CUR.zp1.cur + point, + CUR.zp0.cur + CUR.GS.rp0 ); + + CUR_Func_move( &CUR.zp1, point, distance - org_dist ); + + CUR.GS.rp1 = CUR.GS.rp0; + CUR.GS.rp2 = point; + + if ( ( CUR.opcode & 16 ) != 0 ) + CUR.GS.rp0 = point; + } + + + /*************************************************************************/ + /* */ + /* MIRP[abcde]: Move Indirect Relative Point */ + /* Opcode range: 0xE0-0xFF */ + /* Stack: int32? uint32 --> */ + /* */ + static + void Ins_MIRP( INS_ARG ) + { + FT_UShort point; + FT_ULong cvtEntry; + + FT_F26Dot6 cvt_dist, + distance, + cur_dist, + org_dist; + + + point = (FT_UShort)args[0]; + cvtEntry = (FT_ULong)( args[1] + 1 ); + + /* XXX: UNDOCUMENTED! cvt[-1] = 0 always */ + + if ( BOUNDS( point, CUR.zp1.n_points ) || + BOUNDS( cvtEntry, CUR.cvtSize + 1 ) || + BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) ) + { + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + return; + } + + if ( !cvtEntry ) + cvt_dist = 0; + else + cvt_dist = CUR_Func_read_cvt( cvtEntry - 1 ); + + /* single width test */ + + if ( ABS( cvt_dist ) < CUR.GS.single_width_cutin ) + { + if ( cvt_dist >= 0 ) + cvt_dist = CUR.GS.single_width_value; + else + cvt_dist = -CUR.GS.single_width_value; + } + + /* XXX: UNDOCUMENTED! -- twilight zone */ + + if ( CUR.GS.gep1 == 0 ) + { + CUR.zp1.org[point].x = CUR.zp0.org[CUR.GS.rp0].x + + TT_MULDIV( cvt_dist, + CUR.GS.freeVector.x, + 0x4000 ); + + CUR.zp1.org[point].y = CUR.zp0.org[CUR.GS.rp0].y + + TT_MULDIV( cvt_dist, + CUR.GS.freeVector.y, + 0x4000 ); + + CUR.zp1.cur[point] = CUR.zp1.org[point]; + } + + org_dist = CUR_Func_dualproj( CUR.zp1.org + point, + CUR.zp0.org + CUR.GS.rp0 ); + + cur_dist = CUR_Func_project( CUR.zp1.cur + point, + CUR.zp0.cur + CUR.GS.rp0 ); + + /* auto-flip test */ + + if ( CUR.GS.auto_flip ) + { + if ( ( org_dist ^ cvt_dist ) < 0 ) + cvt_dist = -cvt_dist; + } + + /* control value cutin and round */ + + if ( ( CUR.opcode & 4 ) != 0 ) + { + /* XXX: UNDOCUMENTED! Only perform cut-in test when both points */ + /* refer to the same zone. */ + + if ( CUR.GS.gep0 == CUR.GS.gep1 ) + if ( ABS( cvt_dist - org_dist ) >= CUR.GS.control_value_cutin ) + cvt_dist = org_dist; + + distance = CUR_Func_round( + cvt_dist, + CUR.tt_metrics.compensations[CUR.opcode & 3] ); + } + else + distance = ROUND_None( + cvt_dist, + CUR.tt_metrics.compensations[CUR.opcode & 3] ); + + /* minimum distance test */ + + if ( ( CUR.opcode & 8 ) != 0 ) + { + if ( org_dist >= 0 ) + { + if ( distance < CUR.GS.minimum_distance ) + distance = CUR.GS.minimum_distance; + } + else + { + if ( distance > -CUR.GS.minimum_distance ) + distance = -CUR.GS.minimum_distance; + } + } + + CUR_Func_move( &CUR.zp1, point, distance - cur_dist ); + + CUR.GS.rp1 = CUR.GS.rp0; + + if ( ( CUR.opcode & 16 ) != 0 ) + CUR.GS.rp0 = point; + + /* XXX: UNDOCUMENTED! */ + + CUR.GS.rp2 = point; + } + + + /*************************************************************************/ + /* */ + /* ALIGNRP[]: ALIGN Relative Point */ + /* Opcode range: 0x3C */ + /* Stack: uint32 uint32... --> */ + /* */ + static + void Ins_ALIGNRP( INS_ARG ) + { + FT_UShort point; + FT_F26Dot6 distance; + + FT_UNUSED_ARG; + + + if ( CUR.top < CUR.GS.loop || + BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) ) + { + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + return; + } + + while ( CUR.GS.loop > 0 ) + { + CUR.args--; + + point = (FT_UShort)CUR.stack[CUR.args]; + + if ( BOUNDS( point, CUR.zp1.n_points ) ) + { + if ( CUR.pedantic_hinting ) + { + CUR.error = TT_Err_Invalid_Reference; + return; + } + } + else + { + distance = CUR_Func_project( CUR.zp1.cur + point, + CUR.zp0.cur + CUR.GS.rp0 ); + + CUR_Func_move( &CUR.zp1, point, -distance ); + } + + CUR.GS.loop--; + } + + CUR.GS.loop = 1; + CUR.new_top = CUR.args; + } + + + /*************************************************************************/ + /* */ + /* ISECT[]: moves point to InterSECTion */ + /* Opcode range: 0x0F */ + /* Stack: 5 * uint32 --> */ + /* */ + static + void Ins_ISECT( INS_ARG ) + { + FT_UShort point, + a0, a1, + b0, b1; + + FT_F26Dot6 discriminant; + + FT_F26Dot6 dx, dy, + dax, day, + dbx, dby; + + FT_F26Dot6 val; + + FT_Vector R; + + + point = (FT_UShort)args[0]; + + a0 = (FT_UShort)args[1]; + a1 = (FT_UShort)args[2]; + b0 = (FT_UShort)args[3]; + b1 = (FT_UShort)args[4]; + + if ( BOUNDS( b0, CUR.zp0.n_points ) || + BOUNDS( b1, CUR.zp0.n_points ) || + BOUNDS( a0, CUR.zp1.n_points ) || + BOUNDS( a1, CUR.zp1.n_points ) || + BOUNDS( point, CUR.zp2.n_points ) ) + { + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + return; + } + + dbx = CUR.zp0.cur[b1].x - CUR.zp0.cur[b0].x; + dby = CUR.zp0.cur[b1].y - CUR.zp0.cur[b0].y; + + dax = CUR.zp1.cur[a1].x - CUR.zp1.cur[a0].x; + day = CUR.zp1.cur[a1].y - CUR.zp1.cur[a0].y; + + dx = CUR.zp0.cur[b0].x - CUR.zp1.cur[a0].x; + dy = CUR.zp0.cur[b0].y - CUR.zp1.cur[a0].y; + + CUR.zp2.tags[point] |= FT_Curve_Tag_Touch_Both; + + discriminant = TT_MULDIV( dax, -dby, 0x40 ) + + TT_MULDIV( day, dbx, 0x40 ); + + if ( ABS( discriminant ) >= 0x40 ) + { + val = TT_MULDIV( dx, -dby, 0x40 ) + TT_MULDIV( dy, dbx, 0x40 ); + + R.x = TT_MULDIV( val, dax, discriminant ); + R.y = TT_MULDIV( val, day, discriminant ); + + CUR.zp2.cur[point].x = CUR.zp1.cur[a0].x + R.x; + CUR.zp2.cur[point].y = CUR.zp1.cur[a0].y + R.y; + } + else + { + /* else, take the middle of the middles of A and B */ + + CUR.zp2.cur[point].x = ( CUR.zp1.cur[a0].x + + CUR.zp1.cur[a1].x + + CUR.zp0.cur[b0].x + + CUR.zp0.cur[b1].x ) / 4; + CUR.zp2.cur[point].y = ( CUR.zp1.cur[a0].y + + CUR.zp1.cur[a1].y + + CUR.zp0.cur[b0].y + + CUR.zp0.cur[b1].y ) / 4; + } + } + + + /*************************************************************************/ + /* */ + /* ALIGNPTS[]: ALIGN PoinTS */ + /* Opcode range: 0x27 */ + /* Stack: uint32 uint32 --> */ + /* */ + static + void Ins_ALIGNPTS( INS_ARG ) + { + FT_UShort p1, p2; + FT_F26Dot6 distance; + + + p1 = (FT_UShort)args[0]; + p2 = (FT_UShort)args[1]; + + if ( BOUNDS( args[0], CUR.zp1.n_points ) || + BOUNDS( args[1], CUR.zp0.n_points ) ) + { + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + return; + } + + distance = CUR_Func_project( CUR.zp0.cur + p2, + CUR.zp1.cur + p1 ) / 2; + + CUR_Func_move( &CUR.zp1, p1, distance ); + CUR_Func_move( &CUR.zp0, p2, -distance ); + } + + + /*************************************************************************/ + /* */ + /* IP[]: Interpolate Point */ + /* Opcode range: 0x39 */ + /* Stack: uint32... --> */ + /* */ + static + void Ins_IP( INS_ARG ) + { + FT_F26Dot6 org_a, org_b, org_x, + cur_a, cur_b, cur_x, + distance; + FT_UShort point; + + FT_UNUSED_ARG; + + + if ( CUR.top < CUR.GS.loop ) + { + CUR.error = TT_Err_Invalid_Reference; + return; + } + + /* XXX: There are some glyphs in some braindead but popular */ + /* fonts out there (e.g. [aeu]grave in monotype.ttf) */ + /* calling IP[] with bad values of rp[12]. */ + /* Do something sane when this odd thing happens. */ + + if ( BOUNDS( CUR.GS.rp1, CUR.zp0.n_points ) || + BOUNDS( CUR.GS.rp2, CUR.zp1.n_points ) ) + { + org_a = cur_a = 0; + org_b = cur_b = 0; + } + else + { + org_a = CUR_Func_dualproj( CUR.zp0.org + CUR.GS.rp1, NULL_Vector ); + org_b = CUR_Func_dualproj( CUR.zp1.org + CUR.GS.rp2, NULL_Vector ); + + cur_a = CUR_Func_project( CUR.zp0.cur + CUR.GS.rp1, NULL_Vector ); + cur_b = CUR_Func_project( CUR.zp1.cur + CUR.GS.rp2, NULL_Vector ); + } + + while ( CUR.GS.loop > 0 ) + { + CUR.args--; + + point = (FT_UShort)CUR.stack[CUR.args]; + if ( BOUNDS( point, CUR.zp2.n_points ) ) + { + if ( CUR.pedantic_hinting ) + { + CUR.error = TT_Err_Invalid_Reference; + return; + } + } + else + { + org_x = CUR_Func_dualproj( CUR.zp2.org + point, NULL_Vector ); + cur_x = CUR_Func_project ( CUR.zp2.cur + point, NULL_Vector ); + + if ( ( org_a <= org_b && org_x <= org_a ) || + ( org_a > org_b && org_x >= org_a ) ) + + distance = ( cur_a - org_a ) + ( org_x - cur_x ); + + else if ( ( org_a <= org_b && org_x >= org_b ) || + ( org_a > org_b && org_x < org_b ) ) + + distance = ( cur_b - org_b ) + ( org_x - cur_x ); + + else + /* note: it seems that rounding this value isn't a good */ + /* idea (cf. width of capital `S' in Times) */ + + distance = TT_MULDIV( cur_b - cur_a, + org_x - org_a, + org_b - org_a ) + ( cur_a - cur_x ); + + CUR_Func_move( &CUR.zp2, point, distance ); + } + + CUR.GS.loop--; + } + + CUR.GS.loop = 1; + CUR.new_top = CUR.args; + } + + + /*************************************************************************/ + /* */ + /* UTP[a]: UnTouch Point */ + /* Opcode range: 0x29 */ + /* Stack: uint32 --> */ + /* */ + static + void Ins_UTP( INS_ARG ) + { + FT_UShort point; + FT_Byte mask; + + + point = (FT_UShort)args[0]; + + if ( BOUNDS( point, CUR.zp0.n_points ) ) + { + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + return; + } + + mask = 0xFF; + + if ( CUR.GS.freeVector.x != 0 ) + mask &= ~FT_Curve_Tag_Touch_X; + + if ( CUR.GS.freeVector.y != 0 ) + mask &= ~FT_Curve_Tag_Touch_Y; + + CUR.zp0.tags[point] &= mask; + } + + + /* Local variables for Ins_IUP: */ + struct LOC_Ins_IUP + { + FT_Vector* orgs; /* original and current coordinate */ + FT_Vector* curs; /* arrays */ + }; + + + static + void Shift( FT_UInt p1, + FT_UInt p2, + FT_UInt p, + struct LOC_Ins_IUP* LINK ) + { + FT_UInt i; + FT_F26Dot6 x; + + + x = LINK->curs[p].x - LINK->orgs[p].x; + + for ( i = p1; i < p; i++ ) + LINK->curs[i].x += x; + + for ( i = p + 1; i <= p2; i++ ) + LINK->curs[i].x += x; + } + + + static + void Interp( FT_UInt p1, + FT_UInt p2, + FT_UInt ref1, + FT_UInt ref2, + struct LOC_Ins_IUP* LINK ) + { + FT_UInt i; + FT_F26Dot6 x, x1, x2, d1, d2; + + + if ( p1 > p2 ) + return; + + x1 = LINK->orgs[ref1].x; + d1 = LINK->curs[ref1].x - LINK->orgs[ref1].x; + x2 = LINK->orgs[ref2].x; + d2 = LINK->curs[ref2].x - LINK->orgs[ref2].x; + + if ( x1 == x2 ) + { + for ( i = p1; i <= p2; i++ ) + { + x = LINK->orgs[i].x; + + if ( x <= x1 ) + x += d1; + else + x += d2; + + LINK->curs[i].x = x; + } + return; + } + + if ( x1 < x2 ) + { + for ( i = p1; i <= p2; i++ ) + { + x = LINK->orgs[i].x; + + if ( x <= x1 ) + x += d1; + else + { + if ( x >= x2 ) + x += d2; + else + x = LINK->curs[ref1].x + + TT_MULDIV( x - x1, + LINK->curs[ref2].x - LINK->curs[ref1].x, + x2 - x1 ); + } + LINK->curs[i].x = x; + } + return; + } + + /* x2 < x1 */ + + for ( i = p1; i <= p2; i++ ) + { + x = LINK->orgs[i].x; + if ( x <= x2 ) + x += d2; + else + { + if ( x >= x1 ) + x += d1; + else + x = LINK->curs[ref1].x + + TT_MULDIV( x - x1, + LINK->curs[ref2].x - LINK->curs[ref1].x, + x2 - x1 ); + } + LINK->curs[i].x = x; + } + } + + + /*************************************************************************/ + /* */ + /* IUP[a]: Interpolate Untouched Points */ + /* Opcode range: 0x30-0x31 */ + /* Stack: --> */ + /* */ + static + void Ins_IUP( INS_ARG ) + { + struct LOC_Ins_IUP V; + FT_Byte mask; + + FT_UInt first_point; /* first point of contour */ + FT_UInt end_point; /* end point (last+1) of contour */ + + FT_UInt first_touched; /* first touched point in contour */ + FT_UInt cur_touched; /* current touched point in contour */ + + FT_UInt point; /* current point */ + FT_Short contour; /* current contour */ + + FT_UNUSED_ARG; + + + if ( CUR.opcode & 1 ) + { + mask = FT_Curve_Tag_Touch_X; + V.orgs = CUR.pts.org; + V.curs = CUR.pts.cur; + } + else + { + mask = FT_Curve_Tag_Touch_Y; + V.orgs = (FT_Vector*)( (FT_Pos*)CUR.pts.org + 1 ); + V.curs = (FT_Vector*)( (FT_Pos*)CUR.pts.cur + 1 ); + } + + contour = 0; + point = 0; + + do + { + end_point = CUR.pts.contours[contour]; + first_point = point; + + while ( point <= end_point && (CUR.pts.tags[point] & mask) == 0 ) + point++; + + if ( point <= end_point ) + { + first_touched = point; + cur_touched = point; + + point++; + + while ( point <= end_point ) + { + if ( ( CUR.pts.tags[point] & mask ) != 0 ) + { + if ( point > 0 ) + Interp( cur_touched + 1, + point - 1, + cur_touched, + point, + &V ); + cur_touched = point; + } + + point++; + } + + if ( cur_touched == first_touched ) + Shift( first_point, end_point, cur_touched, &V ); + else + { + Interp( (FT_UShort)( cur_touched + 1 ), + end_point, + cur_touched, + first_touched, + &V ); + + if ( first_touched > 0 ) + Interp( first_point, + first_touched - 1, + cur_touched, + first_touched, + &V ); + } + } + contour++; + } while ( contour < CUR.pts.n_contours ); + } + + + /*************************************************************************/ + /* */ + /* DELTAPn[]: DELTA exceptions P1, P2, P3 */ + /* Opcode range: 0x5D,0x71,0x72 */ + /* Stack: uint32 (2 * uint32)... --> */ + /* */ + static + void Ins_DELTAP( INS_ARG ) + { + FT_ULong k, nump; + FT_UShort A; + FT_ULong C; + FT_Long B; + + + nump = (FT_ULong)args[0]; /* some points theoretically may occur more + than once, thus UShort isn't enough */ + + for ( k = 1; k <= nump; k++ ) + { + if ( CUR.args < 2 ) + { + CUR.error = TT_Err_Too_Few_Arguments; + return; + } + + CUR.args -= 2; + + A = (FT_UShort)CUR.stack[CUR.args + 1]; + B = CUR.stack[CUR.args]; + + /* XXX: Because some popular fonts contain some invalid DeltaP */ + /* instructions, we simply ignore them when the stacked */ + /* point reference is off limit, rather than returning an */ + /* error. As a delta instruction doesn't change a glyph */ + /* in great ways, this shouldn't be a problem. */ + + if ( !BOUNDS( A, CUR.zp0.n_points ) ) + { + C = ( (FT_ULong)B & 0xF0 ) >> 4; + + switch ( CUR.opcode ) + { + case 0x5D: + break; + + case 0x71: + C += 16; + break; + + case 0x72: + C += 32; + break; + } + + C += CUR.GS.delta_base; + + if ( CURRENT_Ppem() == (FT_Long)C ) + { + B = ( (FT_ULong)B & 0xF ) - 8; + if ( B >= 0 ) + B++; + B = B * 64 / ( 1L << CUR.GS.delta_shift ); + + CUR_Func_move( &CUR.zp0, A, B ); + } + } + else + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + } + + CUR.new_top = CUR.args; + } + + + /*************************************************************************/ + /* */ + /* DELTACn[]: DELTA exceptions C1, C2, C3 */ + /* Opcode range: 0x73,0x74,0x75 */ + /* Stack: uint32 (2 * uint32)... --> */ + /* */ + static + void Ins_DELTAC( INS_ARG ) + { + FT_ULong nump, k; + FT_ULong A, C; + FT_Long B; + + + nump = (FT_ULong)args[0]; + + for ( k = 1; k <= nump; k++ ) + { + if ( CUR.args < 2 ) + { + CUR.error = TT_Err_Too_Few_Arguments; + return; + } + + CUR.args -= 2; + + A = (FT_ULong)CUR.stack[CUR.args + 1]; + B = CUR.stack[CUR.args]; + + if ( BOUNDS( A, CUR.cvtSize ) ) + { + if ( CUR.pedantic_hinting ) + { + CUR.error = TT_Err_Invalid_Reference; + return; + } + } + else + { + C = ( (FT_ULong)B & 0xF0 ) >> 4; + + switch ( CUR.opcode ) + { + case 0x73: + break; + + case 0x74: + C += 16; + break; + + case 0x75: + C += 32; + break; + } + + C += CUR.GS.delta_base; + + if ( CURRENT_Ppem() == (FT_Long)C ) + { + B = ( (FT_ULong)B & 0xF ) - 8; + if ( B >= 0 ) + B++; + B = B * 64 / ( 1L << CUR.GS.delta_shift ); + + CUR_Func_move_cvt( A, B ); + } + } + } + + CUR.new_top = CUR.args; + } + + + /*************************************************************************/ + /* */ + /* MISC. INSTRUCTIONS */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* GETINFO[]: GET INFOrmation */ + /* Opcode range: 0x88 */ + /* Stack: uint32 --> uint32 */ + /* */ + /* XXX: According to Apple specs, bits 1 & 2 of the argument ought to be */ + /* consulted before rotated/stretched info is returned. */ + static + void Ins_GETINFO( INS_ARG ) + { + FT_Long K; + + + K = 0; + + /* We return then Windows 3.1 version number */ + /* for the font scaler */ + if ( ( args[0] & 1 ) != 0 ) + K = 3; + + /* Has the glyph been rotated ? */ + if ( CUR.tt_metrics.rotated ) + K |= 0x80; + + /* Has the glyph been stretched ? */ + if ( CUR.tt_metrics.stretched ) + K |= 0x100; + + args[0] = K; + } + + + static + void Ins_UNKNOWN( INS_ARG ) + { + TT_DefRecord* def = CUR.IDefs; + TT_DefRecord* limit = def + CUR.numIDefs; + + FT_UNUSED_ARG; + + + for ( ; def < limit; def++ ) + { + if ( def->opc == CUR.opcode && def->active ) + { + TT_CallRec* call; + + + if ( CUR.callTop >= CUR.callSize ) + { + CUR.error = TT_Err_Stack_Overflow; + return; + } + + call = CUR.callStack + CUR.callTop++; + + call->Caller_Range = CUR.curRange; + call->Caller_IP = CUR.IP+1; + call->Cur_Count = 1; + call->Cur_Restart = def->start; + + INS_Goto_CodeRange( def->range, def->start ); + + CUR.step_ins = FALSE; + return; + } + } + + CUR.error = TT_Err_Invalid_Opcode; + } + + +#ifndef TT_CONFIG_OPTION_INTERPRETER_SWITCH + + + static + TInstruction_Function Instruct_Dispatch[256] = + { + /* Opcodes are gathered in groups of 16. */ + /* Please keep the spaces as they are. */ + + /* SVTCA y */ Ins_SVTCA, + /* SVTCA x */ Ins_SVTCA, + /* SPvTCA y */ Ins_SPVTCA, + /* SPvTCA x */ Ins_SPVTCA, + /* SFvTCA y */ Ins_SFVTCA, + /* SFvTCA x */ Ins_SFVTCA, + /* SPvTL // */ Ins_SPVTL, + /* SPvTL + */ Ins_SPVTL, + /* SFvTL // */ Ins_SFVTL, + /* SFvTL + */ Ins_SFVTL, + /* SPvFS */ Ins_SPVFS, + /* SFvFS */ Ins_SFVFS, + /* GPV */ Ins_GPV, + /* GFV */ Ins_GFV, + /* SFvTPv */ Ins_SFVTPV, + /* ISECT */ Ins_ISECT, + + /* SRP0 */ Ins_SRP0, + /* SRP1 */ Ins_SRP1, + /* SRP2 */ Ins_SRP2, + /* SZP0 */ Ins_SZP0, + /* SZP1 */ Ins_SZP1, + /* SZP2 */ Ins_SZP2, + /* SZPS */ Ins_SZPS, + /* SLOOP */ Ins_SLOOP, + /* RTG */ Ins_RTG, + /* RTHG */ Ins_RTHG, + /* SMD */ Ins_SMD, + /* ELSE */ Ins_ELSE, + /* JMPR */ Ins_JMPR, + /* SCvTCi */ Ins_SCVTCI, + /* SSwCi */ Ins_SSWCI, + /* SSW */ Ins_SSW, + + /* DUP */ Ins_DUP, + /* POP */ Ins_POP, + /* CLEAR */ Ins_CLEAR, + /* SWAP */ Ins_SWAP, + /* DEPTH */ Ins_DEPTH, + /* CINDEX */ Ins_CINDEX, + /* MINDEX */ Ins_MINDEX, + /* AlignPTS */ Ins_ALIGNPTS, + /* INS_0x28 */ Ins_UNKNOWN, + /* UTP */ Ins_UTP, + /* LOOPCALL */ Ins_LOOPCALL, + /* CALL */ Ins_CALL, + /* FDEF */ Ins_FDEF, + /* ENDF */ Ins_ENDF, + /* MDAP[0] */ Ins_MDAP, + /* MDAP[1] */ Ins_MDAP, + + /* IUP[0] */ Ins_IUP, + /* IUP[1] */ Ins_IUP, + /* SHP[0] */ Ins_SHP, + /* SHP[1] */ Ins_SHP, + /* SHC[0] */ Ins_SHC, + /* SHC[1] */ Ins_SHC, + /* SHZ[0] */ Ins_SHZ, + /* SHZ[1] */ Ins_SHZ, + /* SHPIX */ Ins_SHPIX, + /* IP */ Ins_IP, + /* MSIRP[0] */ Ins_MSIRP, + /* MSIRP[1] */ Ins_MSIRP, + /* AlignRP */ Ins_ALIGNRP, + /* RTDG */ Ins_RTDG, + /* MIAP[0] */ Ins_MIAP, + /* MIAP[1] */ Ins_MIAP, + + /* NPushB */ Ins_NPUSHB, + /* NPushW */ Ins_NPUSHW, + /* WS */ Ins_WS, + /* RS */ Ins_RS, + /* WCvtP */ Ins_WCVTP, + /* RCvt */ Ins_RCVT, + /* GC[0] */ Ins_GC, + /* GC[1] */ Ins_GC, + /* SCFS */ Ins_SCFS, + /* MD[0] */ Ins_MD, + /* MD[1] */ Ins_MD, + /* MPPEM */ Ins_MPPEM, + /* MPS */ Ins_MPS, + /* FlipON */ Ins_FLIPON, + /* FlipOFF */ Ins_FLIPOFF, + /* DEBUG */ Ins_DEBUG, + + /* LT */ Ins_LT, + /* LTEQ */ Ins_LTEQ, + /* GT */ Ins_GT, + /* GTEQ */ Ins_GTEQ, + /* EQ */ Ins_EQ, + /* NEQ */ Ins_NEQ, + /* ODD */ Ins_ODD, + /* EVEN */ Ins_EVEN, + /* IF */ Ins_IF, + /* EIF */ Ins_EIF, + /* AND */ Ins_AND, + /* OR */ Ins_OR, + /* NOT */ Ins_NOT, + /* DeltaP1 */ Ins_DELTAP, + /* SDB */ Ins_SDB, + /* SDS */ Ins_SDS, + + /* ADD */ Ins_ADD, + /* SUB */ Ins_SUB, + /* DIV */ Ins_DIV, + /* MUL */ Ins_MUL, + /* ABS */ Ins_ABS, + /* NEG */ Ins_NEG, + /* FLOOR */ Ins_FLOOR, + /* CEILING */ Ins_CEILING, + /* ROUND[0] */ Ins_ROUND, + /* ROUND[1] */ Ins_ROUND, + /* ROUND[2] */ Ins_ROUND, + /* ROUND[3] */ Ins_ROUND, + /* NROUND[0] */ Ins_NROUND, + /* NROUND[1] */ Ins_NROUND, + /* NROUND[2] */ Ins_NROUND, + /* NROUND[3] */ Ins_NROUND, + + /* WCvtF */ Ins_WCVTF, + /* DeltaP2 */ Ins_DELTAP, + /* DeltaP3 */ Ins_DELTAP, + /* DeltaCn[0] */ Ins_DELTAC, + /* DeltaCn[1] */ Ins_DELTAC, + /* DeltaCn[2] */ Ins_DELTAC, + /* SROUND */ Ins_SROUND, + /* S45Round */ Ins_S45ROUND, + /* JROT */ Ins_JROT, + /* JROF */ Ins_JROF, + /* ROFF */ Ins_ROFF, + /* INS_0x7B */ Ins_UNKNOWN, + /* RUTG */ Ins_RUTG, + /* RDTG */ Ins_RDTG, + /* SANGW */ Ins_SANGW, + /* AA */ Ins_AA, + + /* FlipPT */ Ins_FLIPPT, + /* FlipRgON */ Ins_FLIPRGON, + /* FlipRgOFF */ Ins_FLIPRGOFF, + /* INS_0x83 */ Ins_UNKNOWN, + /* INS_0x84 */ Ins_UNKNOWN, + /* ScanCTRL */ Ins_SCANCTRL, + /* SDPVTL[0] */ Ins_SDPVTL, + /* SDPVTL[1] */ Ins_SDPVTL, + /* GetINFO */ Ins_GETINFO, + /* IDEF */ Ins_IDEF, + /* ROLL */ Ins_ROLL, + /* MAX */ Ins_MAX, + /* MIN */ Ins_MIN, + /* ScanTYPE */ Ins_SCANTYPE, + /* InstCTRL */ Ins_INSTCTRL, + /* INS_0x8F */ Ins_UNKNOWN, + + /* INS_0x90 */ Ins_UNKNOWN, + /* INS_0x91 */ Ins_UNKNOWN, + /* INS_0x92 */ Ins_UNKNOWN, + /* INS_0x93 */ Ins_UNKNOWN, + /* INS_0x94 */ Ins_UNKNOWN, + /* INS_0x95 */ Ins_UNKNOWN, + /* INS_0x96 */ Ins_UNKNOWN, + /* INS_0x97 */ Ins_UNKNOWN, + /* INS_0x98 */ Ins_UNKNOWN, + /* INS_0x99 */ Ins_UNKNOWN, + /* INS_0x9A */ Ins_UNKNOWN, + /* INS_0x9B */ Ins_UNKNOWN, + /* INS_0x9C */ Ins_UNKNOWN, + /* INS_0x9D */ Ins_UNKNOWN, + /* INS_0x9E */ Ins_UNKNOWN, + /* INS_0x9F */ Ins_UNKNOWN, + + /* INS_0xA0 */ Ins_UNKNOWN, + /* INS_0xA1 */ Ins_UNKNOWN, + /* INS_0xA2 */ Ins_UNKNOWN, + /* INS_0xA3 */ Ins_UNKNOWN, + /* INS_0xA4 */ Ins_UNKNOWN, + /* INS_0xA5 */ Ins_UNKNOWN, + /* INS_0xA6 */ Ins_UNKNOWN, + /* INS_0xA7 */ Ins_UNKNOWN, + /* INS_0xA8 */ Ins_UNKNOWN, + /* INS_0xA9 */ Ins_UNKNOWN, + /* INS_0xAA */ Ins_UNKNOWN, + /* INS_0xAB */ Ins_UNKNOWN, + /* INS_0xAC */ Ins_UNKNOWN, + /* INS_0xAD */ Ins_UNKNOWN, + /* INS_0xAE */ Ins_UNKNOWN, + /* INS_0xAF */ Ins_UNKNOWN, + + /* PushB[0] */ Ins_PUSHB, + /* PushB[1] */ Ins_PUSHB, + /* PushB[2] */ Ins_PUSHB, + /* PushB[3] */ Ins_PUSHB, + /* PushB[4] */ Ins_PUSHB, + /* PushB[5] */ Ins_PUSHB, + /* PushB[6] */ Ins_PUSHB, + /* PushB[7] */ Ins_PUSHB, + /* PushW[0] */ Ins_PUSHW, + /* PushW[1] */ Ins_PUSHW, + /* PushW[2] */ Ins_PUSHW, + /* PushW[3] */ Ins_PUSHW, + /* PushW[4] */ Ins_PUSHW, + /* PushW[5] */ Ins_PUSHW, + /* PushW[6] */ Ins_PUSHW, + /* PushW[7] */ Ins_PUSHW, + + /* MDRP[00] */ Ins_MDRP, + /* MDRP[01] */ Ins_MDRP, + /* MDRP[02] */ Ins_MDRP, + /* MDRP[03] */ Ins_MDRP, + /* MDRP[04] */ Ins_MDRP, + /* MDRP[05] */ Ins_MDRP, + /* MDRP[06] */ Ins_MDRP, + /* MDRP[07] */ Ins_MDRP, + /* MDRP[08] */ Ins_MDRP, + /* MDRP[09] */ Ins_MDRP, + /* MDRP[10] */ Ins_MDRP, + /* MDRP[11] */ Ins_MDRP, + /* MDRP[12] */ Ins_MDRP, + /* MDRP[13] */ Ins_MDRP, + /* MDRP[14] */ Ins_MDRP, + /* MDRP[15] */ Ins_MDRP, + + /* MDRP[16] */ Ins_MDRP, + /* MDRP[17] */ Ins_MDRP, + /* MDRP[18] */ Ins_MDRP, + /* MDRP[19] */ Ins_MDRP, + /* MDRP[20] */ Ins_MDRP, + /* MDRP[21] */ Ins_MDRP, + /* MDRP[22] */ Ins_MDRP, + /* MDRP[23] */ Ins_MDRP, + /* MDRP[24] */ Ins_MDRP, + /* MDRP[25] */ Ins_MDRP, + /* MDRP[26] */ Ins_MDRP, + /* MDRP[27] */ Ins_MDRP, + /* MDRP[28] */ Ins_MDRP, + /* MDRP[29] */ Ins_MDRP, + /* MDRP[30] */ Ins_MDRP, + /* MDRP[31] */ Ins_MDRP, + + /* MIRP[00] */ Ins_MIRP, + /* MIRP[01] */ Ins_MIRP, + /* MIRP[02] */ Ins_MIRP, + /* MIRP[03] */ Ins_MIRP, + /* MIRP[04] */ Ins_MIRP, + /* MIRP[05] */ Ins_MIRP, + /* MIRP[06] */ Ins_MIRP, + /* MIRP[07] */ Ins_MIRP, + /* MIRP[08] */ Ins_MIRP, + /* MIRP[09] */ Ins_MIRP, + /* MIRP[10] */ Ins_MIRP, + /* MIRP[11] */ Ins_MIRP, + /* MIRP[12] */ Ins_MIRP, + /* MIRP[13] */ Ins_MIRP, + /* MIRP[14] */ Ins_MIRP, + /* MIRP[15] */ Ins_MIRP, + + /* MIRP[16] */ Ins_MIRP, + /* MIRP[17] */ Ins_MIRP, + /* MIRP[18] */ Ins_MIRP, + /* MIRP[19] */ Ins_MIRP, + /* MIRP[20] */ Ins_MIRP, + /* MIRP[21] */ Ins_MIRP, + /* MIRP[22] */ Ins_MIRP, + /* MIRP[23] */ Ins_MIRP, + /* MIRP[24] */ Ins_MIRP, + /* MIRP[25] */ Ins_MIRP, + /* MIRP[26] */ Ins_MIRP, + /* MIRP[27] */ Ins_MIRP, + /* MIRP[28] */ Ins_MIRP, + /* MIRP[29] */ Ins_MIRP, + /* MIRP[30] */ Ins_MIRP, + /* MIRP[31] */ Ins_MIRP + }; + + +#endif /* !TT_CONFIG_OPTION_INTERPRETER_SWITCH */ + + + /*************************************************************************/ + /* */ + /* RUN */ + /* */ + /* This function executes a run of opcodes. It will exit in the */ + /* following cases: */ + /* */ + /* - Errors (in which case it returns FALSE). */ + /* */ + /* - Reaching the end of the main code range (returns TRUE). */ + /* Reaching the end of a code range within a function call is an */ + /* error. */ + /* */ + /* - After executing one single opcode, if the flag `Instruction_Trap' */ + /* is set to TRUE (returns TRUE). */ + /* */ + /* On exit whith TRUE, test IP < CodeSize to know wether it comes from */ + /* an instruction trap or a normal termination. */ + /* */ + /* */ + /* Note: The documented DEBUG opcode pops a value from the stack. This */ + /* behaviour is unsupported; here a DEBUG opcode is always an */ + /* error. */ + /* */ + /* */ + /* THIS IS THE INTERPRETER'S MAIN LOOP. */ + /* */ + /* Instructions appear in the specification's order. */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* */ + /* TT_RunIns */ + /* */ + /* */ + /* Executes one or more instruction in the execution context. This */ + /* is the main function of the TrueType opcode interpreter. */ + /* */ + /* */ + /* exec :: A handle to the target execution context. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* Only the object manager and debugger should call this function. */ + /* */ + /* This function is publicly exported because it is directly */ + /* invoked by the TrueType debugger. */ + /* */ + FT_EXPORT_FUNC( FT_Error ) TT_RunIns( TT_ExecContext exc ) + { + FT_Long ins_counter = 0; /* executed instructions counter */ + + +#ifdef TT_CONFIG_OPTION_STATIC_RASTER + cur = *exc; +#endif + + /* set CVT functions */ + CUR.tt_metrics.ratio = 0; + if ( CUR.metrics.x_ppem != CUR.metrics.y_ppem ) + { + /* non-square pixels, use the stretched routines */ + CUR.func_read_cvt = Read_CVT_Stretched; + CUR.func_write_cvt = Write_CVT_Stretched; + CUR.func_move_cvt = Move_CVT_Stretched; + } + else + { + /* square pixels, use normal routines */ + CUR.func_read_cvt = Read_CVT; + CUR.func_write_cvt = Write_CVT; + CUR.func_move_cvt = Move_CVT; + } + + COMPUTE_Funcs(); + COMPUTE_Round( (FT_Byte)exc->GS.round_state ); + + do + { + CUR.opcode = CUR.code[CUR.IP]; + + if ( ( CUR.length = opcode_length[CUR.opcode] ) < 0 ) + { + if ( CUR.IP + 1 > CUR.codeSize ) + goto LErrorCodeOverflow_; + + CUR.length = CUR.code[CUR.IP + 1] + 2; + } + + if ( CUR.IP + CUR.length > CUR.codeSize ) + goto LErrorCodeOverflow_; + + /* First, let's check for empty stack and overflow */ + CUR.args = CUR.top - ( Pop_Push_Count[CUR.opcode] >> 4 ); + + /* `args' is the top of the stack once arguments have been popped. */ + /* One can also interpret it as the index of the last argument. */ + if ( CUR.args < 0 ) + { + CUR.error = TT_Err_Too_Few_Arguments; + goto LErrorLabel_; + } + + CUR.new_top = CUR.args + ( Pop_Push_Count[CUR.opcode] & 15 ); + + /* `new_top' is the new top of the stack, after the instruction's */ + /* execution. `top' will be set to `new_top' after the `switch' */ + /* statement. */ + if ( CUR.new_top > CUR.stackSize ) + { + CUR.error = TT_Err_Stack_Overflow; + goto LErrorLabel_; + } + + CUR.step_ins = TRUE; + CUR.error = TT_Err_Ok; + +#ifdef TT_CONFIG_OPTION_INTERPRETER_SWITCH + + { + FT_Long* args = CUR.stack + CUR.args; + FT_Byte opcode = CUR.opcode; + + +#undef ARRAY_BOUND_ERROR +#define ARRAY_BOUND_ERROR goto Set_Invalid_Ref + + + switch ( opcode ) + { + case 0x00: /* SVTCA y */ + case 0x01: /* SVTCA x */ + case 0x02: /* SPvTCA y */ + case 0x03: /* SPvTCA x */ + case 0x04: /* SFvTCA y */ + case 0x05: /* SFvTCA x */ + { + FT_Short AA, BB; + + + AA = (FT_Short)( opcode & 1 ) << 14; + BB = AA ^ (FT_Short)0x4000; + + if ( opcode < 4 ) + { + CUR.GS.projVector.x = AA; + CUR.GS.projVector.y = BB; + + CUR.GS.dualVector.x = AA; + CUR.GS.dualVector.y = BB; + } + + if ( ( opcode & 2 ) == 0 ) + { + CUR.GS.freeVector.x = AA; + CUR.GS.freeVector.y = BB; + } + + COMPUTE_Funcs(); + } + break; + + case 0x06: /* SPvTL // */ + case 0x07: /* SPvTL + */ + DO_SPVTL + break; + + case 0x08: /* SFvTL // */ + case 0x09: /* SFvTL + */ + DO_SFVTL + break; + + case 0x0A: /* SPvFS */ + DO_SPVFS + break; + + case 0x0B: /* SFvFS */ + DO_SFVFS + break; + + case 0x0C: /* GPV */ + DO_GPV + break; + + case 0x0D: /* GFV */ + DO_GFV + break; + + case 0x0E: /* SFvTPv */ + DO_SFVTPV + break; + + case 0x0F: /* ISECT */ + Ins_ISECT( EXEC_ARG_ args ); + break; + + case 0x10: /* SRP0 */ + DO_SRP0 + break; + + case 0x11: /* SRP1 */ + DO_SRP1 + break; + + case 0x12: /* SRP2 */ + DO_SRP2 + break; + + case 0x13: /* SZP0 */ + Ins_SZP0( EXEC_ARG_ args ); + break; + + case 0x14: /* SZP1 */ + Ins_SZP1( EXEC_ARG_ args ); + break; + + case 0x15: /* SZP2 */ + Ins_SZP2( EXEC_ARG_ args ); + break; + + case 0x16: /* SZPS */ + Ins_SZPS( EXEC_ARG_ args ); + break; + + case 0x17: /* SLOOP */ + DO_SLOOP + break; + + case 0x18: /* RTG */ + DO_RTG + break; + + case 0x19: /* RTHG */ + DO_RTHG + break; + + case 0x1A: /* SMD */ + DO_SMD + break; + + case 0x1B: /* ELSE */ + Ins_ELSE( EXEC_ARG_ args ); + break; + + case 0x1C: /* JMPR */ + DO_JMPR + break; + + case 0x1D: /* SCVTCI */ + DO_SCVTCI + break; + + case 0x1E: /* SSWCI */ + DO_SSWCI + break; + + case 0x1F: /* SSW */ + DO_SSW + break; + + case 0x20: /* DUP */ + DO_DUP + break; + + case 0x21: /* POP */ + /* nothing :-) */ + break; + + case 0x22: /* CLEAR */ + DO_CLEAR + break; + + case 0x23: /* SWAP */ + DO_SWAP + break; + + case 0x24: /* DEPTH */ + DO_DEPTH + break; + + case 0x25: /* CINDEX */ + DO_CINDEX + break; + + case 0x26: /* MINDEX */ + Ins_MINDEX( EXEC_ARG_ args ); + break; + + case 0x27: /* ALIGNPTS */ + Ins_ALIGNPTS( EXEC_ARG_ args ); + break; + + case 0x28: /* ???? */ + Ins_UNKNOWN( EXEC_ARG_ args ); + break; + + case 0x29: /* UTP */ + Ins_UTP( EXEC_ARG_ args ); + break; + + case 0x2A: /* LOOPCALL */ + Ins_LOOPCALL( EXEC_ARG_ args ); + break; + + case 0x2B: /* CALL */ + Ins_CALL( EXEC_ARG_ args ); + break; + + case 0x2C: /* FDEF */ + Ins_FDEF( EXEC_ARG_ args ); + break; + + case 0x2D: /* ENDF */ + Ins_ENDF( EXEC_ARG_ args ); + break; + + case 0x2E: /* MDAP */ + case 0x2F: /* MDAP */ + Ins_MDAP( EXEC_ARG_ args ); + break; + + + case 0x30: /* IUP */ + case 0x31: /* IUP */ + Ins_IUP( EXEC_ARG_ args ); + break; + + case 0x32: /* SHP */ + case 0x33: /* SHP */ + Ins_SHP( EXEC_ARG_ args ); + break; + + case 0x34: /* SHC */ + case 0x35: /* SHC */ + Ins_SHC( EXEC_ARG_ args ); + break; + + case 0x36: /* SHZ */ + case 0x37: /* SHZ */ + Ins_SHZ( EXEC_ARG_ args ); + break; + + case 0x38: /* SHPIX */ + Ins_SHPIX( EXEC_ARG_ args ); + break; + + case 0x39: /* IP */ + Ins_IP( EXEC_ARG_ args ); + break; + + case 0x3A: /* MSIRP */ + case 0x3B: /* MSIRP */ + Ins_MSIRP( EXEC_ARG_ args ); + break; + + case 0x3C: /* AlignRP */ + Ins_ALIGNRP( EXEC_ARG_ args ); + break; + + case 0x3D: /* RTDG */ + DO_RTDG + break; + + case 0x3E: /* MIAP */ + case 0x3F: /* MIAP */ + Ins_MIAP( EXEC_ARG_ args ); + break; + + case 0x40: /* NPUSHB */ + Ins_NPUSHB( EXEC_ARG_ args ); + break; + + case 0x41: /* NPUSHW */ + Ins_NPUSHW( EXEC_ARG_ args ); + break; + + case 0x42: /* WS */ + DO_WS + break; + + Set_Invalid_Ref: + CUR.error = TT_Err_Invalid_Reference; + break; + + case 0x43: /* RS */ + DO_RS + break; + + case 0x44: /* WCVTP */ + DO_WCVTP + break; + + case 0x45: /* RCVT */ + DO_RCVT + break; + + case 0x46: /* GC */ + case 0x47: /* GC */ + Ins_GC( EXEC_ARG_ args ); + break; + + case 0x48: /* SCFS */ + Ins_SCFS( EXEC_ARG_ args ); + break; + + case 0x49: /* MD */ + case 0x4A: /* MD */ + Ins_MD( EXEC_ARG_ args ); + break; + + case 0x4B: /* MPPEM */ + DO_MPPEM + break; + + case 0x4C: /* MPS */ + DO_MPS + break; + + case 0x4D: /* FLIPON */ + DO_FLIPON + break; + + case 0x4E: /* FLIPOFF */ + DO_FLIPOFF + break; + + case 0x4F: /* DEBUG */ + DO_DEBUG + break; + + case 0x50: /* LT */ + DO_LT + break; + + case 0x51: /* LTEQ */ + DO_LTEQ + break; + + case 0x52: /* GT */ + DO_GT + break; + + case 0x53: /* GTEQ */ + DO_GTEQ + break; + + case 0x54: /* EQ */ + DO_EQ + break; + + case 0x55: /* NEQ */ + DO_NEQ + break; + + case 0x56: /* ODD */ + DO_ODD + break; + + case 0x57: /* EVEN */ + DO_EVEN + break; + + case 0x58: /* IF */ + Ins_IF( EXEC_ARG_ args ); + break; + + case 0x59: /* EIF */ + /* do nothing */ + break; + + case 0x5A: /* AND */ + DO_AND + break; + + case 0x5B: /* OR */ + DO_OR + break; + + case 0x5C: /* NOT */ + DO_NOT + break; + + case 0x5D: /* DELTAP1 */ + Ins_DELTAP( EXEC_ARG_ args ); + break; + + case 0x5E: /* SDB */ + DO_SDB + break; + + case 0x5F: /* SDS */ + DO_SDS + break; + + case 0x60: /* ADD */ + DO_ADD + break; + + case 0x61: /* SUB */ + DO_SUB + break; + + case 0x62: /* DIV */ + DO_DIV + break; + + case 0x63: /* MUL */ + DO_MUL + break; + + case 0x64: /* ABS */ + DO_ABS + break; + + case 0x65: /* NEG */ + DO_NEG + break; + + case 0x66: /* FLOOR */ + DO_FLOOR + break; + + case 0x67: /* CEILING */ + DO_CEILING + break; + + case 0x68: /* ROUND */ + case 0x69: /* ROUND */ + case 0x6A: /* ROUND */ + case 0x6B: /* ROUND */ + DO_ROUND + break; + + case 0x6C: /* NROUND */ + case 0x6D: /* NROUND */ + case 0x6E: /* NRRUND */ + case 0x6F: /* NROUND */ + DO_NROUND + break; + + case 0x70: /* WCVTF */ + DO_WCVTF + break; + + case 0x71: /* DELTAP2 */ + case 0x72: /* DELTAP3 */ + Ins_DELTAP( EXEC_ARG_ args ); + break; + + case 0x73: /* DELTAC0 */ + case 0x74: /* DELTAC1 */ + case 0x75: /* DELTAC2 */ + Ins_DELTAC( EXEC_ARG_ args ); + break; + + case 0x76: /* SROUND */ + DO_SROUND + break; + + case 0x77: /* S45Round */ + DO_S45ROUND + break; + + case 0x78: /* JROT */ + DO_JROT + break; + + case 0x79: /* JROF */ + DO_JROF + break; + + case 0x7A: /* ROFF */ + DO_ROFF + break; + + case 0x7B: /* ???? */ + Ins_UNKNOWN( EXEC_ARG_ args ); + break; + + case 0x7C: /* RUTG */ + DO_RUTG + break; + + case 0x7D: /* RDTG */ + DO_RDTG + break; + + case 0x7E: /* SANGW */ + case 0x7F: /* AA */ + /* nothing - obsolete */ + break; + + case 0x80: /* FLIPPT */ + Ins_FLIPPT( EXEC_ARG_ args ); + break; + + case 0x81: /* FLIPRGON */ + Ins_FLIPRGON( EXEC_ARG_ args ); + break; + + case 0x82: /* FLIPRGOFF */ + Ins_FLIPRGOFF( EXEC_ARG_ args ); + break; + + case 0x83: /* UNKNOWN */ + case 0x84: /* UNKNOWN */ + Ins_UNKNOWN( EXEC_ARG_ args ); + break; + + case 0x85: /* SCANCTRL */ + Ins_SCANCTRL( EXEC_ARG_ args ); + break; + + case 0x86: /* SDPVTL */ + case 0x87: /* SDPVTL */ + Ins_SDPVTL( EXEC_ARG_ args ); + break; + + case 0x88: /* GETINFO */ + Ins_GETINFO( EXEC_ARG_ args ); + break; + + case 0x89: /* IDEF */ + Ins_IDEF( EXEC_ARG_ args ); + break; + + case 0x8A: /* ROLL */ + Ins_ROLL( EXEC_ARG_ args ); + break; + + case 0x8B: /* MAX */ + DO_MAX + break; + + case 0x8C: /* MIN */ + DO_MIN + break; + + case 0x8D: /* SCANTYPE */ + Ins_SCANTYPE( EXEC_ARG_ args ); + break; + + case 0x8E: /* INSTCTRL */ + Ins_INSTCTRL( EXEC_ARG_ args ); + break; + + case 0x8F: + Ins_UNKNOWN( EXEC_ARG_ args ); + break; + + default: + if ( opcode >= 0xE0 ) + Ins_MIRP( EXEC_ARG_ args ); + else if ( opcode >= 0xC0 ) + Ins_MDRP( EXEC_ARG_ args ); + else if ( opcode >= 0xB8 ) + Ins_PUSHW( EXEC_ARG_ args ); + else if ( opcode >= 0xB0 ) + Ins_PUSHB( EXEC_ARG_ args ); + else + Ins_UNKNOWN( EXEC_ARG_ args ); + } + + } + +#else + + Instruct_Dispatch[CUR.opcode]( EXEC_ARG_ &CUR.stack[CUR.args] ); + +#endif /* TT_CONFIG_OPTION_INTERPRETER_SWITCH */ + + if ( CUR.error != TT_Err_Ok ) + { + switch ( CUR.error ) + { + case TT_Err_Invalid_Opcode: /* looking for redefined instructions */ + { + TT_DefRecord* def = CUR.IDefs; + TT_DefRecord* limit = def + CUR.numIDefs; + + + for ( ; def < limit; def++ ) + { + if ( def->active && CUR.opcode == def->opc ) + { + TT_CallRec* callrec; + + + if ( CUR.callTop >= CUR.callSize ) + { + CUR.error = TT_Err_Invalid_Reference; + goto LErrorLabel_; + } + + callrec = &CUR.callStack[CUR.callTop]; + + callrec->Caller_Range = CUR.curRange; + callrec->Caller_IP = CUR.IP + 1; + callrec->Cur_Count = 1; + callrec->Cur_Restart = def->start; + + if ( INS_Goto_CodeRange( def->range, def->start ) == FAILURE ) + goto LErrorLabel_; + + goto LSuiteLabel_; + } + } + } + + CUR.error = TT_Err_Invalid_Opcode; + goto LErrorLabel_; + +#if 0 + break; /* Unreachable code warning suppression. */ + /* Leave to remind in case a later change the editor */ + /* to consider break; */ +#endif + + default: + goto LErrorLabel_; + +#if 0 + break; +#endif + } + } + + CUR.top = CUR.new_top; + + if ( CUR.step_ins ) + CUR.IP += CUR.length; + + /* increment instruction counter and check if we didn't */ + /* run this program for too long (e.g. infinite loops). */ + if ( ++ins_counter > MAX_RUNNABLE_OPCODES ) + return TT_Err_Execution_Too_Long; + + LSuiteLabel_: + if ( CUR.IP >= CUR.codeSize ) + { + if ( CUR.callTop > 0 ) + { + CUR.error = TT_Err_Code_Overflow; + goto LErrorLabel_; + } + else + goto LNo_Error_; + } + } while ( !CUR.instruction_trap ); + + LNo_Error_: + +#ifdef TT_CONFIG_OPTION_STATIC_RASTER + *exc = cur; +#endif + + return TT_Err_Ok; + + LErrorCodeOverflow_: + CUR.error = TT_Err_Code_Overflow; + + LErrorLabel_: + +#ifdef TT_CONFIG_OPTION_STATIC_RASTER + *exc = cur; +#endif + + return CUR.error; + } + + +#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */ + + +/* END */ diff --git a/src/freetype/truetype/ttinterp.h b/src/freetype/truetype/ttinterp.h new file mode 100644 index 0000000000..6e92699cdc --- /dev/null +++ b/src/freetype/truetype/ttinterp.h @@ -0,0 +1,278 @@ +/***************************************************************************/ +/* */ +/* ttinterp.h */ +/* */ +/* TrueType bytecode interpreter (specification). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef TTINTERP_H +#define TTINTERP_H + + +#ifdef FT_FLAT_COMPILE + +#include "ttobjs.h" + +#else + +#include + +#endif + + +#ifdef __cplusplus + extern "C" { +#endif + + +#ifndef TT_CONFIG_OPTION_STATIC_INTEPRETER /* indirect implementation */ + +#define EXEC_OP_ TT_ExecContext exc, +#define EXEC_OP TT_ExecContext exc +#define EXEC_ARG_ exc, +#define EXEC_ARG exc + +#else /* static implementation */ + +#define EXEC_OP_ /* void */ +#define EXEC_OP /* void */ +#define EXEC_ARG_ /* void */ +#define EXEC_ARG /* void */ + +#endif /* TT_CONFIG_OPTION_STATIC_INTERPRETER */ + + + /*************************************************************************/ + /* */ + /* Rounding mode constants. */ + /* */ +#define TT_Round_Off 5 +#define TT_Round_To_Half_Grid 0 +#define TT_Round_To_Grid 1 +#define TT_Round_To_Double_Grid 2 +#define TT_Round_Up_To_Grid 4 +#define TT_Round_Down_To_Grid 3 +#define TT_Round_Super 6 +#define TT_Round_Super_45 7 + + + /*************************************************************************/ + /* */ + /* Function types used by the interpreter, depending on various modes */ + /* (e.g. the rounding mode, whether to render a vertical or horizontal */ + /* line etc). */ + /* */ + /*************************************************************************/ + + /* Rounding function */ + typedef FT_F26Dot6 (*TT_Round_Func)( EXEC_OP_ FT_F26Dot6 distance, + FT_F26Dot6 compensation ); + + /* Point displacement along the freedom vector routine */ + typedef void (*TT_Move_Func)( EXEC_OP_ TT_GlyphZone* zone, + FT_UInt point, + FT_F26Dot6 distance ); + + /* Distance projection along one of the projection vectors */ + typedef FT_F26Dot6 (*TT_Project_Func)( EXEC_OP_ FT_Vector* v1, + FT_Vector* v2 ); + + /* reading a cvt value. Take care of non-square pixels if necessary */ + typedef FT_F26Dot6 (*TT_Get_CVT_Func)( EXEC_OP_ FT_ULong index ); + + /* setting or moving a cvt value. Take care of non-square pixels */ + /* if necessary */ + typedef void (*TT_Set_CVT_Func)( EXEC_OP_ FT_ULong index, + FT_F26Dot6 value ); + + + /*************************************************************************/ + /* */ + /* This structure defines a call record, used to manage function calls. */ + /* */ + typedef struct TT_CallRec_ + { + FT_Int Caller_Range; + FT_Long Caller_IP; + FT_Long Cur_Count; + FT_Long Cur_Restart; + + } TT_CallRec, *TT_CallStack; + + + /*************************************************************************/ + /* */ + /* The main structure for the interpreter which collects all necessary */ + /* variables and states. */ + /* */ + typedef struct TT_ExecContextRec_ + { + TT_Face face; + TT_Size size; + FT_Memory memory; + + /* instructions state */ + + FT_Error error; /* last execution error */ + + FT_Long top; /* top of exec. stack */ + + FT_UInt stackSize; /* size of exec. stack */ + FT_Long* stack; /* current exec. stack */ + + FT_Long args; + FT_UInt new_top; /* new top after exec. */ + + TT_GlyphZone zp0, /* zone records */ + zp1, + zp2, + pts, + twilight; + + FT_Size_Metrics metrics; + TT_Size_Metrics tt_metrics; /* size metrics */ + + TT_GraphicsState GS; /* current graphics state */ + + FT_Int curRange; /* current code range number */ + FT_Byte* code; /* current code range */ + FT_Long IP; /* current instruction pointer */ + FT_Long codeSize; /* size of current range */ + + FT_Byte opcode; /* current opcode */ + FT_Int length; /* length of current opcode */ + + FT_Bool step_ins; /* true if the interpreter must */ + /* increment IP after ins. exec */ + FT_Long cvtSize; + FT_Long* cvt; + + FT_UInt glyphSize; /* glyph instructions buffer size */ + FT_Byte* glyphIns; /* glyph instructions buffer */ + + FT_UInt numFDefs; /* number of function defs */ + FT_UInt maxFDefs; /* maximum number of function defs */ + TT_DefArray FDefs; /* table of FDefs entries */ + + FT_UInt numIDefs; /* number of instruction defs */ + FT_UInt maxIDefs; /* maximum number of ins defs */ + TT_DefArray IDefs; /* table of IDefs entries */ + + FT_UInt maxFunc; /* maximum function index */ + FT_UInt maxIns; /* maximum instruction index */ + + FT_Int callTop, /* top of call stack during execution */ + callSize; /* size of call stack */ + TT_CallStack callStack; /* call stack */ + + FT_UShort maxPoints; /* capacity of this context's `pts' */ + FT_Short maxContours; /* record, expressed in points and */ + /* contours. */ + + TT_CodeRangeTable codeRangeTable; /* table of valid code ranges */ + /* useful for the debugger */ + + FT_UShort storeSize; /* size of current storage */ + FT_Long* storage; /* storage area */ + + FT_F26Dot6 period; /* values used for the */ + FT_F26Dot6 phase; /* `SuperRounding' */ + FT_F26Dot6 threshold; + +#if 0 + /* this seems to be unused */ + FT_Int cur_ppem; /* ppem along the current proj vector */ +#endif + + FT_Bool instruction_trap; /* If `True', the interpreter will */ + /* exit after each instruction */ + + TT_GraphicsState default_GS; /* graphics state resulting from */ + /* the prep program */ + FT_Bool is_composite; /* true if the glyph is composite */ + FT_Bool pedantic_hinting; /* true for pedantic interpretation */ + + /* latest interpreter additions */ + + FT_Long F_dot_P; /* dot product of freedom and projection */ + /* vectors */ + TT_Round_Func func_round; /* current rounding function */ + + TT_Project_Func func_project, /* current projection function */ + func_dualproj, /* current dual proj. function */ + func_freeProj; /* current freedom proj. func */ + + TT_Move_Func func_move; /* current point move function */ + + TT_Get_CVT_Func func_read_cvt; /* read a cvt entry */ + TT_Set_CVT_Func func_write_cvt; /* write a cvt entry (in pixels) */ + TT_Set_CVT_Func func_move_cvt; /* incr a cvt entry (in pixels) */ + + FT_ULong loadSize; + TT_SubGlyph_Stack loadStack; /* loading subglyph stack */ + + } TT_ExecContextRec; + + + extern const TT_GraphicsState tt_default_graphics_state; + + + LOCAL_DEF + FT_Error TT_Goto_CodeRange( TT_ExecContext exec, + FT_Int range, + FT_Long IP ); + + LOCAL_DEF + FT_Error TT_Set_CodeRange( TT_ExecContext exec, + FT_Int range, + void* base, + FT_Long length ); + + LOCAL_DEF + FT_Error TT_Clear_CodeRange( TT_ExecContext exec, + FT_Int range ); + + FT_EXPORT_DEF( TT_ExecContext ) TT_New_Context( TT_Face face ); + + LOCAL_DEF + FT_Error TT_Done_Context( TT_ExecContext exec ); + + LOCAL_DEF + FT_Error TT_Destroy_Context( TT_ExecContext exec, + FT_Memory memory ); + + LOCAL_DEF + FT_Error TT_Load_Context( TT_ExecContext exec, + TT_Face face, + TT_Size size ); + + LOCAL_DEF + FT_Error TT_Save_Context( TT_ExecContext exec, + TT_Size ins ); + + LOCAL_DEF + FT_Error TT_Run_Context( TT_ExecContext exec, + FT_Bool debug ); + + FT_EXPORT_DEF( FT_Error ) TT_RunIns( TT_ExecContext exec ); + + +#ifdef __cplusplus + } +#endif + +#endif /* TTINTERP_H */ + + +/* END */ diff --git a/src/freetype/truetype/ttobjs.c b/src/freetype/truetype/ttobjs.c new file mode 100644 index 0000000000..2ba715dc11 --- /dev/null +++ b/src/freetype/truetype/ttobjs.c @@ -0,0 +1,734 @@ +/***************************************************************************/ +/* */ +/* ttobjs.c */ +/* */ +/* Objects manager (body). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#include +#include +#include +#include +#include + +#include +#include + + +#ifdef FT_FLAT_COMPILE + +#include "ttgload.h" +#include "ttpload.h" + +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER +#include "ttinterp.h" +#endif + +#else /* FT_FLAT_COMPILE */ + +#include +#include + +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER +#include +#endif + +#endif /* FT_FLAT_COMPILE */ + + +#include + + + + /*************************************************************************/ + /* */ + /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ + /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ + /* messages during execution. */ + /* */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_ttobjs + + + /*************************************************************************/ + /* */ + /* GLYPH ZONE FUNCTIONS */ + /* */ + /*************************************************************************/ + + /*************************************************************************/ + /* */ + /* */ + /* TT_Done_GlyphZone */ + /* */ + /* */ + /* Deallocates a glyph zone. */ + /* */ + /* */ + /* zone :: A pointer to the target glyph zone. */ + /* */ + LOCAL_FUNC + void TT_Done_GlyphZone( TT_GlyphZone* zone ) + { + FT_Memory memory = zone->memory; + + + FREE( zone->contours ); + FREE( zone->tags ); + FREE( zone->cur ); + FREE( zone->org ); + + zone->max_points = zone->n_points = 0; + zone->max_contours = zone->n_contours = 0; + } + + + /*************************************************************************/ + /* */ + /* */ + /* TT_New_GlyphZone */ + /* */ + /* */ + /* Allocates a new glyph zone. */ + /* */ + /* */ + /* memory :: A handle to the current memory object. */ + /* */ + /* maxPoints :: The capacity of glyph zone in points. */ + /* */ + /* maxContours :: The capacity of glyph zone in contours. */ + /* */ + /* */ + /* zone :: A pointer to the target glyph zone record. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + LOCAL_FUNC + FT_Error TT_New_GlyphZone( FT_Memory memory, + FT_UShort maxPoints, + FT_Short maxContours, + TT_GlyphZone* zone ) + { + FT_Error error; + + + if ( maxPoints > 0 ) + maxPoints += 2; + + MEM_Set( zone, 0, sizeof ( *zone ) ); + zone->memory = memory; + + if ( ALLOC_ARRAY( zone->org, maxPoints * 2, FT_F26Dot6 ) || + ALLOC_ARRAY( zone->cur, maxPoints * 2, FT_F26Dot6 ) || + ALLOC_ARRAY( zone->tags, maxPoints, FT_Byte ) || + ALLOC_ARRAY( zone->contours, maxContours, FT_UShort ) ) + { + TT_Done_GlyphZone( zone ); + } + + return error; + } + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Init_Face */ + /* */ + /* */ + /* Initializes a given TrueType face object. */ + /* */ + /* */ + /* stream :: The source font stream. */ + /* */ + /* face_index :: The index of the font face in the resource. */ + /* */ + /* num_params :: Number of additional generic parameters. Ignored. */ + /* */ + /* params :: Additional generic parameters. Ignored. */ + /* */ + /* */ + /* face :: The newly built face object. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + LOCAL_DEF + FT_Error TT_Init_Face( FT_Stream stream, + TT_Face face, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ) + { + FT_Error error; + FT_Library library; + SFNT_Interface* sfnt; + + + library = face->root.driver->root.library; + sfnt = (SFNT_Interface*)FT_Get_Module_Interface( library, "sfnt" ); + if ( !sfnt ) + goto Bad_Format; + + /* create input stream from resource */ + if ( FILE_Seek( 0 ) ) + goto Exit; + + /* check that we have a valid TrueType file */ + error = sfnt->init_face( stream, face, face_index, num_params, params ); + if ( error ) + goto Exit; + + /* We must also be able to accept Mac/GX fonts, as well as OT ones */ + if ( face->format_tag != 0x00010000L && /* MS fonts */ + face->format_tag != TTAG_true ) /* Mac fonts */ + { + FT_TRACE2(( "[not a valid TTF font]\n" )); + goto Bad_Format; + } + + /* If we are performing a simple font format check, exit immediately */ + if ( face_index < 0 ) + return TT_Err_Ok; + + /* Load font directory */ + error = sfnt->load_face( stream, face, face_index, num_params, params ); + if ( error ) + goto Exit; + + error = TT_Load_Locations( face, stream ) || + TT_Load_CVT ( face, stream ) || + TT_Load_Programs ( face, stream ); + + /* initialize standard glyph loading routines */ + TT_Init_Glyph_Loading( face ); + + Exit: + return error; + + Bad_Format: + error = FT_Err_Unknown_File_Format; + goto Exit; + } + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Done_Face */ + /* */ + /* */ + /* Finalizes a given face object. */ + /* */ + /* */ + /* face :: A pointer to the face object to destroy. */ + /* */ + LOCAL_DEF + void TT_Done_Face( TT_Face face ) + { + FT_Memory memory = face->root.memory; + FT_Stream stream = face->root.stream; + + SFNT_Interface* sfnt = (SFNT_Interface*)face->sfnt; + + + /* for `extended TrueType formats' (i.e. compressed versions) */ + if ( face->extra.finalizer ) + face->extra.finalizer( face->extra.data ); + + if ( sfnt ) + sfnt->done_face( face ); + + /* freeing the locations table */ + FREE( face->glyph_locations ); + face->num_locations = 0; + + /* freeing the CVT */ + FREE( face->cvt ); + face->cvt_size = 0; + + /* freeing the programs */ + RELEASE_Frame( face->font_program ); + RELEASE_Frame( face->cvt_program ); + face->font_program_size = 0; + face->cvt_program_size = 0; + } + + + /*************************************************************************/ + /* */ + /* SIZE FUNCTIONS */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Init_Size */ + /* */ + /* */ + /* Initializes a new TrueType size object. */ + /* */ + /* */ + /* size :: A handle to the size object. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + LOCAL_DEF + FT_Error TT_Init_Size( TT_Size size ) + { + FT_Error error = TT_Err_Ok; + + +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER + + TT_Face face = (TT_Face)size->root.face; + FT_Memory memory = face->root.memory; + FT_Int i; + + TT_ExecContext exec; + FT_UShort n_twilight; + TT_MaxProfile* maxp = &face->max_profile; + + + size->ttmetrics.valid = FALSE; + + size->max_function_defs = maxp->maxFunctionDefs; + size->max_instruction_defs = maxp->maxInstructionDefs; + + size->num_function_defs = 0; + size->num_instruction_defs = 0; + + size->max_func = 0; + size->max_ins = 0; + + size->cvt_size = face->cvt_size; + size->storage_size = maxp->maxStorage; + + /* Set default metrics */ + { + FT_Size_Metrics* metrics = &size->root.metrics; + TT_Size_Metrics* metrics2 = &size->ttmetrics; + + + metrics->x_ppem = 0; + metrics->y_ppem = 0; + + metrics2->rotated = FALSE; + metrics2->stretched = FALSE; + + /* set default compensation (all 0) */ + for ( i = 0; i < 4; i++ ) + metrics2->compensations[i] = 0; + } + + /* allocate function defs, instruction defs, cvt, and storage area */ + if ( ALLOC_ARRAY( size->function_defs, + size->max_function_defs, + TT_DefRecord ) || + + ALLOC_ARRAY( size->instruction_defs, + size->max_instruction_defs, + TT_DefRecord ) || + + ALLOC_ARRAY( size->cvt, + size->cvt_size, FT_Long ) || + + ALLOC_ARRAY( size->storage, + size->storage_size, FT_Long ) ) + + goto Fail_Memory; + + /* reserve twilight zone */ + n_twilight = maxp->maxTwilightPoints; + error = TT_New_GlyphZone( memory, n_twilight, 0, &size->twilight ); + if ( error ) + goto Fail_Memory; + + size->twilight.n_points = n_twilight; + + /* set `face->interpreter' according to the debug hook present */ + { + FT_Library library = face->root.driver->root.library; + + + face->interpreter = (TT_Interpreter) + library->debug_hooks[FT_DEBUG_HOOK_TRUETYPE]; + if ( !face->interpreter ) + face->interpreter = (TT_Interpreter)TT_RunIns; + } + + /* Fine, now execute the font program! */ + exec = size->context; + /* size objects used during debugging have their own context */ + if ( !size->debug ) + exec = TT_New_Context( face ); + + if ( !exec ) + { + error = TT_Err_Could_Not_Find_Context; + goto Fail_Memory; + } + + size->GS = tt_default_graphics_state; + TT_Load_Context( exec, face, size ); + + exec->callTop = 0; + exec->top = 0; + + exec->period = 64; + exec->phase = 0; + exec->threshold = 0; + + { + FT_Size_Metrics* metrics = &exec->metrics; + TT_Size_Metrics* tt_metrics = &exec->tt_metrics; + + + metrics->x_ppem = 0; + metrics->y_ppem = 0; + metrics->x_scale = 0; + metrics->y_scale = 0; + + tt_metrics->ppem = 0; + tt_metrics->scale = 0; + tt_metrics->ratio = 0x10000L; + } + + exec->instruction_trap = FALSE; + + exec->cvtSize = size->cvt_size; + exec->cvt = size->cvt; + + exec->F_dot_P = 0x10000L; + + /* allow font program execution */ + TT_Set_CodeRange( exec, + tt_coderange_font, + face->font_program, + face->font_program_size ); + + /* disable CVT and glyph programs coderange */ + TT_Clear_CodeRange( exec, tt_coderange_cvt ); + TT_Clear_CodeRange( exec, tt_coderange_glyph ); + + if ( face->font_program_size > 0 ) + { + error = TT_Goto_CodeRange( exec, tt_coderange_font, 0 ); + if ( !error ) + error = face->interpreter( exec ); + + if ( error ) + goto Fail_Exec; + } + else + error = TT_Err_Ok; + + TT_Save_Context( exec, size ); + + if ( !size->debug ) + TT_Done_Context( exec ); + +#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */ + + size->ttmetrics.valid = FALSE; + return error; + +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER + + Fail_Exec: + if ( !size->debug ) + TT_Done_Context( exec ); + + Fail_Memory: + +#endif + + TT_Done_Size( size ); + return error; + } + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Done_Size */ + /* */ + /* */ + /* The TrueType size object finalizer. */ + /* */ + /* */ + /* size :: A handle to the target size object. */ + /* */ + LOCAL_FUNC + void TT_Done_Size( TT_Size size ) + { + +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER + + FT_Memory memory = size->root.face->memory; + + + if ( size->debug ) + { + /* the debug context must be deleted by the debugger itself */ + size->context = NULL; + size->debug = FALSE; + } + + FREE( size->cvt ); + size->cvt_size = 0; + + /* free storage area */ + FREE( size->storage ); + size->storage_size = 0; + + /* twilight zone */ + TT_Done_GlyphZone( &size->twilight ); + + FREE( size->function_defs ); + FREE( size->instruction_defs ); + + size->num_function_defs = 0; + size->max_function_defs = 0; + size->num_instruction_defs = 0; + size->max_instruction_defs = 0; + + size->max_func = 0; + size->max_ins = 0; + +#endif + + size->ttmetrics.valid = FALSE; + } + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Reset_Size */ + /* */ + /* */ + /* Resets a TrueType size when resolutions and character dimensions */ + /* have been changed. */ + /* */ + /* */ + /* size :: A handle to the target size object. */ + /* */ + LOCAL_DEF + FT_Error TT_Reset_Size( TT_Size size ) + { + TT_Face face; + FT_Error error = TT_Err_Ok; + + FT_Size_Metrics* metrics; + + + if ( size->ttmetrics.valid ) + return TT_Err_Ok; + + face = (TT_Face)size->root.face; + + metrics = &size->root.metrics; + + if ( metrics->x_ppem < 1 || metrics->y_ppem < 1 ) + return TT_Err_Invalid_PPem; + + /* compute new transformation */ + if ( metrics->x_ppem >= metrics->y_ppem ) + { + size->ttmetrics.scale = metrics->x_scale; + size->ttmetrics.ppem = metrics->x_ppem; + size->ttmetrics.x_ratio = 0x10000L; + size->ttmetrics.y_ratio = FT_MulDiv( metrics->y_ppem, + 0x10000L, + metrics->x_ppem ); + } + else + { + size->ttmetrics.scale = metrics->y_scale; + size->ttmetrics.ppem = metrics->y_ppem; + size->ttmetrics.x_ratio = FT_MulDiv( metrics->x_ppem, + 0x10000L, + metrics->y_ppem ); + size->ttmetrics.y_ratio = 0x10000L; + } + + /* Compute root ascender, descender, test height, and max_advance */ + metrics->ascender = ( FT_MulFix( face->root.ascender, + metrics->y_scale ) + 32 ) & -64; + metrics->descender = ( FT_MulFix( face->root.descender, + metrics->y_scale ) + 32 ) & -64; + metrics->height = ( FT_MulFix( face->root.height, + metrics->y_scale ) + 32 ) & -64; + metrics->max_advance = ( FT_MulFix( face->root.max_advance_width, + metrics->x_scale ) + 32 ) & -64; + +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER + + { + TT_ExecContext exec; + FT_UInt i, j; + + + /* Scale the cvt values to the new ppem. */ + /* We use by default the y ppem to scale the CVT. */ + for ( i = 0; i < size->cvt_size; i++ ) + size->cvt[i] = FT_MulFix( face->cvt[i], size->ttmetrics.scale ); + + /* All twilight points are originally zero */ + for ( j = 0; j < size->twilight.n_points; j++ ) + { + size->twilight.org[j].x = 0; + size->twilight.org[j].y = 0; + size->twilight.cur[j].x = 0; + size->twilight.cur[j].y = 0; + } + + /* clear storage area */ + for ( i = 0; i < size->storage_size; i++ ) + size->storage[i] = 0; + + size->GS = tt_default_graphics_state; + + /* get execution context and run prep program */ + if ( size->debug ) + exec = size->context; + else + exec = TT_New_Context( face ); + /* debugging instances have their own context */ + + if ( !exec ) + return TT_Err_Could_Not_Find_Context; + + TT_Load_Context( exec, face, size ); + + TT_Set_CodeRange( exec, + tt_coderange_cvt, + face->cvt_program, + face->cvt_program_size ); + + TT_Clear_CodeRange( exec, tt_coderange_glyph ); + + exec->instruction_trap = FALSE; + + exec->top = 0; + exec->callTop = 0; + + if ( face->cvt_program_size > 0 ) + { + error = TT_Goto_CodeRange( exec, tt_coderange_cvt, 0 ); + if ( error ) + goto End; + + if ( !size->debug ) + error = face->interpreter( exec ); + } + else + error = TT_Err_Ok; + + size->GS = exec->GS; + /* save default graphics state */ + + End: + TT_Save_Context( exec, size ); + + if ( !size->debug ) + TT_Done_Context( exec ); + /* debugging instances keep their context */ + } + +#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */ + + if ( !error ) + size->ttmetrics.valid = TRUE; + + return error; + } + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Init_Driver */ + /* */ + /* */ + /* Initializes a given TrueType driver object. */ + /* */ + /* */ + /* driver :: A handle to the target driver object. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + LOCAL_FUNC + FT_Error TT_Init_Driver( TT_Driver driver ) + { + FT_Error error; + + + /* set `extra' in glyph loader */ + error = FT_GlyphLoader_Create_Extra( FT_DRIVER( driver )->glyph_loader ); + + /* init extension registry if needed */ + +#ifdef TT_CONFIG_OPTION_EXTEND_ENGINE + if ( !error ) + return TT_Init_Extensions( driver ); +#endif + + return error; + } + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Done_Driver */ + /* */ + /* */ + /* Finalizes a given TrueType driver. */ + /* */ + /* */ + /* driver :: A handle to the target TrueType driver. */ + /* */ + LOCAL_FUNC + void TT_Done_Driver( TT_Driver driver ) + { + /* destroy extensions registry if needed */ + +#ifdef TT_CONFIG_OPTION_EXTEND_ENGINE + + TT_Done_Extensions( driver ); + +#endif + +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER + + /* destroy the execution context */ + if ( driver->context ) + { + TT_Destroy_Context( driver->context, driver->root.root.memory ); + driver->context = NULL; + } + +#endif + + } + + +/* END */ diff --git a/src/freetype/truetype/ttobjs.h b/src/freetype/truetype/ttobjs.h new file mode 100644 index 0000000000..3e55de3cb1 --- /dev/null +++ b/src/freetype/truetype/ttobjs.h @@ -0,0 +1,412 @@ +/***************************************************************************/ +/* */ +/* ttobjs.h */ +/* */ +/* Objects manager (specification). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef TTOBJS_H +#define TTOBJS_H + + +#include +#include +#include + + +#ifdef __cplusplus + extern "C" { +#endif + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Driver */ + /* */ + /* */ + /* A handle to a TrueType driver object. */ + /* */ + typedef struct TT_DriverRec_* TT_Driver; + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Instance */ + /* */ + /* */ + /* A handle to a TrueType size object. */ + /* */ + typedef struct TT_SizeRec_* TT_Size; + + + /*************************************************************************/ + /* */ + /* */ + /* TT_GlyphSlot */ + /* */ + /* */ + /* A handle to a TrueType glyph slot object. */ + /* */ + /* */ + /* This is a direct typedef of FT_GlyphSlot, as there is nothing */ + /* specific about the TrueType glyph slot. */ + /* */ + typedef FT_GlyphSlot TT_GlyphSlot; + + + /*************************************************************************/ + /* */ + /* */ + /* TT_GraphicsState */ + /* */ + /* */ + /* The TrueType graphics state used during bytecode interpretation. */ + /* */ + typedef struct TT_GraphicsState_ + { + FT_UShort rp0; + FT_UShort rp1; + FT_UShort rp2; + + FT_UnitVector dualVector; + FT_UnitVector projVector; + FT_UnitVector freeVector; + + FT_Long loop; + FT_F26Dot6 minimum_distance; + FT_Int round_state; + + FT_Bool auto_flip; + FT_F26Dot6 control_value_cutin; + FT_F26Dot6 single_width_cutin; + FT_F26Dot6 single_width_value; + FT_Short delta_base; + FT_Short delta_shift; + + FT_Byte instruct_control; + FT_Bool scan_control; + FT_Int scan_type; + + FT_UShort gep0; + FT_UShort gep1; + FT_UShort gep2; + + } TT_GraphicsState; + + + LOCAL_DEF void TT_Done_GlyphZone( TT_GlyphZone* zone ); + + LOCAL_DEF FT_Error TT_New_GlyphZone( FT_Memory memory, + FT_UShort maxPoints, + FT_Short maxContours, + TT_GlyphZone* zone ); + + + /*************************************************************************/ + /* */ + /* EXECUTION SUBTABLES */ + /* */ + /* These sub-tables relate to instruction execution. */ + /* */ + /*************************************************************************/ + + +#define TT_MAX_CODE_RANGES 3 + + + /*************************************************************************/ + /* */ + /* There can only be 3 active code ranges at once: */ + /* - the Font Program */ + /* - the CVT Program */ + /* - a glyph's instructions set */ + /* */ + typedef enum TT_CodeRange_Tag_ + { + tt_coderange_none = 0, + tt_coderange_font, + tt_coderange_cvt, + tt_coderange_glyph + + } TT_CodeRange_Tag; + + + typedef struct TT_CodeRange_ + { + FT_Byte* base; + FT_ULong size; + + } TT_CodeRange; + + typedef TT_CodeRange TT_CodeRangeTable[TT_MAX_CODE_RANGES]; + + + /*************************************************************************/ + /* */ + /* Defines a function/instruction definition record. */ + /* */ + typedef struct TT_DefRecord_ + { + FT_Int range; /* in which code range is it located? */ + FT_Long start; /* where does it start? */ + FT_UInt opc; /* function #, or instruction code */ + FT_Bool active; /* is it active? */ + + } TT_DefRecord, *TT_DefArray; + + + /*************************************************************************/ + /* */ + /* Subglyph transformation record. */ + /* */ + typedef struct TT_Transform_ + { + FT_Fixed xx, xy; /* transformation matrix coefficients */ + FT_Fixed yx, yy; + FT_F26Dot6 ox, oy; /* offsets */ + + } TT_Transform; + + + /*************************************************************************/ + /* */ + /* Subglyph loading record. Used to load composite components. */ + /* */ + typedef struct TT_SubglyphRec_ + { + FT_Long index; /* subglyph index; initialized with -1 */ + FT_Bool is_scaled; /* is the subglyph scaled? */ + FT_Bool is_hinted; /* should it be hinted? */ + FT_Bool preserve_pps; /* preserve phantom points? */ + + FT_Long file_offset; + + FT_BBox bbox; + FT_Pos left_bearing; + FT_Pos advance; + + TT_GlyphZone zone; + + FT_Long arg1; /* first argument */ + FT_Long arg2; /* second argument */ + + FT_UShort element_flag; /* current load element flag */ + + TT_Transform transform; /* transformation matrix */ + + FT_Vector pp1, pp2; /* phantom points */ + + } TT_SubGlyphRec, *TT_SubGlyph_Stack; + + + /*************************************************************************/ + /* */ + /* A note regarding non-squared pixels: */ + /* */ + /* (This text will probably go into some docs at some time; for now, it */ + /* is kept here to explain some definitions in the TIns_Metrics */ + /* record). */ + /* */ + /* The CVT is a one-dimensional array containing values that control */ + /* certain important characteristics in a font, like the height of all */ + /* capitals, all lowercase letter, default spacing or stem width/height. */ + /* */ + /* These values are found in FUnits in the font file, and must be scaled */ + /* to pixel coordinates before being used by the CVT and glyph programs. */ + /* Unfortunately, when using distinct x and y resolutions (or distinct x */ + /* and y pointsizes), there are two possible scalings. */ + /* */ + /* A first try was to implement a `lazy' scheme where all values were */ + /* scaled when first used. However, while some values are always used */ + /* in the same direction, some others are used under many different */ + /* circumstances and orientations. */ + /* */ + /* I have found a simpler way to do the same, and it even seems to work */ + /* in most of the cases: */ + /* */ + /* - All CVT values are scaled to the maximum ppem size. */ + /* */ + /* - When performing a read or write in the CVT, a ratio factor is used */ + /* to perform adequate scaling. Example: */ + /* */ + /* x_ppem = 14 */ + /* y_ppem = 10 */ + /* */ + /* We choose ppem = x_ppem = 14 as the CVT scaling size. All cvt */ + /* entries are scaled to it. */ + /* */ + /* x_ratio = 1.0 */ + /* y_ratio = y_ppem/ppem (< 1.0) */ + /* */ + /* We compute the current ratio like: */ + /* */ + /* - If projVector is horizontal, */ + /* ratio = x_ratio = 1.0 */ + /* */ + /* - if projVector is vertical, */ + /* ratio = y_ratio */ + /* */ + /* - else, */ + /* ratio = sqrt( (proj.x * x_ratio) ^ 2 + (proj.y * y_ratio) ^ 2 ) */ + /* */ + /* Reading a cvt value returns */ + /* ratio * cvt[index] */ + /* */ + /* Writing a cvt value in pixels: */ + /* cvt[index] / ratio */ + /* */ + /* The current ppem is simply */ + /* ratio * ppem */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* Metrics used by the TrueType size and context objects. */ + /* */ + typedef struct TT_Size_Metrics_ + { + /* for non-square pixels */ + FT_Long x_ratio; + FT_Long y_ratio; + + FT_UShort ppem; /* maximum ppem size */ + FT_Long ratio; /* current ratio */ + FT_Fixed scale; + + FT_F26Dot6 compensations[4]; /* device-specific compensations */ + + FT_Bool valid; + + FT_Bool rotated; /* `is the glyph rotated?'-flag */ + FT_Bool stretched; /* `is the glyph stretched?'-flag */ + + } TT_Size_Metrics; + + + /*************************************************************************/ + /* */ + /* TrueType size class. */ + /* */ + typedef struct TT_SizeRec_ + { + FT_SizeRec root; + + TT_Size_Metrics ttmetrics; + +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER + + FT_UInt num_function_defs; /* number of function definitions */ + FT_UInt max_function_defs; + TT_DefArray function_defs; /* table of function definitions */ + + FT_UInt num_instruction_defs; /* number of ins. definitions */ + FT_UInt max_instruction_defs; + TT_DefArray instruction_defs; /* table of ins. definitions */ + + FT_UInt max_func; + FT_UInt max_ins; + + TT_CodeRangeTable codeRangeTable; + + TT_GraphicsState GS; + + FT_ULong cvt_size; /* the scaled control value table */ + FT_Long* cvt; + + FT_UShort storage_size; /* The storage area is now part of */ + FT_Long* storage; /* the instance */ + + TT_GlyphZone twilight; /* The instance's twilight zone */ + + /* debugging variables */ + + /* When using the debugger, we must keep the */ + /* execution context tied to the instance */ + /* object rather than asking it on demand. */ + + FT_Bool debug; + TT_ExecContext context; + +#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */ + + } TT_SizeRec; + + + /*************************************************************************/ + /* */ + /* TrueType driver class. */ + /* */ + typedef struct TT_DriverRec_ + { + FT_DriverRec root; + TT_ExecContext context; /* execution context */ + TT_GlyphZone zone; /* glyph loader points zone */ + + void* extension_component; + + } TT_DriverRec; + + + /*************************************************************************/ + /* */ + /* Face functions */ + /* */ + LOCAL_DEF + FT_Error TT_Init_Face( FT_Stream stream, + TT_Face face, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ); + + LOCAL_DEF + void TT_Done_Face( TT_Face face ); + + + /*************************************************************************/ + /* */ + /* Size functions */ + /* */ + LOCAL_DEF + FT_Error TT_Init_Size( TT_Size size ); + + LOCAL_DEF + void TT_Done_Size( TT_Size size ); + + LOCAL_DEF + FT_Error TT_Reset_Size( TT_Size size ); + + + /*************************************************************************/ + /* */ + /* Driver functions */ + /* */ + LOCAL_DEF + FT_Error TT_Init_Driver( TT_Driver driver ); + + LOCAL_DEF + void TT_Done_Driver( TT_Driver driver ); + + +#ifdef __cplusplus + } +#endif + +#endif /* TTOBJS_H */ + + +/* END */ diff --git a/src/freetype/truetype/ttpload.c b/src/freetype/truetype/ttpload.c new file mode 100644 index 0000000000..d82dd45bea --- /dev/null +++ b/src/freetype/truetype/ttpload.c @@ -0,0 +1,273 @@ +/***************************************************************************/ +/* */ +/* ttpload.h */ +/* */ +/* TrueType glyph data/program tables loader (body). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#include +#include +#include +#include + +#ifdef FT_FLAT_COMPILE +#include "ttpload.h" +#else +#include +#endif + +#include + + + /*************************************************************************/ + /* */ + /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ + /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ + /* messages during execution. */ + /* */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_ttpload + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Load_Locations */ + /* */ + /* */ + /* Loads the locations table. */ + /* */ + /* */ + /* face :: A handle to the target face object. */ + /* */ + /* */ + /* stream :: The input stream. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + LOCAL_FUNC + FT_Error TT_Load_Locations( TT_Face face, + FT_Stream stream ) + { + FT_Error error; + FT_Memory memory = stream->memory; + FT_Short LongOffsets; + FT_ULong table_len; + + + FT_TRACE2(( "Locations " )); + LongOffsets = face->header.Index_To_Loc_Format; + + error = face->goto_table( face, TTAG_loca, stream, &table_len ); + if ( error ) + { + error = TT_Err_Locations_Missing; + goto Exit; + } + + if ( LongOffsets != 0 ) + { + face->num_locations = (FT_UShort)( table_len >> 2 ); + + FT_TRACE2(( "(32bit offsets): %12d ", face->num_locations )); + + if ( ALLOC_ARRAY( face->glyph_locations, + face->num_locations, + FT_Long ) ) + goto Exit; + + if ( ACCESS_Frame( face->num_locations * 4L ) ) + goto Exit; + + { + FT_Long* loc = face->glyph_locations; + FT_Long* limit = loc + face->num_locations; + + + for ( ; loc < limit; loc++ ) + *loc = GET_Long(); + } + + FORGET_Frame(); + } + else + { + face->num_locations = (FT_UShort)( table_len >> 1 ); + + FT_TRACE2(( "(16bit offsets): %12d ", face->num_locations )); + + if ( ALLOC_ARRAY( face->glyph_locations, + face->num_locations, + FT_Long ) ) + goto Exit; + + if ( ACCESS_Frame( face->num_locations * 2L ) ) + goto Exit; + { + FT_Long* loc = face->glyph_locations; + FT_Long* limit = loc + face->num_locations; + + + for ( ; loc < limit; loc++ ) + *loc = (FT_Long)( (FT_ULong)GET_UShort() * 2 ); + } + FORGET_Frame(); + } + + FT_TRACE2(( "loaded\n" )); + + Exit: + return error; + } + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Load_CVT */ + /* */ + /* */ + /* Loads the control value table into a face object. */ + /* */ + /* */ + /* face :: A handle to the target face object. */ + /* */ + /* */ + /* stream :: A handle to the input stream. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + LOCAL_FUNC + FT_Error TT_Load_CVT( TT_Face face, + FT_Stream stream ) + { + FT_Error error; + FT_Memory memory = stream->memory; + FT_ULong table_len; + + + FT_TRACE2(( "CVT " )); + + error = face->goto_table( face, TTAG_cvt, stream, &table_len ); + if ( error ) + { + FT_TRACE2(( "is missing!\n" )); + + face->cvt_size = 0; + face->cvt = NULL; + error = TT_Err_Ok; + + goto Exit; + } + + face->cvt_size = table_len / 2; + + if ( ALLOC_ARRAY( face->cvt, + face->cvt_size, + FT_Short ) ) + goto Exit; + + if ( ACCESS_Frame( face->cvt_size * 2L ) ) + goto Exit; + + { + FT_Short* cur = face->cvt; + FT_Short* limit = cur + face->cvt_size; + + + for ( ; cur < limit; cur++ ) + *cur = GET_Short(); + } + + FORGET_Frame(); + FT_TRACE2(( "loaded\n" )); + + Exit: + return error; + } + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Load_Progams */ + /* */ + /* */ + /* Loads the font program and the cvt program. */ + /* */ + /* */ + /* face :: A handle to the target face object. */ + /* */ + /* */ + /* stream :: A handle to the input stream. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + LOCAL_FUNC + FT_Error TT_Load_Programs( TT_Face face, + FT_Stream stream ) + { + FT_Error error; + FT_ULong table_len; + + + FT_TRACE2(( "Font program " )); + + /* The font program is optional */ + error = face->goto_table( face, TTAG_fpgm, stream, &table_len ); + if ( error ) + { + face->font_program = NULL; + face->font_program_size = 0; + + FT_TRACE2(( "is missing!\n" )); + } + else + { + face->font_program_size = table_len; + if ( EXTRACT_Frame( table_len, face->font_program ) ) + goto Exit; + + FT_TRACE2(( "loaded, %12d bytes\n", face->font_program_size )); + } + + FT_TRACE2(( "Prep program " )); + + error = face->goto_table( face, TTAG_prep, stream, &table_len ); + if ( error ) + { + face->cvt_program = NULL; + face->cvt_program_size = 0; + error = TT_Err_Ok; + + FT_TRACE2(( "is missing!\n" )); + } + else + { + face->cvt_program_size = table_len; + if ( EXTRACT_Frame( table_len, face->cvt_program ) ) + goto Exit; + + FT_TRACE2(( "loaded, %12d bytes\n", face->cvt_program_size )); + } + + Exit: + return error; + } + + +/* END */ diff --git a/src/freetype/truetype/ttpload.h b/src/freetype/truetype/ttpload.h new file mode 100644 index 0000000000..77802a6424 --- /dev/null +++ b/src/freetype/truetype/ttpload.h @@ -0,0 +1,51 @@ +/***************************************************************************/ +/* */ +/* ttpload.h */ +/* */ +/* TrueType glyph data/program tables loader (specification). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef TTPLOAD_H +#define TTPLOAD_H + +#include + + +#ifdef __cplusplus + extern "C" { +#endif + + + LOCAL_DEF + FT_Error TT_Load_Locations( TT_Face face, + FT_Stream stream ); + + LOCAL_DEF + FT_Error TT_Load_CVT( TT_Face face, + FT_Stream stream ); + + LOCAL_DEF + FT_Error TT_Load_Programs( TT_Face face, + FT_Stream stream ); + + +#ifdef __cplusplus + } +#endif + + +#endif /* TTPLOAD_H */ + + +/* END */ diff --git a/src/freetype/type1/module.mk0 b/src/freetype/type1/module.mk0 new file mode 100644 index 0000000000..af99eae25f --- /dev/null +++ b/src/freetype/type1/module.mk0 @@ -0,0 +1,6 @@ +make_module_list: add_type1_driver + +add_type1_driver: + $(OPEN_DRIVER)t1_driver_class$(CLOSE_DRIVER) + $(ECHO_DRIVER)type1 $(ECHO_DRIVER_DESC)Postscript font files with extension *.pfa or *.pfb$(ECHO_DRIVER_DONE) + diff --git a/src/freetype/type1/rules.mk0 b/src/freetype/type1/rules.mk0 new file mode 100644 index 0000000000..b544446ae6 --- /dev/null +++ b/src/freetype/type1/rules.mk0 @@ -0,0 +1,74 @@ +# +# FreeType 2 Type 1 driver configuration rules +# + + +# Copyright 1996-2000 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +# Type1 driver directory +# +T1_DIR := $(SRC_)type1 +T1_DIR_ := $(T1_DIR)$(SEP) + + +# compilation flags for the driver +# +T1_COMPILE := $(FT_COMPILE) + + +# Type1 driver sources (i.e., C files) +# +T1_DRV_SRC := $(T1_DIR_)t1objs.c \ + $(T1_DIR_)t1load.c \ + $(T1_DIR_)t1parse.c \ + $(T1_DIR_)t1tokens.c \ + $(T1_DIR_)t1driver.c \ + $(T1_DIR_)t1hinter.c \ + $(T1_DIR_)t1afm.c \ + $(T1_DIR_)t1gload.c + +# Type1 driver headers +# +T1_DRV_H := $(T1_DRV_SRC:%.c=%.h) + + +# Type1 driver object(s) +# +# T1_DRV_OBJ_M is used during `multi' builds +# T1_DRV_OBJ_S is used during `single' builds +# +T1_DRV_OBJ_M := $(T1_DRV_SRC:$(T1_DIR_)%.c=$(OBJ_)%.$O) +T1_DRV_OBJ_S := $(OBJ_)type1.$O + +# Type1 driver source file for single build +# +T1_DRV_SRC_S := $(T1_DIR_)type1.c + + +# Type1 driver - single object +# +$(T1_DRV_OBJ_S): $(T1_DRV_SRC_S) $(T1_DRV_SRC) $(FREETYPE_H) $(T1_DRV_H) + $(T1_COMPILE) $T$@ $(T1_DRV_SRC_S) + + +# Type1 driver - multiple objects +# +$(OBJ_)%.$O: $(T1_DIR_)%.c $(FREETYPE_H) $(T1_DRV_H) + $(T1_COMPILE) $T$@ $< + + +# update main driver object lists +# +DRV_OBJS_S += $(T1_DRV_OBJ_S) +DRV_OBJS_M += $(T1_DRV_OBJ_M) + + +# EOF diff --git a/src/freetype/type1/t1afm.c b/src/freetype/type1/t1afm.c new file mode 100644 index 0000000000..a6ac1b98a6 --- /dev/null +++ b/src/freetype/type1/t1afm.c @@ -0,0 +1,293 @@ +/***************************************************************************/ +/* */ +/* t1afm.c */ +/* */ +/* AFM support for Type 1 fonts (body). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifdef FT_FLAT_COMPILE + +#include "t1afm.h" + +#else + +#include + +#endif + + +#include +#include + +#include /* for qsort() */ +#include /* for strcmp() */ +#include /* for isalnum() */ + + + /*************************************************************************/ + /* */ + /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ + /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ + /* messages during execution. */ + /* */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_t1afm + + + LOCAL_FUNC + void T1_Done_AFM( FT_Memory memory, + T1_AFM* afm ) + { + FREE( afm->kern_pairs ); + afm->num_pairs = 0; + } + + +#undef IS_KERN_PAIR +#define IS_KERN_PAIR( p ) ( p[0] == 'K' && p[1] == 'P' ) + +#define IS_ALPHANUM( c ) ( isalnum( c ) || \ + c == '_' || \ + c == '.' ) + + + /* read a glyph name and return the equivalent glyph index */ + static + FT_UInt afm_atoindex( FT_Byte** start, + FT_Byte* limit, + T1_Font* type1 ) + { + FT_Byte* p = *start; + FT_Int len; + FT_UInt result = 0; + char temp[64]; + + + /* skip whitespace */ + while ( ( *p == ' ' || *p == '\t' || *p == ':' || *p == ';' ) && + p < limit ) + p++; + *start = p; + + /* now, read glyph name */ + while ( IS_ALPHANUM( *p ) && p < limit ) + p++; + + len = p - *start; + + if ( len > 0 && len < 64 ) + { + FT_Int n; + + + /* copy glyph name to intermediate array */ + MEM_Copy( temp, *start, len ); + temp[len] = 0; + + /* lookup glyph name in face array */ + for ( n = 0; n < type1->num_glyphs; n++ ) + { + char* gname = (char*)type1->glyph_names[n]; + + + if ( gname && gname[0] == temp[0] && strcmp( gname, temp ) == 0 ) + { + result = n; + break; + } + } + } + *start = p; + return result; + } + + + /* read an integer */ + static + int afm_atoi( FT_Byte** start, + FT_Byte* limit ) + { + FT_Byte* p = *start; + int sum = 0; + int sign = 1; + + + /* skip everything that is not a number */ + while ( p < limit && !isdigit( *p ) ) + { + sign = 1; + if ( *p == '-' ) + sign = -1; + + p++; + } + + while ( p < limit && isdigit( *p ) ) + { + sum = sum * 10 + ( *p - '0' ); + p++; + } + *start = p; + + return sum * sign; + } + + +#undef KERN_INDEX +#define KERN_INDEX( g1, g2 ) ( ( (FT_ULong)g1 << 16 ) | g2 ) + + + /* compare two kerning pairs */ + static + int compare_kern_pairs( const void* a, + const void* b ) + { + T1_Kern_Pair* pair1 = (T1_Kern_Pair*)a; + T1_Kern_Pair* pair2 = (T1_Kern_Pair*)b; + + FT_ULong index1 = KERN_INDEX( pair1->glyph1, pair1->glyph2 ); + FT_ULong index2 = KERN_INDEX( pair2->glyph1, pair2->glyph2 ); + + + return ( index1 - index2 ); + } + + + /* parse an AFM file -- for now, only read the kerning pairs */ + LOCAL_FUNC + FT_Error T1_Read_AFM( FT_Face t1_face, + FT_Stream stream ) + { + FT_Error error; + FT_Memory memory = stream->memory; + FT_Byte* start; + FT_Byte* limit; + FT_Byte* p; + FT_Int count = 0; + T1_Kern_Pair* pair; + T1_Font* type1 = &((T1_Face)t1_face)->type1; + T1_AFM* afm = 0; + + + if ( ACCESS_Frame( stream->size ) ) + return error; + + start = (FT_Byte*)stream->cursor; + limit = (FT_Byte*)stream->limit; + p = start; + + /* we are now going to count the occurences of `KP' or `KPX' in */ + /* the AFM file */ + count = 0; + for ( p = start; p < limit - 3; p++ ) + { + if ( IS_KERN_PAIR( p ) ) + count++; + } + + /* Actually, kerning pairs are simply optional! */ + if ( count == 0 ) + goto Exit; + + /* allocate the pairs */ + if ( ALLOC( afm, sizeof ( *afm ) ) || + ALLOC_ARRAY( afm->kern_pairs, count, T1_Kern_Pair ) ) + goto Exit; + + /* now, read each kern pair */ + pair = afm->kern_pairs; + afm->num_pairs = count; + + /* save in face object */ + ((T1_Face)t1_face)->afm_data = afm; + + for ( p = start; p < limit - 3; p++ ) + { + if ( IS_KERN_PAIR( p ) ) + { + FT_Byte* q; + + + /* skip keyword (KP or KPX) */ + q = p + 2; + if ( *q == 'X' ) + q++; + + pair->glyph1 = afm_atoindex( &q, limit, type1 ); + pair->glyph2 = afm_atoindex( &q, limit, type1 ); + pair->kerning.x = afm_atoi( &q, limit ); + + pair->kerning.y = 0; + if ( p[2] != 'X' ) + pair->kerning.y = afm_atoi( &q, limit ); + + pair++; + } + } + + /* now, sort the kern pairs according to their glyph indices */ + qsort( afm->kern_pairs, count, sizeof ( T1_Kern_Pair ), + compare_kern_pairs ); + + Exit: + if ( error ) + FREE( afm ); + + FORGET_Frame(); + + return error; + } + + + /* find the kerning for a given glyph pair */ + LOCAL_FUNC + void T1_Get_Kerning( T1_AFM* afm, + FT_UInt glyph1, + FT_UInt glyph2, + FT_Vector* kerning ) + { + T1_Kern_Pair *min, *mid, *max; + FT_ULong index = KERN_INDEX( glyph1, glyph2 ); + + + /* simple binary search */ + min = afm->kern_pairs; + max = min + afm->num_pairs - 1; + + while ( min <= max ) + { + FT_ULong midi; + + + mid = min + ( max - min ) / 2; + midi = KERN_INDEX( mid->glyph1, mid->glyph2 ); + + if ( midi == index ) + { + *kerning = mid->kerning; + return; + } + + if ( midi < index ) + min = mid + 1; + else + max = mid - 1; + } + + kerning->x = 0; + kerning->y = 0; + } + + +/* END */ diff --git a/src/freetype/type1/t1afm.h b/src/freetype/type1/t1afm.h new file mode 100644 index 0000000000..709154ec7b --- /dev/null +++ b/src/freetype/type1/t1afm.h @@ -0,0 +1,70 @@ +/***************************************************************************/ +/* */ +/* t1afm.h */ +/* */ +/* AFM support for Type 1 fonts (specification). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef T1AFM_H +#define T1AFM_H + +#include + + +#ifdef __cplusplus + extern "C" { +#endif + + + typedef struct T1_Kern_Pair_ + { + FT_UInt glyph1; + FT_UInt glyph2; + FT_Vector kerning; + + } T1_Kern_Pair; + + + typedef struct T1_AFM_ + { + FT_Int num_pairs; + T1_Kern_Pair* kern_pairs; + + } T1_AFM; + + + LOCAL_DEF + FT_Error T1_Read_AFM( FT_Face face, + FT_Stream stream ); + + LOCAL_DEF + void T1_Done_AFM( FT_Memory memory, + T1_AFM* afm ); + + LOCAL_DEF + void T1_Get_Kerning( T1_AFM* afm, + FT_UInt glyph1, + FT_UInt glyph2, + FT_Vector* kerning ); + + +#ifdef __cplusplus + } +#endif + + +#endif /* T1AFM_H */ + + +/* END */ diff --git a/src/freetype/type1/t1driver.c b/src/freetype/type1/t1driver.c new file mode 100644 index 0000000000..49b5a56374 --- /dev/null +++ b/src/freetype/type1/t1driver.c @@ -0,0 +1,381 @@ +/***************************************************************************/ +/* */ +/* t1driver.c */ +/* */ +/* Type 1 driver interface (body). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifdef FT_FLAT_COMPILE + +#include "t1driver.h" +#include "t1gload.h" +#include "t1afm.h" + +#else + +#include +#include +#include + +#endif + + +#include +#include +#include + +#include /* for strcmp() */ + + + /*************************************************************************/ + /* */ + /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ + /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ + /* messages during execution. */ + /* */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_t1driver + + +#ifndef T1_CONFIG_OPTION_NO_AFM + + + /*************************************************************************/ + /* */ + /* */ + /* Get_Kerning */ + /* */ + /* */ + /* A driver method used to return the kerning vector between two */ + /* glyphs of the same face. */ + /* */ + /* */ + /* face :: A handle to the source face object. */ + /* */ + /* left_glyph :: The index of the left glyph in the kern pair. */ + /* */ + /* right_glyph :: The index of the right glyph in the kern pair. */ + /* */ + /* */ + /* kerning :: The kerning vector. This is in font units for */ + /* scalable formats, and in pixels for fixed-sizes */ + /* formats. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* Only horizontal layouts (left-to-right & right-to-left) are */ + /* supported by this function. Other layouts, or more sophisticated */ + /* kernings are out of scope of this method (the basic driver */ + /* interface is meant to be simple). */ + /* */ + /* They can be implemented by format-specific interfaces. */ + /* */ + static + FT_Error Get_Kerning( T1_Face face, + FT_UInt left_glyph, + FT_UInt right_glyph, + FT_Vector* kerning ) + { + T1_AFM* afm; + + + kerning->x = 0; + kerning->y = 0; + + afm = (T1_AFM*)face->afm_data; + if ( afm ) + T1_Get_Kerning( afm, left_glyph, right_glyph, kerning ); + + return T1_Err_Ok; + } + + +#endif /* T1_CONFIG_OPTION_NO_AFM */ + + + static + FT_Error get_t1_glyph_name( T1_Face face, + FT_UInt glyph_index, + FT_Pointer buffer, + FT_UInt buffer_max ) + { + FT_String* gname; + + + gname = face->type1.glyph_names[glyph_index]; + + if ( buffer_max > 0 ) + { + FT_UInt len = strlen( gname ); + + + if ( len >= buffer_max ) + len = buffer_max - 1; + + MEM_Copy( buffer, gname, len ); + ((FT_Byte*)buffer)[len] = 0; + } + + return T1_Err_Ok; + } + + + static + FT_Module_Interface T1_Get_Interface( FT_Module module, + const char* interface ) + { + FT_UNUSED( module ); + + if ( strcmp( interface, "glyph_name" ) == 0 ) + return (FT_Module_Interface)get_t1_glyph_name; + + return 0; + } + + + + /*************************************************************************/ + /* */ + /* */ + /* Set_Char_Sizes */ + /* */ + /* */ + /* A driver method used to reset a size's character sizes (horizontal */ + /* and vertical) expressed in fractional points. */ + /* */ + /* */ + /* char_width :: The character width expressed in 26.6 */ + /* fractional points. */ + /* */ + /* char_height :: The character height expressed in 26.6 */ + /* fractional points. */ + /* */ + /* horz_resolution :: The horizontal resolution of the output device. */ + /* */ + /* vert_resolution :: The vertical resolution of the output device. */ + /* */ + /* */ + /* size :: A handle to the target size object. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + static + FT_Error Set_Char_Sizes( T1_Size size, + FT_F26Dot6 char_width, + FT_F26Dot6 char_height, + FT_UInt horz_resolution, + FT_UInt vert_resolution ) + { + FT_UNUSED( char_width ); + FT_UNUSED( char_height ); + FT_UNUSED( horz_resolution ); + FT_UNUSED( vert_resolution ); + + size->valid = FALSE; + + return T1_Reset_Size( size ); + } + + + /*************************************************************************/ + /* */ + /* */ + /* Set_Pixel_Sizes */ + /* */ + /* */ + /* A driver method used to reset a size's character sizes (horizontal */ + /* and vertical) expressed in integer pixels. */ + /* */ + /* */ + /* pixel_width :: The character width expressed in integer pixels. */ + /* */ + /* pixel_height :: The character height expressed in integer pixels. */ + /* */ + /* */ + /* size :: A handle to the target size object. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + static + FT_Error Set_Pixel_Sizes( T1_Size size, + FT_Int pixel_width, + FT_Int pixel_height ) + { + FT_UNUSED( pixel_width ); + FT_UNUSED( pixel_height ); + + size->valid = FALSE; + + return T1_Reset_Size( size ); + } + + + /*************************************************************************/ + /* */ + /* */ + /* Get_Char_Index */ + /* */ + /* */ + /* Uses a charmap to return a given character code's glyph index. */ + /* */ + /* */ + /* charmap :: A handle to the source charmap object. */ + /* charcode :: The character code. */ + /* */ + /* */ + /* Glyph index. 0 means `undefined character code'. */ + /* */ + static + FT_UInt Get_Char_Index( FT_CharMap charmap, + FT_Long charcode ) + { + T1_Face face; + FT_UInt result = 0; + PSNames_Interface* psnames; + + + face = (T1_Face)charmap->face; + psnames = (PSNames_Interface*)face->psnames; + if ( psnames ) + switch ( charmap->encoding ) + { + /*******************************************************************/ + /* */ + /* Unicode encoding support */ + /* */ + case ft_encoding_unicode: + /* use the `PSNames' module to synthetize the Unicode charmap */ + result = psnames->lookup_unicode( &face->unicode_map, + (FT_ULong)charcode ); + + /* the function returns 0xFFFF if the Unicode charcode has */ + /* no corresponding glyph */ + if ( result == 0xFFFF ) + result = 0; + goto Exit; + + /*******************************************************************/ + /* */ + /* Custom Type 1 encoding */ + /* */ + case ft_encoding_adobe_custom: + { + T1_Encoding* encoding = &face->type1.encoding; + + + if ( charcode >= encoding->code_first && + charcode <= encoding->code_last ) + result = encoding->char_index[charcode]; + goto Exit; + } + + /*******************************************************************/ + /* */ + /* Adobe Standard & Expert encoding support */ + /* */ + default: + if ( charcode < 256 ) + { + FT_UInt code; + FT_Int n; + const char* glyph_name; + + + code = psnames->adobe_std_encoding[charcode]; + if ( charmap->encoding == ft_encoding_adobe_expert ) + code = psnames->adobe_expert_encoding[charcode]; + + glyph_name = psnames->adobe_std_strings( code ); + if ( !glyph_name ) + break; + + for ( n = 0; n < face->type1.num_glyphs; n++ ) + { + const char* gname = face->type1.glyph_names[n]; + + + if ( gname && gname[0] == glyph_name[0] && + strcmp( gname, glyph_name ) == 0 ) + { + result = n; + break; + } + } + } + } + Exit: + return result; + } + + + + const FT_Driver_Class t1_driver_class = + { + { + ft_module_font_driver | ft_module_driver_scalable, + sizeof( FT_DriverRec ), + + "type1", /* driver name */ + 0x10000L, /* driver version 1.0 */ + 0x20000L, /* driver requires FreeType 2.0 or above */ + + 0, /* module specific interface */ + + (FT_Module_Constructor)0, + (FT_Module_Destructor) 0, + (FT_Module_Requester) T1_Get_Interface + }, + + sizeof( T1_FaceRec ), + sizeof( T1_SizeRec ), + sizeof( T1_GlyphSlotRec ), + + (FTDriver_initFace) T1_Init_Face, + (FTDriver_doneFace) T1_Done_Face, + (FTDriver_initSize) T1_Init_Size, + (FTDriver_doneSize) T1_Done_Size, + (FTDriver_initGlyphSlot)T1_Init_GlyphSlot, + (FTDriver_doneGlyphSlot)T1_Done_GlyphSlot, + + (FTDriver_setCharSizes) Set_Char_Sizes, + (FTDriver_setPixelSizes)Set_Pixel_Sizes, + (FTDriver_loadGlyph) T1_Load_Glyph, + (FTDriver_getCharIndex) Get_Char_Index, + +#ifdef T1_CONFIG_OPTION_NO_AFM + (FTDriver_getKerning) 0, + (FTDriver_attachFile) 0, +#else + (FTDriver_getKerning) Get_Kerning, + (FTDriver_attachFile) T1_Read_AFM, +#endif + (FTDriver_getAdvances) 0 + }; + + +#ifdef FT_CONFIG_OPTION_DYNAMIC_DRIVERS + + EXPORT_FUNC( const FT_Driver_Class* ) getDriverClass( void ) + { + return &t1_driver_class; + } + +#endif /* FT_CONFIG_OPTION_DYNAMIC_DRIVERS */ + + +/* END */ diff --git a/src/freetype/type1/t1driver.h b/src/freetype/type1/t1driver.h new file mode 100644 index 0000000000..5d615b5baf --- /dev/null +++ b/src/freetype/type1/t1driver.h @@ -0,0 +1,30 @@ +/***************************************************************************/ +/* */ +/* t1driver.h */ +/* */ +/* High-level Type 1 driver interface (specification). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef T1DRIVER_H +#define T1DRIVER_H + +#include + + FT_EXPORT_VAR( const FT_Driver_Class ) t1_driver_class; + + +#endif /* T1DRIVER_H */ + + +/* END */ diff --git a/src/freetype/type1/t1gload.c b/src/freetype/type1/t1gload.c new file mode 100644 index 0000000000..37cfc8c5d7 --- /dev/null +++ b/src/freetype/type1/t1gload.c @@ -0,0 +1,1823 @@ +/***************************************************************************/ +/* */ +/* t1gload.c */ +/* */ +/* Type 1 Glyph Loader (body). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifdef FT_FLAT_COMPILE + +#include "t1gload.h" + +#ifndef T1_CONFIG_OPTION_DISABLE_HINTER +#include "t1hinter.h" +#endif + +#else /* FT_FLAT_COMPILE */ + +#include + +#ifndef T1_CONFIG_OPTION_DISABLE_HINTER +#include +#endif + +#endif /* FT_FLAT_COMPILE */ + + +#include +#include +#include + +#include /* for strcmp() */ + + + /*************************************************************************/ + /* */ + /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ + /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ + /* messages during execution. */ + /* */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_t1gload + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /********** *********/ + /********** *********/ + /********** GENERIC CHARSTRING PARSING *********/ + /********** *********/ + /********** *********/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + static + void T1_Reset_Builder( T1_Builder* builder, + FT_Bool reset_base ) + { + builder->pos_x = 0; + builder->pos_y = 0; + + builder->left_bearing.x = 0; + builder->left_bearing.y = 0; + builder->advance.x = 0; + builder->advance.y = 0; + + builder->pass = 0; + builder->hint_point = 0; + + if ( builder->loader ) + { + if ( reset_base ) + FT_GlyphLoader_Rewind( builder->loader ); + + FT_GlyphLoader_Prepare( builder->loader ); + } + } + + + /*************************************************************************/ + /* */ + /* */ + /* T1_Init_Builder */ + /* */ + /* */ + /* Initializes a given glyph builder. */ + /* */ + /* */ + /* builder :: A pointer to the glyph builder to initialize. */ + /* */ + /* */ + /* face :: The current face object. */ + /* */ + /* size :: The current size object. */ + /* */ + /* glyph :: The current glyph object. */ + /* */ + /* funcs :: Glyph builder functions (or `methods'). */ + /* */ + LOCAL_FUNC + void T1_Init_Builder( T1_Builder* builder, + T1_Face face, + T1_Size size, + T1_GlyphSlot glyph, + const T1_Builder_Funcs* funcs ) + { + builder->funcs = *funcs; + builder->path_begun = 0; + builder->load_points = 1; + + builder->face = face; + builder->size = size; + builder->glyph = glyph; + builder->memory = face->root.memory; + + if ( glyph ) + { + FT_GlyphLoader* loader = FT_SLOT( glyph )->loader; + + + builder->loader = loader; + builder->base = &loader->base.outline; + builder->current = &loader->current.outline; + } + + if ( size ) + { + builder->scale_x = size->root.metrics.x_scale; + builder->scale_y = size->root.metrics.y_scale; + } + + T1_Reset_Builder( builder, 1 ); + } + + + /*************************************************************************/ + /* */ + /* */ + /* T1_Done_Builder */ + /* */ + /* */ + /* Finalizes a given glyph builder. Its contents can still be used */ + /* after the call, but the function saves important information */ + /* within the corresponding glyph slot. */ + /* */ + /* */ + /* builder :: A pointer to the glyph builder to finalize. */ + /* */ + LOCAL_FUNC + void T1_Done_Builder( T1_Builder* builder ) + { + T1_GlyphSlot glyph = builder->glyph; + + + if ( glyph ) + glyph->root.outline = *builder->base; + } + + + /*************************************************************************/ + /* */ + /* */ + /* T1_Init_Decoder */ + /* */ + /* */ + /* Initializes a given glyph decoder. */ + /* */ + /* */ + /* decoder :: A pointer to the glyph builder to initialize. */ + /* */ + /* */ + /* funcs :: The hinting functions interface. */ + /* */ + LOCAL_FUNC + void T1_Init_Decoder( T1_Decoder* decoder, + const T1_Hinter_Funcs* funcs ) + { + decoder->hinter = *funcs; /* copy hinter interface */ + decoder->top = 0; + decoder->zone = 0; + + decoder->flex_state = 0; + decoder->num_flex_vectors = 0; + + /* Clear loader */ + MEM_Set( &decoder->builder, 0, sizeof ( decoder->builder ) ); + } + + + /*************************************************************************/ + /* */ + /* */ + /* lookup_glyph_by_stdcharcode */ + /* */ + /* */ + /* Looks up a given glyph by its StandardEncoding charcode. Used */ + /* to implement the SEAC Type 1 operator. */ + /* */ + /* */ + /* face :: The current face object. */ + /* */ + /* charcode :: The character code to look for. */ + /* */ + /* */ + /* A glyph index in the font face. Returns -1 if the corresponding */ + /* glyph wasn't found. */ + /* */ + static + FT_Int lookup_glyph_by_stdcharcode( T1_Face face, + FT_Int charcode ) + { + FT_Int n; + const FT_String* glyph_name; + PSNames_Interface* psnames = (PSNames_Interface*)face->psnames; + + + /* check range of standard char code */ + if ( charcode < 0 || charcode > 255 ) + return -1; + + glyph_name = psnames->adobe_std_strings( + psnames->adobe_std_encoding[charcode] ); + + for ( n = 0; n < face->type1.num_glyphs; n++ ) + { + FT_String* name = (FT_String*)face->type1.glyph_names[n]; + + + if ( name && strcmp( name, glyph_name ) == 0 ) + return n; + } + + return -1; + } + + + /*************************************************************************/ + /* */ + /* */ + /* t1operator_seac */ + /* */ + /* */ + /* Implements the `seac' Type 1 operator for a Type 1 decoder. */ + /* */ + /* */ + /* decoder :: The current CID decoder. */ + /* */ + /* asb :: The accent's side bearing. */ + /* */ + /* adx :: The horizontal offset of the accent. */ + /* */ + /* ady :: The vertical offset of the accent. */ + /* */ + /* bchar :: The base character's StandardEncoding charcode. */ + /* */ + /* achar :: The accent character's StandardEncoding charcode. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + static + FT_Error t1operator_seac( T1_Decoder* decoder, + FT_Pos asb, + FT_Pos adx, + FT_Pos ady, + FT_Int bchar, + FT_Int achar ) + { + FT_Error error; + FT_Int bchar_index, achar_index, n_base_points; + FT_Outline* base = decoder->builder.base; + FT_Vector left_bearing, advance; + T1_Face face = decoder->builder.face; + T1_Font* type1 = &face->type1; + + + bchar_index = lookup_glyph_by_stdcharcode( face, bchar ); + achar_index = lookup_glyph_by_stdcharcode( face, achar ); + + if ( bchar_index < 0 || achar_index < 0 ) + { + FT_ERROR(( "t1operator_seac:" )); + FT_ERROR(( " invalid seac character code arguments\n" )); + return T1_Err_Syntax_Error; + } + + /* if we are trying to load a composite glyph, do not load the */ + /* accent character and return the array of subglyphs. */ + if ( decoder->builder.no_recurse ) + { + FT_GlyphSlot glyph = (FT_GlyphSlot)decoder->builder.glyph; + FT_GlyphLoader* loader = glyph->loader; + FT_SubGlyph* subg; + + + /* reallocate subglyph array if necessary */ + error = FT_GlyphLoader_Check_Subglyphs( loader, 2 ); + if ( error ) + goto Exit; + + subg = loader->current.subglyphs; + + /* subglyph 0 = base character */ + subg->index = bchar_index; + subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES | + FT_SUBGLYPH_FLAG_USE_MY_METRICS; + subg->arg1 = 0; + subg->arg2 = 0; + subg++; + + /* subglyph 1 = accent character */ + subg->index = achar_index; + subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES; + subg->arg1 = adx - asb; + subg->arg2 = ady; + + /* set up remaining glyph fields */ + glyph->num_subglyphs = 2; + glyph->subglyphs = loader->current.subglyphs; + glyph->format = ft_glyph_format_composite; + + loader->current.num_subglyphs = 2; + goto Exit; + } + + /* First load `bchar' in builder */ + /* now load the unscaled outline */ + + if ( decoder->builder.loader ) + FT_GlyphLoader_Prepare( decoder->builder.loader ); /* prepare loader */ + + error = T1_Parse_CharStrings( decoder, + type1->charstrings [bchar_index], + type1->charstrings_len[bchar_index], + type1->num_subrs, + type1->subrs, + type1->subrs_len ); + if ( error ) + goto Exit; + + n_base_points = base->n_points; + + /* save the left bearing and width of the base character */ + /* as they will be erased by the next load. */ + + left_bearing = decoder->builder.left_bearing; + advance = decoder->builder.advance; + + decoder->builder.left_bearing.x = 0; + decoder->builder.left_bearing.y = 0; + + /* Now load `achar' on top of the base outline */ + error = T1_Parse_CharStrings( decoder, + type1->charstrings [achar_index], + type1->charstrings_len[achar_index], + type1->num_subrs, + type1->subrs, + type1->subrs_len ); + if ( error ) + return error; + + /* restore the left side bearing and */ + /* advance width of the base character */ + + decoder->builder.left_bearing = left_bearing; + decoder->builder.advance = advance; + + /* Finally, move the accent */ + if ( decoder->builder.load_points ) + { + FT_Outline dummy; + + + dummy.n_points = base->n_points - n_base_points; + dummy.points = base->points + n_base_points; + + FT_Outline_Translate( &dummy, adx - asb, ady ); + } + + Exit: + return error; + } + + + /*************************************************************************/ + /* */ + /* */ + /* t1operator_flex */ + /* */ + /* */ + /* Implements the `flex' Type 1 operator for a Type 1 decoder. */ + /* */ + /* */ + /* decoder :: The current Type 1 decoder. */ + /* threshold :: The threshold. */ + /* end_x :: The horizontal position of the final flex point. */ + /* end_y :: The vertical position of the final flex point. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + static + FT_Error t1operator_flex( T1_Decoder* decoder, + FT_Pos threshold, + FT_Pos end_x, + FT_Pos end_y ) + { + FT_Vector vec; + FT_Vector* flex = decoder->flex_vectors; + FT_Int n; + + FT_UNUSED( threshold ); + FT_UNUSED( end_x ); + FT_UNUSED( end_y ); + + + /* we don't even try to test the threshold in the non-hinting */ + /* builder, even if the flex operator is said to be a path */ + /* construction statement in the specification. This is better */ + /* left to the hinter. */ + + flex = decoder->flex_vectors; + vec = *flex++; + + for ( n = 0; n < 6; n++ ) + { + flex->x += vec.x; + flex->y += vec.y; + + vec = *flex++; + } + + flex = decoder->flex_vectors; + + return decoder->builder.funcs.rcurve_to( &decoder->builder, + flex[0].x, flex[0].y, + flex[1].x, flex[1].y, + flex[2].x, flex[2].y ) || + + decoder->builder.funcs.rcurve_to( &decoder->builder, + flex[3].x, flex[3].y, + flex[4].x, flex[4].y, + flex[5].x, flex[5].y ); + } + + + /*************************************************************************/ + /* */ + /* */ + /* T1_Parse_CharStrings */ + /* */ + /* */ + /* Parses a given Type 1 charstrings program. */ + /* */ + /* */ + /* decoder :: The current Type 1 decoder. */ + /* */ + /* charstring_base :: The base address of the charstring stream. */ + /* */ + /* charstring_len :: The length in bytes of the charstring stream. */ + /* */ + /* num_subrs :: The number of sub-routines. */ + /* */ + /* subrs_base :: An array of sub-routines addresses. */ + /* */ + /* subrs_len :: An array of sub-routines lengths. */ + /* */ + /* */ + /* Free error code. 0 means success. */ + /* */ + LOCAL_FUNC + FT_Error T1_Parse_CharStrings( T1_Decoder* decoder, + FT_Byte* charstring_base, + FT_Int charstring_len, + FT_Int num_subrs, + FT_Byte** subrs_base, + FT_Int* subrs_len ) + { + FT_Error error; + T1_Decoder_Zone* zone; + FT_Byte* ip; + FT_Byte* limit; + T1_Builder* builder = &decoder->builder; + T1_Builder_Funcs* builds = &builder->funcs; + T1_Hinter_Funcs* hints = &decoder->hinter; + + static + const FT_Int args_count[op_max] = + { + 0, /* none */ + 0, /* endchar */ + 2, /* hsbw */ + 5, /* seac */ + 4, /* sbw */ + 0, /* closepath */ + 1, /* hlineto */ + 1, /* hmoveto */ + 4, /* hvcurveto */ + 2, /* rlineto */ + 2, /* rmoveto */ + 6, /* rrcurveto */ + 4, /* vhcurveto */ + 1, /* vlineto */ + 1, /* vmoveto */ + 0, /* dotsection */ + 2, /* hstem */ + 6, /* hstem3 */ + 2, /* vstem */ + 6, /* vstem3 */ + 2, /* div */ + -1, /* callothersubr */ + 1, /* callsubr */ + 0, /* pop */ + 0, /* return */ + 2 /* setcurrentpoint */ + }; + + + /* First of all, initialize the decoder */ + decoder->top = decoder->stack; + decoder->zone = decoder->zones; + zone = decoder->zones; + + builder->path_begun = 0; + + zone->base = charstring_base; + limit = zone->limit = charstring_base + charstring_len; + ip = zone->cursor = zone->base; + + error = T1_Err_Ok; + + /* now, execute loop */ + while ( ip < limit ) + { + FT_Int* top = decoder->top; + T1_Operator op = op_none; + FT_Long value = 0; + + + /* Start with the decompression of operator or value */ + switch ( *ip++ ) + { + case 1: + op = op_hstem; + break; + + case 3: + op = op_vstem; + break; + case 4: + op = op_vmoveto; + break; + case 5: + op = op_rlineto; + break; + case 6: + op = op_hlineto; + break; + case 7: + op = op_vlineto; + break; + case 8: + op = op_rrcurveto; + break; + case 9: + op = op_closepath; + break; + case 10: + op = op_callsubr; + break; + case 11: + op = op_return; + break; + + case 13: + op = op_hsbw; + break; + case 14: + op = op_endchar; + break; + + case 21: + op = op_rmoveto; + break; + case 22: + op = op_hmoveto; + break; + + case 30: + op = op_vhcurveto; + break; + case 31: + op = op_hvcurveto; + break; + + case 12: + if ( ip > limit ) + { + FT_ERROR(( "T1_Parse_CharStrings: invalid escape (12+EOF)\n" )); + goto Syntax_Error; + } + + switch ( *ip++ ) + { + case 0: + op = op_dotsection; + break; + case 1: + op = op_vstem3; + break; + case 2: + op = op_hstem3; + break; + case 6: + op = op_seac; + break; + case 7: + op = op_sbw; + break; + case 12: + op = op_div; + break; + case 16: + op = op_callothersubr; + break; + case 17: + op = op_pop; + break; + case 33: + op = op_setcurrentpoint; + break; + + default: + FT_ERROR(( "T1_Parse_CharStrings: invalid escape (12+%d)\n", + ip[-1] )); + goto Syntax_Error; + } + break; + + case 255: /* four bytes integer */ + if ( ip + 4 > limit ) + { + FT_ERROR(( "T1_Parse_CharStrings: unexpected EOF in integer\n" )); + goto Syntax_Error; + } + + value = ( (FT_Long)ip[0] << 24 ) | + ( (FT_Long)ip[1] << 16 ) | + ( (FT_Long)ip[2] << 8 ) | + ip[3]; + ip += 4; + break; + + default: + if ( ip[-1] >= 32 ) + { + if ( ip[-1] < 247 ) + value = (FT_Long)ip[-1] - 139; + else + { + if ( ++ip > limit ) + { + FT_ERROR(( "T1_Parse_CharStrings:" )); + FT_ERROR(( " unexpected EOF in integer\n" )); + goto Syntax_Error; + } + + if ( ip[-2] < 251 ) + value = ((FT_Long)( ip[-2] - 247 ) << 8 ) + ip[-1] + 108; + else + value = -( ( ( (FT_Long)ip[-2] - 251 ) << 8 ) + ip[-1] + 108 ); + } + } + else + { + FT_ERROR(( "T1_Parse_CharStrings: invalid byte (%d)\n", + ip[-1] )); + goto Syntax_Error; + } + } + + /* push value if necessary */ + if ( op == op_none ) + { + if ( top - decoder->stack >= T1_MAX_CHARSTRINGS_OPERANDS ) + { + FT_ERROR(( "T1_Parse_CharStrings: stack overflow!\n" )); + goto Syntax_Error; + } + + *top++ = value; + decoder->top = top; + } + + else if ( op == op_callothersubr ) /* check arguments differently */ + { + if ( top - decoder->stack < 2 ) + goto Stack_Underflow; + + top -= 2; + + switch ( top[1] ) + { + case 1: /* start flex feature */ + if ( top[0] != 0 ) + goto Unexpected_OtherSubr; + + decoder->flex_state = 1; + decoder->num_flex_vectors = 0; + decoder->flex_vectors[0].x = 0; + decoder->flex_vectors[0].y = 0; + break; + + case 2: /* add flex vector */ + { + FT_Int index; + FT_Vector* flex; + + + if ( top[0] != 0 ) + goto Unexpected_OtherSubr; + + top -= 2; + if ( top < decoder->stack ) + goto Stack_Underflow; + + index = decoder->num_flex_vectors++; + if ( index >= 7 ) + { + FT_ERROR(( "T1_Parse_CharStrings: too many flex vectors!\n" )); + goto Syntax_Error; + } + + flex = decoder->flex_vectors + index; + flex->x += top[0]; + flex->y += top[1]; + } + break; + + case 0: /* end flex feature */ + if ( decoder->flex_state == 0 || + decoder->num_flex_vectors != 7 ) + { + FT_ERROR(( "T1_Parse_CharStrings: unexpected flex end\n" )); + goto Syntax_Error; + } + + if ( top[0] != 3 ) + goto Unexpected_OtherSubr; + + top -= 3; + if ( top < decoder->stack ) + goto Stack_Underflow; + + /* now consume the remaining `pop pop setcurrentpoint' */ + if ( ip + 6 > limit || + ip[0] != 12 || ip[1] != 17 || /* pop */ + ip[2] != 12 || ip[3] != 17 || /* pop */ + ip[4] != 12 || ip[5] != 33 ) /* setcurrentpoint */ + { + FT_ERROR(( "T1_Parse_CharStrings: invalid flex charstring\n" )); + goto Syntax_Error; + } + + decoder->flex_state = 0; + decoder->top = top; + + error = t1operator_flex( decoder, top[0], top[1], top[2] ); + break; + + case 3: /* change hints */ + if ( top[0] != 1 ) + goto Unexpected_OtherSubr; + + /* eat the following `pop' */ + if ( ip + 2 > limit ) + { + FT_ERROR(( "T1_Parse_CharStrings: invalid escape (12+%d)\n", + ip[-1] )); + goto Syntax_Error; + } + + if ( ip[0] != 12 || ip[1] != 17 ) + { + FT_ERROR(( "T1_Parse_CharStrings:" )); + FT_ERROR(( " `pop' expected, found (%d %d)\n", ip[0], ip[1] )); + goto Syntax_Error; + } + + ip += 2; + + error = hints->change_hints( builder ); + break; + + default: + /* invalid OtherSubrs call */ + Unexpected_OtherSubr: + FT_ERROR(( "T1_Parse_CharStrings: unexpected OtherSubrs [%d %d]\n", + top[0], top[1] )); + goto Syntax_Error; + } + decoder->top = top; + } + else + { + FT_Int num_args = args_count[op]; + + + if ( top - decoder->stack < num_args ) + goto Stack_Underflow; + + top -= num_args; + + switch ( op ) + { + case op_endchar: + error = builds->end_char( builder ); + break; + + case op_hsbw: + error = builds->set_bearing_point( builder, top[0], 0, + top[1], 0 ); + break; + + case op_seac: + /* return immediately after the processing */ + return t1operator_seac( decoder, top[0], top[1], + top[2], top[3], top[4] ); + + case op_sbw: + error = builds->set_bearing_point( builder, top[0], top[1], + top[2], top[3] ); + break; + + case op_closepath: + error = builds->close_path( builder ); + break; + + case op_hlineto: + error = builds->rline_to( builder, top[0], 0 ); + break; + + case op_hmoveto: + error = builds->rmove_to( builder, top[0], 0 ); + break; + + case op_hvcurveto: + error = builds->rcurve_to( builder, top[0], 0, + top[1], top[2], + 0, top[3] ); + break; + + case op_rlineto: + error = builds->rline_to( builder, top[0], top[1] ); + break; + + case op_rmoveto: + /* ignore operator when in flex mode */ + if ( decoder->flex_state == 0 ) + error = builds->rmove_to( builder, top[0], top[1] ); + else + top += 2; + break; + + case op_rrcurveto: + error = builds->rcurve_to( builder, top[0], top[1], + top[2], top[3], + top[4], top[5] ); + break; + + case op_vhcurveto: + error = builds->rcurve_to( builder, 0, top[0], + top[1], top[2], + top[3], 0 ); + break; + + case op_vlineto: + error = builds->rline_to( builder, 0, top[0] ); + break; + + case op_vmoveto: + error = builds->rmove_to( builder, 0, top[0] ); + break; + + case op_dotsection: + error = hints->dot_section( builder ); + break; + + case op_hstem: + error = hints->stem( builder, top[0], top[1], 0 ); + break; + + case op_hstem3: + error = hints->stem3( builder, top[0], top[1], top[2], + top[3], top[4], top[5], 0 ); + break; + + case op_vstem: + error = hints->stem( builder, top[0], top[1], 1 ); + break; + + case op_vstem3: + error = hints->stem3( builder, top[0], top[1], top[2], + top[3], top[4], top[5], 1 ); + break; + + case op_div: + if ( top[1] ) + { + *top = top[0] / top[1]; + ++top; + } + else + { + FT_ERROR(( "T1_Parse_CHarStrings: division by 0\n" )); + goto Syntax_Error; + } + break; + + case op_callsubr: + { + FT_Int index = top[0]; + + + if ( index < 0 || index >= num_subrs ) + { + FT_ERROR(( "T1_Parse_CharStrings: invalid subrs index\n" )); + goto Syntax_Error; + } + + if ( zone - decoder->zones >= T1_MAX_SUBRS_CALLS ) + { + FT_ERROR(( "T1_Parse_CharStrings: too many nested subrs\n" )); + goto Syntax_Error; + } + + zone->cursor = ip; /* save current instruction pointer */ + + zone++; + zone->base = subrs_base[index]; + zone->limit = zone->base + subrs_len[index]; + zone->cursor = zone->base; + + if ( !zone->base ) + { + FT_ERROR(( "T1_Parse_CharStrings: invoking empty subrs!\n" )); + goto Syntax_Error; + } + + decoder->zone = zone; + ip = zone->base; + limit = zone->limit; + } + break; + + case op_pop: + FT_ERROR(( "T1_Parse_CharStrings: unexpected POP\n" )); + goto Syntax_Error; + + case op_return: + if ( zone <= decoder->zones ) + { + FT_ERROR(( "T1_Parse_CharStrings: unexpected return\n" )); + goto Syntax_Error; + } + + zone--; + ip = zone->cursor; + limit = zone->limit; + decoder->zone = zone; + break; + + case op_setcurrentpoint: + FT_ERROR(( "T1_Parse_CharStrings:" )); + FT_ERROR(( " unexpected `setcurrentpoint'\n" )); + goto Syntax_Error; + break; + + default: + FT_ERROR(( "T1_Parse_CharStrings: unhandled opcode %d\n", op )); + goto Syntax_Error; + } + + decoder->top = top; + } + } + + return error; + + Syntax_Error: + return T1_Err_Syntax_Error; + + Stack_Underflow: + return T1_Err_Stack_Underflow; + } + + + /*************************************************************************/ + /* */ + /* */ + /* T1_Add_Points */ + /* */ + /* */ + /* Checks that there is enough room in the current load glyph outline */ + /* to accept `num_points' additional outline points. If not, this */ + /* function grows the load outline's arrays accordingly. */ + /* */ + /* */ + /* builder :: A pointer to the glyph builder object. */ + /* */ + /* num_points :: The number of points that will be added later. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* This function does NOT update the points count in the glyph */ + /* builder. This must be done by the caller itself, after this */ + /* function has been invoked. */ + /* */ + LOCAL_FUNC + FT_Error T1_Add_Points( T1_Builder* builder, + FT_Int num_points ) + { + return FT_GlyphLoader_Check_Points( builder->loader, num_points, 0 ); + } + + + /*************************************************************************/ + /* */ + /* */ + /* T1_Add_Contours */ + /* */ + /* */ + /* Checks that there is enough room in the current load glyph outline */ + /* to accept `num_contours' additional contours. If not, this */ + /* function grows the load outline's arrays accordingly. */ + /* */ + /* */ + /* builder :: A pointer to the glyph builder object. */ + /* */ + /* num_contours :: The number of contours that will be added later. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* This function does NOT update the contours count in the load glyph */ + /* This must be done by the caller itself, after this function is */ + /* invoked. */ + /* */ + LOCAL_FUNC + FT_Error T1_Add_Contours( T1_Builder* builder, + FT_Int num_contours ) + { + return FT_GlyphLoader_Check_Points( builder->loader, 0, num_contours ); + } + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /********** *********/ + /********** COMPUTE THE MAXIMUM ADVANCE WIDTH *********/ + /********** *********/ + /********** The following code is in charge of computing *********/ + /********** the maximum advance width of the font. It *********/ + /********** quickly processes each glyph charstring to *********/ + /********** extract the value from either a `sbw' or `seac' *********/ + /********** operator. *********/ + /********** *********/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + static + FT_Error maxadv_sbw( T1_Decoder* decoder, + FT_Pos sbx, + FT_Pos sby, + FT_Pos wx, + FT_Pos wy ) + { + FT_UNUSED( sbx ); + FT_UNUSED( sby ); + FT_UNUSED( wy ); + + if ( wx > decoder->builder.advance.x ) + decoder->builder.advance.x = wx; + + return -1; /* return an error code to exit the Type 1 parser */ + /* immediately. */ + } + + + static + FT_Int maxadv_error( void ) + { + /* we should never reach this code, unless with a buggy font */ + return -2; + } + + + /* the maxadv_gbuilder_interface is used when computing the maximum */ + /* advance width of all glyphs in a given font. We only process the */ + /* `sbw' operator here, and return an error for all others. */ + + /* Note that `seac' is processed by the T1_Decoder. */ + static + const T1_Builder_Funcs maxadv_builder_interface = + { + (T1_Builder_EndChar) maxadv_error, + (T1_Builder_Sbw) maxadv_sbw, + (T1_Builder_ClosePath)maxadv_error, + (T1_Builder_RLineTo) maxadv_error, + (T1_Builder_RMoveTo) maxadv_error, + (T1_Builder_RCurveTo) maxadv_error + }; + + + /* the maxadv_hinter_interface always return an error. */ + static + const T1_Hinter_Funcs maxadv_hinter_interface = + { + (T1_Hinter_DotSection) maxadv_error, + (T1_Hinter_ChangeHints)maxadv_error, + (T1_Hinter_Stem) maxadv_error, + (T1_Hinter_Stem3) maxadv_error, + }; + + + LOCAL_FUNC + FT_Error T1_Compute_Max_Advance( T1_Face face, + FT_Int* max_advance ) + { + FT_Error error; + T1_Decoder decoder; + FT_Int glyph_index; + T1_Font* type1 = &face->type1; + + + *max_advance = 0; + + /* Initialize load decoder */ + T1_Init_Decoder( &decoder, &maxadv_hinter_interface ); + + T1_Init_Builder( &decoder.builder, face, 0, 0, + &maxadv_builder_interface ); + + /* For each glyph, parse the glyph charstring and extract */ + /* the advance width. */ + for ( glyph_index = 0; glyph_index < type1->num_glyphs; glyph_index++ ) + { + /* now get load the unscaled outline */ + error = T1_Parse_CharStrings( &decoder, + type1->charstrings [glyph_index], + type1->charstrings_len[glyph_index], + type1->num_subrs, + type1->subrs, + type1->subrs_len ); + /* ignore the error if one occured - skip to next glyph */ + } + + *max_advance = decoder.builder.advance.x; + return T1_Err_Ok; + } + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /********** *********/ + /********** UNHINTED GLYPH LOADER *********/ + /********** *********/ + /********** The following code is in charge of loading a *********/ + /********** single outline. It completely ignores hinting *********/ + /********** and is used when FT_LOAD_NO_HINTING is set. *********/ + /********** *********/ + /********** The Type 1 hinter is located in `t1hint.c' *********/ + /********** *********/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + static + FT_Error close_open_path( T1_Builder* builder ) + { + FT_Error error; + FT_Outline* cur = builder->current; + FT_Int num_points; + FT_Int first_point; + + + /* Some fonts, like Hershey, are made of `open paths' which are */ + /* now managed directly by FreeType. In this case, it is necessary */ + /* to close the path by duplicating its points in reverse order, */ + /* which is precisely the purpose of this function. */ + + /* first compute the number of points to duplicate */ + if ( cur->n_contours > 1 ) + first_point = cur->contours[cur->n_contours - 2] + 1; + else + first_point = 0; + + num_points = cur->n_points - first_point - 2; + if ( num_points > 0 ) + { + FT_Vector* source_point; + char* source_tags; + FT_Vector* point; + char* tags; + + + error = T1_Add_Points( builder, num_points ); + if ( error ) + return error; + + point = cur->points + cur->n_points; + tags = cur->tags + cur->n_points; + + source_point = point - 2; + source_tags = tags - 2; + + cur->n_points += num_points; + + if ( builder->load_points ) + do + { + *point++ = *source_point--; + *tags++ = *source_tags--; + num_points--; + + } while ( num_points > 0 ); + } + + builder->path_begun = 0; + return T1_Err_Ok; + } + + + static + FT_Error gload_closepath( T1_Builder* builder ) + { + FT_Outline* cur = builder->current; + + + /* XXXX: We must not include the last point in the path if it */ + /* is located on the first point. */ + if ( cur->n_points > 1 ) + { + FT_Int first = 0; + FT_Vector* p1 = cur->points + first; + FT_Vector* p2 = cur->points + cur->n_points - 1; + + + if ( cur->n_contours > 1 ) + { + first = cur->contours[cur->n_contours - 2] + 1; + p1 = cur->points + first; + } + + if ( p1->x == p2->x && p1->y == p2->y ) + cur->n_points--; + } + + /* save current contour, if any */ + if ( cur->n_contours > 0 ) + cur->contours[cur->n_contours - 1] = cur->n_points - 1; + +#ifndef T1_CONFIG_OPTION_DISABLE_HINTER + /* hint last points if necessary -- this is not strictly required */ + /* there, but it helps for debugging, and doesn't affect performance */ + if ( builder->pass == 1 ) + T1_Hint_Points( builder ); +#endif + + builder->path_begun = 0; + return T1_Err_Ok; + } + + + static + FT_Error gload_endchar( T1_Builder* builder ) + { + FT_Error error; + + + /* close path if needed */ + if ( builder->path_begun ) + { + error = close_open_path( builder ); + if ( error ) + return error; + } + + error = gload_closepath( builder ); + + FT_GlyphLoader_Add( builder->loader ); + + return error; + } + + + static + FT_Error gload_sbw( T1_Builder* builder, + FT_Pos sbx, + FT_Pos sby, + FT_Pos wx, + FT_Pos wy ) + { + builder->left_bearing.x += sbx; + builder->left_bearing.y += sby; + builder->advance.x = wx; + builder->advance.y = wy; + + builder->last.x = sbx; + builder->last.y = sby; + + return 0; + } + + + static + FT_Error gload_rlineto( T1_Builder* builder, + FT_Pos dx, + FT_Pos dy ) + { + FT_Error error; + FT_Outline* cur = builder->current; + FT_Vector vec; + + + /* grow buffer if necessary */ + error = T1_Add_Points( builder, 1 ); + if ( error ) + return error; + + if ( builder->load_points ) + { + /* save point */ + vec.x = builder->last.x + dx; + vec.y = builder->last.y + dy; + + cur->points[cur->n_points] = vec; + cur->tags [cur->n_points] = FT_Curve_Tag_On; + + builder->last = vec; + } + cur->n_points++; + + builder->path_begun = 1; + + return T1_Err_Ok; + } + + + static + FT_Error gload_rmoveto( T1_Builder* builder, + FT_Pos dx, + FT_Pos dy ) + { + FT_Error error; + FT_Outline* cur = builder->current; + FT_Vector vec; + + + /* in the case where `path_begun' is set, we have an `rmoveto' */ + /* after some normal path definition. If the face's paint type */ + /* is set to 1, this means that we have an `open path', also */ + /* called a `stroke'. The FreeType raster doesn't support */ + /* opened paths, so we'll close it explicitely there. */ + + if ( builder->path_begun && builder->face->type1.paint_type == 1 ) + { + if ( builder->face->type1.paint_type == 1 ) + { + error = close_open_path( builder ); + if ( error ) + return error; + } + } + + /* grow buffer if necessary */ + error = T1_Add_Contours( builder, 1 ) || + T1_Add_Points ( builder, 1 ); + if ( error ) + return error; + + /* save current contour, if any */ + if ( cur->n_contours > 0 ) + cur->contours[cur->n_contours - 1] = cur->n_points - 1; + + if ( builder->load_points ) + { + /* save point */ + vec.x = builder->last.x + dx; + vec.y = builder->last.y + dy; + cur->points[cur->n_points] = vec; + cur->tags [cur->n_points] = FT_Curve_Tag_On; + + builder->last = vec; + } + + cur->n_contours++; + cur->n_points++; + + return T1_Err_Ok; + } + + + static + FT_Error gload_rrcurveto( T1_Builder* builder, + FT_Pos dx1, + FT_Pos dy1, + FT_Pos dx2, + FT_Pos dy2, + FT_Pos dx3, + FT_Pos dy3 ) + { + FT_Error error; + FT_Outline* cur = builder->current; + FT_Vector vec; + FT_Vector* points; + char* tags; + + + /* grow buffer if necessary */ + error = T1_Add_Points( builder, 3 ); + if ( error ) + return error; + + if ( builder->load_points ) + { + /* save point */ + points = cur->points + cur->n_points; + tags = cur->tags + cur->n_points; + + vec.x = builder->last.x + dx1; + vec.y = builder->last.y + dy1; + points[0] = vec; + tags[0] = FT_Curve_Tag_Cubic; + + vec.x += dx2; + vec.y += dy2; + points[1] = vec; + tags[1] = FT_Curve_Tag_Cubic; + + vec.x += dx3; + vec.y += dy3; + points[2] = vec; + tags[2] = FT_Curve_Tag_On; + + builder->last = vec; + } + + cur->n_points += 3; + builder->path_begun = 1; + + return T1_Err_Ok; + } + + + static + FT_Error gload_ignore( void ) + { + return 0; + } + + + static + const T1_Builder_Funcs gload_builder_interface = + { + gload_endchar, + gload_sbw, + gload_closepath, + gload_rlineto, + gload_rmoveto, + gload_rrcurveto + }; + + + static + const T1_Builder_Funcs gload_builder_interface_null = + { + (T1_Builder_EndChar) gload_ignore, + (T1_Builder_Sbw) gload_sbw, /* record left bearing */ + (T1_Builder_ClosePath)gload_ignore, + (T1_Builder_RLineTo) gload_ignore, + (T1_Builder_RMoveTo) gload_ignore, + (T1_Builder_RCurveTo) gload_ignore + }; + + + static + const T1_Hinter_Funcs gload_hinter_interface = + { + (T1_Hinter_DotSection) gload_ignore, /* dotsection */ + (T1_Hinter_ChangeHints)gload_ignore, /* changehints */ + (T1_Hinter_Stem) gload_ignore, /* hstem & vstem */ + (T1_Hinter_Stem3) gload_ignore, /* hstem3 & vestem3 */ + }; + + +#ifndef T1_CONFIG_OPTION_DISABLE_HINTER + + + /*************************************************************************/ + /* */ + /* Hinter overview: */ + /* */ + /* This is a two-pass hinter. On the first pass, the hints are all */ + /* recorded by the hinter, and no point is loaded in the outline. */ + /* */ + /* When the first pass is finished, all stems hints are grid-fitted */ + /* at once. */ + /* */ + /* Then, a second pass is performed to load the outline points as */ + /* well as hint/scale them correctly. */ + /* */ + /*************************************************************************/ + + + static + FT_Error t1_load_hinted_glyph( T1_Decoder* decoder, + FT_UInt glyph_index, + FT_Bool recurse ) + { + T1_Builder* builder = &decoder->builder; + T1_GlyphSlot glyph = builder->glyph; + T1_Font* type1 = &builder->face->type1; + FT_UInt old_points, old_contours; + FT_GlyphLoader* loader = decoder->builder.loader; + FT_Error error; + + + /* Pass 1 -- try to load first glyph, simply recording points */ + old_points = loader->base.outline.n_points; + old_contours = loader->base.outline.n_contours; + + FT_GlyphLoader_Prepare( decoder->builder.loader ); + + T1_Reset_Builder( builder, 0 ); + + builder->no_recurse = recurse; + builder->pass = 0; + glyph->hints->hori_stems.num_stems = 0; + glyph->hints->vert_stems.num_stems = 0; + + error = T1_Parse_CharStrings( decoder, + type1->charstrings [glyph_index], + type1->charstrings_len[glyph_index], + type1->num_subrs, + type1->subrs, + type1->subrs_len ); + if ( error ) + goto Exit; + + /* check for composite (i.e. `seac' operator) */ + if ( glyph->root.format == ft_glyph_format_composite ) + { + /* this is a composite glyph, we must then load the first one, */ + /* then load the second one on top of it and translate it by a */ + /* fixed amount. */ + FT_UInt n_base_points; + FT_SubGlyph* subglyph = loader->base.subglyphs; + T1_Size size = builder->size; + FT_Pos dx, dy; + FT_Vector left_bearing, advance; + + + /* clean glyph format */ + glyph->root.format = ft_glyph_format_none; + + /* First load `bchar' in builder */ + builder->no_recurse = 0; + error = t1_load_hinted_glyph( decoder, subglyph->index, 0 ); + if ( error ) + goto Exit; + + /* save the left bearing and width of the base character */ + /* as they will be erased by the next load */ + left_bearing = builder->left_bearing; + advance = builder->advance; + + /* Then load `achar' in builder */ + n_base_points = builder->base->n_points; + subglyph++; + error = t1_load_hinted_glyph( decoder, subglyph->index, 0 ); + if ( error ) + goto Exit; + + /* Finally, move the accent */ + dx = FT_MulFix( subglyph->arg1, size->root.metrics.x_scale ); + dy = FT_MulFix( subglyph->arg2, size->root.metrics.y_scale ); + dx = ( dx + 32 ) & -64; + dy = ( dy + 32 ) & -64; + { + FT_Outline dummy; + + + dummy.n_points = loader->base.outline.n_points - n_base_points; + dummy.points = loader->base.outline.points + n_base_points; + + FT_Outline_Translate( &dummy, dx, dy ); + } + + /* restore the left side bearing and */ + /* advance width of the base character */ + builder->left_bearing = left_bearing; + builder->advance = advance; + } + else + { + /* All right, pass 1 is finished, now grid-fit all stem hints */ + T1_Hint_Stems( &decoder->builder ); + + /* undo the end-char */ + builder->base->n_points = old_points; + builder->base->n_contours = old_contours; + + /* Pass 2 -- record and scale/hint the points */ + T1_Reset_Builder( builder, 0 ); + + builder->pass = 1; + builder->no_recurse = 0; + + error = T1_Parse_CharStrings( decoder, + type1->charstrings [glyph_index], + type1->charstrings_len[glyph_index], + type1->num_subrs, + type1->subrs, + type1->subrs_len ); + } + + /* save new glyph tables */ + if ( recurse ) + T1_Done_Builder( builder ); + + Exit: + return error; + } + + +#endif /* !T1_CONFIG_OPTION_DISABLE_HINTER */ + + + LOCAL_FUNC + FT_Error T1_Load_Glyph( T1_GlyphSlot glyph, + T1_Size size, + FT_Int glyph_index, + FT_Int load_flags ) + { + FT_Error error; + T1_Decoder decoder; + T1_Face face = (T1_Face)glyph->root.face; + FT_Bool hinting; + T1_Font* type1 = &face->type1; + + + if ( load_flags & FT_LOAD_NO_RECURSE ) + load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING; + + glyph->x_scale = size->root.metrics.x_scale; + glyph->y_scale = size->root.metrics.y_scale; + + glyph->root.outline.n_points = 0; + glyph->root.outline.n_contours = 0; + + glyph->root.format = ft_glyph_format_outline; /* by default */ + + hinting = 0; + +#ifndef T1_CONFIG_OPTION_DISABLE_HINTER + + hinting = ( load_flags & ( FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING ) ) == 0; + + if ( hinting ) + { + T1_Init_Decoder( &decoder, &t1_hinter_funcs ); + T1_Init_Builder( &decoder.builder, face, size, glyph, + &gload_builder_interface ); + + error = t1_load_hinted_glyph( &decoder, glyph_index, 1 ); + } + else + +#endif /* !T1_CONFIG_OPTION_DISABLE_HINTER */ + + { + T1_Init_Decoder( &decoder, &gload_hinter_interface ); + + T1_Init_Builder( &decoder.builder, face, size, glyph, + &gload_builder_interface ); + + decoder.builder.no_recurse = ( load_flags & FT_LOAD_NO_RECURSE ) != 0; + + /* now load the unscaled outline */ + error = T1_Parse_CharStrings( &decoder, + type1->charstrings [glyph_index], + type1->charstrings_len[glyph_index], + type1->num_subrs, + type1->subrs, + type1->subrs_len ); + + /* save new glyph tables */ + T1_Done_Builder( &decoder.builder ); + } + + /* Now, set the metrics -- this is rather simple, as */ + /* the left side bearing is the xMin, and the top side */ + /* bearing the yMax */ + if ( !error ) + { + /* for composite glyphs, return only the left side bearing and the */ + /* advance width */ + if ( glyph->root.format == ft_glyph_format_composite ) + { + glyph->root.metrics.horiBearingX = decoder.builder.left_bearing.x; + glyph->root.metrics.horiAdvance = decoder.builder.advance.x; + } + else + { + FT_BBox cbox; + FT_Glyph_Metrics* metrics = &glyph->root.metrics; + + + /* apply the font matrix */ + FT_Outline_Transform( &glyph->root.outline, + &face->type1.font_matrix ); + + FT_Outline_Get_CBox( &glyph->root.outline, &cbox ); + + /* grid fit the bounding box if necessary */ + if ( hinting ) + { + cbox.xMin &= -64; + cbox.yMin &= -64; + cbox.xMax = ( cbox.xMax + 63 ) & -64; + cbox.yMax = ( cbox.yMax + 63 ) & -64; + } + + metrics->width = cbox.xMax - cbox.xMin; + metrics->height = cbox.yMax - cbox.yMin; + + metrics->horiBearingX = cbox.xMin; + metrics->horiBearingY = cbox.yMax; + + /* copy the _unscaled_ advance width */ + metrics->horiAdvance = decoder.builder.advance.x; + + /* make up vertical metrics */ + metrics->vertBearingX = 0; + metrics->vertBearingY = 0; + metrics->vertAdvance = 0; + + glyph->root.format = ft_glyph_format_outline; + + glyph->root.outline.flags = 0; + + if ( size->root.metrics.y_ppem < 24 ) + glyph->root.outline.flags |= ft_outline_high_precision; + + glyph->root.outline.flags |= ft_outline_reverse_fill; + + if ( hinting ) + { + /* adjust the advance width */ + /* XXX TODO: consider stem hints grid-fit */ + metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, + glyph->x_scale ); + } + else if ( ( load_flags & FT_LOAD_NO_SCALE ) == 0 ) + { + /* scale the outline and the metrics */ + FT_Int n; + FT_Outline* cur = decoder.builder.base; + FT_Vector* vec = cur->points; + FT_Fixed x_scale = glyph->x_scale; + FT_Fixed y_scale = glyph->y_scale; + + + /* First of all, scale the points */ + for ( n = cur->n_points; n > 0; n--, vec++ ) + { + vec->x = FT_MulFix( vec->x, x_scale ); + vec->y = FT_MulFix( vec->y, y_scale ); + } + + /* Then scale the metrics */ + metrics->width = FT_MulFix( metrics->width, x_scale ); + metrics->height = FT_MulFix( metrics->height, y_scale ); + + metrics->horiBearingX = FT_MulFix( metrics->horiBearingX, x_scale ); + metrics->horiBearingY = FT_MulFix( metrics->horiBearingY, y_scale ); + + metrics->vertBearingX = FT_MulFix( metrics->vertBearingX, x_scale ); + metrics->vertBearingY = FT_MulFix( metrics->vertBearingY, y_scale ); + + metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale ); + metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale ); + } + } + } + + return error; + } + + +/* END */ diff --git a/src/freetype/type1/t1gload.h b/src/freetype/type1/t1gload.h new file mode 100644 index 0000000000..658a929d06 --- /dev/null +++ b/src/freetype/type1/t1gload.h @@ -0,0 +1,326 @@ +/***************************************************************************/ +/* */ +/* t1gload.h */ +/* */ +/* Type 1 Glyph Loader (specification). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef T1GLOAD_H +#define T1GLOAD_H + + +#ifdef FT_FLAT_COMPILE + +#include "t1objs.h" + +#else + +#include + +#endif + + +#ifdef __cplusplus + extern "C" { +#endif + + + typedef struct T1_Builder_ T1_Builder; + + typedef FT_Error (*T1_Builder_EndChar)( T1_Builder* loader ); + + typedef FT_Error (*T1_Builder_Sbw)( T1_Builder* loader, + FT_Pos sbx, + FT_Pos sby, + FT_Pos wx, + FT_Pos wy ); + + typedef FT_Error (*T1_Builder_ClosePath)( T1_Builder* loader ); + + typedef FT_Error (*T1_Builder_RLineTo)( T1_Builder* loader, + FT_Pos dx, + FT_Pos dy ); + + typedef FT_Error (*T1_Builder_RMoveTo)( T1_Builder* loader, + FT_Pos dx, + FT_Pos dy ); + + typedef FT_Error (*T1_Builder_RCurveTo)( T1_Builder* loader, + FT_Pos dx1, + FT_Pos dy1, + FT_Pos dx2, + FT_Pos dy2, + FT_Pos dx3, + FT_Pos dy3 ); + + + /*************************************************************************/ + /* */ + /* */ + /* T1_Builder_Funcs */ + /* */ + /* */ + /* A structure to store the address of various functions used by a */ + /* glyph builder to implement the outline's `path construction'. */ + /* */ + typedef struct T1_Builder_Funcs_ + { + T1_Builder_EndChar end_char; + T1_Builder_Sbw set_bearing_point; + T1_Builder_ClosePath close_path; + T1_Builder_RLineTo rline_to; + T1_Builder_RMoveTo rmove_to; + T1_Builder_RCurveTo rcurve_to; + + } T1_Builder_Funcs; + + + /*************************************************************************/ + /* */ + /* */ + /* T1_Builder */ + /* */ + /* */ + /* A structure used during glyph loading to store its outline. */ + /* */ + /* */ + /* memory :: The current memory object. */ + /* */ + /* face :: The current face object. */ + /* */ + /* size :: The current size object. */ + /* */ + /* glyph :: The current glyph slot. */ + /* */ + /* loader :: The current glyph loader. */ + /* */ + /* current :: The current glyph outline. */ + /* */ + /* base :: The base glyph outline. */ + /* */ + /* last :: The last point position. */ + /* */ + /* scale_x :: The horizontal scale (FUnits to sub-pixels). */ + /* */ + /* scale_y :: The vertical scale (FUnits to sub-pixels). */ + /* */ + /* pos_x :: The horizontal translation (for composite glyphs). */ + /* */ + /* pos_y :: The vertical translation (for composite glyphs). */ + /* */ + /* left_bearing :: The left side bearing point. */ + /* */ + /* advance :: The horizontal advance vector. */ + /* */ + /* no_recurse :: */ + /* */ + /* bbox :: The glyph's bounding box. */ + /* */ + /* path_begun :: A flag which indicates that a new path has begun. */ + /* */ + /* load_points :: A flag which indicates, if not set, that no points */ + /* are loaded. */ + /* */ + /* pass :: The pass number for multi-pass hinters. */ + /* */ + /* hint_point :: The index of the next point to hint. */ + /* */ + /* funcs :: A table of builder functions used to perform the */ + /* outline's path construction. */ + /* */ + struct T1_Builder_ + { + FT_Memory memory; + T1_Face face; + T1_Size size; + T1_GlyphSlot glyph; + FT_GlyphLoader* loader; + + FT_Outline* current; /* the current glyph outline */ + FT_Outline* base; /* the composite glyph outline */ + + FT_Vector last; + + FT_Fixed scale_x; + FT_Fixed scale_y; + + FT_Pos pos_x; + FT_Pos pos_y; + + FT_Vector left_bearing; + FT_Vector advance; + FT_Bool no_recurse; + + FT_BBox bbox; /* bounding box */ + FT_Bool path_begun; + FT_Bool load_points; + + FT_Int pass; + FT_Int hint_point; + + /* path construction function interface */ + T1_Builder_Funcs funcs; + }; + + + typedef FT_Error (*T1_Hinter_ChangeHints)( T1_Builder* builder ); + + typedef FT_Error (*T1_Hinter_DotSection)( T1_Builder* builder ); + + typedef FT_Error (*T1_Hinter_Stem)( T1_Builder* builder, + FT_Pos pos, + FT_Pos width, + FT_Bool vertical ); + + typedef FT_Error (*T1_Hinter_Stem3)( T1_Builder* builder, + FT_Pos pos0, + FT_Pos width0, + FT_Pos pos1, + FT_Pos width1, + FT_Pos pos2, + FT_Pos width2, + FT_Bool vertical ); + + + /*************************************************************************/ + /* */ + /* */ + /* T1_Hinter_Funcs */ + /* */ + /* */ + /* A structure to store the address of various functions used by a */ + /* Type 1 hinter to perform outline hinting. */ + /* */ + typedef struct T1_Hinter_Func_ + { + T1_Hinter_ChangeHints change_hints; + T1_Hinter_DotSection dot_section; + T1_Hinter_Stem stem; + T1_Hinter_Stem3 stem3; + + } T1_Hinter_Funcs; + + + typedef enum T1_Operator_ + { + op_none = 0, + op_endchar, + op_hsbw, + op_seac, + op_sbw, + op_closepath, + op_hlineto, + op_hmoveto, + op_hvcurveto, + op_rlineto, + op_rmoveto, + op_rrcurveto, + op_vhcurveto, + op_vlineto, + op_vmoveto, + op_dotsection, + op_hstem, + op_hstem3, + op_vstem, + op_vstem3, + op_div, + op_callothersubr, + op_callsubr, + op_pop, + op_return, + op_setcurrentpoint, + + op_max /* never remove this one */ + + } T1_Operator; + + + /* execution context charstring zone */ + typedef struct T1_Decoder_Zone_ + { + FT_Byte* base; + FT_Byte* limit; + FT_Byte* cursor; + + } T1_Decoder_Zone; + + + typedef struct T1_Decoder_ + { + T1_Builder builder; + T1_Hinter_Funcs hinter; + + FT_Int stack[T1_MAX_CHARSTRINGS_OPERANDS]; + FT_Int* top; + + T1_Decoder_Zone zones[T1_MAX_SUBRS_CALLS + 1]; + T1_Decoder_Zone* zone; + + FT_Int flex_state; + FT_Int num_flex_vectors; + FT_Vector flex_vectors[7]; + + } T1_Decoder; + + + LOCAL_DEF + void T1_Init_Builder( T1_Builder* builder, + T1_Face face, + T1_Size size, + T1_GlyphSlot glyph, + const T1_Builder_Funcs* funcs ); + + LOCAL_DEF + void T1_Done_Builder( T1_Builder* builder ); + + LOCAL_DEF + void T1_Init_Decoder( T1_Decoder* decoder, + const T1_Hinter_Funcs* funcs ); + + LOCAL_DEF + FT_Error T1_Compute_Max_Advance( T1_Face face, + FT_Int* max_advance ); + + LOCAL_DEF + FT_Error T1_Parse_CharStrings( T1_Decoder* decoder, + FT_Byte* charstring_base, + FT_Int charstring_len, + FT_Int num_subrs, + FT_Byte** subrs_base, + FT_Int* subrs_len ); + + LOCAL_DEF + FT_Error T1_Add_Points( T1_Builder* builder, + FT_Int num_points ); + + LOCAL_DEF + FT_Error T1_Add_Contours( T1_Builder* builder, + FT_Int num_contours ); + + LOCAL_DEF + FT_Error T1_Load_Glyph( T1_GlyphSlot glyph, + T1_Size size, + FT_Int glyph_index, + FT_Int load_flags ); + + +#ifdef __cplusplus + } +#endif + + +#endif /* T1GLOAD_H */ + + +/* END */ diff --git a/src/freetype/type1/t1hinter.c b/src/freetype/type1/t1hinter.c new file mode 100644 index 0000000000..7ce746228a --- /dev/null +++ b/src/freetype/type1/t1hinter.c @@ -0,0 +1,1347 @@ +/***************************************************************************/ +/* */ +/* t1hinter.c */ +/* */ +/* Type 1 hinter (body). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + + /*************************************************************************/ + /* */ + /* The Hinter is in charge of fitting th scaled outline to the pixel */ + /* grid in order to considerably improve the quality of the Type 1 font */ + /* driver's output. */ + /* */ + /*************************************************************************/ + + +#include + + +#ifdef FT_FLAT_COMPILE + +#include "t1objs.h" +#include "t1hinter.h" + +#else + +#include +#include + +#endif + + + /*************************************************************************/ + /* */ + /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ + /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ + /* messages during execution. */ + /* */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_t1hint + + +#undef ONE_PIXEL +#define ONE_PIXEL 64 + +#undef ROUND +#define ROUND( x ) ( ( x + ONE_PIXEL / 2 ) & -ONE_PIXEL ) + +#undef SCALE +#define SCALE( val ) FT_MulFix( val, scale ) + +/* various constants used to describe the alignment of a horizontal */ +/* stem with regards to the blue zones */ + +#define T1_ALIGN_NONE 0 +#define T1_ALIGN_BOTTOM 1 +#define T1_ALIGN_TOP 2 +#define T1_ALIGN_BOTH 3 + + + /* very simple bubble sort (not a lot of elements, mostly */ + /* pre-sorted, no need for quicksort) */ + + static + void t1_sort_blues( FT_Int* blues, + FT_Int count ) + { + FT_Int i, swap; + FT_Int* cur; + + + for ( i = 2; i < count; i += 2 ) + { + cur = blues + i; + do + { + if ( cur[-1] < cur[0] ) + break; + + swap = cur[-2]; cur[-2] = cur[0]; cur[0] = swap; + swap = cur[-1]; cur[-1] = cur[1]; cur[1] = swap; + cur -= 2; + + } while ( cur > blues ); + } + } + + + /*************************************************************************/ + /* */ + /* */ + /* t1_set_blue_zones */ + /* */ + /* */ + /* Sets a size object's blue zones during reset. This will compute */ + /* the `snap' zone corresponding to each blue zone. */ + /* */ + /* */ + /* size :: A handle to target size object. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* This functions does the following: */ + /* */ + /* 1. It extracts the bottom and top blue zones from the face object. */ + /* */ + /* 2. Each zone is then grown by `BlueFuzz', overlapping is */ + /* eliminated by adjusting the zone edges appropriately. */ + /* */ + /* 3. For each zone, we keep its original font units position, its */ + /* original scaled position, as well as its grown/adjusted edges. */ + /* */ + static + FT_Error t1_set_blue_zones( T1_Size size ) + { + T1_Face face = (T1_Face)size->root.face; + T1_Private* priv = &face->type1.private_dict; + FT_Int n; + FT_Int blues[24]; + FT_Int num_bottom; + FT_Int num_top; + FT_Int num_blues; + T1_Size_Hints* hints = size->hints; + T1_Snap_Zone* zone; + FT_Pos pix, orus; + FT_Pos min, max, threshold; + FT_Fixed scale; + FT_Bool is_bottom; + + + /***********************************************************************/ + /* */ + /* copy bottom and top blue zones in local arrays */ + /* */ + + /* First of all, check the sizes of the /BlueValues and /OtherBlues */ + /* tables. They all must contain an even number of arguments. */ + if ( priv->num_other_blues & 1 || + priv->num_blue_values & 1 ) + { + FT_ERROR(( "t1_set_blue_zones: odd number of blue values\n" )); + return T1_Err_Syntax_Error; + } + + /* copy the bottom blue zones from /OtherBlues */ + num_top = 0; + num_bottom = priv->num_other_blues; + + for ( n = 0; n < num_bottom; n++ ) + blues[n] = priv->other_blues[n]; + + /* add the first blue zone in /BlueValues to the table */ + num_top = priv->num_blue_values - 2; + if ( num_top >= 0 ) + { + blues[num_bottom ] = priv->blue_values[0]; + blues[num_bottom + 1] = priv->blue_values[1]; + + num_bottom += 2; + } + + /* sort the bottom blue zones */ + t1_sort_blues( blues, num_bottom ); + + hints->num_bottom_zones = num_bottom >> 1; + + /* now copy the /BlueValues to the top of the blues array */ + if ( num_top > 0 ) + { + for ( n = 0; n < num_top; n++ ) + blues[num_bottom + n] = priv->blue_values[n + 2]; + + /* sort the top blue zones */ + t1_sort_blues( blues + num_bottom, num_top ); + } + else + num_top = 0; + + num_blues = num_top + num_bottom; + hints->num_blue_zones = ( num_blues ) >> 1; + + /***********************************************************************/ + /* */ + /* build blue snap zones from the local blues arrays */ + /* */ + + scale = size->root.metrics.y_scale; + zone = hints->blue_zones; + threshold = ONE_PIXEL / 4; /* 0.25 pixels */ + + for ( n = 0; n < num_blues; n += 2, zone++ ) + { + is_bottom = n < num_bottom ? 1 : 0; + + orus = blues[n + is_bottom]; /* get alignement coordinate */ + pix = SCALE( orus ); /* scale it */ + + min = SCALE( blues[n ] - priv->blue_fuzz ); + max = SCALE( blues[n + 1] + priv->blue_fuzz ); + + if ( min > pix - threshold ) + min = pix - threshold; + if ( max < pix + threshold ) + max = pix + threshold; + + zone->orus = orus; + zone->pix = pix; + zone->min = min; + zone->max = max; + } + + /* adjust edges in case of overlap */ + zone = hints->blue_zones; + for ( n = 0; n < num_blues - 2; n += 2, zone++ ) + { + if ( n != num_bottom - 2 && + zone[0].max > zone[1].min ) + zone[0].max = zone[1].min = ( zone[0].pix + zone[1].pix ) / 2; + } + + /* compare the current pixel size with the BlueScale value */ + /* to know whether to supress overshoots */ + + hints->supress_overshoots = + size->root.metrics.y_ppem < FT_MulFix( 1000, priv->blue_scale ); + +#ifdef FT_DEBUG_LEVEL_TRACE + + /* now print the new blue values in tracing mode */ + + FT_TRACE2(( "Blue Zones for size object at $%08lx:\n", (long)size )); + FT_TRACE2(( " orus pix min max\n" )); + FT_TRACE2(( "-------------------------------\n" )); + + zone = hints->blue_zones; + for ( n = 0; n < hints->num_blue_zones; n++ ) + { + FT_TRACE2(( " %3d %.2f %.2f %.2f\n", + zone->orus, + zone->pix / 64.0, + zone->min / 64.0, + zone->max / 64.0 )); + zone++; + } + FT_TRACE2(( "\nOvershoots are %s\n\n", + hints->supress_overshoots ? "supressed" : "active" )); + +#endif /* DEBUG_LEVEL_TRACE */ + + return T1_Err_Ok; + } + + + /*************************************************************************/ + /* */ + /* */ + /* t1_set_snap_zones */ + /* */ + /* */ + /* This function set a size object's stem snap zones. */ + /* */ + /* */ + /* size :: A handle to the target size object. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* This function performs the following: */ + /* */ + /* 1. It reads and scales the stem snap widths from the parent face. */ + /* */ + /* 2. A `snap zone' is computed for each snap width, by `growing' it */ + /* with a threshold of 1/2 pixel. Overlapping is avoided through */ + /* proper edge adjustment. */ + /* */ + /* 3. Each width whose zone contain the scaled standard set width is */ + /* removed from the table. */ + /* */ + /* 4. Finally, the standard set width is scaled, and its correponding */ + /* `snap zone' is inserted into the sorted snap zones table. */ + /* */ + static + FT_Error t1_set_snap_zones( T1_Size size ) + { + FT_Int n, direction, n_zones, num_zones; + T1_Snap_Zone* zone; + T1_Snap_Zone* base_zone; + FT_Short* orgs; + FT_Pos standard_width; + FT_Fixed scale; + + T1_Face face = (T1_Face)size->root.face; + T1_Private* priv = &face->type1.private_dict; + T1_Size_Hints* hints = size->hints; + + + /* start with horizontal snap zones */ + direction = 0; + standard_width = priv->standard_width[0]; + n_zones = priv->num_snap_widths; + base_zone = hints->snap_widths; + orgs = priv->snap_widths; + scale = size->root.metrics.x_scale; + + while ( direction < 2 ) + { + /*********************************************************************/ + /* */ + /* Read and scale stem snap widths table from the physical font */ + /* record. */ + /* */ + + FT_Pos prev, orus, pix, min, max, threshold; + + + threshold = ONE_PIXEL / 4; + zone = base_zone; + + if ( n_zones > 0 ) + { + orus = *orgs++; + pix = SCALE( orus ); + min = pix - threshold; + max = pix + threshold; + + zone->orus = orus; + zone->pix = pix; + zone->min = min; + prev = pix; + + for ( n = 1; n < n_zones; n++ ) + { + orus = *orgs++; + pix = SCALE( orus ); + + if ( pix - prev < 2 * threshold ) + { + min = max = ( pix + prev ) / 2; + } + else + min = pix - threshold; + + zone->max = max; + zone++; + zone->orus = orus; + zone->pix = pix; + zone->min = min; + + max = pix + threshold; + prev = pix; + } + zone->max = max; + } + +#ifdef FT_DEBUG_LEVEL_TRACE + + /* print the scaled stem snap values in tracing mode */ + + FT_TRACE2(( "Set_Snap_Zones: first %s pass\n", + direction ? "vertical" : "horizontal" )); + + FT_TRACE2(( "Scaled original stem snap zones:\n" )); + FT_TRACE2(( " orus pix min max\n" )); + FT_TRACE2(( "-----------------------------\n" )); + + zone = base_zone; + for ( n = 0; n < n_zones; n++, zone++ ) + FT_TRACE2(( " %3d %.2f %.2f %.2f\n", + zone->orus, + zone->pix / 64.0, + zone->min / 64.0, + zone->max / 64.0 )); + FT_TRACE2(( "\n" )); + + FT_TRACE2(( "Standard width = %d\n", standard_width )); + +#endif /* FT_DEBUG_LEVEL_TRACE */ + + /*********************************************************************/ + /* */ + /* Now, each snap width which is in the range of the standard set */ + /* width will be removed from the list. */ + /* */ + + if ( standard_width > 0 ) + { + T1_Snap_Zone* parent; + FT_Pos std_pix, std_min, std_max; + + + std_pix = SCALE( standard_width ); + + std_min = std_pix - threshold; + std_max = std_pix + threshold; + + num_zones = 0; + zone = base_zone; + parent = base_zone; + + for ( n = 0; n < n_zones; n++ ) + { + if ( zone->pix >= std_min && zone->pix <= std_max ) + { + /* this zone must be removed from the list */ + if ( std_min > zone->min ) + std_min = zone->min; + if ( std_max < zone->max ) + std_max = zone->max; + } + else + { + *parent++ = *zone; + num_zones++; + } + zone++; + } + + /*******************************************************************/ + /* */ + /* Now, insert the standard width zone */ + /* */ + + zone = base_zone + num_zones; + while ( zone > base_zone && zone[-1].pix > std_max ) + { + zone[0] = zone[-1]; + zone--; + } + + /* check border zones */ + if ( zone > base_zone && zone[-1].max > std_min ) + zone[-1].max = std_min; + + if ( zone < base_zone + num_zones && zone[1].min < std_max ) + zone[1].min = std_max; + + zone->orus = standard_width; + zone->pix = std_pix; + zone->min = std_min; + zone->max = std_max; + + num_zones++; + } + else + num_zones = n_zones; + + /* save total number of stem snaps now */ + if ( direction ) + hints->num_snap_heights = num_zones; + else + hints->num_snap_widths = num_zones; + +#ifdef FT_DEBUG_LEVEL_TRACE + + /* print the scaled stem snap values in tracing mode */ + + FT_TRACE2(( "Set_Snap_Zones: second %s pass\n", + direction ? "vertical" : "horizontal" )); + + FT_TRACE2(( "Scaled clipped stem snap zones:\n" )); + FT_TRACE2(( " orus pix min max\n" )); + FT_TRACE2(( "-----------------------------\n" )); + + zone = base_zone; + for ( n = 0; n < num_zones; n++, zone++ ) + FT_TRACE2(( " %3d %.2f %.2f %.2f\n", + zone->orus, + zone->pix / 64.0, + zone->min / 64.0, + zone->max / 64.0 )); + FT_TRACE2(( "\n" )); + + FT_TRACE2(( "Standard width = %d\n", standard_width )); + +#endif /* FT_DEBUG_LEVEL_TRACE */ + + /* continue with vertical snap zone */ + direction++; + standard_width = priv->standard_height[0]; + n_zones = priv->num_snap_heights; + base_zone = hints->snap_heights; + orgs = priv->snap_heights; + scale = size->root.metrics.y_scale; + } + + return T1_Err_Ok; + } + + + /*************************************************************************/ + /* */ + /* */ + /* T1_New_Size_Hinter */ + /* */ + /* */ + /* Allocates a new hinter structure for a given size object. */ + /* */ + /* */ + /* size :: A handle to the target size object. */ + /* */ + /* */ + /* FreeType Error code. 0 means success. */ + /* */ + LOCAL_FUNC + FT_Error T1_New_Size_Hinter( T1_Size size ) + { + FT_Memory memory = size->root.face->memory; + + + return MEM_Alloc( size->hints, sizeof ( *size->hints ) ); + } + + + /*************************************************************************/ + /* */ + /* */ + /* T1_Done_Size_Hinter */ + /* */ + /* */ + /* Releases a given size object's hinter structure. */ + /* */ + /* */ + /* size :: A handle to the target size object. */ + /* */ + LOCAL_FUNC + void T1_Done_Size_Hinter( T1_Size size ) + { + FT_Memory memory = size->root.face->memory; + + + FREE( size->hints ); + } + + + /*************************************************************************/ + /* */ + /* */ + /* T1_Reset_Size_Hinter */ + /* */ + /* */ + /* Recomputes hinting information when a given size object has */ + /* changed its resolutions/char sizes/pixel sizes. */ + /* */ + /* */ + /* size :: A handle to the size object. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + LOCAL_FUNC + FT_Error T1_Reset_Size_Hinter( T1_Size size ) + { + return t1_set_blue_zones( size ) || t1_set_snap_zones( size ); + } + + + /*************************************************************************/ + /* */ + /* */ + /* T1_New_Glyph_Hinter */ + /* */ + /* */ + /* Allocates a new hinter structure for a given glyph slot. */ + /* */ + /* */ + /* glyph :: A handle to the target glyph slot. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + LOCAL_FUNC + FT_Error T1_New_Glyph_Hinter( T1_GlyphSlot glyph ) + { + FT_Memory memory = glyph->root.face->memory; + + + return MEM_Alloc( glyph->hints, sizeof ( *glyph->hints ) ); + } + + + /*************************************************************************/ + /* */ + /* */ + /* T1_Done_Glyph_Hinter */ + /* */ + /* */ + /* Releases a given glyph slot's hinter structure. */ + /* */ + /* */ + /* glyph :: A handle to the glyph slot. */ + /* */ + LOCAL_FUNC + void T1_Done_Glyph_Hinter( T1_GlyphSlot glyph ) + { + FT_Memory memory = glyph->root.face->memory; + + + FREE( glyph->hints ); + } + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /********** **********/ + /********** HINTED GLYPH LOADER **********/ + /********** **********/ + /********** The following code is in charge of the first **********/ + /********** and second pass when loading a single outline **********/ + /********** **********/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + static + FT_Error t1_hinter_ignore( void ) + { + /* do nothing, used for `dotsection' which is unsupported for now */ + return 0; + } + + + static + FT_Error t1_hinter_stem( T1_Builder* builder, + FT_Pos pos, + FT_Int width, + FT_Bool vertical ) + { + T1_Stem_Table* stem_table; + T1_Stem_Hint* stems; + T1_Stem_Hint* cur_stem; + FT_Int min, max, n, num_stems; + FT_Bool new_stem; + T1_Glyph_Hints* hinter = builder->glyph->hints; + + + /* select the appropriate stem array */ + stem_table = vertical ? &hinter->vert_stems : &hinter->hori_stems; + stems = stem_table->stems; + num_stems = stem_table->num_stems; + + /* Compute minimum and maximum coord for the stem */ + min = pos + ( vertical + ? builder->left_bearing.x + : builder->left_bearing.y ); + + if ( width >= 0 ) + max = min + width; + else + { + /* a negative width indicates a `ghost' stem */ + if ( width == -21 ) + min += width; + + max = min; + } + + /* Now scan the array. If we find a stem with the same borders */ + /* simply activate it. */ + cur_stem = stems; + new_stem = 1; + + for ( n = 0; n < num_stems; n++, cur_stem++ ) + { + if ( cur_stem->min_edge.orus == min && + cur_stem->max_edge.orus == max ) + { + /* This stem is already in the table, simply activate it */ + if ( ( cur_stem->hint_flags & T1_HINT_FLAG_ACTIVE ) == 0 ) + { + cur_stem->hint_flags |= T1_HINT_FLAG_ACTIVE; + stem_table->num_active++; + } + new_stem = 0; + break; + } + } + + /* add a new stem to the array if necessary */ + if ( new_stem ) + { + if ( cur_stem >= stems + T1_HINTER_MAX_EDGES ) + { + FT_ERROR(( "t1_hinter_stem: too many stems in glyph charstring\n" )); + return T1_Err_Syntax_Error; + } + + /* on the first pass, we record the stem, otherwise, this is */ + /* a bug in the glyph loader! */ + if ( builder->pass == 0 ) + { + cur_stem->min_edge.orus = min; + cur_stem->max_edge.orus = max; + cur_stem->hint_flags = T1_HINT_FLAG_ACTIVE; + + stem_table->num_stems++; + stem_table->num_active++; + } + else + { + FT_ERROR(( "t1_hinter_stem:" )); + FT_ERROR(( " fatal glyph loader bug -- pass2-stem\n" )); + return T1_Err_Syntax_Error; + } + } + + return T1_Err_Ok; + } + + + static + FT_Error t1_hinter_stem3( T1_Builder* builder, + FT_Pos pos0, + FT_Int width0, + FT_Pos pos1, + FT_Int width1, + FT_Pos pos2, + FT_Int width2, + FT_Bool vertical ) + { + /* For now, simply call `stem' 3 times */ + return t1_hinter_stem( builder, pos0, width0, vertical ) || + t1_hinter_stem( builder, pos1, width1, vertical ) || + t1_hinter_stem( builder, pos2, width2, vertical ); + } + + + static + FT_Error t1_hinter_changehints( T1_Builder* builder ) + { + FT_Int dimension; + T1_Stem_Table* stem_table; + T1_Glyph_Hints* hinter = builder->glyph->hints; + + + /* If we are in the second pass of glyph hinting, we must */ + /* call the function T1_Hint_Points() on the builder in order */ + /* to force the fit the latest points to the pixel grid. */ + if ( builder->pass == 1 ) + T1_Hint_Points( builder ); + + /* Simply de-activate all hints in all arrays */ + stem_table = &hinter->hori_stems; + + for ( dimension = 2; dimension > 0; dimension-- ) + { + T1_Stem_Hint* cur = stem_table->stems; + T1_Stem_Hint* limit = cur + stem_table->num_stems; + + + for ( ; cur < limit; cur++ ) + cur->hint_flags &= ~T1_HINT_FLAG_ACTIVE; + + stem_table->num_active = 0; + stem_table = &hinter->vert_stems; + } + + return T1_Err_Ok; + } + + + const T1_Hinter_Funcs t1_hinter_funcs = + { + (T1_Hinter_ChangeHints)t1_hinter_changehints, + (T1_Hinter_DotSection) t1_hinter_ignore, + (T1_Hinter_Stem) t1_hinter_stem, + (T1_Hinter_Stem3) t1_hinter_stem3 + }; + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /********** *********/ + /********** *********/ + /********** STEM HINTS MANAGEMENT *********/ + /********** *********/ + /********** The following code is in charge of computing *********/ + /********** the placement of each scaled stem hint. *********/ + /********** *********/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* */ + /* t1_sort_hints */ + /* */ + /* */ + /* Sorta the list of active stems in increasing order, through the */ + /* `sort' indexing table. */ + /* */ + /* */ + /* table :: A stem hints table. */ + /* */ + static + void t1_sort_hints( T1_Stem_Table* table ) + { + FT_Int num_stems = table->num_stems; + FT_Int num_active = 0; + FT_Int* sort = table->sort; + T1_Stem_Hint* stems = table->stems; + FT_Int n; + + + /* record active stems in sort table */ + for ( n = 0; n < num_stems; n++ ) + { + if ( stems[n].hint_flags & T1_HINT_FLAG_ACTIVE ) + sort[num_active++] = n; + } + + /* Now sort the indices. There are usually very few stems, */ + /* and they are pre-sorted in 90% cases, so we choose a */ + /* simple bubble sort (quicksort would be slower). */ + for ( n = 1; n < num_active; n++ ) + { + FT_Int p = n - 1; + T1_Stem_Hint* cur = stems + sort[n]; + + + do + { + FT_Int swap; + T1_Stem_Hint* prev = stems + sort[p]; + + + /* note that by definition, the active stems cannot overlap */ + /* so we simply compare their `min' to sort them (we could compare */ + /* their max values also; this wouldn't change anything). */ + if ( prev->min_edge.orus <= cur->min_edge.orus ) + break; + + /* swap elements */ + swap = sort[p ]; + sort[p ] = sort[p + 1]; + sort[p + 1] = swap; + p--; + + } while ( p >= 0 ); + } + + table->num_active = num_active; + } + + + /*************************************************************************/ + /* */ + /* */ + /* t1_hint_horizontal_stems */ + /* */ + /* */ + /* Computes the location of each scaled horizontal stem hint. This */ + /* takes care of the blue zones and the horizontal stem snap table. */ + /* */ + /* */ + /* table :: The horizontal stem hints table. */ + /* */ + /* hints :: The current size's hint structure. */ + /* */ + /* blueShift :: The value of the /BlueShift as taken from the face */ + /* object. */ + /* */ + /* scale :: The 16.16 scale used to convert outline units to */ + /* 26.6 pixels. */ + /* */ + /* */ + /* For now, all stems are hinted independently from each other. It */ + /* might be necessary, for better performance, to introduce the */ + /* notion of `controlled' hints describing things like counter-stems, */ + /* stem3, as well as overlapping stems control. */ + /* */ + static + void t1_hint_horizontal_stems( T1_Stem_Table* table, + T1_Size_Hints* hints, + FT_Pos blueShift, + FT_Fixed scale ) + { + T1_Stem_Hint* stem = table->stems; + T1_Stem_Hint* limit = stem + table->num_stems; + + + /* first of all, scale the blueShift */ + blueShift = SCALE( blueShift ); + + /* then scan the horizontal stem table */ + for ( ; stem < limit; stem++ ) + { + FT_Pos bottom_orus = stem->min_edge.orus; + FT_Pos top_orus = stem->max_edge.orus; + + FT_Pos top_pix = SCALE( top_orus ); + FT_Pos bottom_pix = SCALE( bottom_orus ); + FT_Pos width_pix = top_pix - bottom_pix; + + FT_Pos bottom = bottom_pix; + FT_Pos top = top_pix; + FT_Int align = T1_ALIGN_NONE; + + + /*********************************************************************/ + /* */ + /* Snap pixel width if in stem snap range */ + /* */ + + { + T1_Snap_Zone* zone = hints->snap_heights; + T1_Snap_Zone* zone_limit = zone + hints->num_snap_heights; + FT_Pos best_dist = 32000; + T1_Snap_Zone* best_zone = 0; + + + for ( ; zone < zone_limit; zone++ ) + { + FT_Pos dist; + + + dist = width_pix - zone->min; + if ( dist < 0 ) + dist = -dist; + if ( dist < best_dist ) + { + best_zone = zone; + best_dist = dist; + } + } + + if ( best_zone ) + { + if ( width_pix > best_zone->pix ) + { + width_pix -= 0x20; + if ( width_pix < best_zone->pix ) + width_pix = best_zone->pix; + } + else + { + width_pix += 0x20; + if ( width_pix > best_zone->pix ) + width_pix = best_zone->pix; + } + } + } + + /*********************************************************************/ + /* */ + /* round width - minimum 1 pixel if this isn't a ghost stem */ + /* */ + + if ( width_pix > 0 ) + width_pix = width_pix < ONE_PIXEL ? ONE_PIXEL : ROUND( width_pix ); + + + /*********************************************************************/ + /* */ + /* Now check for bottom blue zones alignement */ + /* */ + + { + FT_Int num_blues = hints->num_bottom_zones; + T1_Snap_Zone* blue = hints->blue_zones; + T1_Snap_Zone* blue_limit = blue + num_blues; + + + for ( ; blue < blue_limit; blue++ ) + { + if ( bottom_pix < blue->min ) + break; + + if ( bottom_pix <= blue->max ) + { + align = T1_ALIGN_BOTTOM; + bottom = ROUND( blue->pix ); + + /* implement blue shift */ + if ( !hints->supress_overshoots ) + { + FT_Pos delta = blue->pix - bottom_pix; + + + delta = delta < blueShift ? 0 : ROUND( delta ); + bottom -= delta; + } + } + } + } + + /*********************************************************************/ + /* */ + /* check for top blue zones alignement */ + /* */ + + { + FT_Int num_blues = hints->num_blue_zones - + hints->num_bottom_zones; + + T1_Snap_Zone* blue = hints->blue_zones + + hints->num_bottom_zones; + + T1_Snap_Zone* blue_limit = blue + num_blues; + + + for ( ; blue < blue_limit; blue++ ) + { + if ( top_pix < blue->min ) + break; + + if ( top_pix <= blue->max ) + { + align |= T1_ALIGN_TOP; + top = ROUND( blue->pix ); + + /* implement blue shift */ + if ( !hints->supress_overshoots ) + { + FT_Pos delta = top - blue->pix; + + + delta = delta < blueShift ? 0 : ROUND( delta ); + top += delta; + } + } + } + } + + /*********************************************************************/ + /* */ + /* compute the hinted stem position, according to its alignment */ + /* */ + + switch ( align ) + { + case T1_ALIGN_BOTTOM: /* bottom zone alignment */ + bottom_pix = bottom; + top_pix = bottom + width_pix; + break; + + case T1_ALIGN_TOP: /* top zone alignment */ + top_pix = top; + bottom_pix = top - width_pix; + break; + + case T1_ALIGN_BOTH: /* bottom+top zone alignment */ + bottom_pix = bottom; + top_pix = top; + break; + + default: /* no alignment */ + /* XXX TODO: Add management of controlled stems */ + bottom = ( SCALE( bottom_orus + top_orus ) - width_pix ) / 2; + + bottom_pix = ROUND( bottom ); + top_pix = bottom_pix + width_pix; + } + + stem->min_edge.pix = bottom_pix; + stem->max_edge.pix = top_pix; + } + } + + + /*************************************************************************/ + /* */ + /* */ + /* t1_hint_vertical_stems */ + /* */ + /* */ + /* Computes the location of each scaled vertical stem hint. This */ + /* takes care of the vertical stem snap table. */ + /* */ + /* */ + /* table :: The vertical stem hints table. */ + /* hints :: The current size's hint structure. */ + /* scale :: The 16.16 scale used to convert outline units to */ + /* 26.6 pixels. */ + /* */ + /* */ + /* For now, all stems are hinted independently from each other. It */ + /* might be necessary, for better performance, to introduce the */ + /* notion of `controlled' hints describing things like counter-stems, */ + /* stem3 as well as overlapping stems control. */ + /* */ + static + void t1_hint_vertical_stems( T1_Stem_Table* table, + T1_Size_Hints* hints, + FT_Fixed scale ) + { + T1_Stem_Hint* stem = table->stems; + T1_Stem_Hint* limit = stem + table->num_stems; + + + for ( ; stem < limit; stem++ ) + { + FT_Pos stem_left = stem->min_edge.orus; + FT_Pos stem_right = stem->max_edge.orus; + FT_Pos width_pix, left; + + + width_pix = SCALE( stem_right - stem_left ); + + /* Snap pixel width if in stem snap range */ + { + T1_Snap_Zone* zone = hints->snap_heights; + T1_Snap_Zone* zone_limit = zone + hints->num_snap_heights; + FT_Pos best_dist = 32000; + T1_Snap_Zone* best_zone = 0; + + + for ( ; zone < zone_limit; zone++ ) + { + FT_Pos dist; + + + dist = width_pix - zone->min; + if ( dist < 0 ) + dist = -dist; + if ( dist < best_dist ) + { + best_zone = zone; + best_dist = dist; + } + } + + if ( best_zone ) + { + if ( width_pix > best_zone->pix ) + { + width_pix -= 0x20; + if ( width_pix < best_zone->pix ) + width_pix = best_zone->pix; + } + else + { + width_pix += 0x20; + if ( width_pix > best_zone->pix ) + width_pix = best_zone->pix; + } + } + } + + /* round width - minimum 1 pixel if this isn't a ghost stem */ + if ( width_pix > 0 ) + width_pix = width_pix < ONE_PIXEL ? ONE_PIXEL + : ROUND( width_pix ); + + /* now place the snapped and rounded stem */ + + /* XXX TODO: implement controlled stems for the overlapping */ + /* cases */ + + left = ( SCALE( stem_left + stem_right ) - width_pix ) / 2; + + stem->min_edge.pix = ROUND( left ); + stem->max_edge.pix = stem->min_edge.pix + width_pix; + } + } + + + /*************************************************************************/ + /* */ + /* */ + /* t1_hint_point */ + /* */ + /* */ + /* Grid-fit a coordinate with regards to a given stem hints table. */ + /* */ + /* */ + /* table :: The source stem hints table. */ + /* coord :: The original coordinate, expressed in font units. */ + /* scale :: The 16.16 scale used to convert font units into */ + /* 26.6 pixels. */ + /* */ + /* */ + /* The hinted/scaled value in 26.6 pixels. */ + /* */ + /* */ + /* For now, all stems are hinted independently from each other. It */ + /* might be necessary, for better performance, to introduce the */ + /* notion of `controlled' hints describing things like counter-stems, */ + /* stem3 as well as overlapping stems control. */ + /* */ + static + FT_Pos t1_hint_point( T1_Stem_Table* table, + FT_Pos coord, + FT_Fixed scale ) + { + FT_Int num_active = table->num_active; + FT_Int n; + T1_Stem_Hint* prev = 0; + T1_Stem_Hint* cur = 0; + T1_Edge* min; + T1_Edge* max; + FT_Pos delta; + + + /* only hint when there is at least one stem defined */ + if ( num_active <= 0 ) + return SCALE( coord ); + + /* scan the stem table to determine placement of coordinate */ + /* relative to the list of sorted and stems */ + for ( n = 0; n < num_active; n++, prev = cur ) + { + cur = table->stems + table->sort[n]; + + /* is it on the left of the current edge? */ + delta = cur->min_edge.orus - coord; + if ( delta == 0 ) + return cur->min_edge.pix; + + if ( delta > 0 ) + { + /* if this is the left of the first edge, simply shift */ + if ( !prev ) + return cur->min_edge.pix - SCALE( delta ); + + /* otherwise, interpolate between the maximum of the */ + /* previous stem, and the minimum of the current one */ + min = &prev->max_edge; + max = &cur->min_edge; + + goto Interpolate; + } + + /* is it within the current edge? */ + delta = cur->max_edge.orus - coord; + if ( delta == 0 ) + return cur->max_edge.pix; + + if ( delta > 0 ) + { + /* interpolate within the stem */ + min = &cur->min_edge; + max = &cur->max_edge; + + goto Interpolate; + } + } + + /* apparently, this coordinate is on the right of the last stem */ + delta = coord - cur->max_edge.orus; + return cur->max_edge.pix + SCALE( delta ); + + Interpolate: + return min->pix + FT_MulDiv( coord - min->orus, + max->pix - min->pix, + max->orus - min->orus ); + } + + + /*************************************************************************/ + /* */ + /* */ + /* T1_Hint_Points */ + /* */ + /* */ + /* This function grid-fits several points in a given Type 1 builder */ + /* at once. */ + /* */ + /* */ + /* builder :: A handle to target Type 1 builder. */ + /* */ + LOCAL_FUNC + void T1_Hint_Points( T1_Builder* builder ) + { + FT_Int first = builder->hint_point; + FT_Int last = builder->current->n_points - 1; + + T1_Size size = builder->size; + FT_Fixed scale_x = size->root.metrics.x_scale; + FT_Fixed scale_y = size->root.metrics.y_scale; + + T1_Glyph_Hints* hints = builder->glyph->hints; + T1_Stem_Table* hori_stems = &hints->hori_stems; + T1_Stem_Table* vert_stems = &hints->vert_stems; + + FT_Vector* cur = builder->current->points + first; + FT_Vector* limit = cur + last - first + 1; + + + /* first of all, sort the active stem hints */ + t1_sort_hints( hori_stems ); + t1_sort_hints( vert_stems ); + + for ( ; cur < limit; cur++ ) + { + cur->x = t1_hint_point( vert_stems, cur->x, scale_x ); + cur->y = t1_hint_point( hori_stems, cur->y, scale_y ); + } + + builder->hint_point = builder->current->n_points; + } + + + /*************************************************************************/ + /* */ + /* */ + /* T1_Hint_Stems */ + /* */ + /* */ + /* This function is used to compute the location of each stem hint */ + /* between the first and second passes of the glyph loader on the */ + /* charstring. */ + /* */ + /* */ + /* builder :: A handle to the target builder. */ + /* */ + LOCAL_FUNC + void T1_Hint_Stems( T1_Builder* builder ) + { + T1_Glyph_Hints* hints = builder->glyph->hints; + T1_Private* priv = &builder->face->type1.private_dict; + + T1_Size size = builder->size; + FT_Fixed scale_x = size->root.metrics.x_scale; + FT_Fixed scale_y = size->root.metrics.y_scale; + + + t1_hint_horizontal_stems( &hints->hori_stems, + builder->size->hints, + priv->blue_shift, + scale_y ); + + t1_hint_vertical_stems( &hints->vert_stems, + builder->size->hints, + scale_x ); + } + + +/* END */ diff --git a/src/freetype/type1/t1hinter.h b/src/freetype/type1/t1hinter.h new file mode 100644 index 0000000000..a82882e097 --- /dev/null +++ b/src/freetype/type1/t1hinter.h @@ -0,0 +1,273 @@ +/***************************************************************************/ +/* */ +/* t1hinter.h */ +/* */ +/* Type 1 hinter (body). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef T1HINTER_H +#define T1HINTER_H + + +#ifdef FT_FLAT_COMPILE + +#include "t1objs.h" +#include "t1gload.h" + +#else + +#include +#include + +#endif + + +#ifdef __cplusplus + extern "C" { +#endif + + + /*************************************************************************/ + /* */ + /* */ + /* T1_Snap_Zone */ + /* */ + /* */ + /* A `snap zone' is used to model either a blue zone or a stem width */ + /* at a given character size. It is made of a minimum and maximum */ + /* edge, defined in 26.6 pixels, as well as an `original' and */ + /* `scaled' position. */ + /* */ + /* The position corresponds to the stem width (for stem snap zones) */ + /* or to the blue position (for blue zones). */ + /* */ + /* */ + /* orus :: The original position in font units. */ + /* */ + /* pix :: The current position in sub-pixel units. */ + /* */ + /* min :: The minimum boundary in sub-pixel units. */ + /* */ + /* max :: The maximum boundary in sub-pixel units. */ + /* */ + typedef struct T1_Snap_Zone_ + { + FT_Pos orus; + FT_Pos pix; + FT_Pos min; + FT_Pos max; + + } T1_Snap_Zone; + + + /*************************************************************************/ + /* */ + /* */ + /* T1_Edge */ + /* */ + /* */ + /* A very simple structure used to model a stem edge. */ + /* */ + /* */ + /* orus :: The original edge position in font units. */ + /* */ + /* pix :: The scaled edge position in sub-pixel units. */ + /* */ + typedef struct T1_Edge_ + { + FT_Pos orus; + FT_Pos pix; + + } T1_Edge; + + + /*************************************************************************/ + /* */ + /* */ + /* T1_Stem_Hint */ + /* */ + /* */ + /* A simple structure used to model a stem hint. */ + /* */ + /* */ + /* min_edge :: The hint's minimum edge. */ + /* */ + /* max_edge :: The hint's maximum edge. */ + /* */ + /* hint_flags :: Some flags describing the stem properties. */ + /* */ + /* */ + /* The min and max edges of a ghost stem have the same position, even */ + /* if they are coded in a weird way in the charstrings. */ + /* */ + typedef struct T1_Stem_Hint_ + { + T1_Edge min_edge; + T1_Edge max_edge; + FT_Int hint_flags; + + } T1_Stem_Hint; + + +#define T1_HINT_FLAG_ACTIVE 1 /* indicates an active stem */ +#define T1_HINT_FLAG_MIN_BORDER 2 /* unused for now */ +#define T1_HINT_FLAG_MAX_BORDER 4 /* unused for now */ + + /* hinter's configuration constants */ +#define T1_HINTER_MAX_BLUES 24 /* maximum number of blue zones */ +#define T1_HINTER_MAX_SNAPS 16 /* maximum number of stem snap zones */ +#define T1_HINTER_MAX_EDGES 64 /* maximum number of stem hints */ + + + /*************************************************************************/ + /* */ + /* */ + /* T1_Size_Hints */ + /* */ + /* */ + /* A structure used to model the hinting information related to a size */ + /* object. */ + /* */ + /* */ + /* supress_overshoots :: A boolean flag to tell whether overshoot */ + /* supression should occur. */ + /* */ + /* num_blue_zones :: The total number of blue zones (top+bottom). */ + /* */ + /* num_bottom_zones :: The number of bottom zones. */ + /* */ + /* blue_zones :: The blue zones table. Bottom zones are */ + /* stored first in the table, followed by all */ + /* top zones. */ + /* */ + /* num_snap_widths :: The number of horizontal stem snap zones. */ + /* */ + /* snap_widths :: An array of horizontal stem snap zones. */ + /* */ + /* num_snap_heights :: The number of vertical stem snap zones. */ + /* */ + /* snap_heights :: An array of vertical stem snap zones. */ + /* */ + struct T1_Size_Hints_ + { + FT_Bool supress_overshoots; + + FT_Int num_blue_zones; + FT_Int num_bottom_zones; + T1_Snap_Zone blue_zones[T1_HINTER_MAX_BLUES]; + + FT_Int num_snap_widths; + T1_Snap_Zone snap_widths[T1_HINTER_MAX_SNAPS]; + + FT_Int num_snap_heights; + T1_Snap_Zone snap_heights[T1_HINTER_MAX_SNAPS]; + }; + + + /*************************************************************************/ + /* */ + /* */ + /* T1_Stem_Table */ + /* */ + /* */ + /* A simple structure used to model a set of stem hints in a single */ + /* direction during the loading of a given glyph outline. Not all */ + /* stem hints are active at a time. Moreover, stems must be sorted */ + /* regularly. */ + /* */ + /* */ + /* num_stems :: The total number of stems in the table. */ + /* */ + /* num_active :: The number of active stems in the table. */ + /* */ + /* stems :: A table of all stems. */ + /* */ + /* sort :: A table of indices into the stems table, used to */ + /* keep a sorted list of the active stems. */ + /* */ + typedef struct T1_Stem_Table_ + { + FT_Int num_stems; + FT_Int num_active; + + T1_Stem_Hint stems[T1_HINTER_MAX_EDGES]; + FT_Int sort [T1_HINTER_MAX_EDGES]; + + } T1_Stem_Table; + + + /*************************************************************************/ + /* */ + /* */ + /* T1_Glyph_Hints */ + /* */ + /* */ + /* A structure used to model the stem hints of a given glyph outline */ + /* during glyph loading. */ + /* */ + /* */ + /* hori_stems :: The horizontal stem hints table. */ + /* vert_stems :: The vertical stem hints table. */ + /* */ + struct T1_Glyph_Hints_ + { + T1_Stem_Table hori_stems; + T1_Stem_Table vert_stems; + }; + + + /*************************************************************************/ + /* */ + /* */ + /* t1_hinter_funcs */ + /* */ + /* */ + /* A table containing the address of various functions used during */ + /* the loading of an hinted scaled outline. */ + /* */ + extern const T1_Hinter_Funcs t1_hinter_funcs; + + + LOCAL_DEF + FT_Error T1_New_Size_Hinter( T1_Size size ); + + LOCAL_DEF + void T1_Done_Size_Hinter( T1_Size size ); + + LOCAL_DEF + FT_Error T1_Reset_Size_Hinter( T1_Size size ); + + LOCAL_DEF + FT_Error T1_New_Glyph_Hinter( T1_GlyphSlot glyph ); + + LOCAL_DEF + void T1_Done_Glyph_Hinter( T1_GlyphSlot glyph ); + + + LOCAL_DEF + void T1_Hint_Points( T1_Builder* builder ); + + LOCAL_DEF + void T1_Hint_Stems( T1_Builder* builder ); + + +#ifdef __cplusplus + } +#endif + + +#endif /* T1HINTER_H */ + + +/* END */ diff --git a/src/freetype/type1/t1load.c b/src/freetype/type1/t1load.c new file mode 100644 index 0000000000..00a56a2463 --- /dev/null +++ b/src/freetype/type1/t1load.c @@ -0,0 +1,1594 @@ +/***************************************************************************/ +/* */ +/* t1load.c */ +/* */ +/* Type 1 font loader (body). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#include +#include +#include + + +#ifdef FT_FLAT_COMPILE + +#include "t1tokens.h" +#include "t1parse.h" + +#else + +#include +#include + +#endif + + +#include + +#include /* for strncpy(), strncmp(), strlen() */ + + + /*************************************************************************/ + /* */ + /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ + /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ + /* messages during execution. */ + /* */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_t1load + + + typedef FT_Error (*T1_Parse_Func)( T1_Parser* parser ); + + + /*************************************************************************/ + /* */ + /* */ + /* Init_T1_Parser */ + /* */ + /* */ + /* Initializes a given parser object to build a given T1_Face. */ + /* */ + /* */ + /* parser :: A handle to the newly built parser object. */ + /* */ + /* */ + /* face :: A handle to the target Type 1 face object. */ + /* */ + /* tokenizer :: A handle to the target Type 1 token manager. */ + /* */ + LOCAL_FUNC + void Init_T1_Parser( T1_Parser* parser, + T1_Face face, + T1_Tokenizer tokenizer ) + { + parser->error = 0; + parser->face = face; + parser->tokenizer = tokenizer; + parser->top = parser->stack; + parser->limit = parser->stack + T1_MAX_STACK_DEPTH; + + parser->state_index = 0; + parser->state_stack[0] = dict_none; + + parser->encoding_type = t1_encoding_none; + parser->encoding_names = 0; + parser->encoding_offsets = 0; + parser->encoding_lengths = 0; + + parser->dump_tokens = 0; + face->type1.private_dict.lenIV = 4; /* XXX : is it sure? */ + } + + + /*************************************************************************/ + /* */ + /* */ + /* Next_T1_Token */ + /* */ + /* */ + /* Grabs the next significant token from a parser's input stream. */ + /* This function ignores a number of tokens, and translates */ + /* alternate forms into their common ones. */ + /* */ + /* */ + /* parser :: A handle to the source parser. */ + /* */ + /* */ + /* token :: The extracted token descriptor. */ + /* */ + /* */ + /* FreeTyoe error code. 0 means success. */ + /* */ + LOCAL_FUNC + FT_Error Next_T1_Token( T1_Parser* parser, + T1_Token* token ) + { + FT_Error error; + T1_Tokenizer tokzer = parser->tokenizer; + + + L1: + error = Read_Token( tokzer ); + if ( error ) + return error; + + /* we now must ignore a number of tokens like `dup', `executeonly', */ + /* `readonly', etc. */ + *token = tokzer->token; + if ( token->kind == tok_keyword ) + switch( token->kind2 ) + { + case key_dup: + case key_execonly: + case key_readonly: + case key_noaccess: + case key_userdict: + /* do nothing - loop */ + goto L1; + + /* we also translate some other keywords from their alternative */ + /* to their `normal' form */ + + case key_NP_alternate: + token->kind2 = key_NP; + break; + + case key_RD_alternate: + token->kind2 = key_RD; + break; + + case key_ND_alternate: + token->kind2 = key_ND; + break; + + default: + ; + } + +#if defined( FT_DEBUG_LEVEL_ERROR ) || defined( FT_DEBUG_LEVEL_TRACE ) + + /* Dump the token when requested. This feature is only available */ + /* in the `error' and `trace' debug levels. */ + if ( parser->dump_tokens ) + { + FT_String temp_string[128]; + FT_Int len; + + + len = token->len; + if ( len > 127 ) + len = 127; + strncpy( temp_string, + (FT_String*)tokzer->base + token->start, + len ); + temp_string[len] = '\0'; + FT_ERROR(( "%s\n", temp_string )); + } + +#endif /* FT_DEBUG_LEVEL_ERROR or FT_DEBUG_LEVEL_TRACE */ + + return T1_Err_Ok; + } + + + static + FT_Error Expect_Keyword( T1_Parser* parser, + T1_TokenType keyword ) + { + T1_Token token; + FT_Error error; + + + error = Next_T1_Token( parser, &token ); + if ( error ) + goto Exit; + + if ( token.kind != tok_keyword || + token.kind2 != keyword ) + { + error = T1_Err_Syntax_Error; + FT_ERROR(( "Expect_Keyword: keyword `%s' expected.\n", + t1_keywords[keyword - key_first_] )); + } + + Exit: + return error; + } + + + static + FT_Error Expect_Keyword2( T1_Parser* parser, + T1_TokenType keyword1, + T1_TokenType keyword2 ) + { + T1_Token token; + FT_Error error; + + + error = Next_T1_Token( parser, &token ); + if ( error ) + goto Exit; + + if ( token.kind != tok_keyword || + ( token.kind2 != keyword1 && + token.kind2 != keyword2 ) ) + { + error = T1_Err_Syntax_Error; + FT_ERROR(( "Expect_Keyword2: keyword `%s' or `%s' expected.\n", + t1_keywords[keyword1 - key_first_], + t1_keywords[keyword2 - key_first_] )); + } + + Exit: + return error; + } + + + static + void Parse_Encoding( T1_Parser* parser ) + { + T1_Token* token = parser->top+1; + FT_Memory memory = parser->face->root.memory; + T1_Encoding* encode = &parser->face->type1.encoding; + FT_Error error = 0; + + + if ( token->kind == tok_keyword && + ( token->kind2 == key_StandardEncoding || + token->kind2 == key_ExpertEncoding ) ) + { + encode->num_chars = 256; + encode->code_first = 32; + encode->code_last = 255; + + if ( ALLOC_ARRAY( encode->char_index, 256, FT_Short ) ) + goto Exit; + + encode->char_name = 0; /* no need to store glyph names */ + + /* Now copy the encoding */ + switch ( token->kind2 ) + { + case key_ExpertEncoding: + parser->encoding_type = t1_encoding_expert; + break; + + default: + parser->encoding_type = t1_encoding_standard; + break; + } + } + else + { + FT_ERROR(( "Parse_Encoding: invalid encoding type\n" )); + error = T1_Err_Syntax_Error; + } + + Exit: + parser->error = error; + } + + + /*************************************************************************/ + /* */ + /* */ + /* IMPLEMENTATION OF THE `DEF' KEYWORD DEPENDING ON */ + /* CURRENT DICTIONARY STATE */ + /* */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* */ + /* Do_Def_Font */ + /* */ + /* */ + /* This function performs a `def' if in the Font dictionary. Its */ + /* purpose is to build the T1_Face attributes directly from the */ + /* stream. */ + /* */ + /* */ + /* parser :: A handle to the current parser. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + static + FT_Error Do_Def_Font( T1_Parser* parser ) + { + T1_Token* top = parser->top; + T1_Face face = parser->face; + T1_Font* type1 = &face->type1; + + + switch ( top[0].kind2 ) + { + case imm_FontName: + /* in some cases, the /FontName is an immediate like */ + /* /TimesNewRoman. In this case, we simply copy the */ + /* token string (without the /). */ + if ( top[1].kind == tok_immediate ) + { + FT_Memory memory = parser->tokenizer->memory; + FT_Error error; + FT_Int len = top[1].len; + + + if ( ALLOC( type1->font_name, len + 1 ) ) + { + parser->error = error; + return error; + } + + MEM_Copy( type1->font_name, + parser->tokenizer->base + top[1].start, + len ); + type1->font_name[len] = '\0'; + } + else + type1->font_name = CopyString( parser ); + break; + + case imm_Encoding: + Parse_Encoding( parser ); + break; + + case imm_PaintType: + type1->paint_type = (FT_Byte)CopyInteger( parser ); + break; + + case imm_FontType: + type1->font_type = (FT_Byte)CopyInteger( parser ); + break; + + case imm_FontMatrix: + CopyMatrix( parser, &type1->font_matrix ); + break; + + case imm_FontBBox: + CopyBBox( parser, &type1->font_bbox ); + break; + + case imm_UniqueID: + type1->private_dict.unique_id = CopyInteger( parser ); + break; + + case imm_StrokeWidth: + type1->stroke_width = CopyInteger( parser ); + break; + + case imm_FontID: + type1->font_id = CopyInteger( parser ); + break; + + default: + /* ignore all other things */ + parser->error = T1_Err_Ok; + } + + return parser->error; + } + + + /*************************************************************************/ + /* */ + /* */ + /* Do_Def_FontInfo */ + /* */ + /* */ + /* This function performs a `def' if in the FontInfo dictionary. Its */ + /* purpose is to build the T1_FontInfo structure directly from the */ + /* stream. */ + /* */ + /* */ + /* parser :: A handle to the current parser. */ + /* */ + /* */ + /* FreeTyoe error code. 0 means success. */ + /* */ + static + FT_Error Do_Def_FontInfo( T1_Parser* parser ) + { + T1_Token* top = parser->top; + T1_FontInfo* info = &parser->face->type1.font_info; + + + switch ( top[0].kind2 ) + { + case imm_version: + info->version = CopyString( parser ); + break; + + case imm_Notice: + info->notice = CopyString( parser ); + break; + + case imm_FullName: + info->full_name = CopyString( parser ); + break; + + case imm_FamilyName: + info->family_name = CopyString( parser ); + break; + + case imm_Weight: + info->weight = CopyString( parser ); + break; + + case imm_ItalicAngle: + info->italic_angle = CopyInteger( parser ); + break; + + case imm_isFixedPitch: + info->is_fixed_pitch = CopyBoolean( parser ); + break; + + case imm_UnderlinePosition: + info->underline_position = (FT_Short)CopyInteger( parser ); + break; + + case imm_UnderlineThickness: + info->underline_thickness = (FT_Short)CopyInteger( parser ); + break; + + default: + /* ignore all other things */ + parser->error = T1_Err_Ok; + } + + return parser->error; + } + + + /*************************************************************************/ + /* */ + /* */ + /* Do_Def_Private */ + /* */ + /* */ + /* This function performs a `def' if in the Private dictionary. Its */ + /* purpose is to build the T1_Private structure directly from the */ + /* stream. */ + /* */ + /* */ + /* parser :: A handle to the current parser. */ + /* */ + /* */ + /* FreeTyoe error code. 0 means success. */ + /* */ + static + FT_Error Do_Def_Private( T1_Parser* parser ) + { + T1_Token* top = parser->top; + T1_Private* priv = &parser->face->type1.private_dict; + + + switch ( top[0].kind2 ) + { + /* Ignore the definitions of RD, NP, ND, and their alternate forms */ + case imm_RD: + case imm_RD_alternate: + case imm_ND: + case imm_ND_alternate: + case imm_NP: + case imm_NP_alternate: + parser->error = T1_Err_Ok; + break; + + case imm_BlueValues: + CopyArray( parser, &priv->num_blue_values, + priv->blue_values, 14 ); + break; + + case imm_OtherBlues: + CopyArray( parser, &priv->num_other_blues, + priv->other_blues, 10 ); + break; + + case imm_FamilyBlues: + CopyArray( parser, &priv->num_family_blues, + priv->family_blues, 14 ); + break; + + case imm_FamilyOtherBlues: + CopyArray( parser, &priv->num_family_other_blues, + priv->family_other_blues, 10 ); + break; + + case imm_BlueScale: + priv->blue_scale = CopyFloat( parser, 0x10000L ); + break; + + case imm_BlueShift: + priv->blue_shift = CopyInteger( parser ); + break; + + case imm_BlueFuzz: + priv->blue_fuzz = CopyInteger( parser ); + break; + + case imm_StdHW: + CopyArray( parser, 0, (FT_Short*)&priv->standard_width, 1 ); + break; + + case imm_StdVW: + CopyArray( parser, 0, (FT_Short*)&priv->standard_height, 1 ); + break; + + case imm_StemSnapH: + CopyArray( parser, &priv->num_snap_widths, + priv->snap_widths, 12 ); + break; + + case imm_StemSnapV: + CopyArray( parser, &priv->num_snap_heights, + priv->snap_heights, 12 ); + break; + + case imm_ForceBold: + priv->force_bold = CopyBoolean( parser ); + break; + + case imm_LanguageGroup: + priv->language_group = CopyInteger( parser ); + break; + + case imm_password: + priv->password = CopyInteger( parser ); + break; + + case imm_UniqueID: + priv->unique_id = CopyInteger( parser ); + break; + + case imm_lenIV: + priv->lenIV = CopyInteger( parser ); + break; + + case imm_MinFeature: + CopyArray( parser, 0, priv->min_feature, 2 ); + break; + + default: + /* ignore all other things */ + parser->error = T1_Err_Ok; + } + + return parser->error; + } + + + /*************************************************************************/ + /* */ + /* */ + /* Do_Def_Error */ + /* */ + /* */ + /* This function returns a simple syntax error when invoked. It is */ + /* used for the `def' keyword if in the `encoding', `subrs', */ + /* `othersubrs', and `charstrings' dictionary states. */ + /* */ + /* */ + /* parser :: A handle to the current parser. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + static + FT_Error Do_Def_Error( T1_Parser* parser ) + { + FT_ERROR(( "Do_Def_Error:" )); + FT_ERROR(( " `def' keyword encountered in bad dictionary/array\n" )); + + parser->error = T1_Err_Syntax_Error; + + return parser->error; + } + + + static + FT_Error Do_Def_Ignore( T1_Parser* parser ) + { + FT_UNUSED( parser ); + return T1_Err_Ok; + } + + + static + T1_Parse_Func def_funcs[dict_max] = + { + Do_Def_Error, + Do_Def_Font, + Do_Def_FontInfo, + Do_Def_Ignore, + Do_Def_Private, + Do_Def_Ignore, + Do_Def_Ignore, + Do_Def_Ignore, + Do_Def_Ignore, + Do_Def_Ignore, + Do_Def_Ignore, + }; + + + /*************************************************************************/ + /* */ + /* */ + /* IMPLEMENTATION OF THE `PUT' KEYWORD DEPENDING ON */ + /* CURRENT DICTIONARY STATE */ + /* */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* */ + /* Do_Put_Encoding */ + /* */ + /* */ + /* This function performs a `put' if in the Encoding array. The */ + /* glyph name is copied into the T1 recorder, and the charcode and */ + /* glyph name pointer are written into the face object encoding. */ + /* */ + /* */ + /* parser :: A handle to the current parser. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + static + FT_Error Do_Put_Encoding( T1_Parser* parser ) + { + FT_Error error = T1_Err_Ok; + T1_Face face = parser->face; + T1_Token* top = parser->top; + T1_Encoding* encode = &face->type1.encoding; + FT_Int index; + + + /* record and check the character code */ + if ( top[0].kind != tok_number ) + { + FT_TRACE4(( "Do_Put_Encoding: number expected\n" )); + goto Syntax_Error; + } + index = (FT_Int)CopyInteger( parser ); + if ( parser->error ) + return parser->error; + + if ( index < 0 || index >= encode->num_chars ) + { + FT_TRACE4(( "Do_Put_Encoding: invalid character code\n" )); + goto Syntax_Error; + } + + /* record the immediate name */ + if ( top[1].kind != tok_immediate ) + { + FT_TRACE4(( "Do_Put_Encoding: immediate name expected\n" )); + goto Syntax_Error; + } + + /* if the glyph name is `.notdef', store a NULL char name; */ + /* otherwise, record the glyph name */ + if ( top[1].kind == imm_notdef ) + { + parser->table.elements[index] = 0; + parser->table.lengths [index] = 0; + } + else + { + FT_String temp_name[128]; + T1_Token* token = top + 1; + FT_Int len = token->len - 1; + + + /* copy immediate name */ + if ( len > 127 ) + len = 127; + MEM_Copy( temp_name, parser->tokenizer->base + token->start + 1, len ); + temp_name[len] = '\0'; + + error = T1_Add_Table( &parser->table, index, + (FT_Byte*)temp_name, len + 1 ); + + /* adjust code_first and code_last */ + if ( index < encode->code_first ) encode->code_first = index; + if ( index > encode->code_last ) encode->code_last = index; + } + return error; + + Syntax_Error: + /* ignore the error, and simply clear the stack */ + FT_TRACE4(( "Do_Put_Encoding: invalid syntax encountered\n" )); + parser->top = parser->stack; + + return T1_Err_Ok; + } + + + /*************************************************************************/ + /* */ + /* */ + /* IMPLEMENTATION OF THE "RD" KEYWORD DEPENDING ON */ + /* CURRENT DICTIONARY STATE */ + /* */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* */ + /* Do_RD_Subrs */ + /* */ + /* */ + /* This function performs an `RD' if in the Subrs dictionary. It */ + /* simply records the array of bytecodes/charstrings corresponding to */ + /* the sub-routine. */ + /* */ + /* */ + /* parser :: A handle to the current parser. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + static + FT_Error Do_RD_Subrs( T1_Parser* parser ) + { + FT_Error error = T1_Err_Ok; + T1_Face face = parser->face; + T1_Token* top = parser->top; + T1_Tokenizer tokzer = parser->tokenizer; + FT_Int index, count; + + + /* record and check the character code */ + if ( top[0].kind != tok_number || + top[1].kind != tok_number ) + { + FT_ERROR(( "Do_RD_Subrs: number expected\n" )); + goto Syntax_Error; + } + index = (FT_Int)CopyInteger( parser ); + error = parser->error; + if ( error ) + goto Exit; + + count = (FT_Int)CopyInteger( parser ); + error = parser->error; + if ( error ) + goto Exit; + + if ( index < 0 || index >= face->type1.num_subrs ) + { + FT_ERROR(( "Do_RD_Subrs: invalid character code\n" )); + goto Syntax_Error; + } + + /* decrypt charstring and skip it */ + { + FT_Byte* base = tokzer->base + tokzer->cursor; + + + tokzer->cursor += count; + + /* some fonts use a value of -1 for lenIV to indicate that */ + /* the charstrings are unencoded. */ + /* */ + /* Thanks to Tom Kacvinsky for pointing this out. */ + /* */ + if ( face->type1.private_dict.lenIV >= 0 ) + { + t1_decrypt( base, count, 4330 ); + + base += face->type1.private_dict.lenIV; + count -= face->type1.private_dict.lenIV; + } + + error = T1_Add_Table( &parser->table, index, base, count ); + } + + /* consume the closing NP or `put' */ + error = Expect_Keyword2( parser, key_NP, key_put ); + + Exit: + return error; + + Syntax_Error: + return T1_Err_Syntax_Error; + } + + + /*************************************************************************/ + /* */ + /* */ + /* Do_RD_CharStrings */ + /* */ + /* */ + /* This function performs an `RD' if in the CharStrings dictionary. */ + /* It simply records the array of bytecodes/charstrings corresponding */ + /* to the glyph program string. */ + /* */ + /* */ + /* parser :: A handle to the current parser. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + static + FT_Error Do_RD_Charstrings( T1_Parser* parser ) + { + FT_Error error = T1_Err_Ok; + T1_Face face = parser->face; + T1_Token* top = parser->top; + T1_Tokenizer tokzer = parser->tokenizer; + FT_Int index, count; + + + /* check the character name argument */ + if ( top[0].kind != tok_immediate ) + { + FT_ERROR(( "Do_RD_Charstrings: immediate character name expected\n" )); + goto Syntax_Error; + } + + /* check the count argument */ + if ( top[1].kind != tok_number ) + { + FT_ERROR(( "Do_RD_Charstrings: number expected\n" )); + goto Syntax_Error; + } + + parser->args++; + count = (FT_Int)CopyInteger( parser ); + error = parser->error; + if ( error ) + goto Exit; + + /* record the glyph name and get the corresponding glyph index */ + if ( top[0].kind2 == imm_notdef ) + index = 0; + else + { + FT_String temp_name[128]; + T1_Token* token = top; + FT_Int len = token->len - 1; + + + /* copy immediate name */ + if ( len > 127 ) + len = 127; + MEM_Copy( temp_name, parser->tokenizer->base + token->start + 1, len ); + temp_name[len] = '\0'; + + index = parser->cur_name++; + error = T1_Add_Table( &parser->table, index * 2, + (FT_Byte*)temp_name, len + 1 ); + if ( error ) + goto Exit; + } + + /* decrypt and record charstring, then skip them */ + { + FT_Byte* base = tokzer->base + tokzer->cursor; + + + tokzer->cursor += count; /* skip */ + + if ( face->type1.private_dict.lenIV >= 0 ) + { + t1_decrypt( base, count, 4330 ); + + base += face->type1.private_dict.lenIV; + count -= face->type1.private_dict.lenIV; + } + + error = T1_Add_Table( &parser->table, index * 2 + 1, base, count ); + } + + /* consume the closing `ND' */ + if ( !error ) + error = Expect_Keyword( parser, key_ND ); + + Exit: + return error; + + Syntax_Error: + return T1_Err_Syntax_Error; + } + + + static + FT_Error Expect_Dict_Arguments( T1_Parser* parser, + FT_Int num_args, + T1_TokenType immediate, + T1_DictState new_state, + FT_Int* count ) + { + /* check that we have enough arguments in the stack, including */ + /* the `dict' keyword */ + if ( parser->top - parser->stack < num_args ) + { + FT_ERROR(( "Expect_Dict_Arguments: expecting at least %d arguments", + num_args )); + goto Syntax_Error; + } + + /* check that we have the correct immediate, if needed */ + if ( num_args == 2 ) + { + if ( parser->top[-2].kind != tok_immediate || + parser->top[-2].kind2 != immediate ) + { + FT_ERROR(( "Expect_Dict_Arguments: expecting `/%s' dictionary\n", + t1_immediates[immediate - imm_first_] )); + goto Syntax_Error; + } + } + + parser->args = parser->top-1; + + /* check that the count argument is a number */ + if ( parser->args->kind != tok_number ) + { + FT_ERROR(( "Expect_Dict_Arguments:" )); + FT_ERROR(( " expecting numerical count argument for `dict'\n" )); + goto Syntax_Error; + } + + if ( count ) + { + *count = CopyInteger( parser ); + if ( parser->error ) + return parser->error; + } + + /* save the dictionary state */ + parser->state_stack[++parser->state_index] = new_state; + + /* consume the `begin' keyword and clear the stack */ + parser->top -= num_args; + return Expect_Keyword( parser, key_begin ); + + Syntax_Error: + return T1_Err_Syntax_Error; + } + + + static + FT_Error Expect_Array_Arguments( T1_Parser* parser ) + { + T1_Token* top = parser->top; + FT_Error error = T1_Err_Ok; + T1_DictState new_state; + FT_Int count; + T1_Face face = parser->face; + FT_Memory memory = face->root.memory; + + + /* Check arguments format */ + if ( top - parser->stack < 2 ) + { + FT_ERROR(( "Expect_Array_Arguments: two arguments expected\n" )); + error = T1_Err_Stack_Underflow; + goto Exit; + } + + parser->top -= 2; + top -= 2; + parser->args = top + 1; + + if ( top[0].kind != tok_immediate ) + { + FT_ERROR(( "Expect_Array_Arguments:" )); + FT_ERROR(( " first argument must be an immediate name\n" )); + goto Syntax_Error; + } + + if ( top[1].kind != tok_number ) + { + FT_ERROR(( "Expect_Array_Arguments:" )); + FT_ERROR(( " second argument must be a number\n" )); + goto Syntax_Error; + } + + count = (FT_Int)CopyInteger( parser ); + + /* Is this an array we know about? */ + switch ( top[0].kind2 ) + { + case imm_Encoding: + { + T1_Encoding* encode = &face->type1.encoding; + + + new_state = dict_encoding; + + encode->code_first = count; + encode->code_last = 0; + encode->num_chars = count; + + /* Allocate the table of character indices. The table of */ + /* character names is allocated through init_t1_recorder(). */ + if ( ALLOC_ARRAY( encode->char_index, count, FT_Short ) ) + return error; + + error = T1_New_Table( &parser->table, count, memory ); + if ( error ) + goto Exit; + + parser->encoding_type = t1_encoding_array; + } + break; + + case imm_Subrs: + new_state = dict_subrs; + face->type1.num_subrs = count; + + error = T1_New_Table( &parser->table, count, memory ); + if ( error ) + goto Exit; + break; + + case imm_CharStrings: + new_state = dict_charstrings; + break; + + default: + new_state = dict_unknown_array; + } + + parser->state_stack[++parser->state_index] = new_state; + + Exit: + return error; + + Syntax_Error: + return T1_Err_Syntax_Error; + } + + + static + FT_Error Finalize_Parsing( T1_Parser* parser ) + { + T1_Face face = parser->face; + T1_Font* type1 = &face->type1; + FT_Memory memory = face->root.memory; + T1_Table* strings = &parser->table; + PSNames_Interface* psnames = (PSNames_Interface*)face->psnames; + + FT_Int num_glyphs; + FT_Int n; + FT_Error error; + + + num_glyphs = type1->num_glyphs = parser->cur_name; + + /* allocate glyph names and charstrings arrays */ + if ( ALLOC_ARRAY( type1->glyph_names, num_glyphs, FT_String* ) || + ALLOC_ARRAY( type1->charstrings, num_glyphs, FT_Byte* ) || + ALLOC_ARRAY( type1->charstrings_len, num_glyphs, FT_Int* ) ) + return error; + + /* copy glyph names and charstrings offsets and lengths */ + type1->charstrings_block = strings->block; + for ( n = 0; n < num_glyphs; n++ ) + { + type1->glyph_names[n] = (FT_String*)strings->elements[2 * n]; + type1->charstrings[n] = strings->elements[2 * n + 1]; + type1->charstrings_len[n] = strings->lengths [2 * n + 1]; + } + + /* now free the old tables */ + FREE( strings->elements ); + FREE( strings->lengths ); + + if ( !psnames ) + { + FT_ERROR(( "Finalize_Parsing: `PSNames' module missing!\n" )); + return T1_Err_Unimplemented_Feature; + } + + /* compute encoding if required */ + if ( parser->encoding_type == t1_encoding_none ) + { + FT_ERROR(( "Finalize_Parsing: no encoding specified in font file\n" )); + return T1_Err_Syntax_Error; + } + + { + FT_Int n; + T1_Encoding* encode = &type1->encoding; + + + encode->code_first = encode->num_chars - 1; + encode->code_last = 0; + + for ( n = 0; n < encode->num_chars; n++ ) + { + FT_String** names; + FT_Int index; + FT_Int m; + + + switch ( parser->encoding_type ) + { + case t1_encoding_standard: + index = psnames->adobe_std_encoding[n]; + names = 0; + break; + + case t1_encoding_expert: + index = psnames->adobe_expert_encoding[n]; + names = 0; + break; + + default: + index = n; + names = (FT_String**)parser->encoding_offsets; + } + + encode->char_index[n] = 0; + + if ( index ) + { + FT_String* name; + + + if ( names ) + name = names[index]; + else + name = (FT_String*)psnames->adobe_std_strings(index); + + if ( name ) + { + FT_Int len = strlen( name ); + + + /* lookup glyph index from name */ + for ( m = 0; m < num_glyphs; m++ ) + { + if ( strncmp( type1->glyph_names[m], name, len ) == 0 ) + { + encode->char_index[n] = m; + break; + } + } + + if ( n < encode->code_first ) encode->code_first = n; + if ( n > encode->code_last ) encode->code_last = n; + } + } + } + + parser->encoding_type = t1_encoding_none; + + FREE( parser->encoding_names ); + FREE( parser->encoding_lengths ); + FREE( parser->encoding_offsets ); + } + + return T1_Err_Ok; + } + + + /*************************************************************************/ + /* */ + /* */ + /* Parse_T1_FontProgram */ + /* */ + /* */ + /* Parses a given Type 1 font file and builds its face object. */ + /* */ + /* */ + /* parser :: A handle to the target parser object. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* The parser contains a handle to the target face object. */ + /* */ + LOCAL_FUNC + FT_Error Parse_T1_FontProgram( T1_Parser* parser ) + { + FT_Error error; + T1_Font* type1 = &parser->face->type1; + + + for (;;) + { + T1_Token token; + T1_Token* top; + T1_DictState dict_state; + FT_Int dict_index; + + + error = Next_T1_Token( parser, &token ); + top = parser->top; + dict_index = parser->state_index; + dict_state = parser->state_stack[dict_index]; + + switch ( token.kind ) + { + /* a keyword has been detected */ + case tok_keyword: + switch ( token.kind2 ) + { + case key_dict: + switch ( dict_state ) + { + case dict_none: + /* All right, we are beginning the font dictionary. */ + /* Check that we only have one number argument, then */ + /* consume the `begin' and change to `dict_font' */ + /* state. */ + error = Expect_Dict_Arguments( parser, 1, tok_error, + dict_font, 0 ); + if ( error ) + goto Exit; + + /* clear stack from all the previous content. This */ + /* could be some stupid Postscript code. */ + parser->top = parser->stack; + break; + + case dict_font: + /* This must be the /FontInfo dictionary, so check */ + /* that we have at least two arguments, that they */ + /* are `/FontInfo' and a number, then change the */ + /* dictionary state. */ + error = Expect_Dict_Arguments( parser, 2, imm_FontInfo, + dict_fontinfo, 0 ); + if ( error ) + goto Exit; + break; + + case dict_none2: + error = Expect_Dict_Arguments( parser, 2, imm_Private, + dict_private, 0 ); + if ( error ) + goto Exit; + break; + + case dict_private: + { + T1_Face face = parser->face; + FT_Int count; + + + error = Expect_Dict_Arguments( parser, 2, imm_CharStrings, + dict_charstrings, &count ); + if ( error ) + goto Exit; + + type1->num_glyphs = count; + error = T1_New_Table( &parser->table, count * 2, + face->root.memory ); + if ( error ) + goto Exit; + + /* record `.notdef' as the first glyph in the font */ + error = T1_Add_Table( &parser->table, 0, + (FT_Byte*)".notdef", 8 ); + parser->cur_name = 1; + /* XXX: DO SOMETHING HERE */ + } + break; + + default: + /* All other uses are invalid */ + FT_ERROR(( "Parse_T1_FontProgram:" )); + FT_ERROR(( " invalid use of `dict' keyword\n" )); + goto Syntax_Error; + } + break; + + case key_array: + /* Are we in an array yet? If so, raise an error */ + switch ( dict_state ) + { + case dict_encoding: + case dict_subrs: + case dict_othersubrs: + case dict_charstrings: + case dict_unknown_array: + FT_ERROR(( "Parse_T1_FontProgram: nested array definitions\n" )); + goto Syntax_Error; + + default: + ; + } + error = Expect_Array_Arguments( parser ); + if ( error ) + goto Exit; + break; + + case key_ND: + case key_NP: + case key_def: + /* Are we in an array? If so, finalize it. */ + switch ( dict_state ) + { + case dict_encoding: /* finish encoding array */ + /* copy table names to the face object */ + T1_Done_Table( &parser->table ); + + parser->encoding_names = parser->table.block; + parser->encoding_lengths = parser->table.lengths; + parser->encoding_offsets = parser->table.elements; + + parser->state_index--; + break; + + case dict_subrs: + /* copy recorder sub-routines */ + T1_Done_Table( &parser->table ); + + parser->subrs = parser->table.block; + type1->subrs = parser->table.elements; + type1->subrs_len = parser->table.lengths; + type1->subrs_block = parser->table.block; + + parser->state_index--; + break; + + case dict_charstrings: + case dict_othersubrs: + case dict_unknown_array: + FT_ERROR(( "Parse_T1_FontProgram: unsupported array\n" )); + goto Syntax_Error; + break; + + default: /* normal `def' processing */ + /* Check that we have sufficient operands in the stack */ + if ( top >= parser->stack + 2 ) + { + /* Now check that the first operand is an immediate. */ + /* If so, call the appropriate `def' routine based */ + /* on the current parser state. */ + if ( top[-2].kind == tok_immediate ) + { + parser->top -= 2; + parser->args = parser->top + 1; + error = def_funcs[dict_state](parser); + } + else + { + /* This is an error, but some fonts contain */ + /* stupid Postscript code. We simply ignore */ + /* an invalid `def' by clearing the stack. */ +#if 0 + FT_ERROR(( "Parse_T1_FontProgram: immediate expected\n" )); + goto Syntax_Error; +#else + parser->top = parser->stack; +#endif + } + } + else + { + FT_ERROR(( "Parse_T1_FontProgram: not enough arguments\n" )); + goto Stack_Underflow; + } + } + break; + + case key_index: + if ( top <= parser->stack ) + { + FT_ERROR(( "Parse_T1_FontProgram: not enough arguments\n" )); + goto Stack_Underflow; + } + + /* simply ignore? */ + parser->top --; + break; + + case key_put: + /* Check that we have sufficient operands in stack */ + if ( top < parser->stack + 2 ) + { + FT_ERROR(( "Parse_T1_FontProgram: not enough arguments\n" )); + goto Stack_Underflow; + } + + parser->top -= 2; + parser->args = parser->top; + + switch ( dict_state ) + { + case dict_encoding: + error = Do_Put_Encoding( parser ); + if ( error ) + goto Exit; + break; + + case dict_unknown_array: /* ignore the `put' */ + break; + + default: +#if 0 + FT_ERROR(( "Parse_T1_FontProgram: invalid context\n" )); + goto Syntax_Error; +#else + /* invalid context; simply ignore the `put' and */ + /* clear the stack (stupid Postscript code) */ + FT_TRACE4(( "Parse_T1_FontProgram: invalid context ignored.\n" )); + parser->top = parser->stack; +#endif + } + break; + + case key_RD: + /* Check that we have sufficient operands in stack */ + if ( top < parser->stack + 2 ) + { + FT_ERROR(( "Parse_T1_FontProgram: not enough arguments\n" )); + goto Stack_Underflow; + } + + parser->top -= 2; + parser->args = parser->top; + switch ( dict_state ) + { + case dict_subrs: + error = Do_RD_Subrs( parser ); + if ( error ) + goto Exit; + break; + + case dict_charstrings: + error = Do_RD_Charstrings( parser ); + if ( error ) + goto Exit; + break; + + default: + FT_ERROR(( "Parse_T1_FontProgram: invalid context\n" )); + goto Syntax_Error; + } + break; + + case key_end: + /* Were we in a dictionary or in an array? */ + if ( dict_index <= 0 ) + { + FT_ERROR(( "Parse_T1_FontProgram: no dictionary defined\n" )); + goto Syntax_Error; + } + + switch ( dict_state ) + { + /* jump to the private dictionary if we are closing the */ + /* `/Font' dictionary */ + case dict_font: + goto Open_Private; + + /* exit the parser when closing the CharStrings dictionary */ + case dict_charstrings: + return Finalize_Parsing( parser ); + + default: + /* Pop the current dictionary state and return to previous */ + /* one. Consume the `def'. */ + + /* Because some buggy fonts (BitStream) have incorrect */ + /* syntax, we never escape from the private dictionary */ + if ( dict_state != dict_private ) + parser->state_index--; + + /* many fonts use `NP' instead of `def' or `put', so */ + /* we simply ignore the next token */ +#if 0 + error = Expect_Keyword2( parser, key_def, key_put ); + if ( error ) + goto Exit; +#else + (void)Expect_Keyword2( parser, key_def, key_put ); +#endif + } + break; + + case key_for: + /* check that we have four arguments and simply */ + /* ignore them */ + if ( top - parser->stack < 4 ) + { + FT_ERROR(( "Parse_T1_FontProgram: not enough arguments\n" )); + goto Stack_Underflow; + } + + parser->top -= 4; + break; + + case key_currentdict: + Open_Private: + parser->state_index = 0; + parser->state_stack[0] = dict_none2; + error = Open_PrivateDict( parser->tokenizer ); + if ( error ) + goto Exit; + break; + + case key_true: + case key_false: + case key_StandardEncoding: + case key_ExpertEncoding: + goto Push_Element; + + default: + FT_ERROR(( "Parse_T1_FontProgram:" )); + FT_ERROR(( " invalid keyword in context\n" )); + error = T1_Err_Syntax_Error; + } + break; + + /* check for the presence of `/BlendAxisTypes' -- we cannot deal */ + /* with multiple master fonts, so we must return a correct error */ + /* code to allow another driver to load them */ + case tok_immediate: + if ( token.kind2 == imm_BlendAxisTypes ) + { + error = FT_Err_Unknown_File_Format; + goto Exit; + } + /* fallthrough */ + + /* A number was detected */ + case tok_string: + case tok_program: + case tok_array: + case tok_hexarray: + case tok_any: + case tok_number: /* push number on stack */ + + Push_Element: + if ( top >= parser->limit ) + { + error = T1_Err_Stack_Overflow; + goto Exit; + } + else + *parser->top++ = token; + break; + + /* anything else is an error per se the spec, but we */ + /* frequently encounter stupid postscript code in fonts, */ + /* so just ignore them */ + default: + error = T1_Err_Ok; /* ignore token */ + } + + if ( error ) + return error; + } + + Exit: + return error; + + Syntax_Error: + return T1_Err_Syntax_Error; + + Stack_Underflow: + return T1_Err_Stack_Underflow; + } + + +/* END */ diff --git a/src/freetype/type1/t1load.h b/src/freetype/type1/t1load.h new file mode 100644 index 0000000000..d278374f0f --- /dev/null +++ b/src/freetype/type1/t1load.h @@ -0,0 +1,57 @@ +/***************************************************************************/ +/* */ +/* t1load.h */ +/* */ +/* Type 1 font loader (specification). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef T1LOAD_H +#define T1LOAD_H + +#include + + +#ifdef FT_FLAT_COMPILE + +#include "t1parse.h" + +#else + +#include + +#endif + + +#ifdef __cplusplus + extern "C" { +#endif + + LOCAL_DEF + void Init_T1_Parser( T1_Parser* parser, + T1_Face face, + T1_Tokenizer tokenizer ); + + + LOCAL_DEF + FT_Error Parse_T1_FontProgram( T1_Parser* parser ); + + +#ifdef __cplusplus + } +#endif + +#endif /* T1LOAD_H */ + + +/* END */ diff --git a/src/freetype/type1/t1objs.c b/src/freetype/type1/t1objs.c new file mode 100644 index 0000000000..1e6f9ca2a3 --- /dev/null +++ b/src/freetype/type1/t1objs.c @@ -0,0 +1,544 @@ +/***************************************************************************/ +/* */ +/* t1objs.c */ +/* */ +/* Type 1 objects manager (body). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#include +#include + + +#ifdef FT_FLAT_COMPILE + +#include "t1gload.h" +#include "t1load.h" +#include "t1afm.h" + +#ifndef T1_CONFIG_OPTION_DISABLE_HINTER +#include "t1hinter.h" +#endif + +#else /* FT_FLAT_COMPILE */ + +#include +#include +#include + +#ifndef T1_CONFIG_OPTION_DISABLE_HINTER +#include +#endif + +#endif /* FT_FLAT_COMPILE */ + + +#include + + + /*************************************************************************/ + /* */ + /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ + /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ + /* messages during execution. */ + /* */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_t1objs + + + /*************************************************************************/ + /* */ + /* SIZE FUNCTIONS */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* */ + /* T1_Done_Size */ + /* */ + /* */ + /* The Type 1 size object destructor. Used to discard a given size */ + /* object. */ + /* */ + /* */ + /* size :: A handle to the target size object. */ + /* */ + LOCAL_FUNC + void T1_Done_Size( T1_Size size ) + { + if ( size ) + { + +#ifndef T1_CONFIG_OPTION_DISABLE_HINTER + T1_Done_Size_Hinter( size ); +#endif + + size->valid = 0; + } + } + + + /*************************************************************************/ + /* */ + /* */ + /* T1_Init_Size */ + /* */ + /* */ + /* The size object initializer. */ + /* */ + /* */ + /* size :: A handle to the target size object. */ + /* */ + /* */ + /* FreeTrue error code. 0 means success. */ + /* */ + LOCAL_DEF + FT_Error T1_Init_Size( T1_Size size ) + { + FT_Error error; + + + size->valid = 0; + +#ifndef T1_CONFIG_OPTION_DISABLE_HINTER + error = T1_New_Size_Hinter( size ); + + return error; +#else + + FT_UNUSED( error ); + + return T1_Err_Ok; + +#endif + } + + + /*************************************************************************/ + /* */ + /* */ + /* T1_Reset_Size */ + /* */ + /* */ + /* Resets an instance to a new pointsize/transform. This function is */ + /* in charge of resetting the blue zones,a s well as the stem snap */ + /* tables for a given size. */ + /* */ + /* */ + /* size :: The target size object. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + LOCAL_FUNC + FT_Error T1_Reset_Size( T1_Size size ) + { + /* recompute ascender, descender, etc. */ + T1_Face face = (T1_Face)size->root.face; + FT_Size_Metrics* metrics = &size->root.metrics; + + + if ( metrics->x_ppem < 1 || metrics->y_ppem < 1 ) + return FT_Err_Invalid_Argument; + + /* Compute root ascender, descender, test height, and max_advance */ + metrics->ascender = ( FT_MulFix( face->root.ascender, + metrics->y_scale ) + 32 ) & -64; + metrics->descender = ( FT_MulFix( face->root.descender, + metrics->y_scale ) + 32 ) & -64; + metrics->height = ( FT_MulFix( face->root.height, + metrics->y_scale ) + 32 ) & -64; + metrics->max_advance = ( FT_MulFix( face->root.max_advance_width, + metrics->x_scale ) + 32 ) & -64; + +#ifndef T1_CONFIG_OPTION_DISABLE_HINTER + return T1_Reset_Size_Hinter( size ); +#else + return 0; +#endif + } + + + /*************************************************************************/ + /* */ + /* FACE FUNCTIONS */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* */ + /* T1_Done_Face */ + /* */ + /* */ + /* The face object destructor. */ + /* */ + /* */ + /* face :: A typeless pointer to the face object to destroy. */ + /* */ + LOCAL_FUNC + void T1_Done_Face( T1_Face face ) + { + FT_Memory memory; + T1_Font* type1 = &face->type1; + + + if ( face ) + { + memory = face->root.memory; + + /* release font info strings */ + { + T1_FontInfo* info = &type1->font_info; + + + FREE( info->version ); + FREE( info->notice ); + FREE( info->full_name ); + FREE( info->family_name ); + FREE( info->weight ); + } + + /* release top dictionary */ + FREE( type1->charstrings_len ); + FREE( type1->charstrings ); + FREE( type1->glyph_names ); + + FREE( type1->subrs ); + FREE( type1->subrs_len ); + + FREE( type1->subrs_block ); + FREE( type1->charstrings_block ); + FREE( type1->glyph_names_block ); + + FREE( type1->encoding.char_index ); + FREE( type1->font_name ); + +#ifndef T1_CONFIG_OPTION_NO_AFM + /* release afm data if present */ + if ( face->afm_data ) + T1_Done_AFM( memory, (T1_AFM*)face->afm_data ); +#endif + + /* release unicode map, if any */ + FREE( face->unicode_map.maps ); + face->unicode_map.num_maps = 0; + + face->root.family_name = 0; + face->root.style_name = 0; + } + } + + + /*************************************************************************/ + /* */ + /* */ + /* T1_Init_Face */ + /* */ + /* */ + /* The face object constructor. */ + /* */ + /* */ + /* stream :: input stream where to load font data. */ + /* */ + /* face_index :: The index of the font face in the resource. */ + /* */ + /* num_params :: Number of additional generic parameters. Ignored. */ + /* */ + /* params :: Additional generic parameters. Ignored. */ + /* */ + /* */ + /* face :: The face record to build. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + LOCAL_FUNC + FT_Error T1_Init_Face( FT_Stream stream, + T1_Face face, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ) + { + T1_Tokenizer tokenizer; + FT_Error error; + PSNames_Interface* psnames; + + FT_UNUSED( num_params ); + FT_UNUSED( params ); + FT_UNUSED( face_index ); + FT_UNUSED( face ); + + + face->root.num_faces = 1; + + psnames = (PSNames_Interface*)face->psnames; + if ( !psnames ) + { + psnames = (PSNames_Interface*) + FT_Get_Module_Interface( FT_FACE_LIBRARY( face ), + "psnames" ); + + face->psnames = psnames; + } + + /* open the tokenizer, this will also check the font format */ + error = New_Tokenizer( stream, &tokenizer ); + if ( error ) + goto Fail; + + /* if we just wanted to check the format, leave successfully now */ + if ( face_index < 0 ) + goto Leave; + + /* check the face index */ + if ( face_index != 0 ) + { + FT_ERROR(( "T1_Init_Face: invalid face index\n" )); + error = T1_Err_Invalid_Argument; + goto Leave; + } + + /* Now, load the font program into the face object */ + { + T1_Parser parser; + + + Init_T1_Parser( &parser, face, tokenizer ); + error = Parse_T1_FontProgram( &parser ); + if ( error ) + goto Leave; + + /* Init the face object fields */ + /* Now set up root face fields */ + { + FT_Face root = (FT_Face)&face->root; + T1_Font* type1 = &face->type1; + + + root->num_glyphs = type1->num_glyphs; + root->num_charmaps = 1; + + root->face_index = face_index; + root->face_flags = FT_FACE_FLAG_SCALABLE; + + root->face_flags |= FT_FACE_FLAG_HORIZONTAL; + + root->face_flags |= FT_FACE_FLAG_GLYPH_NAMES; + + if ( type1->font_info.is_fixed_pitch ) + root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH; + + /* XXX: TODO -- add kerning with .afm support */ + + /* get style name - be careful, some broken fonts only */ + /* have a `/FontName' dictionary entry! */ + root->family_name = type1->font_info.family_name; + if ( root->family_name ) + { + char* full = type1->font_info.full_name; + char* family = root->family_name; + + + while ( *family && *full == *family ) + { + family++; + full++; + } + + root->style_name = ( *full == ' ' ? full + 1 + : (char *)"Regular" ); + } + else + { + /* do we have a `/FontName'? */ + if (type1->font_name) + { + root->family_name = type1->font_name; + root->style_name = "Regular"; + } + } + + /* no embedded bitmap support */ + root->num_fixed_sizes = 0; + root->available_sizes = 0; + + root->bbox = type1->font_bbox; + root->units_per_EM = 1000; + root->ascender = (FT_Short)type1->font_bbox.yMax; + root->descender = -(FT_Short)type1->font_bbox.yMin; + root->height = ( ( root->ascender + root->descender) * 12 ) + / 10; + + /* now compute the maximum advance width */ + + root->max_advance_width = type1->private_dict.standard_width[0]; + + /* compute max advance width for proportional fonts */ + if ( !type1->font_info.is_fixed_pitch ) + { + FT_Int max_advance; + + + error = T1_Compute_Max_Advance( face, &max_advance ); + + /* in case of error, keep the standard width */ + if ( !error ) + root->max_advance_width = max_advance; + else + error = 0; /* clear error */ + } + + root->max_advance_height = root->height; + + root->underline_position = type1->font_info.underline_position; + root->underline_thickness = type1->font_info.underline_thickness; + + root->max_points = 0; + root->max_contours = 0; + } + } + + /* charmap support - synthetize unicode charmap when possible */ + { + FT_Face root = &face->root; + FT_CharMap charmap = face->charmaprecs; + + + /* synthesize a Unicode charmap if there is support in the `PSNames' */ + /* module.. */ + if ( face->psnames ) + { + PSNames_Interface* psnames = (PSNames_Interface*)face->psnames; + + + if ( psnames->unicode_value ) + { + error = psnames->build_unicodes( + root->memory, + face->type1.num_glyphs, + (const char**)face->type1.glyph_names, + &face->unicode_map ); + if ( !error ) + { + root->charmap = charmap; + charmap->face = (FT_Face)face; + charmap->encoding = ft_encoding_unicode; + charmap->platform_id = 3; + charmap->encoding_id = 1; + charmap++; + } + + /* simply clear the error in case of failure (which really) */ + /* means that out of memory or no unicode glyph names */ + error = 0; + } + } + + /* now, support either the standard, expert, or custom encodings */ + charmap->face = (FT_Face)face; + charmap->platform_id = 7; /* a new platform id for Adobe fonts ?? */ + + switch ( face->type1.encoding_type ) + { + case t1_encoding_standard: + charmap->encoding = ft_encoding_adobe_standard; + charmap->encoding_id = 0; + break; + + case t1_encoding_expert: + charmap->encoding = ft_encoding_adobe_expert; + charmap->encoding_id = 1; + break; + + default: + charmap->encoding = ft_encoding_adobe_custom; + charmap->encoding_id = 2; + break; + } + + root->charmaps = face->charmaps; + root->num_charmaps = charmap - face->charmaprecs + 1; + face->charmaps[0] = &face->charmaprecs[0]; + face->charmaps[1] = &face->charmaprecs[1]; + } + + Leave: + Done_Tokenizer( tokenizer ); + + Fail: + return error; + } + + + /*************************************************************************/ + /* */ + /* */ + /* T1_Done_GlyphSlot */ + /* */ + /* */ + /* The glyph slot object destructor. */ + /* */ + /* */ + /* glyph :: The glyph slot handle to destroy. */ + /* */ + LOCAL_FUNC + void T1_Done_GlyphSlot( T1_GlyphSlot glyph ) + { +#ifndef T1_CONFIG_OPTION_DISABLE_HINTER + + T1_Done_Glyph_Hinter( glyph ); + +#else + + FT_UNUSED( glyph ); + +#endif + } + + + /*************************************************************************/ + /* */ + /* */ + /* T1_Init_GlyphSlot */ + /* */ + /* */ + /* The glyph slot object constructor. */ + /* */ + /* */ + /* glyph :: The glyph slot handle to initialize. */ + /* */ + LOCAL_FUNC + FT_Error T1_Init_GlyphSlot( T1_GlyphSlot glyph ) + { + FT_Error error = FT_Err_Ok; + + +#ifndef T1_CONFIG_OPTION_DISABLE_HINTER + + error = T1_New_Glyph_Hinter( glyph ); + +#else + + FT_UNUSED( glyph ); + +#endif + + return error; + } + + +/* END */ diff --git a/src/freetype/type1/t1objs.h b/src/freetype/type1/t1objs.h new file mode 100644 index 0000000000..47b0a37be1 --- /dev/null +++ b/src/freetype/type1/t1objs.h @@ -0,0 +1,172 @@ +/***************************************************************************/ +/* */ +/* t1objs.h */ +/* */ +/* Type 1 objects manager (specification). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef T1OBJS_H +#define T1OBJS_H + +#include +#include +#include + +#include + +#ifdef __cplusplus + extern "C" { +#endif + + + /* The following structures must be defined by the hinter */ + typedef struct T1_Size_Hints_ T1_Size_Hints; + typedef struct T1_Glyph_Hints_ T1_Glyph_Hints; + + + /*************************************************************************/ + /* */ + /* */ + /* T1_Driver */ + /* */ + /* */ + /* A handle to a Type 1 driver object. */ + /* */ + typedef struct T1_DriverRec_* T1_Driver; + + + /*************************************************************************/ + /* */ + /* */ + /* T1_Size */ + /* */ + /* */ + /* A handle to a Type 1 size object. */ + /* */ + typedef struct T1_SizeRec_* T1_Size; + + + /*************************************************************************/ + /* */ + /* */ + /* T1_GlyphSlot */ + /* */ + /* */ + /* A handle to a Type 1 glyph slot object. */ + /* */ + typedef struct T1_GlyphSlotRec_* T1_GlyphSlot; + + + /*************************************************************************/ + /* */ + /* */ + /* T1_CharMap */ + /* */ + /* */ + /* A handle to a Type 1 character mapping object. */ + /* */ + /* */ + /* The Type 1 format doesn't use a charmap but an encoding table. */ + /* The driver is responsible for making up charmap objects */ + /* corresponding to these tables. */ + /* */ + typedef struct T1_CharMapRec_* T1_CharMap; + + + /*************************************************************************/ + /* */ + /* HERE BEGINS THE TYPE1 SPECIFIC STUFF */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* */ + /* T1_SizeRec */ + /* */ + /* */ + /* Type 1 size record. */ + /* */ + typedef struct T1_SizeRec_ + { + FT_SizeRec root; + FT_Bool valid; + T1_Size_Hints* hints; /* defined in the hinter. This allows */ + /* us to experiment with different */ + /* hinting schemes without having to */ + /* change `t1objs' each time. */ + } T1_SizeRec; + + + /*************************************************************************/ + /* */ + /* */ + /* T1_GlyphSlotRec */ + /* */ + /* */ + /* Type 1 glyph slot record. */ + /* */ + typedef struct T1_GlyphSlotRec_ + { + FT_GlyphSlotRec root; + + FT_Bool hint; + FT_Bool scaled; + + FT_Int max_points; + FT_Int max_contours; + + FT_Fixed x_scale; + FT_Fixed y_scale; + + T1_Glyph_Hints* hints; /* defined in the hinter */ + + } T1_GlyphSlotRec; + + + LOCAL_DEF + FT_Error T1_Init_Face( FT_Stream stream, + T1_Face face, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ); + + LOCAL_DEF + void T1_Done_Face( T1_Face face ); + + LOCAL_DEF + FT_Error T1_Init_Size( T1_Size size ); + + LOCAL_DEF + void T1_Done_Size( T1_Size size ); + + LOCAL_DEF + FT_Error T1_Reset_Size( T1_Size size ); + + LOCAL_DEF + FT_Error T1_Init_GlyphSlot( T1_GlyphSlot slot ); + + LOCAL_DEF + void T1_Done_GlyphSlot( T1_GlyphSlot slot ); + + +#ifdef __cplusplus + } +#endif + +#endif /* T1OBJS_H */ + + +/* END */ diff --git a/src/freetype/type1/t1parse.c b/src/freetype/type1/t1parse.c new file mode 100644 index 0000000000..8b7ca25245 --- /dev/null +++ b/src/freetype/type1/t1parse.c @@ -0,0 +1,761 @@ +/***************************************************************************/ +/* */ +/* t1parse.c */ +/* */ +/* Type 1 parser (body). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#include +#include + + +#ifdef FT_FLAT_COMPILE + +#include "t1parse.h" + +#else + +#include + +#endif + + +#include /* for sscanf() */ +#include /* for strncpy() */ + + + /*************************************************************************/ + /* */ + /* */ + /* T1_New_Table */ + /* */ + /* */ + /* Initializes a T1_Table structure. */ + /* */ + /* */ + /* table :: The address of the target table. */ + /* */ + /* */ + /* count :: The table size (i.e. maximum number of elements). */ + /* memory :: The memory object to use for all subsequent */ + /* reallocations. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + LOCAL_FUNC + FT_Error T1_New_Table( T1_Table* table, + FT_Int count, + FT_Memory memory ) + { + FT_Error error; + + + table->memory = memory; + + if ( ALLOC_ARRAY( table->elements, count, FT_Byte* ) ) + return error; + + if ( ALLOC_ARRAY( table->lengths, count, FT_Byte* ) ) + { + FREE( table->elements ); + return error; + } + + table->max_elems = count; + table->num_elems = 0; + + table->block = 0; + table->capacity = 0; + table->cursor = 0; + + return error; + } + + + static + FT_Error reallocate_t1_table( T1_Table* table, + FT_Int new_size ) + { + FT_Memory memory = table->memory; + FT_Byte* old_base = table->block; + FT_Error error; + + + /* reallocate the base block */ + if ( REALLOC( table->block, table->capacity, new_size ) ) + return error; + table->capacity = new_size; + + /* shift all offsets if necessary */ + if ( old_base ) + { + FT_Long delta = table->block - old_base; + FT_Byte** offset = table->elements; + FT_Byte** limit = offset + table->max_elems; + + + if ( delta ) + for ( ; offset < limit; offset ++ ) + if (offset[0]) + offset[0] += delta; + } + + return T1_Err_Ok; + } + + + /*************************************************************************/ + /* */ + /* */ + /* T1_Add_Table */ + /* */ + /* */ + /* Adds an object to a T1_Table, possibly growing its memory block. */ + /* */ + /* */ + /* table :: The target table. */ + /* */ + /* */ + /* index :: The index of the object in the table. */ + /* */ + /* object :: The address of the object to copy in memory. */ + /* */ + /* length :: The length in bytes of the source object. */ + /* */ + /* */ + /* FreeType error code. 0 means success. An error is returned if a */ + /* reallocation failed. */ + /* */ + LOCAL_FUNC + FT_Error T1_Add_Table( T1_Table* table, + FT_Int index, + void* object, + FT_Int length ) + { + if ( index < 0 || index > table->max_elems ) + { + FT_ERROR(( "T1_Add_Table: invalid index\n" )); + return T1_Err_Syntax_Error; + } + + /* grow the base block if needed */ + if ( table->cursor + length > table->capacity ) + { + FT_Error error; + FT_Int new_size = table->capacity; + + + while ( new_size < table->cursor + length ) + new_size += 1024; + + error = reallocate_t1_table( table, new_size ); + if ( error ) + return error; + } + + /* add the object to the base block and adjust offset */ + table->elements[index] = table->block + table->cursor; + table->lengths [index] = length; + MEM_Copy( table->block + table->cursor, object, length ); + + table->cursor += length; + + return T1_Err_Ok; + } + + + /*************************************************************************/ + /* */ + /* */ + /* T1_Done_Table */ + /* */ + /* */ + /* Finalize a T1_Table (reallocate it to its current cursor). */ + /* */ + /* */ + /* table :: The target table. */ + /* */ + /* */ + /* This function does NOT release the heap's memory block. It is up */ + /* to the caller to clean it, or reference it in its own structures. */ + /* */ + LOCAL_FUNC + void T1_Done_Table( T1_Table* table ) + { + FT_Memory memory = table->memory; + FT_Error error; + FT_Byte* old_base; + + + /* should never fail, as rec.cursor <= rec.size */ + old_base = table->block; + if ( !old_base ) + return; + + (void)REALLOC( table->block, table->capacity, table->cursor ); + table->capacity = table->cursor; + + if ( old_base != table->block ) + { + FT_Long delta = table->block - old_base; + FT_Byte** element = table->elements; + FT_Byte** limit = element + table->max_elems; + + + for ( ; element < limit; element++ ) + if ( element[0] ) + element[0] += delta; + } + } + + + LOCAL_FUNC + FT_String* CopyString( T1_Parser* parser ) + { + FT_String* string = NULL; + T1_Token* token = parser->args++; + FT_Memory memory = parser->tokenizer->memory; + FT_Error error; + + + if ( token->kind == tok_string ) + { + FT_Int len = token->len - 2; + + + if ( ALLOC( string, len + 1 ) ) + { + parser->error = error; + return 0; + } + + MEM_Copy( string, parser->tokenizer->base + token->start + 1, len ); + string[len] = '\0'; + + parser->error = T1_Err_Ok; + } + else + { + FT_ERROR(( "T1_CopyString: syntax error, string token expected!\n" )); + parser->error = T1_Err_Syntax_Error; + } + + return string; + } + + + static + FT_Error parse_int( FT_Byte* base, + FT_Byte* limit, + FT_Long* result ) + { + FT_Bool sign = 0; + FT_Long sum = 0; + + + if ( base >= limit ) + goto Fail; + + /* check sign */ + if ( *base == '+' ) + base++; + + else if ( *base == '-' ) + { + sign++; + base++; + } + + /* parse digits */ + if ( base >= limit ) + goto Fail; + + do + { + sum = ( 10 * sum + ( *base++ - '0' ) ); + + } while ( base < limit ); + + if ( sign ) + sum = -sum; + + *result = sum; + return T1_Err_Ok; + + Fail: + FT_ERROR(( "parse_int: integer expected\n" )); + *result = 0; + return T1_Err_Syntax_Error; + } + + + static + FT_Error parse_float( FT_Byte* base, + FT_Byte* limit, + FT_Long scale, + FT_Long* result ) + { +#if 1 + + /* XXX: We are simply much too lazy to code this function */ + /* properly for now. We will do that when the rest of */ + /* the driver works properly. */ + char temp[32]; + int len = limit - base; + double value; + + + if ( len > 31 ) + goto Fail; + + strncpy( temp, (char*)base, len ); + temp[len] = '\0'; + if ( sscanf( temp, "%lf", &value ) != 1 ) + goto Fail; + + *result = (FT_Long)( scale * value ); + return 0; + +#else + + FT_Byte* cur; + FT_Bool sign = 0; /* sign */ + FT_Long number_int = 0; /* integer part */ + FT_Long number_frac = 0; /* fractional part */ + FT_Long exponent = 0; /* exponent value */ + FT_Int num_frac = 0; /* number of fractional digits */ + + + /* check sign */ + if ( *base == '+' ) + base++; + + else if ( *base == '-' ) + { + sign++; + base++; + } + + /* find integer part */ + cur = base; + while ( cur < limit ) + { + FT_Byte c = *cur; + + + if ( c == '.' || c == 'e' || c == 'E' ) + break; + + cur++; + } + + if ( cur > base ) + { + error = parse_integer( base, cur, &number_int ); + if ( error ) + goto Fail; + } + + /* read fractional part, if any */ + if ( *cur == '.' ) + { + cur++; + base = cur; + while ( cur < limit ) + { + FT_Byte c = *cur; + + + if ( c == 'e' || c == 'E' ) + break; + cur++; + } + + num_frac = cur - base; + + if ( cur > base ) + { + error = parse_integer( base, cur, &number_frac ); + if ( error ) + goto Fail; + base = cur; + } + } + + /* read exponent, if any */ + if ( *cur == 'e' || *cur == 'E' ) + { + cur++; + base = cur; + error = parse_integer( base, limit, &exponent ); + if ( error ) + goto Fail; + + /* now check that exponent is within `correct bounds' */ + /* i.e. between -6 and 6 */ + if ( exponent < -6 || exponent > 6 ) + goto Fail; + } + + /* now adjust integer value and exponent for fractional part */ + while ( num_frac > 0 ) + { + number_int *= 10; + exponent--; + num_frac--; + } + + number_int += num_frac; + + /* skip point if any, read fractional part */ + if ( cur + 1 < limit ) + { + if (*cur.. + } + + /* now compute scaled float value */ + /* XXX: incomplete! */ + +#endif /* 1 */ + + Fail: + FT_ERROR(( "parse_float: syntax error!\n" )); + return T1_Err_Syntax_Error; + } + + + static + FT_Error parse_integer( FT_Byte* base, + FT_Byte* limit, + FT_Long* result ) + { + FT_Byte* cur; + + + /* the lexical analyser accepts floats as well as integers */ + /* now; check that we really have an int in this token */ + cur = base; + while ( cur < limit ) + { + FT_Byte c = *cur++; + + + if ( c == '.' || c == 'e' || c == 'E' ) + goto Float_Number; + } + + /* now read the number's value */ + return parse_int( base, limit, result ); + + Float_Number: + /* we really have a float there; simply call parse_float in this */ + /* case with a scale of `10' to perform round */ + { + FT_Error error; + + + error = parse_float( base, limit, 10, result ); + if ( !error ) + { + if ( *result >= 0 ) + *result = ( *result + 5 ) / 10; /* round value */ + else + *result = -( ( 5 - *result ) / 10 ); + } + return error; + } + } + + + LOCAL_FUNC + FT_Long CopyInteger( T1_Parser* parser ) + { + FT_Long sum = 0; + T1_Token* token = parser->args++; + + + if ( token->kind == tok_number ) + { + FT_Byte* base = parser->tokenizer->base + token->start; + FT_Byte* limit = base + token->len; + + + /* now read the number's value */ + parser->error = parse_integer( base, limit, &sum ); + return sum; + } + + FT_ERROR(( "CopyInteger: number expected\n" )); + parser->args--; + parser->error = T1_Err_Syntax_Error; + return 0; + } + + + LOCAL_FUNC + FT_Bool CopyBoolean( T1_Parser* parser ) + { + FT_Error error = T1_Err_Ok; + FT_Bool result = 0; + T1_Token* token = parser->args++; + + + if ( token->kind == tok_keyword ) + { + if ( token->kind2 == key_false ) + result = 0; + + else if ( token->kind2 == key_true ) + result = !0; + + else + goto Fail; + } + else + { + Fail: + FT_ERROR(( "CopyBoolean:" )); + FT_ERROR(( " syntax error; `false' or `true' expected\n" )); + error = T1_Err_Syntax_Error; + } + parser->error = error; + return result; + } + + + LOCAL_FUNC + FT_Long CopyFloat( T1_Parser* parser, + FT_Int scale ) + { + FT_Error error; + FT_Long sum = 0; + T1_Token* token = parser->args++; + + + if ( token->kind == tok_number ) + { + FT_Byte* base = parser->tokenizer->base + token->start; + FT_Byte* limit = base + token->len; + + + error = parser->error = parse_float( base, limit, scale, &sum ); + if ( error ) + goto Fail; + + return sum; + } + + Fail: + FT_ERROR(( "CopyFloat: syntax error!\n" )); + parser->error = T1_Err_Syntax_Error; + return 0; + } + + + LOCAL_FUNC + void CopyBBox( T1_Parser* parser, + FT_BBox* bbox ) + { + T1_Token* token = parser->args++; + FT_Int n; + FT_Error error; + + + if ( token->kind == tok_program || + token->kind == tok_array ) + { + /* get rid of `['/`]', or `{'/`}' */ + FT_Byte* base = parser->tokenizer->base + token->start + 1; + FT_Byte* limit = base + token->len - 2; + FT_Byte* cur; + FT_Byte* start; + + + /* read each parameter independently */ + cur = base; + for ( n = 0; n < 4; n++ ) + { + FT_Long* result; + + + /* skip whitespace */ + while ( cur < limit && *cur == ' ' ) + cur++; + + /* skip numbers */ + start = cur; + while ( cur < limit && *cur != ' ' ) + cur++; + + /* compute result address */ + switch ( n ) + { + case 0: + result = &bbox->xMin; + break; + case 1: + result = &bbox->yMin; + break; + case 2: + result = &bbox->xMax; + break; + default: + result = &bbox->yMax; + } + + error = parse_integer( start, cur, result ); + if ( error ) + goto Fail; + } + parser->error = 0; + return; + } + + Fail: + FT_ERROR(( "CopyBBox: syntax error!\n" )); + parser->error = T1_Err_Syntax_Error; + } + + + LOCAL_FUNC + void CopyMatrix( T1_Parser* parser, + FT_Matrix* matrix ) + { + T1_Token* token = parser->args++; + FT_Error error; + + + if ( token->kind == tok_array ) + { + /* get rid of `[' and `]' */ + FT_Byte* base = parser->tokenizer->base + token->start + 1; + FT_Byte* limit = base + token->len - 2; + FT_Byte* cur; + FT_Byte* start; + FT_Int n; + + + /* read each parameter independently */ + cur = base; + for ( n = 0; n < 4; n++ ) + { + FT_Long* result; + + + /* skip whitespace */ + while ( cur < limit && *cur == ' ' ) + cur++; + + /* skip numbers */ + start = cur; + while ( cur < limit && *cur != ' ') + cur++; + + /* compute result address */ + switch ( n ) + { + case 0: + result = &matrix->xx; + break; + case 1: + result = &matrix->yx; + break; + case 2: + result = &matrix->xy; + break; + default: + result = &matrix->yy; + } + + error = parse_float( start, cur, 65536000L, result ); + if ( error ) + goto Fail; + } + parser->error = 0; + return; + } + + Fail: + FT_ERROR(( "CopyMatrix: syntax error!\n" )); + parser->error = T1_Err_Syntax_Error; + } + + + LOCAL_FUNC + void CopyArray( T1_Parser* parser, + FT_Byte* num_elements, + FT_Short* elements, + FT_Int max_elements ) + { + T1_Token* token = parser->args++; + FT_Error error; + + + if ( token->kind == tok_array || + token->kind == tok_program ) /* in the case of MinFeature */ + { + /* get rid of `['/`]', or `{'/`}' */ + FT_Byte* base = parser->tokenizer->base + token->start + 1; + FT_Byte* limit = base + token->len - 2; + FT_Byte* cur; + FT_Byte* start; + FT_Int n; + + + /* read each parameter independently */ + cur = base; + for ( n = 0; n < max_elements; n++ ) + { + FT_Long result; + + + /* test end of string */ + if ( cur >= limit ) + break; + + /* skip whitespace */ + while ( cur < limit && *cur == ' ' ) + cur++; + + /* end of list? */ + if ( cur >= limit ) + break; + + /* skip numbers */ + start = cur; + while ( cur < limit && *cur != ' ' ) + cur++; + + error = parse_integer( start, cur, &result ); + if ( error ) + goto Fail; + + *elements++ = (FT_Short)result; + } + + if ( num_elements ) + *num_elements = (FT_Byte)n; + + parser->error = 0; + return; + } + + Fail: + FT_ERROR(( "CopyArray: syntax error!\n" )); + parser->error = T1_Err_Syntax_Error; + } + + +/* END */ diff --git a/src/freetype/type1/t1parse.h b/src/freetype/type1/t1parse.h new file mode 100644 index 0000000000..2c42b8cec4 --- /dev/null +++ b/src/freetype/type1/t1parse.h @@ -0,0 +1,261 @@ +/***************************************************************************/ +/* */ +/* t1parse.h */ +/* */ +/* Type 1 parser (specification). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + + /*************************************************************************/ + /* */ + /* The Type1 parser component is in charge of simply parsing the font */ + /* input stream and convert simple tokens and elements into integers, */ + /* floats, matrices, strings, etc. */ + /* */ + /* It is used by the Type1 loader. */ + /* */ + /*************************************************************************/ + + +#ifndef T1PARSE_H +#define T1PARSE_H + +#include + + +#ifdef FT_FLAT_COMPILE + +#include "t1tokens.h" + +#else + +#include + +#endif + + +#ifdef __cplusplus + extern "C" { +#endif + + + /*************************************************************************/ + /* */ + /* */ + /* T1_DictState */ + /* */ + /* */ + /* An enumeration used to describe the Type 1 parser's state, i.e. */ + /* which dictionary (or array) it is scanning and processing at the */ + /* current moment. */ + /* */ + typedef enum T1_DictState_ + { + dict_none = 0, + dict_font, /* parsing the font dictionary */ + dict_fontinfo, /* parsing the font info dictionary */ + dict_none2, /* beginning to parse the encrypted section */ + dict_private, /* parsing the private dictionary */ + dict_encoding, /* parsing the encoding array */ + dict_subrs, /* parsing the subrs array */ + dict_othersubrs, /* parsing the othersubrs array (?) */ + dict_charstrings, /* parsing the charstrings dictionary */ + dict_unknown_array, /* parsing/ignoring an unknown array */ + dict_unknown_dict, /* parsing/ignoring an unknown dictionary */ + + dict_max /* do not remove from list */ + + } T1_DictState; + + + /*************************************************************************/ + /* */ + /* */ + /* T1_Table */ + /* */ + /* */ + /* A T1_Table is a simple object used to store an array of objects in */ + /* a single memory block. */ + /* */ + /* */ + /* block :: The address in memory of the growheap's block. This */ + /* can change between two object adds, due to */ + /* reallocation. */ + /* */ + /* cursor :: The current top of the grow heap within its block. */ + /* */ + /* capacity :: The current size of the heap block. Increments by */ + /* 1kByte chunks. */ + /* */ + /* max_elems :: The maximum number of elements in table. */ + /* */ + /* num_elems :: The current number of elements in table. */ + /* */ + /* elements :: A table of element addresses within the block. */ + /* */ + /* lengths :: A table of element sizes within the block. */ + /* */ + /* memory :: The object used for memory operations */ + /* (alloc/realloc). */ + /* */ + typedef struct T1_Table_ + { + FT_Byte* block; /* current memory block */ + FT_Int cursor; /* current cursor in memory block */ + FT_Int capacity; /* current size of memory block */ + + FT_Int max_elems; + FT_Int num_elems; + FT_Byte** elements; /* addresses of table elements */ + FT_Int* lengths; /* lengths of table elements */ + + FT_Memory memory; + + } T1_Table; + + + /*************************************************************************/ + /* */ + /* */ + /* T1_Parser */ + /* */ + /* */ + /* A Type 1 parser. This object is in charge of parsing Type 1 ASCII */ + /* streams and builds dictionaries for a T1_Face object. */ + /* */ + /* */ + /* error :: The current error code. 0 means success. */ + /* */ + /* face :: The target T1_Face object being built. */ + /* */ + /* tokenizer :: The tokenizer (lexical analyser) used for */ + /* processing the input stream. */ + /* */ + /* dump_tokens :: XXX */ + /* */ + /* stack :: The current token stack. Note that we don't */ + /* use intermediate Postscript objects here! */ + /* */ + /* top :: The current top of token stack. */ + /* */ + /* limit :: The current upper bound of the token stack. */ + /* Used for overflow checks. */ + /* */ + /* args :: The arguments of a given operator. Used and */ + /* increased by the various CopyXXX() functions. */ + /* */ + /* state_index :: The index of the top of the dictionary state */ + /* stack. */ + /* */ + /* state_stack :: The dictionary states stack. */ + /* */ + /* table :: A T1_Table object used to record various kinds */ + /* of dictionaries or arrays (like `/Encoding', */ + /* `/Subrs', `/CharStrings'). */ + /* */ + /* cur_name :: XXX */ + /* */ + /* encoding_type :: XXX */ + /* */ + /* encoding_names :: XXX */ + /* */ + /* encoding_lengths :: XXX */ + /* */ + /* encoding_offsets :: XXX */ + /* */ + /* subrs :: XXX */ + /* */ + /* charstrings :: XXX */ + /* */ + typedef struct T1_Parser_ + { + FT_Error error; + T1_Face face; + + T1_Tokenizer tokenizer; + FT_Bool dump_tokens; + + T1_Token stack[T1_MAX_STACK_DEPTH]; + T1_Token* top; + T1_Token* limit; + T1_Token* args; + + FT_Int state_index; + T1_DictState state_stack[T1_MAX_DICT_DEPTH]; + + T1_Table table; + + FT_Int cur_name; + + T1_EncodingType encoding_type; + FT_Byte* encoding_names; + FT_Int* encoding_lengths; + FT_Byte** encoding_offsets; + + FT_Byte* subrs; + FT_Byte* charstrings; + + } T1_Parser; + + + LOCAL_DEF + FT_Error T1_New_Table( T1_Table* table, + FT_Int count, + FT_Memory memory ); + + LOCAL_DEF + FT_Error T1_Add_Table( T1_Table* table, + FT_Int index, + void* object, + FT_Int length ); + + LOCAL_DEF + void T1_Done_Table( T1_Table* table ); + + + LOCAL_DEF + FT_String* CopyString( T1_Parser* parser ); + + LOCAL_DEF + FT_Long CopyInteger( T1_Parser* parser ); + + LOCAL_DEF + FT_Bool CopyBoolean( T1_Parser* parser ); + + LOCAL_DEF + FT_Long CopyFloat( T1_Parser* parser, + FT_Int scale ); + + LOCAL_DEF + void CopyBBox( T1_Parser* parser, + FT_BBox* bbox ); + + LOCAL_DEF + void CopyMatrix( T1_Parser* parser, + FT_Matrix* matrix ); + + LOCAL_DEF + void CopyArray( T1_Parser* parser, + FT_Byte* num_elements, + FT_Short* elements, + FT_Int max_elements ); + + +#ifdef __cplusplus + } +#endif + +#endif /* T1PARSE_H */ + + +/* END */ diff --git a/src/freetype/type1/t1tokens.c b/src/freetype/type1/t1tokens.c new file mode 100644 index 0000000000..2953322c99 --- /dev/null +++ b/src/freetype/type1/t1tokens.c @@ -0,0 +1,1101 @@ +/***************************************************************************/ +/* */ +/* t1parse.c */ +/* */ +/* Type 1 parser (body). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + + /*************************************************************************/ + /* */ + /* The tokenizer is in charge of loading and reading a Type1 font file */ + /* (either in PFB or PFA format), and extracting successive tokens and */ + /* keywords from its two streams (i.e. the font program, and the private */ + /* dictionary). */ + /* */ + /* Eexec decryption is performed automatically when entering the private */ + /* dictionary, or when retrieving char strings. */ + /* */ + /*************************************************************************/ + + +#include +#include + + +#ifdef FT_FLAT_COMPILE + +#include "t1tokens.h" +#include "t1load.h" + +#else + +#include +#include + +#endif + + +#include /* for strncmp() */ + + +#undef READ_BUFFER_INCREMENT +#define READ_BUFFER_INCREMENT 0x400 + + + /*************************************************************************/ + /* */ + /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ + /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ + /* messages during execution. */ + /* */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_t1load + + + /* An array of Type1 keywords supported by this engine. This table */ + /* places the keyword in lexicographical order. It should always */ + /* correspond to the enums `key_xxx'! */ + /* */ + const char* t1_keywords[key_max - key_first_] = + { + "-|", "ExpertEncoding", "ND", "NP", "RD", "StandardEncoding", "array", + "begin", "closefile", "currentdict", "currentfile", "def", "dict", "dup", + "eexec", "end", "executeonly", "false", "for", "index", "noaccess", + "put", "readonly", "true", "userdict", "|", "|-" + }; + + + const char* t1_immediates[imm_max - imm_first_] = + { + "-|", ".notdef", "BlendAxisTypes", "BlueFuzz", "BlueScale", "BlueShift", + "BlueValues", "CharStrings", "Encoding", "FamilyBlues", "FamilyName", + "FamilyOtherBlues", "FID", "FontBBox", "FontID", "FontInfo", "FontMatrix", + "FontName", "FontType", "ForceBold", "FullName", "ItalicAngle", + "LanguageGroup", "Metrics", "MinFeature", "ND", "NP", "Notice", + "OtherBlues", "OtherSubrs", "PaintType", "Private", "RD", "RndStemUp", + "StdHW", "StdVW", "StemSnapH", "StemSnapV", "StrokeWidth", "Subrs", + "UnderlinePosition", "UnderlineThickness", "UniqueID", "Weight", + "isFixedPitch", "lenIV", "password", "version", "|", "|-" + }; + + + /* lexicographic comparison of two strings */ + static + int lexico_strcmp( const char* str1, + int str1_len, + const char* str2 ) + { + int c2 = 0; + + + for ( ; str1_len > 0; str1_len-- ) + { + int c1, diff; + + + c1 = *str1++; + c2 = *str2++; + + diff = c1 - c2; + if ( diff ) + return diff; + }; + + return -*str2; + } + + + /* find a given token/name, performing binary search */ + static + int Find_Name( char* base, + int length, + const char** table, + int table_len ) + { + int left, right; + + + left = 0; + right = table_len - 1; + + while ( right - left > 1 ) + { + int middle = left + ( ( right - left ) >> 1 ); + int cmp; + + + cmp = lexico_strcmp( base, length, table[middle] ); + if ( !cmp ) + return middle; + + if ( cmp < 0 ) + right = middle; + else + left = middle; + } + + if ( !lexico_strcmp( base, length, table[left ] ) ) + return left; + if ( !lexico_strcmp( base, length, table[right] ) ) + return right; + + return -1; + } + + + /* read the small PFB section header */ + static + FT_Error Read_PFB_Tag( FT_Stream stream, + FT_UShort* atag, + FT_ULong* asize ) + { + FT_UShort tag; + FT_ULong size; + FT_Error error; + + + FT_TRACE2(( "Read_PFB_Tag: reading\n" )); + + if ( ACCESS_Frame( 6L ) ) + return error; + + tag = GET_UShort(); + size = GET_ULong(); + + FORGET_Frame(); + + *atag = tag; + *asize = ( ( size & 0xFF ) << 24 ) | + ( ( ( size >> 8 ) & 0xFF ) << 16 ) | + ( ( ( size >> 16 ) & 0xFF ) << 8 ) | + ( ( ( size >> 24 ) & 0xFF ) ); + + FT_TRACE2(( " tag = %04x\n", tag )); + FT_TRACE4(( " asze = %08x\n", size )); + FT_TRACE2(( " size = %08x\n", *asize )); + + return T1_Err_Ok; + } + + + static + FT_Error grow( T1_Tokenizer tokzer ) + { + FT_Error error; + FT_Long left_bytes; + FT_Memory memory = tokzer->memory; + + + left_bytes = tokzer->max - tokzer->limit; + + if ( left_bytes > 0 ) + { + FT_Stream stream = tokzer->stream; + + + if ( left_bytes > READ_BUFFER_INCREMENT ) + left_bytes = READ_BUFFER_INCREMENT; + + FT_TRACE2(( "Growing tokenizer buffer by %d bytes\n", left_bytes )); + + if ( !REALLOC( tokzer->base, tokzer->limit, + tokzer->limit + left_bytes ) && + !FILE_Read( tokzer->base + tokzer->limit, left_bytes ) ) + tokzer->limit += left_bytes; + } + else + { + FT_ERROR(( "Unexpected end of Type1 fragment!\n" )); + error = T1_Err_Invalid_File_Format; + } + + tokzer->error = error; + return error; + } + + + /*************************************************************************/ + /* */ + /* */ + /* t1_decrypt */ + /* */ + /* */ + /* Performs the Type 1 charstring decryption process. */ + /* */ + /* */ + /* buffer :: The base address of the data to decrypt. */ + /* length :: The number of bytes to decrypt (beginning from the base */ + /* address. */ + /* seed :: The encryption seed (4330 for charstrings). */ + /* */ + LOCAL_FUNC + void t1_decrypt( FT_Byte* buffer, + FT_Int length, + FT_UShort seed ) + { + while ( length > 0 ) + { + FT_Byte plain; + + + plain = ( *buffer ^ ( seed >> 8 ) ); + seed = ( *buffer + seed ) * 52845 + 22719; + *buffer++ = plain; + length--; + } + } + + + /*************************************************************************/ + /* */ + /* */ + /* New_Tokenizer */ + /* */ + /* */ + /* Creates a new tokenizer from a given input stream. This function */ + /* automatically recognizes `pfa' or `pfb' files. The function */ + /* Read_Token() can then be used to extract successive tokens from */ + /* the stream. */ + /* */ + /* */ + /* stream :: The input stream. */ + /* */ + /* */ + /* tokenizer :: A handle to a new tokenizer object. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* This function copies the stream handle within the object. Callers */ + /* should not discard `stream'. This is done by the Done_Tokenizer() */ + /* function. */ + /* */ + LOCAL_FUNC + FT_Error New_Tokenizer( FT_Stream stream, + T1_Tokenizer* tokenizer ) + { + FT_Memory memory = stream->memory; + T1_Tokenizer tokzer; + FT_Error error; + FT_UShort tag; + FT_ULong size; + + FT_Byte* tok_base; + FT_ULong tok_limit; + FT_ULong tok_max; + + + *tokenizer = 0; + + /* allocate object */ + if ( FILE_Seek( 0L ) || + ALLOC( tokzer, sizeof ( *tokzer ) ) ) + return error; + + tokzer->stream = stream; + tokzer->memory = stream->memory; + + tokzer->in_pfb = 0; + tokzer->in_private = 0; + + tok_base = 0; + tok_limit = 0; + tok_max = stream->size; + + error = Read_PFB_Tag( stream, &tag, &size ); + if ( error ) + goto Fail; + + if ( tag != 0x8001 ) + { + /* assume that it is a PFA file -- an error will be produced later */ + /* if a character with value > 127 is encountered */ + + /* rewind to start of file */ + if ( FILE_Seek( 0L ) ) + goto Fail; + + size = stream->size; + } + else + tokzer->in_pfb = 1; + + /* if it is a memory-based resource, set up pointer */ + if ( !stream->read ) + { + tok_base = (FT_Byte*)stream->base + stream->pos; + tok_limit = size; + tok_max = size; + + /* check that the `size' field is valid */ + if ( FILE_Skip( size ) ) + goto Fail; + } + else if ( tag == 0x8001 ) + { + /* read segment in memory */ + if ( ALLOC( tok_base, size ) ) + goto Fail; + + if ( FILE_Read( tok_base, size ) ) + { + FREE( tok_base ); + goto Fail; + } + + tok_limit = size; + tok_max = size; + } + + tokzer->base = tok_base; + tokzer->limit = tok_limit; + tokzer->max = tok_max; + tokzer->cursor = 0; + + *tokenizer = tokzer; + + /* now check font format; we must see `%!PS-AdobeFont-1' */ + /* or `%!FontType' */ + { + if ( 16 > tokzer->limit ) + grow( tokzer ); + + if ( tokzer->limit <= 16 || + ( strncmp( (const char*)tokzer->base, "%!PS-AdobeFont-1", 16 ) && + strncmp( (const char*)tokzer->base, "%!FontType", 10 ) ) ) + { + FT_TRACE2(( "[not a Type1 font]\n" )); + error = FT_Err_Unknown_File_Format; + goto Fail; + } + } + return T1_Err_Ok; + + Fail: + FREE( tokzer->base ); + FREE( tokzer ); + return error; + } + + + /* return the value of an hexadecimal digit */ + static + int hexa_value( char c ) + { + unsigned int d; + + + d = (unsigned int)( c - '0' ); + if ( d <= 9 ) + return (int)d; + + d = (unsigned int)( c - 'a' ); + if ( d <= 5 ) + return (int)( d + 10 ); + + d = (unsigned int)( c - 'A' ); + if ( d <= 5 ) + return (int)( d + 10 ); + + return -1; + } + + + /*************************************************************************/ + /* */ + /* */ + /* Done_Tokenizer */ + /* */ + /* */ + /* Closes a given tokenizer. This function will also close the */ + /* stream embedded in the object. */ + /* */ + /* */ + /* tokenizer :: The target tokenizer object. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + LOCAL_FUNC + FT_Error Done_Tokenizer( T1_Tokenizer tokenizer ) + { + FT_Memory memory = tokenizer->memory; + + + /* clear read buffer if needed (disk-based resources) */ + if ( tokenizer->in_private || !tokenizer->stream->base ) + FREE( tokenizer->base ); + + FREE( tokenizer ); + return T1_Err_Ok; + } + + + /*************************************************************************/ + /* */ + /* */ + /* Open_PrivateDict */ + /* */ + /* */ + /* This function must be called to set the tokenizer to the private */ + /* section of the Type1 file. It recognizes automatically the */ + /* the kind of eexec encryption used (ascii or binary). */ + /* */ + /* */ + /* tokenizer :: The target tokenizer object. */ + /* lenIV :: The value of the `lenIV' variable. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + LOCAL_FUNC + FT_Error Open_PrivateDict( T1_Tokenizer tokenizer ) + { + T1_Tokenizer tokzer = tokenizer; + FT_Stream stream = tokzer->stream; + FT_Memory memory = tokzer->memory; + FT_Error error = 0; + + FT_UShort tag; + FT_ULong size; + + FT_Byte* private_dict; + + /* are we already in the private dictionary ? */ + if ( tokzer->in_private ) + return 0; + + if ( tokzer->in_pfb ) + { + /* in the case of the PFB format, the private dictionary can be */ + /* made of several segments. We thus first read the number of */ + /* segments to compute the total size of the private dictionary */ + /* then re-read them into memory. */ + FT_Long start_pos = FILE_Pos(); + FT_ULong private_dict_size = 0; + + + for (;;) + { + error = Read_PFB_Tag( stream, &tag, &size ); + if ( error || tag != 0x8002 ) + break; + + private_dict_size += size; + + if ( FILE_Skip( size ) ) + goto Fail; + } + + /* check that we have a private dictionary there */ + /* and allocate private dictionary buffer */ + if ( private_dict_size == 0 ) + { + FT_ERROR(( "Open_PrivateDict:" )); + FT_ERROR(( " invalid private dictionary section\n" )); + error = T1_Err_Invalid_File_Format; + goto Fail; + } + + if ( ALLOC( private_dict, private_dict_size ) ) + goto Fail; + + /* read all sections into buffer */ + if ( FILE_Seek( start_pos ) ) + goto Fail_Private; + + private_dict_size = 0; + for (;;) + { + error = Read_PFB_Tag( stream, &tag, &size ); + if ( error || tag != 0x8002 ) + { + error = 0; + break; + } + + if ( FILE_Read( private_dict + private_dict_size, size ) ) + goto Fail_Private; + + private_dict_size += size; + } + + /* we must free the field `tokzer.base' if we are in a disk-based */ + /* PFB file. */ + if ( stream->read ) + FREE( tokzer->base ); + + tokzer->base = private_dict; + tokzer->cursor = 0; + tokzer->limit = private_dict_size; + tokzer->max = private_dict_size; + } + else + { + char* base; + + + /* we are in a PFA file; read each token until we find `eexec' */ + while ( tokzer->token.kind2 != key_eexec ) + { + error = Read_Token( tokzer ); + if ( error ) + goto Fail; + } + + /* now determine whether the private dictionary is encoded in binary */ + /* or hexadecimal ASCII format. */ + + /* we need to access the next 4 bytes (after the final \r following */ + /* the `eexec' keyword); if they all are hexadecimal digits, then */ + /* we have a case of ASCII storage. */ + while ( tokzer->cursor + 5 > tokzer->limit ) + { + error = grow( tokzer ); + if ( error ) + goto Fail; + } + + /* skip whitespace/line feed after `eexec' */ + base = (char*)tokzer->base + tokzer->cursor + 1; + if ( ( hexa_value( base[0] ) | hexa_value( base[1] ) | + hexa_value( base[2] ) | hexa_value( base[3] ) ) < 0 ) + { + /* binary encoding -- `simply' read the stream */ + + /* if it is a memory-based resource, we need to allocate a new */ + /* storage buffer for the private dictionary, as it must be */ + /* decrypted later */ + if ( stream->base ) + { + size = stream->size - tokzer->cursor - 1; /* remaining bytes */ + + if ( ALLOC( private_dict, size ) ) /* alloc private dict buffer */ + goto Fail; + + /* copy eexec-encrypted bytes */ + MEM_Copy( private_dict, tokzer->base + tokzer->cursor + 1, size ); + + /* reset pointers - forget about file mapping */ + tokzer->base = private_dict; + tokzer->limit = size; + tokzer->max = size; + tokzer->cursor = 0; + } + /* On the opposite, for disk based resources, we simply grow */ + /* the current buffer until its completion, and decrypt the */ + /* bytes within it. In all cases, the `base' buffer will be */ + /* discarded on DoneTokenizer if we are in the private dict. */ + else + { + /* grow the read buffer to the full file */ + while ( tokzer->limit < tokzer->max ) + { + error = grow( tokenizer ); + if ( error ) + goto Fail; + } + + /* set up cursor to first encrypted byte */ + tokzer->cursor++; + } + } + else + { + /* ASCII hexadecimal encoding. This sucks... */ + FT_Byte* write; + FT_Byte* cur; + FT_Byte* limit; + FT_Int count; + + + /* allocate a buffer, read each one byte at a time */ + count = stream->size - tokzer->cursor; + size = count / 2; + + if ( ALLOC( private_dict, size ) ) /* alloc private dict buffer */ + goto Fail; + + write = private_dict; + cur = tokzer->base + tokzer->cursor; + limit = tokzer->base + tokzer->limit; + + /* read each bytes */ + while ( count > 0 ) + { + /* ensure that we can read the next 2 bytes! */ + while ( cur + 2 > limit ) + { + int cursor = cur - tokzer->base; + + + error = grow( tokzer ); + if ( error ) + goto Fail_Private; + cur = tokzer->base + cursor; + limit = tokzer->base + tokzer->limit; + } + + /* check for new line */ + if ( cur[0] == '\r' || cur[0] == '\n' ) + { + cur++; + count--; + } + else + { + int hex1 = hexa_value(cur[0]); + + + /* exit if we have a non-hexadecimal digit which isn't */ + /* a new-line character */ + if ( hex1 < 0 ) + break; + + /* otherwise, store byte */ + *write++ = ( hex1 << 4 ) | hexa_value( cur[1] ); + cur += 2; + count -= 2; + } + } + + /* get rid of old buffer in the case of disk-based resources */ + if ( !stream->base ) + FREE( tokzer->base ); + + /* set up pointers */ + tokzer->base = private_dict; + tokzer->limit = size; + tokzer->max = size; + tokzer->cursor = 0; + } + } + + /* finally, decrypt the private dictionary - and skip the lenIV bytes */ + t1_decrypt( tokzer->base, tokzer->limit, 55665 ); + tokzer->cursor += 4; + + Fail: + return error; + + Fail_Private: + FREE( private_dict ); + goto Fail; + } + + + /*************************************************************************/ + /* */ + /* */ + /* Read_Token */ + /* */ + /* */ + /* Reads a new token from the current input stream. This function */ + /* extracts a token from the font program until Open_PrivateDict() */ + /* has been called. After this, it returns tokens from the */ + /* (eexec-encrypted) private dictionary. */ + /* */ + /* */ + /* tokenizer :: The target tokenizer object. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* Use the function Read_CharStrings() to read the binary charstrings */ + /* from the private dict. */ + /* */ + LOCAL_FUNC + FT_Error Read_Token( T1_Tokenizer tokenizer ) + { + T1_Tokenizer tok = tokenizer; + FT_Long cur, limit; + FT_Byte* base; + char c, starter, ender; + FT_Bool token_started; + + T1_TokenType kind; + + + tok->error = T1_Err_Ok; + tok->token.kind = tok_any; + + base = tok->base; + limit = tok->limit; + cur = tok->cursor; + + token_started = 0; + + for (;;) + { + if ( cur >= limit ) + { + if ( grow( tok ) ) + goto Exit; + base = tok->base; + limit = tok->limit; + } + + c = (char)base[cur++]; + + /* check that we have an ASCII character */ + if ( (FT_Byte)c > 127 ) + { + FT_ERROR(( "Read_Token:" )); + FT_ERROR(( " unexpected binary data in Type1 fragment!\n" )); + tok->error = T1_Err_Invalid_File_Format; + goto Exit; + } + + switch ( c ) + { + case '\r': + case '\n': + case ' ' : + case '\t': /* skip initial whitespace => skip to next */ + if ( token_started ) + { + /* possibly a name, keyword, wathever */ + tok->token.kind = tok_any; + tok->token.len = cur-tok->token.start - 1; + goto Exit; + } + /* otherwise, skip everything */ + break; + + case '%': /* this is a comment -- skip everything */ + for (;;) + { + FT_Int left = limit - cur; + + + while ( left > 0 ) + { + c = (char)base[cur++]; + if ( c == '\r' || c == '\n' ) + goto Next; + left--; + } + + if ( grow( tokenizer ) ) + goto Exit; + base = tok->base; + limit = tok->limit; + } + + case '(': /* a Postscript string */ + kind = tok_string; + ender = ')'; + + L1: + if ( !token_started ) + { + token_started = 1; + tok->token.start = cur - 1; + } + + { + FT_Int nest_level = 1; + + + starter = c; + for (;;) + { + FT_Int left = limit - cur; + + + while ( left > 0 ) + { + c = (char)base[cur++]; + + if ( c == starter ) + nest_level++; + + else if ( c == ender ) + { + nest_level--; + if ( nest_level <= 0 ) + { + tok->token.kind = kind; + tok->token.len = cur - tok->token.start; + goto Exit; + } + } + left--; + } + + if ( grow( tok ) ) + goto Exit; + base = tok->base; + limit = tok->limit; + } + } + + case '[': /* a Postscript array */ + if ( token_started ) + goto Any_Token; + + kind = tok_array; + ender = ']'; + goto L1; + break; + + case '{': /* a Postscript program */ + if ( token_started ) + goto Any_Token; + + kind = tok_program; + ender = '}'; + goto L1; + break; + + case '<': /* a Postscript hex byte array? */ + if ( token_started ) + goto Any_Token; + + kind = tok_hexarray; + ender = '>'; + goto L1; + break; + + case '0': /* any number */ + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if ( token_started ) + goto Next; + + tok->token.kind = tok_number; + token_started = 1; + tok->token.start = cur - 1; + + L2: + for (;;) + { + FT_Int left = limit-cur; + + + while ( left > 0 ) + { + c = (char)base[cur++]; + + switch ( c ) + { + case '[': /* ] */ + case '{': /* } */ + case '(': /* ) */ + case '<': + case '/': + goto Any_Token; + + case ' ': + case '\r': + case '\t': + case '\n': + tok->token.len = cur - tok->token.start - 1; + goto Exit; + + default: + ; + } + left--; + } + + if ( grow( tok ) ) + goto Exit; + base = tok->base; + limit = tok->limit; + } + + case '.': /* maybe a number */ + case '-': + case '+': + if ( token_started ) + goto Next; + + token_started = 1; + tok->token.start = cur - 1; + + for (;;) + { + FT_Int left = limit - cur; + + + if ( left > 0 ) + { + /* test for any following digit, interpreted as number */ + c = (char)base[cur]; + tok->token.kind = ( c >= '0' && c <= '9' ? tok_number : tok_any ); + goto L2; + } + + if ( grow( tok ) ) + goto Exit; + base = tok->base; + limit = tok->limit; + } + + case '/': /* maybe an immediate name */ + if ( !token_started ) + { + token_started = 1; + tok->token.start = cur - 1; + + for (;;) + { + FT_Int left = limit - cur; + + + if ( left > 0 ) + { + /* test for single '/', interpreted as garbage */ + c = (char)base[cur]; + tok->token.kind = ( c == ' ' || c == '\t' || + c == '\r' || c == '\n' ) ? tok_any + : tok_immediate; + goto L2; + } + + if ( grow( tok ) ) + goto Exit; + base = tok->base; + limit = tok->limit; + } + } + else + { + Any_Token: /* possibly a name or wathever */ + cur--; + tok->token.len = cur - tok->token.start; + goto Exit; + } + + default: + if ( !token_started ) + { + token_started = 1; + tok->token.start = cur - 1; + } + } + + Next: + ; + } + + Exit: + tok->cursor = cur; + + if ( !tok->error ) + { + /* now, tries to match keywords and immediate names */ + FT_Int index; + + + switch ( tok->token.kind ) + { + case tok_immediate: /* immediate name */ + index = Find_Name( (char*)( tok->base + tok->token.start + 1 ), + tok->token.len - 1, + t1_immediates, + imm_max - imm_first_ ); + tok->token.kind2 = ( index >= 0 ) + ? (T1_TokenType)( imm_first_ + index ) + : tok_error; + break; + + case tok_any: /* test for keyword */ + index = Find_Name( (char*)( tok->base + tok->token.start ), + tok->token.len, + t1_keywords, + key_max - key_first_ ); + if ( index >= 0 ) + { + tok->token.kind = tok_keyword; + tok->token.kind2 = (T1_TokenType)( key_first_ + index ); + } + else + tok->token.kind2 = tok_error; + break; + + default: + tok->token.kind2 = tok_error; + } + } + return tokenizer->error; + } + + +#if 0 + + /*************************************************************************/ + /* */ + /* */ + /* Read_CharStrings */ + /* */ + /* */ + /* Reads a charstrings element from the current input stream. These */ + /* are binary bytes that encode each individual glyph outline. */ + /* */ + /* The caller is responsible for skipping the `lenIV' bytes at the */ + /* start of the record. */ + /* */ + /* */ + /* tokenizer :: The target tokenizer object. */ + /* num_chars :: The number of binary bytes to read. */ + /* */ + /* */ + /* buffer :: The target array of bytes. These are */ + /* eexec-decrypted. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* Use the function Read_CharStrings() to read binary charstrings */ + /* from the private dict. */ + /* */ + LOCAL_FUNC + FT_Error Read_CharStrings( T1_Tokenizer tokenizer, + FT_Int num_chars, + FT_Byte* buffer ) + { + for (;;) + { + FT_Int left = tokenizer->limit - tokenizer->cursor; + + + if ( left >= num_chars ) + { + MEM_Copy( buffer, tokenizer->base + tokenizer->cursor, num_chars ); + t1_decrypt( buffer, num_chars, 4330 ); + tokenizer->cursor += num_chars; + return T1_Err_Ok; + } + + if ( grow( tokenizer ) ) + return tokenizer->error; + } + } + +#endif /* 0 */ + + +/* END */ diff --git a/src/freetype/type1/t1tokens.h b/src/freetype/type1/t1tokens.h new file mode 100644 index 0000000000..119c54ba19 --- /dev/null +++ b/src/freetype/type1/t1tokens.h @@ -0,0 +1,258 @@ +/***************************************************************************/ +/* */ +/* t1tokens.h */ +/* */ +/* Type 1 tokenizer (specification). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef T1TOKENS_H +#define T1TOKENS_H + + +#ifdef FT_FLAT_COMPILE + +#include "t1objs.h" + +#else + +#include + +#endif + + +#ifdef __cplusplus + extern "C" { +#endif + + + /* enum value of first keyword */ +#define key_first_ 100 + + /* enum value of first immediate name */ +#define imm_first_ 200 + + + typedef enum T1_TokenType_ + { + tok_error = 0, + + tok_eof, /* end of file */ + + /* simple token types */ + + tok_keyword, /* keyword */ + tok_number, /* number (integer or real) */ + tok_string, /* postscript string */ + tok_program, /* postscript program */ + tok_immediate, /* any immediate name */ + tok_array, /* matrix, array, etc.. */ + tok_hexarray, /* array of hexadecimal nibbles */ + tok_any, /* anything else */ + + /* Postscript keywords -- placed in lexicographical order */ + + key_RD_alternate = key_first_, /* `-|' = alternate form of RD */ + key_ExpertEncoding, + key_ND, + key_NP, + key_RD, + key_StandardEncoding, + key_array, + key_begin, + key_closefile, + key_currentdict, + key_currentfile, + key_def, + key_dict, + key_dup, + key_eexec, + key_end, + key_execonly, + key_false, + key_for, + key_index, + key_noaccess, + key_put, + key_readonly, + key_true, + key_userdict, + key_NP_alternate, /* `|' = alternate form of NP */ + key_ND_alternate, /* `|-' = alternate form of ND */ + + key_max, /* always keep this value there */ + + /* Postscript immediate names -- other names will be ignored, except */ + /* in charstrings */ + + imm_RD_alternate = imm_first_, /* `-|' = alternate form of RD */ + imm_notdef, /* `/.notdef' immediate */ + imm_BlendAxisTypes, + imm_BlueFuzz, + imm_BlueScale, + imm_BlueShift, + imm_BlueValues, + imm_CharStrings, + imm_Encoding, + imm_FamilyBlues, + imm_FamilyName, + imm_FamilyOtherBlues, + imm_FID, + imm_FontBBox, + imm_FontID, + imm_FontInfo, + imm_FontMatrix, + imm_FontName, + imm_FontType, + imm_ForceBold, + imm_FullName, + imm_ItalicAngle, + imm_LanguageGroup, + imm_Metrics, + imm_MinFeature, + imm_ND, + imm_NP, + imm_Notice, + imm_OtherBlues, + imm_OtherSubrs, + imm_PaintType, + imm_Private, + imm_RD, + imm_RndStemUp, + imm_StdHW, + imm_StdVW, + imm_StemSnapH, + imm_StemSnapV, + imm_StrokeWidth, + imm_Subrs, + imm_UnderlinePosition, + imm_UnderlineThickness, + imm_UniqueID, + imm_Weight, + + imm_isFixedPitch, + imm_lenIV, + imm_password, + imm_version, + + imm_NP_alternate, /* `|' = alternate form of NP */ + imm_ND_alternate, /* `|-' = alternate form of ND */ + + imm_max /* always keep this value here */ + + } T1_TokenType; + + + /* these arrays are visible for debugging purposes */ + extern const char* t1_keywords[]; + extern const char* t1_immediates[]; + + + /*************************************************************************/ + /* */ + /* */ + /* T1_Token */ + /* */ + /* */ + /* A structure used to describe a token in the current input stream. */ + /* Note that the Type1 driver doesn't try to interpret tokens until */ + /* it really needs to. */ + /* */ + /* */ + /* kind :: The token type. Describes the token to the loader. */ + /* */ + /* kind2 :: Detailed token type. */ + /* */ + /* start :: The index of the first character of token in the input */ + /* stream. */ + /* */ + /* len :: The length of the token in characters. */ + /* */ + typedef struct T1_Token_ + { + T1_TokenType kind; /* simple type */ + T1_TokenType kind2; /* detailed type */ + FT_Int start; /* index of first token character */ + FT_Int len; /* length of token in chars */ + + } T1_Token; + + + typedef struct T1_TokenParser_ + { + FT_Memory memory; + FT_Stream stream; + + FT_Bool in_pfb; /* true if PFB file, PFA otherwise */ + FT_Bool in_private; /* true if in private dictionary */ + + FT_Byte* base; /* base address of current read buffer */ + FT_Long cursor; /* current position in read buffer */ + FT_Long limit; /* limit of current read buffer */ + FT_Long max; /* maximum size of read buffer */ + + FT_Error error; /* last error */ + T1_Token token; /* last token read */ + + } T1_TokenParser; + + + /*************************************************************************/ + /* */ + /* */ + /* T1_Tokenizer */ + /* */ + /* */ + /* A handle to an object used to extract tokens from the input. The */ + /* object is able to perform PFA/PFB recognition, eexec decryption of */ + /* the private dictionary, as well as eexec decryption of the */ + /* charstrings. */ + /* */ + typedef T1_TokenParser* T1_Tokenizer; + + + LOCAL_DEF + FT_Error New_Tokenizer( FT_Stream stream, + T1_Tokenizer* tokenizer ); + + LOCAL_DEF + FT_Error Done_Tokenizer( T1_Tokenizer tokenizer ); + + LOCAL_DEF + FT_Error Open_PrivateDict( T1_Tokenizer tokenizer ); + + LOCAL_DEF + FT_Error Read_Token( T1_Tokenizer tokenizer ); + + +#if 0 + LOCAL_DEF + FT_Error Read_CharStrings( T1_Tokenizer tokenizer, + FT_Int num_chars, + FT_Byte* buffer ); +#endif /* 0 */ + + LOCAL_DEF + void t1_decrypt( FT_Byte* buffer, + FT_Int length, + FT_UShort seed ); + + +#ifdef __cplusplus + } +#endif + +#endif /* T1TOKENS_H */ + + +/* END */ diff --git a/src/freetype/type1/type1.c b/src/freetype/type1/type1.c new file mode 100644 index 0000000000..d2058d620f --- /dev/null +++ b/src/freetype/type1/type1.c @@ -0,0 +1,59 @@ +/***************************************************************************/ +/* */ +/* type1.c */ +/* */ +/* FreeType Type 1 driver component (body only). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#define FT_MAKE_OPTION_SINGLE_OBJECT + + +#ifdef FT_FLAT_COMPILE + +#include "t1driver.c" +#include "t1objs.c" +#include "t1load.c" +#include "t1gload.c" +#include "t1tokens.c" +#include "t1parse.c" + +#ifndef T1_CONFIG_OPTION_DISABLE_HINTER +#include "t1hinter.c" +#endif + +#ifndef T1_CONFIG_OPTION_NO_AFM +#include "t1afm.c" +#endif + +#else /* FT_FLAT_COMPILE */ + +#include +#include +#include +#include +#include +#include + +#ifndef T1_CONFIG_OPTION_DISABLE_HINTER +#include +#endif + +#ifndef T1_CONFIG_OPTION_NO_AFM +#include +#endif + +#endif /* FT_FLAT_COMPILE */ + + +/* END */ diff --git a/src/freetype/type1z/Readme.txt b/src/freetype/type1z/Readme.txt new file mode 100644 index 0000000000..6502fb9d9f --- /dev/null +++ b/src/freetype/type1z/Readme.txt @@ -0,0 +1,10 @@ +This directory contains an experimental Type 1 driver that will ultimately +replace the "official" one in "src/type1". + +This driver doesn't provide a mini Postscript interpreter, but uses +pattern matching in order to load data from fonts. It works better and +faster than the official driver, but will replace it only when we finish +the auto-hinting module.. + +You don't need to compile it to support Type 1 fonts, the driver should +co-exist peacefully with the rest of the engine however.. diff --git a/src/freetype/type1z/module.mk b/src/freetype/type1z/module.mk new file mode 100644 index 0000000000..545887d824 --- /dev/null +++ b/src/freetype/type1z/module.mk @@ -0,0 +1,7 @@ +make_module_list: add_type1_driver + +add_type1_driver: + $(OPEN_DRIVER)t1_driver_class$(CLOSE_DRIVER) + $(ECHO_DRIVER)type1 $(ECHO_DRIVER_DESC)Postscript font files with extension *.pfa or *.pfb$(ECHO_DRIVER_DONE) + +# EOF diff --git a/src/freetype/type1z/rules.mk b/src/freetype/type1z/rules.mk new file mode 100644 index 0000000000..3411fd171c --- /dev/null +++ b/src/freetype/type1z/rules.mk @@ -0,0 +1,72 @@ +# +# FreeType 2 Type1z driver configuration rules +# + + +# Copyright 1996-2000 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +# Type1z driver directory +# +T1Z_DIR := $(SRC_)type1z +T1Z_DIR_ := $(T1Z_DIR)$(SEP) + + +# compilation flags for the driver +# +T1Z_COMPILE := $(FT_COMPILE) + + +# Type1 driver sources (i.e., C files) +# +T1Z_DRV_SRC := $(T1Z_DIR_)z1parse.c \ + $(T1Z_DIR_)z1load.c \ + $(T1Z_DIR_)z1driver.c \ + $(T1Z_DIR_)z1afm.c \ + $(T1Z_DIR_)z1gload.c \ + $(T1Z_DIR_)z1objs.c + +# Type1 driver headers +# +T1Z_DRV_H := $(T1Z_DRV_SRC:%.c=%.h) \ + $(T1Z_DIR_)z1tokens.h + + +# Type1z driver object(s) +# +# T1Z_DRV_OBJ_M is used during `multi' builds +# T1Z_DRV_OBJ_S is used during `single' builds +# +T1Z_DRV_OBJ_M := $(T1Z_DRV_SRC:$(T1Z_DIR_)%.c=$(OBJ_)%.$O) +T1Z_DRV_OBJ_S := $(OBJ_)type1z.$O + +# Type1z driver source file for single build +# +T1Z_DRV_SRC_S := $(T1Z_DIR_)type1z.c + + +# Type1z driver - single object +# +$(T1Z_DRV_OBJ_S): $(T1Z_DRV_SRC_S) $(T1Z_DRV_SRC) $(FREETYPE_H) $(T1Z_DRV_H) + $(T1Z_COMPILE) $T$@ $(T1Z_DRV_SRC_S) + + +# Type1z driver - multiple objects +# +$(OBJ_)%.$O: $(T1Z_DIR_)%.c $(FREETYPE_H) $(T1Z_DRV_H) + $(T1Z_COMPILE) $T$@ $< + + +# update main driver object lists +# +DRV_OBJS_S += $(T1Z_DRV_OBJ_S) +DRV_OBJS_M += $(T1Z_DRV_OBJ_M) + +# EOF diff --git a/src/freetype/type1z/type1z.c b/src/freetype/type1z/type1z.c new file mode 100644 index 0000000000..17e89ac157 --- /dev/null +++ b/src/freetype/type1z/type1z.c @@ -0,0 +1,49 @@ +/***************************************************************************/ +/* */ +/* type1z.c */ +/* */ +/* FreeType experimental Type 1 driver component (body only). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#define FT_MAKE_OPTION_SINGLE_OBJECT + + +#ifdef FT_FLAT_COMPILE + +#include "z1parse.c" +#include "z1load.c" +#include "z1objs.c" +#include "z1driver.c" +#include "z1gload.c" + +#ifndef Z1_CONFIG_OPTION_NO_AFM +#include "z1afm.c" +#endif + +#else /* FT_FLAT_COMPILE */ + +#include +#include +#include +#include +#include + +#ifndef Z1_CONFIG_OPTION_NO_AFM +#include +#endif + +#endif /* FT_FLAT_COMPILE */ + + +/* END */ diff --git a/src/freetype/type1z/z1afm.c b/src/freetype/type1z/z1afm.c new file mode 100644 index 0000000000..b329cd347f --- /dev/null +++ b/src/freetype/type1z/z1afm.c @@ -0,0 +1,293 @@ +/***************************************************************************/ +/* */ +/* z1afm.c */ +/* */ +/* AFM support for Type 1 fonts (body). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifdef FT_FLAT_COMPILE + +#include "z1afm.h" + +#else + +#include + +#endif + + +#include +#include + +#include /* for qsort() */ +#include /* for strcmp() */ +#include /* for isalnum() */ + + + /*************************************************************************/ + /* */ + /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ + /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ + /* messages during execution. */ + /* */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_z1afm + + + LOCAL_FUNC + void Z1_Done_AFM( FT_Memory memory, + Z1_AFM* afm ) + { + FREE( afm->kern_pairs ); + afm->num_pairs = 0; + } + + +#undef IS_KERN_PAIR +#define IS_KERN_PAIR( p ) ( p[0] == 'K' && p[1] == 'P' ) + +#define IS_ALPHANUM( c ) ( isalnum( c ) || \ + c == '_' || \ + c == '.' ) + + + /* read a glyph name and return the equivalent glyph index */ + static + FT_UInt afm_atoindex( FT_Byte** start, + FT_Byte* limit, + T1_Font* type1 ) + { + FT_Byte* p = *start; + FT_Int len; + FT_UInt result = 0; + char temp[64]; + + + /* skip whitespace */ + while ( ( *p == ' ' || *p == '\t' || *p == ':' || *p == ';' ) && + p < limit ) + p++; + *start = p; + + /* now, read glyph name */ + while ( IS_ALPHANUM( *p ) && p < limit ) + p++; + + len = p - *start; + + if ( len > 0 && len < 64 ) + { + FT_Int n; + + + /* copy glyph name to intermediate array */ + MEM_Copy( temp, *start, len ); + temp[len] = 0; + + /* lookup glyph name in face array */ + for ( n = 0; n < type1->num_glyphs; n++ ) + { + char* gname = (char*)type1->glyph_names[n]; + + + if ( gname && gname[0] == temp[0] && strcmp( gname, temp ) == 0 ) + { + result = n; + break; + } + } + } + *start = p; + return result; + } + + + /* read an integer */ + static + int afm_atoi( FT_Byte** start, + FT_Byte* limit ) + { + FT_Byte* p = *start; + int sum = 0; + int sign = 1; + + + /* skip everything that is not a number */ + while ( p < limit && !isdigit( *p ) ) + { + sign = 1; + if ( *p == '-' ) + sign = -1; + + p++; + } + + while ( p < limit && isdigit( *p ) ) + { + sum = sum * 10 + ( *p - '0' ); + p++; + } + *start = p; + + return sum * sign; + } + + +#undef KERN_INDEX +#define KERN_INDEX( g1, g2 ) ( ( (FT_ULong)g1 << 16 ) | g2 ) + + + /* compare two kerning pairs */ + static + int compare_kern_pairs( const void* a, + const void* b ) + { + Z1_Kern_Pair* pair1 = (Z1_Kern_Pair*)a; + Z1_Kern_Pair* pair2 = (Z1_Kern_Pair*)b; + + FT_ULong index1 = KERN_INDEX( pair1->glyph1, pair1->glyph2 ); + FT_ULong index2 = KERN_INDEX( pair2->glyph1, pair2->glyph2 ); + + + return ( index1 - index2 ); + } + + + /* parse an AFM file -- for now, only read the kerning pairs */ + LOCAL_FUNC + FT_Error Z1_Read_AFM( FT_Face t1_face, + FT_Stream stream ) + { + FT_Error error; + FT_Memory memory = stream->memory; + FT_Byte* start; + FT_Byte* limit; + FT_Byte* p; + FT_Int count = 0; + Z1_Kern_Pair* pair; + T1_Font* type1 = &((T1_Face)t1_face)->type1; + Z1_AFM* afm = 0; + + + if ( ACCESS_Frame( stream->size ) ) + return error; + + start = (FT_Byte*)stream->cursor; + limit = (FT_Byte*)stream->limit; + p = start; + + /* we are now going to count the occurences of `KP' or `KPX' in */ + /* the AFM file */ + count = 0; + for ( p = start; p < limit - 3; p++ ) + { + if ( IS_KERN_PAIR( p ) ) + count++; + } + + /* Actually, kerning pairs are simply optional! */ + if ( count == 0 ) + goto Exit; + + /* allocate the pairs */ + if ( ALLOC( afm, sizeof ( *afm ) ) || + ALLOC_ARRAY( afm->kern_pairs, count, Z1_Kern_Pair ) ) + goto Exit; + + /* now, read each kern pair */ + pair = afm->kern_pairs; + afm->num_pairs = count; + + /* save in face object */ + ((T1_Face)t1_face)->afm_data = afm; + + for ( p = start; p < limit - 3; p++ ) + { + if ( IS_KERN_PAIR( p ) ) + { + FT_Byte* q; + + + /* skip keyword (KP or KPX) */ + q = p + 2; + if ( *q == 'X' ) + q++; + + pair->glyph1 = afm_atoindex( &q, limit, type1 ); + pair->glyph2 = afm_atoindex( &q, limit, type1 ); + pair->kerning.x = afm_atoi( &q, limit ); + + pair->kerning.y = 0; + if ( p[2] != 'X' ) + pair->kerning.y = afm_atoi( &q, limit ); + + pair++; + } + } + + /* now, sort the kern pairs according to their glyph indices */ + qsort( afm->kern_pairs, count, sizeof ( Z1_Kern_Pair ), + compare_kern_pairs ); + + Exit: + if ( error ) + FREE( afm ); + + FORGET_Frame(); + + return error; + } + + + /* find the kerning for a given glyph pair */ + LOCAL_FUNC + void Z1_Get_Kerning( Z1_AFM* afm, + FT_UInt glyph1, + FT_UInt glyph2, + FT_Vector* kerning ) + { + Z1_Kern_Pair *min, *mid, *max; + FT_ULong index = KERN_INDEX( glyph1, glyph2 ); + + + /* simple binary search */ + min = afm->kern_pairs; + max = min + afm->num_pairs - 1; + + while ( min <= max ) + { + FT_ULong midi; + + + mid = min + ( max - min ) / 2; + midi = KERN_INDEX( mid->glyph1, mid->glyph2 ); + + if ( midi == index ) + { + *kerning = mid->kerning; + return; + } + + if ( midi < index ) + min = mid + 1; + else + max = mid - 1; + } + + kerning->x = 0; + kerning->y = 0; + } + + +/* END */ diff --git a/src/freetype/type1z/z1afm.h b/src/freetype/type1z/z1afm.h new file mode 100644 index 0000000000..bfacce7135 --- /dev/null +++ b/src/freetype/type1z/z1afm.h @@ -0,0 +1,79 @@ +/***************************************************************************/ +/* */ +/* z1afm.h */ +/* */ +/* AFM support for Type 1 fonts (specification). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef Z1AFM_H +#define Z1AFM_H + + +#ifdef FT_FLAT_COMPILE + +#include "z1objs.h" + +#else + +#include + +#endif + + +#ifdef __cplusplus + extern "C" { +#endif + + + typedef struct Z1_Kern_Pair_ + { + FT_UInt glyph1; + FT_UInt glyph2; + FT_Vector kerning; + + } Z1_Kern_Pair; + + + typedef struct Z1_AFM_ + { + FT_Int num_pairs; + Z1_Kern_Pair* kern_pairs; + + } Z1_AFM; + + + LOCAL_DEF + FT_Error Z1_Read_AFM( FT_Face face, + FT_Stream stream ); + + LOCAL_DEF + void Z1_Done_AFM( FT_Memory memory, + Z1_AFM* afm ); + + LOCAL_DEF + void Z1_Get_Kerning( Z1_AFM* afm, + FT_UInt glyph1, + FT_UInt glyph2, + FT_Vector* kerning ); + + +#ifdef __cplusplus + } +#endif + + +#endif /* Z1AFM_H */ + + +/* END */ diff --git a/src/freetype/type1z/z1driver.c b/src/freetype/type1z/z1driver.c new file mode 100644 index 0000000000..aea2c10f1f --- /dev/null +++ b/src/freetype/type1z/z1driver.c @@ -0,0 +1,340 @@ +/***************************************************************************/ +/* */ +/* z1driver.c */ +/* */ +/* Experimental Type 1 driver interface (body). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifdef FT_FLAT_COMPILE + +#include "z1driver.h" +#include "z1gload.h" +#include "z1load.h" +#include "z1afm.h" + +#else + +#include +#include +#include +#include + +#endif + + +#include +#include +#include + +#include /* for strcmp() */ + + + /*************************************************************************/ + /* */ + /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ + /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ + /* messages during execution. */ + /* */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_z1driver + + + static + FT_Error get_z1_glyph_name( T1_Face face, + FT_UInt glyph_index, + FT_Pointer buffer, + FT_UInt buffer_max ) + { + FT_String* gname; + + + gname = face->type1.glyph_names[glyph_index]; + + if ( buffer_max > 0 ) + { + FT_UInt len = strlen( gname ); + + + if (len >= buffer_max) + len = buffer_max - 1; + + MEM_Copy( buffer, gname, len ); + ((FT_Byte*)buffer)[len] = 0; + } + + return T1_Err_Ok; + } + + + /*************************************************************************/ + /* */ + /* */ + /* Get_Interface */ + /* */ + /* */ + /* Each driver can provide one or more extensions to the base */ + /* FreeType API. These can be used to access format specific */ + /* features (e.g., all TrueType/OpenType resources share a common */ + /* file structure and common tables which can be accessed through the */ + /* `sfnt' interface), or more simply generic ones (e.g., the */ + /* `postscript names' interface which can be used to retrieve the */ + /* PostScript name of a given glyph index). */ + /* */ + /* */ + /* driver :: A handle to a driver object. */ + /* */ + /* */ + /* interface :: A string designing the interface. Examples are */ + /* `sfnt', `post_names', `charmaps', etc. */ + /* */ + /* */ + /* A typeless pointer to the extension's interface (normally a table */ + /* of function pointers). Returns NULL if the requested extension */ + /* isn't available (i.e., wasn't compiled in the driver at build */ + /* time). */ + /* */ + static + FT_Module_Interface Get_Interface( FT_Driver driver, + const FT_String* interface ) + { + FT_UNUSED( driver ); + FT_UNUSED( interface ); + + if ( strcmp( (const char*)interface, "glyph_name" ) == 0 ) + return (FT_Module_Interface)get_z1_glyph_name; + +#ifndef Z1_CONFIG_OPTION_NO_MM_SUPPORT + if ( strcmp( (const char*)interface, "get_mm" ) == 0 ) + return (FT_Module_Interface)Z1_Get_Multi_Master; + + if ( strcmp( (const char*)interface, "set_mm_design") == 0 ) + return (FT_Module_Interface)Z1_Set_MM_Design; + + if ( strcmp( (const char*)interface, "set_mm_blend") == 0 ) + return (FT_Module_Interface)Z1_Set_MM_Blend; +#endif + return 0; + } + + +#ifndef Z1_CONFIG_OPTION_NO_AFM + + /*************************************************************************/ + /* */ + /* */ + /* Get_Kerning */ + /* */ + /* */ + /* A driver method used to return the kerning vector between two */ + /* glyphs of the same face. */ + /* */ + /* */ + /* face :: A handle to the source face object. */ + /* */ + /* left_glyph :: The index of the left glyph in the kern pair. */ + /* */ + /* right_glyph :: The index of the right glyph in the kern pair. */ + /* */ + /* */ + /* kerning :: The kerning vector. This is in font units for */ + /* scalable formats, and in pixels for fixed-sizes */ + /* formats. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* Only horizontal layouts (left-to-right & right-to-left) are */ + /* supported by this function. Other layouts, or more sophisticated */ + /* kernings are out of scope of this method (the basic driver */ + /* interface is meant to be simple). */ + /* */ + /* They can be implemented by format-specific interfaces. */ + /* */ + static + FT_Error Get_Kerning( T1_Face face, + FT_UInt left_glyph, + FT_UInt right_glyph, + FT_Vector* kerning ) + { + Z1_AFM* afm; + + + kerning->x = 0; + kerning->y = 0; + + afm = (Z1_AFM*)face->afm_data; + if ( afm ) + Z1_Get_Kerning( afm, left_glyph, right_glyph, kerning ); + + return T1_Err_Ok; + } + + +#endif /* T1_CONFIG_OPTION_NO_AFM */ + + + /*************************************************************************/ + /* */ + /* */ + /* Get_Char_Index */ + /* */ + /* */ + /* Uses a charmap to return a given character code's glyph index. */ + /* */ + /* */ + /* charmap :: A handle to the source charmap object. */ + /* charcode :: The character code. */ + /* */ + /* */ + /* Glyph index. 0 means `undefined character code'. */ + /* */ + static + FT_UInt Get_Char_Index( FT_CharMap charmap, + FT_Long charcode ) + { + T1_Face face; + FT_UInt result = 0; + PSNames_Interface* psnames; + + + face = (T1_Face)charmap->face; + psnames = (PSNames_Interface*)face->psnames; + if ( psnames ) + switch ( charmap->encoding ) + { + /*******************************************************************/ + /* */ + /* Unicode encoding support */ + /* */ + case ft_encoding_unicode: + /* use the `PSNames' module to synthetize the Unicode charmap */ + result = psnames->lookup_unicode( &face->unicode_map, + (FT_ULong)charcode ); + + /* the function returns 0xFFFF if the Unicode charcode has */ + /* no corresponding glyph */ + if ( result == 0xFFFF ) + result = 0; + goto Exit; + + /*******************************************************************/ + /* */ + /* Custom Type 1 encoding */ + /* */ + case ft_encoding_adobe_custom: + { + T1_Encoding* encoding = &face->type1.encoding; + + + if ( charcode >= encoding->code_first && + charcode <= encoding->code_last ) + result = encoding->char_index[charcode]; + goto Exit; + } + + /*******************************************************************/ + /* */ + /* Adobe Standard & Expert encoding support */ + /* */ + default: + if ( charcode < 256 ) + { + FT_UInt code; + FT_Int n; + const char* glyph_name; + + + code = psnames->adobe_std_encoding[charcode]; + if ( charmap->encoding == ft_encoding_adobe_expert ) + code = psnames->adobe_expert_encoding[charcode]; + + glyph_name = psnames->adobe_std_strings( code ); + if ( !glyph_name ) + break; + + for ( n = 0; n < face->type1.num_glyphs; n++ ) + { + const char* gname = face->type1.glyph_names[n]; + + + if ( gname && gname[0] == glyph_name[0] && + strcmp( gname, glyph_name ) == 0 ) + { + result = n; + break; + } + } + } + } + Exit: + return result; + } + + + const FT_Driver_Class t1_driver_class = + { + { + ft_module_font_driver | ft_module_driver_scalable, + sizeof( FT_DriverRec ), + + "type1", + 0x10000L, + 0x20000L, + + 0, /* format interface */ + + (FT_Module_Constructor)Z1_Init_Driver, + (FT_Module_Destructor) Z1_Done_Driver, + (FT_Module_Requester) Get_Interface, + }, + + sizeof( T1_FaceRec ), + sizeof( Z1_SizeRec ), + sizeof( Z1_GlyphSlotRec ), + + (FTDriver_initFace) Z1_Init_Face, + (FTDriver_doneFace) Z1_Done_Face, + (FTDriver_initSize) 0, + (FTDriver_doneSize) 0, + (FTDriver_initGlyphSlot)0, + (FTDriver_doneGlyphSlot)0, + + (FTDriver_setCharSizes) 0, + (FTDriver_setPixelSizes)0, + (FTDriver_loadGlyph) Z1_Load_Glyph, + (FTDriver_getCharIndex) Get_Char_Index, + +#ifdef Z1_CONFIG_OPTION_NO_AFM + (FTDriver_getKerning) 0, + (FTDriver_attachFile) 0, +#else + (FTDriver_getKerning) Get_Kerning, + (FTDriver_attachFile) Z1_Read_AFM, +#endif + (FTDriver_getAdvances) 0 + }; + + +#ifdef FT_CONFIG_OPTION_DYNAMIC_DRIVERS + + EXPORT_FUNC( const FT_Driver_Class* ) getDriverClass( void ) + { + return &t1z_driver_class; + } + +#endif /* FT_CONFIG_OPTION_DYNAMIC_DRIVERS */ + + +/* END */ diff --git a/src/freetype/type1z/z1driver.h b/src/freetype/type1z/z1driver.h new file mode 100644 index 0000000000..08bd544d56 --- /dev/null +++ b/src/freetype/type1z/z1driver.h @@ -0,0 +1,29 @@ +/***************************************************************************/ +/* */ +/* z1driver.h */ +/* */ +/* High-level experimental Type 1 driver interface (specification). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef Z1DRIVER_H +#define Z1DRIVER_H + +#include + + FT_EXPORT_VAR( const FT_Driver_Class ) t1_driver_class; + +#endif /* Z1DRIVER_H */ + + +/* END */ diff --git a/src/freetype/type1z/z1gload.c b/src/freetype/type1z/z1gload.c new file mode 100644 index 0000000000..0b25d2ecc7 --- /dev/null +++ b/src/freetype/type1z/z1gload.c @@ -0,0 +1,1482 @@ +/***************************************************************************/ +/* */ +/* z1gload.c */ +/* */ +/* Experimental Type 1 Glyph Loader (body). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifdef FT_FLAT_COMPILE + +#include "z1gload.h" + +#else + +#include + +#endif + + +#include +#include +#include + +#include /* for strcmp() */ + + + /*************************************************************************/ + /* */ + /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ + /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ + /* messages during execution. */ + /* */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_z1gload + + + typedef enum Z1_Operator_ + { + op_none = 0, + op_endchar, + op_hsbw, + op_seac, + op_sbw, + op_closepath, + op_hlineto, + op_hmoveto, + op_hvcurveto, + op_rlineto, + op_rmoveto, + op_rrcurveto, + op_vhcurveto, + op_vlineto, + op_vmoveto, + op_dotsection, + op_hstem, + op_hstem3, + op_vstem, + op_vstem3, + op_div, + op_callothersubr, + op_callsubr, + op_pop, + op_return, + op_setcurrentpoint, + + op_max /* never remove this one */ + + } Z1_Operator; + + static + const FT_Int t1_args_count[op_max] = + { + 0, /* none */ + 0, /* endchar */ + 2, /* hsbw */ + 5, /* seac */ + 4, /* sbw */ + 0, /* closepath */ + 1, /* hlineto */ + 1, /* hmoveto */ + 4, /* hvcurveto */ + 2, /* rlineto */ + 2, /* rmoveto */ + 6, /* rrcurveto */ + 4, /* vhcurveto */ + 1, /* vlineto */ + 1, /* vmoveto */ + 0, /* dotsection */ + 2, /* hstem */ + 6, /* hstem3 */ + 2, /* vstem */ + 6, /* vstem3 */ + 2, /* div */ + -1, /* callothersubr */ + 1, /* callsubr */ + 0, /* pop */ + 0, /* return */ + 2 /* setcurrentpoint */ + }; + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /********** *********/ + /********** *********/ + /********** GENERIC CHARSTRING PARSING *********/ + /********** *********/ + /********** *********/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* */ + /* Z1_Init_Builder */ + /* */ + /* */ + /* Initializes a given glyph builder. */ + /* */ + /* */ + /* builder :: A pointer to the glyph builder to initialize. */ + /* */ + /* */ + /* face :: The current face object. */ + /* */ + /* size :: The current size object. */ + /* */ + /* glyph :: The current glyph object. */ + /* */ + LOCAL_FUNC + void Z1_Init_Builder( Z1_Builder* builder, + T1_Face face, + Z1_Size size, + Z1_GlyphSlot glyph ) + { + builder->path_begun = 0; + builder->load_points = 1; + + builder->face = face; + builder->glyph = glyph; + builder->memory = face->root.memory; + + if ( glyph ) + { + FT_GlyphLoader* loader = glyph->root.loader; + + + builder->loader = loader; + builder->current = &loader->current.outline; + builder->base = &loader->base.outline; + + FT_GlyphLoader_Rewind( loader ); + } + + if ( size ) + { + builder->scale_x = size->root.metrics.x_scale; + builder->scale_y = size->root.metrics.y_scale; + } + + builder->pos_x = 0; + builder->pos_y = 0; + + builder->left_bearing.x = 0; + builder->left_bearing.y = 0; + builder->advance.x = 0; + builder->advance.y = 0; + } + + + /*************************************************************************/ + /* */ + /* */ + /* Z1_Done_Builder */ + /* */ + /* */ + /* Finalizes a given glyph builder. Its contents can still be used */ + /* after the call, but the function saves important information */ + /* within the corresponding glyph slot. */ + /* */ + /* */ + /* builder :: A pointer to the glyph builder to finalize. */ + /* */ + LOCAL_FUNC + void Z1_Done_Builder( Z1_Builder* builder ) + { + Z1_GlyphSlot glyph = builder->glyph; + + + if ( glyph ) + glyph->root.outline = *builder->base; + } + + + /*************************************************************************/ + /* */ + /* */ + /* Z1_Init_Decoder */ + /* */ + /* */ + /* Initializes a given glyph decoder. */ + /* */ + /* */ + /* decoder :: A pointer to the glyph builder to initialize. */ + /* */ + LOCAL_FUNC + void Z1_Init_Decoder( Z1_Decoder* decoder ) + { + decoder->top = 0; + decoder->zone = 0; + decoder->flex_state = 0; + decoder->num_flex_vectors = 0; + decoder->blend = 0; + + /* Clear loader */ + MEM_Set( &decoder->builder, 0, sizeof ( decoder->builder ) ); + } + + + /* check that there is enough space for `count' more points */ + static + FT_Error check_points( Z1_Builder* builder, + FT_Int count ) + { + return FT_GlyphLoader_Check_Points( builder->loader, count, 0 ); + } + + + /* add a new point; do not check space */ + static + void add_point( Z1_Builder* builder, + FT_Pos x, + FT_Pos y, + FT_Byte flag ) + { + FT_Outline* outline = builder->current; + + + if ( builder->load_points ) + { + FT_Vector* point = outline->points + outline->n_points; + FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points; + + + point->x = x; + point->y = y; + *control = flag ? FT_Curve_Tag_On : FT_Curve_Tag_Cubic; + + builder->last = *point; + } + + outline->n_points++; + } + + + /* check space for a new on-curve point, then add it */ + static + FT_Error add_point1( Z1_Builder* builder, + FT_Pos x, + FT_Pos y ) + { + FT_Error error; + + + error = check_points( builder, 1 ); + if ( !error ) + add_point( builder, x, y, 1 ); + + return error; + } + + + /* check space for a new contour, then add it */ + static + FT_Error add_contour( Z1_Builder* builder ) + { + FT_Outline* outline = builder->current; + FT_Error error; + + + if ( !builder->load_points ) + { + outline->n_contours++; + return FT_Err_Ok; + } + + /* reallocate contours array if necessary */ + error = FT_GlyphLoader_Check_Points( builder->loader, 0, 1 ); + if ( !error ) + { + if ( outline->n_contours > 0 ) + outline->contours[outline->n_contours - 1] = outline->n_points - 1; + + outline->n_contours++; + } + + return error; + } + + + /* if a path was begun, add its first on-curve point */ + static + FT_Error start_point( Z1_Builder* builder, + FT_Pos x, + FT_Pos y ) + { + /* test whether we are building a new contour */ + if ( !builder->path_begun ) + { + FT_Error error; + + + builder->path_begun = 1; + error = add_contour( builder ); + if ( error ) + return error; + } + return add_point1( builder, x, y ); + } + + + /* close the current contour */ + static + void close_contour( Z1_Builder* builder ) + { + FT_Outline* outline = builder->current; + + + /* XXX: we must not include the last point in the path if it */ + /* is located on the first point */ + if ( outline->n_points > 1 ) + { + FT_Int first = 0; + FT_Vector* p1 = outline->points + first; + FT_Vector* p2 = outline->points + outline->n_points-1; + + + if ( outline->n_contours > 1 ) + { + first = outline->contours[outline->n_contours - 2] + 1; + p1 = outline->points + first; + } + + if ( p1->x == p2->x && p1->y == p2->y ) + outline->n_points--; + } + + if ( outline->n_contours > 0 ) + outline->contours[outline->n_contours - 1] = outline->n_points - 1; + } + + + /*************************************************************************/ + /* */ + /* */ + /* lookup_glyph_by_stdcharcode */ + /* */ + /* */ + /* Looks up a given glyph by its StandardEncoding charcode. Used */ + /* to implement the SEAC Type 1 operator. */ + /* */ + /* */ + /* face :: The current face object. */ + /* */ + /* charcode :: The character code to look for. */ + /* */ + /* */ + /* A glyph index in the font face. Returns -1 if the corresponding */ + /* glyph wasn't found. */ + /* */ + static + FT_Int lookup_glyph_by_stdcharcode( T1_Face face, + FT_Int charcode ) + { + FT_Int n; + const FT_String* glyph_name; + PSNames_Interface* psnames = (PSNames_Interface*)face->psnames; + + + /* check range of standard char code */ + if ( charcode < 0 || charcode > 255 ) + return -1; + + glyph_name = psnames->adobe_std_strings( + psnames->adobe_std_encoding[charcode]); + + for ( n = 0; n < face->type1.num_glyphs; n++ ) + { + FT_String* name = (FT_String*)face->type1.glyph_names[n]; + + + if ( name && strcmp( name,glyph_name ) == 0 ) + return n; + } + + return -1; + } + + + /*************************************************************************/ + /* */ + /* */ + /* t1operator_seac */ + /* */ + /* */ + /* Implements the `seac' Type 1 operator for a Type 1 decoder. */ + /* */ + /* */ + /* decoder :: The current CID decoder. */ + /* */ + /* asb :: The accent's side bearing. */ + /* */ + /* adx :: The horizontal offset of the accent. */ + /* */ + /* ady :: The vertical offset of the accent. */ + /* */ + /* bchar :: The base character's StandardEncoding charcode. */ + /* */ + /* achar :: The accent character's StandardEncoding charcode. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + static + FT_Error t1operator_seac( Z1_Decoder* decoder, + FT_Pos asb, + FT_Pos adx, + FT_Pos ady, + FT_Int bchar, + FT_Int achar ) + { + FT_Error error; + FT_Int bchar_index, achar_index, n_base_points; + FT_Outline* base = decoder->builder.base; + FT_Vector left_bearing, advance; + T1_Face face = decoder->builder.face; + T1_Font* type1 = &face->type1; + + + bchar_index = lookup_glyph_by_stdcharcode( face, bchar ); + achar_index = lookup_glyph_by_stdcharcode( face, achar ); + + if ( bchar_index < 0 || achar_index < 0 ) + { + FT_ERROR(( "t1operator_seac:" )); + FT_ERROR(( " invalid seac character code arguments\n" )); + return T1_Err_Syntax_Error; + } + + /* if we are trying to load a composite glyph, do not load the */ + /* accent character and return the array of subglyphs. */ + if ( decoder->builder.no_recurse ) + { + FT_GlyphSlot glyph = (FT_GlyphSlot)decoder->builder.glyph; + FT_GlyphLoader* loader = glyph->loader; + FT_SubGlyph* subg; + + + /* reallocate subglyph array if necessary */ + error = FT_GlyphLoader_Check_Subglyphs( loader, 2 ); + if ( error ) + goto Exit; + + subg = loader->current.subglyphs; + + /* subglyph 0 = base character */ + subg->index = bchar_index; + subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES | + FT_SUBGLYPH_FLAG_USE_MY_METRICS; + subg->arg1 = 0; + subg->arg2 = 0; + subg++; + + /* subglyph 1 = accent character */ + subg->index = achar_index; + subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES; + subg->arg1 = adx - asb; + subg->arg2 = ady; + + /* set up remaining glyph fields */ + glyph->num_subglyphs = 2; + glyph->subglyphs = loader->base.subglyphs; + glyph->format = ft_glyph_format_composite; + + loader->current.num_subglyphs = 2; + } + + /* First load `bchar' in builder */ + /* now load the unscaled outline */ + + FT_GlyphLoader_Prepare( decoder->builder.loader ); /* prepare loader */ + + error = Z1_Parse_CharStrings( decoder, + type1->charstrings [bchar_index], + type1->charstrings_len[bchar_index], + type1->num_subrs, + type1->subrs, + type1->subrs_len ); + if ( error ) + goto Exit; + + n_base_points = base->n_points; + + /* save the left bearing and width of the base character */ + /* as they will be erased by the next load. */ + + left_bearing = decoder->builder.left_bearing; + advance = decoder->builder.advance; + + decoder->builder.left_bearing.x = 0; + decoder->builder.left_bearing.y = 0; + + /* Now load `achar' on top of */ + /* the base outline */ + error = Z1_Parse_CharStrings( decoder, + type1->charstrings [achar_index], + type1->charstrings_len[achar_index], + type1->num_subrs, + type1->subrs, + type1->subrs_len ); + if ( error ) + return error; + + /* restore the left side bearing and */ + /* advance width of the base character */ + + decoder->builder.left_bearing = left_bearing; + decoder->builder.advance = advance; + + /* Finally, move the accent */ + if ( decoder->builder.load_points ) + { + FT_Outline dummy; + + + dummy.n_points = base->n_points - n_base_points; + dummy.points = base->points + n_base_points; + FT_Outline_Translate( &dummy, adx - asb, ady ); + } + + Exit: + return error; + } + + +#define USE_ARGS( n ) do \ + { \ + top -= n; \ + if ( top < decoder->stack ) \ + goto Stack_Underflow; \ + } while ( 0 ) + + + /*************************************************************************/ + /* */ + /* */ + /* Z1_Parse_CharStrings */ + /* */ + /* */ + /* Parses a given Type 1 charstrings program. */ + /* */ + /* */ + /* decoder :: The current Type 1 decoder. */ + /* */ + /* charstring_base :: The base address of the charstring stream. */ + /* */ + /* charstring_len :: The length in bytes of the charstring stream. */ + /* */ + /* num_subrs :: The number of sub-routines. */ + /* */ + /* subrs_base :: An array of sub-routines addresses. */ + /* */ + /* subrs_len :: An array of sub-routines lengths. */ + /* */ + /* */ + /* Free error code. 0 means success. */ + /* */ + LOCAL_FUNC + FT_Error Z1_Parse_CharStrings( Z1_Decoder* decoder, + FT_Byte* charstring_base, + FT_Int charstring_len, + FT_Int num_subrs, + FT_Byte** subrs_base, + FT_Int* subrs_len ) + { + FT_Error error; + Z1_Decoder_Zone* zone; + FT_Byte* ip; + FT_Byte* limit; + Z1_Builder* builder = &decoder->builder; + FT_Outline* outline; + FT_Pos x, y; + + + /* First of all, initialize the decoder */ + decoder->top = decoder->stack; + decoder->zone = decoder->zones; + zone = decoder->zones; + + builder->path_begun = 0; + + zone->base = charstring_base; + limit = zone->limit = charstring_base + charstring_len; + ip = zone->cursor = zone->base; + + error = T1_Err_Ok; + outline = builder->current; + + x = builder->pos_x; + y = builder->pos_y; + + /* now, execute loop */ + while ( ip < limit ) + { + FT_Int* top = decoder->top; + Z1_Operator op = op_none; + FT_Long value = 0; + + + /*********************************************************************/ + /* */ + /* Decode operator or operand */ + /* */ + /* */ + + /* first of all, decompress operator or value */ + switch ( *ip++ ) + { + case 1: + op = op_hstem; + break; + + case 3: + op = op_vstem; + break; + case 4: + op = op_vmoveto; + break; + case 5: + op = op_rlineto; + break; + case 6: + op = op_hlineto; + break; + case 7: + op = op_vlineto; + break; + case 8: + op = op_rrcurveto; + break; + case 9: + op = op_closepath; + break; + case 10: + op = op_callsubr; + break; + case 11: + op = op_return; + break; + + case 13: + op = op_hsbw; + break; + case 14: + op = op_endchar; + break; + + case 21: + op = op_rmoveto; + break; + case 22: + op = op_hmoveto; + break; + + case 30: + op = op_vhcurveto; + break; + case 31: + op = op_hvcurveto; + break; + + case 12: + if ( ip > limit ) + { + FT_ERROR(( "Z1_Parse_CharStrings: invalid escape (12+EOF)\n" )); + goto Syntax_Error; + } + + switch ( *ip++ ) + { + case 0: + op = op_dotsection; + break; + case 1: + op = op_vstem3; + break; + case 2: + op = op_hstem3; + break; + case 6: + op = op_seac; + break; + case 7: + op = op_sbw; + break; + case 12: + op = op_div; + break; + case 16: + op = op_callothersubr; + break; + case 17: + op = op_pop; + break; + case 33: + op = op_setcurrentpoint; + break; + + default: + FT_ERROR(( "Z1_Parse_CharStrings: invalid escape (12+%d)\n", + ip[-1] )); + goto Syntax_Error; + } + break; + + case 255: /* four bytes integer */ + if ( ip + 4 > limit ) + { + FT_ERROR(( "Z1_Parse_CharStrings: unexpected EOF in integer\n" )); + goto Syntax_Error; + } + + value = ( (FT_Long)ip[0] << 24 ) | + ( (FT_Long)ip[1] << 16 ) | + ( (FT_Long)ip[2] << 8 ) | + ip[3]; + ip += 4; + break; + + default: + if ( ip[-1] >= 32 ) + { + if ( ip[-1] < 247 ) + value = (FT_Long)ip[-1] - 139; + else + { + if ( ++ip > limit ) + { + FT_ERROR(( "Z1_Parse_CharStrings:" )); + FT_ERROR(( " unexpected EOF in integer\n" )); + goto Syntax_Error; + } + + if ( ip[-2] < 251 ) + value = ( (FT_Long)( ip[-2] - 247 ) << 8 ) + ip[-1] + 108; + else + value = -( ( ( (FT_Long)ip[-2] - 251 ) << 8 ) + ip[-1] + 108 ); + } + } + else + { + FT_ERROR(( "Z1_Parse_CharStrings: invalid byte (%d)\n", + ip[-1] )); + goto Syntax_Error; + } + } + + /*********************************************************************/ + /* */ + /* Push value on stack, or process operator */ + /* */ + /* */ + if ( op == op_none ) + { + if ( top - decoder->stack >= T1_MAX_CHARSTRINGS_OPERANDS ) + { + FT_ERROR(( "Z1_Parse_CharStrings: stack overflow!\n" )); + goto Syntax_Error; + } + + FT_TRACE4(( " %ld", value )); + + *top++ = value; + decoder->top = top; + } + else if ( op == op_callothersubr ) /* callothersubr */ + { + FT_TRACE4(( " callothersubr" )); + + if ( top - decoder->stack < 2 ) + goto Stack_Underflow; + + top -= 2; + switch ( top[1] ) + { + case 1: /* start flex feature */ + if ( top[0] != 0 ) + goto Unexpected_OtherSubr; + + decoder->flex_state = 1; + decoder->num_flex_vectors = 0; + if ( start_point( builder, x, y ) || + check_points( builder, 6 ) ) + goto Memory_Error; + break; + + case 2: /* add flex vectors */ + { + FT_Int index; + + if ( top[0] != 0 ) + goto Unexpected_OtherSubr; + + /* note that we should not add a point for index 0; */ + /* this will move our current position to the flex */ + /* point without adding any point to the outline */ + index = decoder->num_flex_vectors++; + if ( index > 0 && index < 7 ) + add_point( builder, + x, + y, + (FT_Byte)( index == 3 || index == 6 ) ); + } + break; + + case 0: /* end flex feature */ + if ( top[0] != 3 ) + goto Unexpected_OtherSubr; + + if ( decoder->flex_state == 0 || + decoder->num_flex_vectors != 7 ) + { + FT_ERROR(( "Z1_Parse_CharStrings: unexpected flex end\n" )); + goto Syntax_Error; + } + + /* now consume the remaining `pop pop setcurpoint' */ + if ( ip + 6 > limit || + ip[0] != 12 || ip[1] != 17 || /* pop */ + ip[2] != 12 || ip[3] != 17 || /* pop */ + ip[4] != 12 || ip[5] != 33 ) /* setcurpoint */ + { + FT_ERROR(( "Z1_Parse_CharStrings: invalid flex charstring\n" )); + goto Syntax_Error; + } + + ip += 6; + decoder->flex_state = 0; + break; + + case 3: /* change hints */ + if ( top[0] != 1 ) + goto Unexpected_OtherSubr; + + /* eat the following `pop' */ + if ( ip + 2 > limit ) + { + FT_ERROR(( "Z1_Parse_CharStrings: invalid escape (12+%d)\n", + ip[-1] )); + goto Syntax_Error; + } + + if ( ip[0] != 12 || ip[1] != 17 ) + { + FT_ERROR(( "Z1_Parse_CharStrings:" )); + FT_ERROR(( " `pop' expected, found (%d %d)\n", + ip[0], ip[1] )); + goto Syntax_Error; + } + ip += 2; + break; + + case 12: + case 13: + /* counter control hints, clear stack */ + top = decoder->stack; + break; + + case 14: + case 15: + case 16: + case 17: + case 18: /* multiple masters */ + { + T1_Blend* blend = decoder->blend; + FT_UInt num_points, nn, mm; + FT_Int* delta; + FT_Int* values; + + + if ( !blend ) + { + FT_ERROR(( "Z1_Parse_CharStrings:" )); + FT_ERROR(( " unexpected multiple masters operator!\n" )); + goto Syntax_Error; + } + + num_points = top[1] - 13 + ( top[1] == 18 ); + if ( top[0] != (FT_Int)( num_points * blend->num_designs ) ) + { + FT_ERROR(( "Z1_Parse_CharStrings:" )); + FT_ERROR(( " incorrect number of mm arguments\n" )); + goto Syntax_Error; + } + + top -= blend->num_designs*num_points; + if ( top < decoder->stack ) + goto Stack_Underflow; + + /* we want to compute: */ + /* */ + /* a0*w0 + a1*w1 + ... + ak*wk */ + /* */ + /* but we only have the a0, a1-a0, a2-a0, .. ak-a0 */ + /* however, given that w0 + w1 + ... + wk == 1, we can */ + /* rewrite it easily as: */ + /* */ + /* a0 + (a1-a0)*w1 + (a2-a0)*w2 + .. + (ak-a0)*wk */ + /* */ + /* where k == num_designs-1 */ + /* */ + /* I guess that's why it's written in this `compact' */ + /* form. */ + /* */ + delta = top + num_points; + values = top; + for ( nn = 0; nn < num_points; nn++ ) + { + FT_Int x = values[0]; + + + for ( mm = 1; mm < blend->num_designs; mm++ ) + x += FT_MulFix( *delta++, blend->weight_vector[mm] ); + + *values++ = x; + } + /* note that `top' will be incremented later by calls to `pop' */ + break; + } + + default: + Unexpected_OtherSubr: + FT_ERROR(( "Z1_Parse_CharStrings: invalid othersubr [%d %d]!\n", + top[0], top[1] )); + goto Syntax_Error; + } + decoder->top = top; + } + else /* general operator */ + { + FT_Int num_args = t1_args_count[op]; + + + if ( top - decoder->stack < num_args ) + goto Stack_Underflow; + + top -= num_args; + + switch ( op ) + { + case op_endchar: + FT_TRACE4(( " endchar" )); + + close_contour( builder ); + + /* add current outline to the glyph slot */ + FT_GlyphLoader_Add( builder->loader ); + + /* return now! */ + FT_TRACE4(( "\n\n" )); + return T1_Err_Ok; + + case op_hsbw: + FT_TRACE4(( " hsbw" )); + + builder->left_bearing.x += top[0]; + builder->advance.x = top[1]; + builder->advance.y = 0; + + builder->last.x = x = top[0]; + builder->last.y = y = 0; + + /* the `metrics_only' indicates that we only want to compute */ + /* the glyph's metrics (lsb + advance width), not load the */ + /* rest of it; so exit immediately */ + if ( builder->metrics_only ) + return T1_Err_Ok; + + break; + + case op_seac: + /* return immediately after the processing */ + return t1operator_seac( decoder, top[0], top[1], + top[2], top[3], top[4] ); + + case op_sbw: + FT_TRACE4(( " sbw" )); + + builder->left_bearing.x += top[0]; + builder->left_bearing.y += top[1]; + builder->advance.x = top[2]; + builder->advance.y = top[3]; + + builder->last.x = x = top[0]; + builder->last.y = y = top[1]; + + /* the `metrics_only' indicates that we only want to compute */ + /* the glyph's metrics (lsb + advance width), not load the */ + /* rest of it; so exit immediately */ + if ( builder->metrics_only ) + return T1_Err_Ok; + + break; + + case op_closepath: + FT_TRACE4(( " closepath" )); + + close_contour( builder ); + builder->path_begun = 0; + break; + + case op_hlineto: + FT_TRACE4(( " hlineto" )); + + if ( start_point( builder, x, y ) ) + goto Memory_Error; + + x += top[0]; + goto Add_Line; + + case op_hmoveto: + FT_TRACE4(( " hmoveto" )); + + x += top[0]; + break; + + case op_hvcurveto: + FT_TRACE4(( " hvcurveto" )); + + if ( start_point( builder, x, y ) || + check_points( builder, 3 ) ) + goto Memory_Error; + + x += top[0]; + add_point( builder, x, y, 0 ); + x += top[1]; + y += top[2]; + add_point( builder, x, y, 0 ); + y += top[3]; + add_point( builder, x, y, 1 ); + break; + + case op_rlineto: + FT_TRACE4(( " rlineto" )); + + if ( start_point( builder, x, y ) ) + goto Memory_Error; + + x += top[0]; + y += top[1]; + + Add_Line: + if ( add_point1( builder, x, y ) ) + goto Memory_Error; + break; + + case op_rmoveto: + FT_TRACE4(( " rmoveto" )); + + x += top[0]; + y += top[1]; + break; + + case op_rrcurveto: + FT_TRACE4(( " rcurveto" )); + + if ( start_point( builder, x, y ) || + check_points( builder, 3 ) ) + goto Memory_Error; + + x += top[0]; + y += top[1]; + add_point( builder, x, y, 0 ); + + x += top[2]; + y += top[3]; + add_point( builder, x, y, 0 ); + + x += top[4]; + y += top[5]; + add_point( builder, x, y, 1 ); + break; + + case op_vhcurveto: + FT_TRACE4(( " vhcurveto" )); + + if ( start_point( builder, x, y ) || + check_points( builder, 3 ) ) + goto Memory_Error; + + y += top[0]; + add_point( builder, x, y, 0 ); + x += top[1]; + y += top[2]; + add_point( builder, x, y, 0 ); + x += top[3]; + add_point( builder, x, y, 1 ); + break; + + case op_vlineto: + FT_TRACE4(( " vlineto" )); + + if ( start_point( builder, x, y ) ) + goto Memory_Error; + + y += top[0]; + goto Add_Line; + + case op_vmoveto: + FT_TRACE4(( " vmoveto" )); + + y += top[0]; + break; + + case op_div: + FT_TRACE4(( " div" )); + + if ( top[1] ) + { + *top = top[0] / top[1]; + ++top; + } + else + { + FT_ERROR(( "Z1_Parse_CharStrings: division by 0\n" )); + goto Syntax_Error; + } + break; + + case op_callsubr: + { + FT_Int index; + + + FT_TRACE4(( " callsubr" )); + + index = top[0]; + if ( index < 0 || index >= num_subrs ) + { + FT_ERROR(( "Z1_Parse_CharStrings: invalid subrs index\n" )); + goto Syntax_Error; + } + + if ( zone - decoder->zones >= T1_MAX_SUBRS_CALLS ) + { + FT_ERROR(( "Z1_Parse_CharStrings: too many nested subrs\n" )); + goto Syntax_Error; + } + + zone->cursor = ip; /* save current instruction pointer */ + + zone++; + zone->base = subrs_base[index]; + zone->limit = zone->base + subrs_len[index]; + zone->cursor = zone->base; + + if ( !zone->base ) + { + FT_ERROR(( "Z1_Parse_CharStrings: invoking empty subrs!\n" )); + goto Syntax_Error; + } + + decoder->zone = zone; + ip = zone->base; + limit = zone->limit; + break; + } + + case op_pop: + FT_TRACE4(( " pop" )); + + /* theorically, the arguments are already on the stack */ + top++; + break; + + case op_return: + FT_TRACE4(( " return" )); + + if ( zone <= decoder->zones ) + { + FT_ERROR(( "Z1_Parse_CharStrings: unexpected return\n" )); + goto Syntax_Error; + } + + zone--; + ip = zone->cursor; + limit = zone->limit; + decoder->zone = zone; + break; + + case op_dotsection: + FT_TRACE4(( " dotsection" )); + + break; + + case op_hstem: + FT_TRACE4(( " hstem" )); + + break; + + case op_hstem3: + FT_TRACE4(( " hstem3" )); + + break; + + case op_vstem: + FT_TRACE4(( " vstem" )); + + break; + + case op_vstem3: + FT_TRACE4(( " vstem3" )); + + break; + + case op_setcurrentpoint: + FT_TRACE4(( " setcurrentpoint" )); + + FT_ERROR(( "Z1_Parse_CharStrings:" )); + FT_ERROR(( " unexpected `setcurrentpoint'\n" )); + goto Syntax_Error; + + default: + FT_ERROR(( "Z1_Parse_CharStrings: unhandled opcode %d\n", op )); + goto Syntax_Error; + } + + decoder->top = top; + + } /* general operator processing */ + + } /* while ip < limit */ + + FT_TRACE4(( "..end..\n\n" )); + return error; + + Syntax_Error: + return T1_Err_Syntax_Error; + + Stack_Underflow: + return T1_Err_Stack_Underflow; + + Memory_Error: + return builder->error; + } + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /********** *********/ + /********** COMPUTE THE MAXIMUM ADVANCE WIDTH *********/ + /********** *********/ + /********** The following code is in charge of computing *********/ + /********** the maximum advance width of the font. It *********/ + /********** quickly processes each glyph charstring to *********/ + /********** extract the value from either a `sbw' or `seac' *********/ + /********** operator. *********/ + /********** *********/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + LOCAL_FUNC + FT_Error Z1_Compute_Max_Advance( T1_Face face, + FT_Int* max_advance ) + { + FT_Error error; + Z1_Decoder decoder; + FT_Int glyph_index; + T1_Font* type1 = &face->type1; + + + *max_advance = 0; + + /* Initialize load decoder */ + Z1_Init_Decoder( &decoder ); + Z1_Init_Builder( &decoder.builder, face, 0, 0 ); + + decoder.blend = face->blend; + decoder.builder.metrics_only = 1; + decoder.builder.load_points = 0; + + /* for each glyph, parse the glyph charstring and extract */ + /* the advance width */ + for ( glyph_index = 0; glyph_index < type1->num_glyphs; glyph_index++ ) + { + /* now get load the unscaled outline */ + error = Z1_Parse_CharStrings( &decoder, + type1->charstrings [glyph_index], + type1->charstrings_len[glyph_index], + type1->num_subrs, + type1->subrs, + type1->subrs_len ); + /* ignore the error if one occured - skip to next glyph */ + } + + *max_advance = decoder.builder.advance.x; + return T1_Err_Ok; + } + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /********** *********/ + /********** UNHINTED GLYPH LOADER *********/ + /********** *********/ + /********** The following code is in charge of loading a *********/ + /********** single outline. It completely ignores hinting *********/ + /********** and is used when FT_LOAD_NO_HINTING is set. *********/ + /********** *********/ + /********** The Type 1 hinter is located in `t1hint.c' *********/ + /********** *********/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + LOCAL_FUNC + FT_Error Z1_Load_Glyph( Z1_GlyphSlot glyph, + Z1_Size size, + FT_Int glyph_index, + FT_Int load_flags ) + { + FT_Error error; + Z1_Decoder decoder; + T1_Face face = (T1_Face)glyph->root.face; + FT_Bool hinting; + T1_Font* type1 = &face->type1; + + + if ( load_flags & FT_LOAD_NO_RECURSE ) + load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING; + + glyph->x_scale = size->root.metrics.x_scale; + glyph->y_scale = size->root.metrics.y_scale; + + glyph->root.outline.n_points = 0; + glyph->root.outline.n_contours = 0; + + hinting = ( load_flags & FT_LOAD_NO_SCALE ) == 0 && + ( load_flags & FT_LOAD_NO_HINTING ) == 0; + + glyph->root.format = ft_glyph_format_outline; + + Z1_Init_Decoder( &decoder ); + Z1_Init_Builder( &decoder.builder, face, size, glyph ); + + decoder.blend = ((T1_Face)glyph->root.face)->blend; + decoder.builder.no_recurse = ( load_flags & FT_LOAD_NO_RECURSE ) != 0; + + /* now load the unscaled outline */ + error = Z1_Parse_CharStrings( &decoder, + type1->charstrings [glyph_index], + type1->charstrings_len[glyph_index], + type1->num_subrs, + type1->subrs, + type1->subrs_len ); + + /* save new glyph tables */ + Z1_Done_Builder( &decoder.builder ); + + /* now, set the metrics -- this is rather simple, as */ + /* the left side bearing is the xMin, and the top side */ + /* bearing the yMax */ + if ( !error ) + { + glyph->root.outline.flags &= ft_outline_owner; + glyph->root.outline.flags |= ft_outline_reverse_fill; + + /* for composite glyphs, return only left side bearing and */ + /* advance width */ + if ( load_flags & FT_LOAD_NO_RECURSE ) + { + glyph->root.metrics.horiBearingX = decoder.builder.left_bearing.x; + glyph->root.metrics.horiAdvance = decoder.builder.advance.x; + } + else + { + FT_BBox cbox; + FT_Glyph_Metrics* metrics = &glyph->root.metrics; + + + /* copy the _unscaled_ advance width */ + metrics->horiAdvance = decoder.builder.advance.x; + + /* make up vertical metrics */ + metrics->vertBearingX = 0; + metrics->vertBearingY = 0; + metrics->vertAdvance = 0; + + glyph->root.format = ft_glyph_format_outline; + + if ( size && size->root.metrics.y_ppem < 24 ) + glyph->root.outline.flags |= ft_outline_high_precision; + +#if 0 + glyph->root.outline.second_pass = TRUE; + glyph->root.outline.high_precision = size->root.metrics.y_ppem < 24; + glyph->root.outline.dropout_mode = 2; +#endif /* 0 */ + + if ( ( load_flags & FT_LOAD_NO_SCALE ) == 0 ) + { + /* scale the outline and the metrics */ + FT_Int n; + FT_Outline* cur = decoder.builder.base; + FT_Vector* vec = cur->points; + FT_Fixed x_scale = glyph->x_scale; + FT_Fixed y_scale = glyph->y_scale; + + + /* First of all, scale the points */ + for ( n = cur->n_points; n > 0; n--, vec++ ) + { + vec->x = FT_MulFix( vec->x, x_scale ); + vec->y = FT_MulFix( vec->y, y_scale ); + } + + FT_Outline_Get_CBox( &glyph->root.outline, &cbox ); + + /* Then scale the metrics */ + metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale ); + metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale ); + + metrics->vertBearingX = FT_MulFix( metrics->vertBearingX, x_scale ); + metrics->vertBearingY = FT_MulFix( metrics->vertBearingY, y_scale ); + } + + /* apply the font matrix */ + FT_Outline_Transform( &glyph->root.outline, + &face->type1.font_matrix ); + + /* compute the other metrics */ + FT_Outline_Get_CBox( &glyph->root.outline, &cbox ); + + /* grid fit the bounding box if necessary */ + if ( hinting ) + { + cbox.xMin &= -64; + cbox.yMin &= -64; + cbox.xMax = ( cbox.xMax+63 ) & -64; + cbox.yMax = ( cbox.yMax+63 ) & -64; + } + + metrics->width = cbox.xMax - cbox.xMin; + metrics->height = cbox.yMax - cbox.yMin; + + metrics->horiBearingX = cbox.xMin; + metrics->horiBearingY = cbox.yMax; + } + } + return error; + } + + +/* END */ diff --git a/src/freetype/type1z/z1gload.h b/src/freetype/type1z/z1gload.h new file mode 100644 index 0000000000..5bb6dc0a25 --- /dev/null +++ b/src/freetype/type1z/z1gload.h @@ -0,0 +1,187 @@ +/***************************************************************************/ +/* */ +/* z1gload.h */ +/* */ +/* Experimental Type 1 Glyph Loader (specification). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef Z1GLOAD_H +#define Z1GLOAD_H + + +#ifdef FT_FLAT_COMPILE + +#include "z1objs.h" + +#else + +#include + +#endif + + +#ifdef __cplusplus + extern "C" { +#endif + + + /*************************************************************************/ + /* */ + /* */ + /* Z1_Builder */ + /* */ + /* */ + /* A structure used during glyph loading to store its outline. */ + /* */ + /* */ + /* memory :: The current memory object. */ + /* */ + /* face :: The current face object. */ + /* */ + /* glyph :: The current glyph slot. */ + /* */ + /* loader :: The current glyph loader. */ + /* */ + /* current :: The current glyph outline. */ + /* */ + /* base :: The base glyph outline. */ + /* */ + /* last :: The last point position. */ + /* */ + /* scale_x :: The horizontal scale (FUnits to sub-pixels). */ + /* */ + /* scale_y :: The vertical scale (FUnits to sub-pixels). */ + /* */ + /* pos_x :: The horizontal translation (for composite glyphs). */ + /* */ + /* pos_y :: The vertical translation (for composite glyphs). */ + /* */ + /* left_bearing :: The left side bearing point. */ + /* */ + /* advance :: The horizontal advance vector. */ + /* */ + /* no_recurse :: */ + /* */ + /* bbox :: The glyph's bounding box. */ + /* */ + /* path_begun :: A flag which indicates that a new path has begun. */ + /* */ + /* load_points :: A flag which indicates, if not set, that no points */ + /* are loaded. */ + /* */ + /* error :: The current error code. */ + /* */ + /* metrics_only :: A flag whether to compute metrics only. */ + /* */ + typedef struct Z1_Builder_ + { + FT_Memory memory; + T1_Face face; + Z1_GlyphSlot glyph; + FT_GlyphLoader* loader; + + FT_Outline* current; /* the current glyph outline */ + FT_Outline* base; /* the composite glyph outline */ + + FT_Vector last; + + FT_Fixed scale_x; + FT_Fixed scale_y; + + FT_Pos pos_x; + FT_Pos pos_y; + + FT_Vector left_bearing; + FT_Vector advance; + + FT_BBox bbox; /* bounding box */ + FT_Bool path_begun; + FT_Bool load_points; + FT_Bool no_recurse; + + FT_Error error; /* only used for memory errors */ + FT_Bool metrics_only; + + } Z1_Builder; + + + /* execution context charstring zone */ + typedef struct Z1_Decoder_Zone_ + { + FT_Byte* base; + FT_Byte* limit; + FT_Byte* cursor; + + } Z1_Decoder_Zone; + + + typedef struct Z1_Decoder_ + { + Z1_Builder builder; + + FT_Int stack[T1_MAX_CHARSTRINGS_OPERANDS]; + FT_Int* top; + + Z1_Decoder_Zone zones[T1_MAX_SUBRS_CALLS + 1]; + Z1_Decoder_Zone* zone; + + FT_Int flex_state; + FT_Int num_flex_vectors; + FT_Vector flex_vectors[7]; + + T1_Blend* blend; /* for multiple masters */ + + } Z1_Decoder; + + + LOCAL_DEF + void Z1_Init_Builder( Z1_Builder* builder, + T1_Face face, + Z1_Size size, + Z1_GlyphSlot glyph ); + + LOCAL_DEF + void Z1_Done_Builder( Z1_Builder* builder ); + + LOCAL_DEF + void Z1_Init_Decoder( Z1_Decoder* decoder ); + + LOCAL_DEF + FT_Error Z1_Compute_Max_Advance( T1_Face face, + FT_Int* max_advance ); + + LOCAL_DEF + FT_Error Z1_Parse_CharStrings( Z1_Decoder* decoder, + FT_Byte* charstring_base, + FT_Int charstring_len, + FT_Int num_subrs, + FT_Byte** subrs_base, + FT_Int* subrs_len ); + + LOCAL_DEF + FT_Error Z1_Load_Glyph( Z1_GlyphSlot glyph, + Z1_Size size, + FT_Int glyph_index, + FT_Int load_flags ); + + +#ifdef __cplusplus + } +#endif + + +#endif /* Z1GLOAD_H */ + + +/* END */ diff --git a/src/freetype/type1z/z1load.c b/src/freetype/type1z/z1load.c new file mode 100644 index 0000000000..46478d1a85 --- /dev/null +++ b/src/freetype/type1z/z1load.c @@ -0,0 +1,1725 @@ +/***************************************************************************/ +/* */ +/* z1load.c */ +/* */ +/* Experimental Type 1 font loader (body). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + + /*************************************************************************/ + /* */ + /* This is the new and improved Type 1 data loader for FreeType 2. The */ + /* old loader has several problems: it is slow, complex, difficult to */ + /* maintain, and contains incredible hacks to make it accept some */ + /* ill-formed Type 1 fonts without hiccup-ing. Moreover, about 5% of */ + /* the Type 1 fonts on my machine still aren't loaded correctly by it. */ + /* */ + /* This version is much simpler, much faster and also easier to read and */ + /* maintain by a great order of magnitude. The idea behind it is to */ + /* _not_ try to read the Type 1 token stream with a state machine (i.e. */ + /* a Postscript-like interpreter) but rather to perform simple pattern */ + /* matching. */ + /* */ + /* Indeed, nearly all data definitions follow a simple pattern like */ + /* */ + /* ... /Field ... */ + /* */ + /* where can be a number, a boolean, a string, or an array of */ + /* numbers. There are a few exceptions, namely the encoding, font name, */ + /* charstrings, and subrs; they are handled with a special pattern */ + /* matching routine. */ + /* */ + /* All other common cases are handled very simply. The matching rules */ + /* are defined in the file `t1tokens.h' through the use of several */ + /* macros calls PARSE_XXX. */ + /* */ + /* This file is included twice here; the first time to generate parsing */ + /* callback functions, the second to generate a table of keywords (with */ + /* pointers to the associated callback). */ + /* */ + /* The function `parse_dict' simply scans *linearly* a given dictionary */ + /* (either the top-level or private one) and calls the appropriate */ + /* callback when it encounters an immediate keyword. */ + /* */ + /* This is by far the fastest way one can find to parse and read all */ + /* data. */ + /* */ + /* This led to tremendous code size reduction. Note that later, the */ + /* glyph loader will also be _greatly_ simplified, and the automatic */ + /* hinter will replace the clumsy `t1hinter'. */ + /* */ + /*************************************************************************/ + + +#include +#include +#include + +#include +#include + + +#ifdef FT_FLAT_COMPILE + +#include "z1load.h" + +#else + +#include + +#endif + + +#include /* for strncmp(), strcmp() */ +#include /* for isalnum() */ + + + /*************************************************************************/ + /* */ + /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ + /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ + /* messages during execution. */ + /* */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_z1load + + +#ifndef Z1_CONFIG_OPTION_NO_MM_SUPPORT + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** MULTIPLE MASTERS SUPPORT *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static + FT_Error t1_allocate_blend( T1_Face face, + FT_UInt num_designs, + FT_UInt num_axis ) + { + T1_Blend* blend; + FT_Memory memory = face->root.memory; + FT_Error error = 0; + + + blend = face->blend; + if ( !blend ) + { + if ( ALLOC( blend, sizeof ( *blend ) ) ) + goto Exit; + + face->blend = blend; + } + + /* allocate design data if needed */ + if ( num_designs > 0 ) + { + if ( blend->num_designs == 0 ) + { + FT_UInt nn; + + + /* allocate the blend `private' and `font_info' dictionaries */ + if ( ALLOC_ARRAY( blend->font_infos[1], num_designs, T1_FontInfo ) || + ALLOC_ARRAY( blend->privates[1], num_designs, T1_Private ) || + ALLOC_ARRAY( blend->weight_vector, num_designs * 2, FT_Fixed ) ) + goto Exit; + + blend->default_weight_vector = blend->weight_vector + num_designs; + + blend->font_infos[0] = &face->type1.font_info; + blend->privates [0] = &face->type1.private_dict; + + for ( nn = 2; nn <= num_designs; nn++ ) + { + blend->privates[nn] = blend->privates [nn - 1] + 1; + blend->font_infos[nn] = blend->font_infos[nn - 1] + 1; + } + + blend->num_designs = num_designs; + } + else if ( blend->num_designs != num_designs ) + goto Fail; + } + + /* allocate axis data if needed */ + if ( num_axis > 0 ) + { + if ( blend->num_axis != 0 && blend->num_axis != num_axis ) + goto Fail; + + blend->num_axis = num_axis; + } + + /* allocate the blend design pos table if needed */ + num_designs = blend->num_designs; + num_axis = blend->num_axis; + if ( num_designs && num_axis && blend->design_pos[0] == 0 ) + { + FT_UInt n; + + + if ( ALLOC_ARRAY( blend->design_pos[0], + num_designs * num_axis, FT_Fixed ) ) + goto Exit; + + for ( n = 1; n < num_designs; n++ ) + blend->design_pos[n] = blend->design_pos[0] + num_axis * n; + } + + Exit: + return error; + + Fail: + error = -1; + goto Exit; + } + + + LOCAL_FUNC + FT_Error Z1_Get_Multi_Master( T1_Face face, + FT_Multi_Master* master ) + { + T1_Blend* blend = face->blend; + FT_UInt n; + FT_Error error; + + + error = T1_Err_Invalid_Argument; + + if ( blend ) + { + master->num_axis = blend->num_axis; + master->num_designs = blend->num_designs; + + for ( n = 0; n < blend->num_axis; n++ ) + { + FT_MM_Axis* axis = master->axis + n; + T1_DesignMap* map = blend->design_map + n; + + + axis->name = blend->axis_names[n]; + axis->minimum = map->design_points[0]; + axis->maximum = map->design_points[map->num_points - 1]; + } + error = 0; + } + return error; + } + + + LOCAL_FUNC + FT_Error Z1_Set_MM_Blend( T1_Face face, + FT_UInt num_coords, + FT_Fixed* coords ) + { + T1_Blend* blend = face->blend; + FT_Error error; + FT_UInt n, m; + + + error = T1_Err_Invalid_Argument; + + if ( blend && blend->num_axis == num_coords ) + { + /* recompute the weight vector from the blend coordinates */ + error = FT_Err_Ok; + + for ( n = 0; n < blend->num_designs; n++ ) + { + FT_Fixed result = 0x10000L; /* 1.0 fixed */ + + + for ( m = 0; m < blend->num_axis; m++ ) + { + FT_Fixed factor; + + + /* get current blend axis position */ + factor = coords[m]; + if ( factor < 0 ) factor = 0; + if ( factor > 0x10000L ) factor = 0x10000L; + + if ( ( n & ( 1 << m ) ) == 0 ) + factor = 0x10000L - factor; + + result = FT_MulFix( result, factor ); + } + blend->weight_vector[n] = result; + } + + error = FT_Err_Ok; + } + return error; + } + + + LOCAL_FUNC + FT_Error Z1_Set_MM_Design( T1_Face face, + FT_UInt num_coords, + FT_Long* coords ) + { + T1_Blend* blend = face->blend; + FT_Error error; + FT_UInt n, p; + + + error = T1_Err_Invalid_Argument; + if ( blend && blend->num_axis == num_coords ) + { + /* compute the blend coordinates through the blend design map */ + FT_Fixed final_blends[T1_MAX_MM_DESIGNS]; + + + for ( n = 0; n < blend->num_axis; n++ ) + { + FT_Long design = coords[n]; + FT_Fixed the_blend; + T1_DesignMap* map = blend->design_map + n; + FT_Fixed* designs = map->design_points; + FT_Fixed* blends = map->blend_points; + FT_Int before = -1, after = -1; + + for ( p = 0; p < map->num_points; p++ ) + { + FT_Fixed p_design = designs[p]; + + + /* exact match ? */ + if ( design == p_design ) + { + the_blend = blends[p]; + goto Found; + } + + if ( design < p_design ) + { + after = p; + break; + } + + before = p; + } + + /* now, interpolate if needed */ + if ( before < 0 ) + the_blend = blends[0]; + + else if ( after < 0 ) + the_blend = blends[map->num_points - 1]; + + else + the_blend = FT_MulDiv( design - designs[before], + blends [after] - blends [before], + designs[after] - designs[before] ); + + Found: + final_blends[n] = the_blend; + } + + error = Z1_Set_MM_Blend( face, num_coords, final_blends ); + } + + return error; + } + + + LOCAL_FUNC + void Z1_Done_Blend( T1_Face face ) + { + FT_Memory memory = face->root.memory; + T1_Blend* blend = face->blend; + + + if ( blend ) + { + FT_UInt num_designs = blend->num_designs; + FT_UInt num_axis = blend->num_axis; + FT_UInt n; + + + /* release design pos table */ + FREE( blend->design_pos[0] ); + for ( n = 1; n < num_designs; n++ ) + blend->design_pos[n] = 0; + + /* release blend `private' and `font info' dictionaries */ + FREE( blend->privates[1] ); + FREE( blend->font_infos[1] ); + + for ( n = 0; n < num_designs; n++ ) + { + blend->privates [n] = 0; + blend->font_infos[n] = 0; + } + + /* release weight vectors */ + FREE( blend->weight_vector ); + blend->default_weight_vector = 0; + + /* release axis names */ + for ( n = 0; n < num_axis; n++ ) + FREE( blend->axis_names[n] ); + + /* release design map */ + for ( n = 0; n < num_axis; n++ ) + { + T1_DesignMap* dmap = blend->design_map + n; + + + FREE( dmap->design_points ); + dmap->num_points = 0; + } + + FREE( face->blend ); + } + } + + + static + void parse_blend_axis_types( T1_Face face, + Z1_Loader* loader ) + { + Z1_Token_Rec axis_tokens[ T1_MAX_MM_AXIS ]; + FT_Int n, num_axis; + FT_Error error = 0; + T1_Blend* blend; + FT_Memory memory; + + + /* take an array of objects */ + Z1_ToTokenArray( &loader->parser, axis_tokens, + T1_MAX_MM_AXIS, &num_axis ); + if ( num_axis <= 0 || num_axis > T1_MAX_MM_AXIS ) + { + FT_ERROR(( "parse_blend_axis_types: incorrect number of axes: %d\n", + num_axis )); + error = T1_Err_Invalid_File_Format; + goto Exit; + } + + /* allocate blend if necessary */ + error = t1_allocate_blend( face, 0, (FT_UInt)num_axis ); + if ( error ) + goto Exit; + + blend = face->blend; + memory = face->root.memory; + + /* each token is an immediate containing the name of the axis */ + for ( n = 0; n < num_axis; n++ ) + { + Z1_Token_Rec* token = axis_tokens + n; + FT_Byte* name; + FT_Int len; + + /* skip first slash, if any */ + if (token->start[0] == '/') + token->start++; + + len = token->limit - token->start; + if ( len <= 0 ) + { + error = T1_Err_Invalid_File_Format; + goto Exit; + } + + if ( ALLOC( blend->axis_names[n], len + 1 ) ) + goto Exit; + + name = (FT_Byte*)blend->axis_names[n]; + MEM_Copy( name, token->start, len ); + name[len] = 0; + } + + Exit: + loader->parser.error = error; + } + + + static + void parse_blend_design_positions( T1_Face face, + Z1_Loader* loader ) + { + Z1_Token_Rec design_tokens[ T1_MAX_MM_DESIGNS ]; + FT_Int num_designs; + FT_Int num_axis; + Z1_Parser* parser = &loader->parser; + + FT_Error error = 0; + T1_Blend* blend; + + + /* get the array of design tokens - compute number of designs */ + Z1_ToTokenArray( parser, design_tokens, T1_MAX_MM_DESIGNS, &num_designs ); + if ( num_designs <= 0 || num_designs > T1_MAX_MM_DESIGNS ) + { + FT_ERROR(( "parse_blend_design_positions:" )); + FT_ERROR(( " incorrect number of designs: %d\n", + num_designs )); + error = T1_Err_Invalid_File_Format; + goto Exit; + } + + { + FT_Byte* old_cursor = parser->cursor; + FT_Byte* old_limit = parser->limit; + FT_UInt n; + + + blend = face->blend; + num_axis = 0; /* make compiler happy */ + + for ( n = 0; n < (FT_UInt)num_designs; n++ ) + { + Z1_Token_Rec axis_tokens[ T1_MAX_MM_DESIGNS ]; + Z1_Token_Rec* token; + FT_Int axis, n_axis; + + + /* read axis/coordinates tokens */ + token = design_tokens + n; + parser->cursor = token->start - 1; + parser->limit = token->limit + 1; + Z1_ToTokenArray( parser, axis_tokens, T1_MAX_MM_AXIS, &n_axis ); + + if ( n == 0 ) + { + num_axis = n_axis; + error = t1_allocate_blend( face, num_designs, num_axis ); + if ( error ) + goto Exit; + blend = face->blend; + } + else if ( n_axis != num_axis ) + { + FT_ERROR(( "parse_blend_design_positions: incorrect table\n" )); + error = T1_Err_Invalid_File_Format; + goto Exit; + } + + /* now, read each axis token into the design position */ + for ( axis = 0; axis < n_axis; axis++ ) + { + Z1_Token_Rec* token2 = axis_tokens + axis; + + + parser->cursor = token2->start; + parser->limit = token2->limit; + blend->design_pos[n][axis] = Z1_ToFixed( parser, 0 ); + } + } + + loader->parser.cursor = old_cursor; + loader->parser.limit = old_limit; + } + + Exit: + loader->parser.error = error; + } + + + static + void parse_blend_design_map( T1_Face face, + Z1_Loader* loader ) + { + FT_Error error = 0; + Z1_Parser* parser = &loader->parser; + T1_Blend* blend; + Z1_Token_Rec axis_tokens[ T1_MAX_MM_AXIS ]; + FT_Int n, num_axis; + FT_Byte* old_cursor; + FT_Byte* old_limit; + FT_Memory memory = face->root.memory; + + + Z1_ToTokenArray( parser, axis_tokens, T1_MAX_MM_AXIS, &num_axis ); + if ( num_axis <= 0 || num_axis > T1_MAX_MM_AXIS ) + { + FT_ERROR(( "parse_blend_design_map: incorrect number of axes: %d\n", + num_axis )); + error = T1_Err_Invalid_File_Format; + goto Exit; + } + old_cursor = parser->cursor; + old_limit = parser->limit; + + error = t1_allocate_blend( face, 0, num_axis ); + if ( error ) + goto Exit; + blend = face->blend; + + /* now, read each axis design map */ + for ( n = 0; n < num_axis; n++ ) + { + T1_DesignMap* map = blend->design_map + n; + Z1_Token_Rec* token; + FT_Int p, num_points; + + + token = axis_tokens + n; + parser->cursor = token->start; + parser->limit = token->limit; + + /* count the number of map points */ + { + FT_Byte* p = token->start; + FT_Byte* limit = token->limit; + + + num_points = 0; + for ( ; p < limit; p++ ) + if ( p[0] == '[' ) + num_points++; + } + if ( num_points <= 0 || num_points > T1_MAX_MM_MAP_POINTS ) + { + FT_ERROR(( "parse_blend_design_map: incorrect table\n" )); + error = T1_Err_Invalid_File_Format; + goto Exit; + } + + /* allocate design map data */ + if ( ALLOC_ARRAY( map->design_points, num_points * 2, FT_Fixed ) ) + goto Exit; + map->blend_points = map->design_points + num_points; + map->num_points = (FT_Byte)num_points; + + for ( p = 0; p < num_points; p++ ) + { + map->design_points[p] = Z1_ToInt( parser ); + map->blend_points [p] = Z1_ToFixed( parser, 0 ); + } + } + + parser->cursor = old_cursor; + parser->limit = old_limit; + + Exit: + parser->error = error; + } + + + static + void parse_weight_vector( T1_Face face, + Z1_Loader* loader ) + { + FT_Error error = 0; + Z1_Parser* parser = &loader->parser; + T1_Blend* blend = face->blend; + Z1_Token_Rec master; + FT_UInt n; + FT_Byte* old_cursor; + FT_Byte* old_limit; + + + if ( !blend || blend->num_designs == 0 ) + { + FT_ERROR(( "parse_weight_vector: too early!\n" )); + error = T1_Err_Invalid_File_Format; + goto Exit; + } + + Z1_ToToken( parser, &master ); + if ( master.type != t1_token_array ) + { + FT_ERROR(( "parse_weight_vector: incorrect format!\n" )); + error = T1_Err_Invalid_File_Format; + goto Exit; + } + + old_cursor = parser->cursor; + old_limit = parser->limit; + + parser->cursor = master.start; + parser->limit = master.limit; + + for ( n = 0; n < blend->num_designs; n++ ) + { + blend->default_weight_vector[n] = + blend->weight_vector[n] = Z1_ToFixed( parser, 0 ); + } + + parser->cursor = old_cursor; + parser->limit = old_limit; + + Exit: + parser->error = error; + } + + + /* the keyword `/shareddict' appears in some multiple master fonts */ + /* with a lot of Postscript garbage behind it (that's completely out */ + /* of spec!); we detect it and terminate the parsing */ + /* */ + static + void parse_shared_dict( T1_Face face, + Z1_Loader* loader ) + { + Z1_Parser* parser = &loader->parser; + + FT_UNUSED( face ); + + + parser->cursor = parser->limit; + parser->error = 0; + } + +#endif /* Z1_CONFIG_OPTION_NO_MM_SUPPORT */ + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** TYPE 1 SYMBOL PARSING *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* First of all, define the token field static variables. This is a set */ + /* of Z1_Field_Rec variables used later. */ + /* */ + /*************************************************************************/ + +#define Z1_NEW_STRING( _name, _field ) \ + static \ + const Z1_Field_Rec t1_field_ ## _field = \ + Z1_FIELD_STRING( T1TYPE, _field ); + +#define Z1_NEW_BOOL( _name, _field ) \ + static \ + const Z1_Field_Rec t1_field_ ## _field = \ + Z1_FIELD_BOOL( T1TYPE, _field ); + +#define Z1_NEW_NUM( _name, _field ) \ + static \ + const Z1_Field_Rec t1_field_ ## _field = \ + Z1_FIELD_NUM( T1TYPE, _field ); + +#define Z1_NEW_FIXED( _name, _field ) \ + static \ + const Z1_Field_Rec t1_field_ ## _field = \ + Z1_FIELD_FIXED( T1TYPE, _field, _power ); + +#define Z1_NEW_NUM_TABLE( _name, _field, _max, _count ) \ + static \ + const Z1_Field_Rec t1_field_ ## _field = \ + Z1_FIELD_NUM_ARRAY( T1TYPE, _field, _count, _max ); + +#define Z1_NEW_FIXED_TABLE( _name, _field, _max, _count ) \ + static \ + const Z1_Field_Rec t1_field_ ## _field = \ + Z1_FIELD_FIXED_ARRAY( T1TYPE, _field, _count, _max ); + +#define Z1_NEW_NUM_TABLE2( _name, _field, _max ) \ + static \ + const Z1_Field_Rec t1_field_ ## _field = \ + Z1_FIELD_NUM_ARRAY2( T1TYPE, _field, _max ); + +#define Z1_NEW_FIXED_TABLE2( _name, _field, _max ) \ + static \ + const Z1_Field_Rec t1_field_ ## _field = \ + Z1_FIELD_FIXED_ARRAY2( T1TYPE, _field, _max ); + + +#define Z1_FONTINFO_STRING( n, f ) Z1_NEW_STRING( n, f ) +#define Z1_FONTINFO_NUM( n, f ) Z1_NEW_NUM( n, f ) +#define Z1_FONTINFO_BOOL( n, f ) Z1_NEW_BOOL( n, f ) +#define Z1_PRIVATE_NUM( n, f ) Z1_NEW_NUM( n, f ) +#define Z1_PRIVATE_FIXED( n, f ) Z1_NEW_FIXED( n, f ) +#define Z1_PRIVATE_NUM_TABLE( n, f, m, c ) Z1_NEW_NUM_TABLE( n, f, m, c ) +#define Z1_PRIVATE_NUM_TABLE2( n, f, m ) Z1_NEW_NUM_TABLE2( n, f, m ) +#define Z1_TOPDICT_NUM( n, f ) Z1_NEW_NUM( n, f ) +#define Z1_TOPDICT_NUM_FIXED2( n, f, m ) Z1_NEW_FIXED_TABLE2( n, f, m ) + + + /* including this file defines all field variables */ +#ifdef FT_FLAT_COMPILE + +#include "z1tokens.h" + +#else + +#include + +#endif + + + /*************************************************************************/ + /* */ + /* Second, define the keyword variables. This is a set of Z1_KeyWord */ + /* structures used to model the way each keyword is `loaded'. */ + /* */ + /*************************************************************************/ + + typedef void (*Z1_Parse_Func)( T1_Face face, + Z1_Loader* loader ); + + + typedef enum Z1_KeyWord_Type_ + { + t1_keyword_callback = 0, + t1_keyword_field, + t1_keyword_field_table + + } Z1_KeyWord_Type; + + + typedef enum Z1_KeyWord_Location_ + { + t1_keyword_type1 = 0, + t1_keyword_font_info, + t1_keyword_private + + } Z1_KeyWord_Location; + + + typedef struct Z1_KeyWord_ + { + const char* name; + Z1_KeyWord_Type type; + Z1_KeyWord_Location location; + Z1_Parse_Func parsing; + const Z1_Field_Rec* field; + + } Z1_KeyWord; + + +#define Z1_KEYWORD_CALLBACK( name, callback ) \ + { \ + name, t1_keyword_callback, t1_keyword_type1, callback, 0 \ + } + +#define Z1_KEYWORD_TYPE1( name, f ) \ + { \ + name, t1_keyword_field, t1_keyword_type1, 0, &t1_field_ ## f \ + } + +#define Z1_KEYWORD_FONTINFO( name, f ) \ + { \ + name, t1_keyword_field, t1_keyword_font_info, 0, &t1_field_ ## f \ + } + +#define Z1_KEYWORD_PRIVATE( name, f ) \ + { \ + name, t1_keyword_field, t1_keyword_private, 0, &t1_field_ ## f \ + } + +#define Z1_KEYWORD_FONTINFO_TABLE( name, f ) \ + { \ + name, t1_keyword_field_table, t1_keyword_font_info, 0, \ + &t1_field_ ## f \ + } + +#define Z1_KEYWORD_PRIVATE_TABLE( name, f ) \ + { \ + name, t1_keyword_field_table, t1_keyword_private, 0, \ + &t1_field_ ## f \ + } + + +#undef Z1_FONTINFO_STRING +#undef Z1_FONTINFO_NUM +#undef Z1_FONTINFO_BOOL +#undef Z1_PRIVATE_NUM +#undef Z1_PRIVATE_FIXED +#undef Z1_PRIVATE_NUM_TABLE +#undef Z1_PRIVATE_NUM_TABLE2 +#undef Z1_TOPDICT_NUM +#undef Z1_TOPDICT_NUM_FIXED2 + +#define Z1_FONTINFO_STRING( n, f ) Z1_KEYWORD_FONTINFO( n, f ), +#define Z1_FONTINFO_NUM( n, f ) Z1_KEYWORD_FONTINFO( n, f ), +#define Z1_FONTINFO_BOOL( n, f ) Z1_KEYWORD_FONTINFO( n, f ), +#define Z1_PRIVATE_NUM( n, f ) Z1_KEYWORD_PRIVATE( n, f ), +#define Z1_PRIVATE_FIXED( n, f ) Z1_KEYWORD_PRIVATE( n, f ), +#define Z1_PRIVATE_NUM_TABLE( n, f, m, c ) Z1_KEYWORD_PRIVATE_TABLE( n, f ), +#define Z1_PRIVATE_NUM_TABLE2( n, f, m ) Z1_KEYWORD_PRIVATE_TABLE( n, f ), +#define Z1_TOPDICT_NUM( n, f ) Z1_KEYWORD_TYPE1( n, f ), +#define Z1_TOPDICT_NUM_FIXED2( n, f, m ) Z1_KEYWORD_TYPE1( n, f ), + + + static + FT_Error t1_load_keyword( T1_Face face, + Z1_Loader* loader, + Z1_KeyWord* keyword ) + { + FT_Error error; + void* dummy_object; + void** objects; + FT_UInt max_objects; + T1_Blend* blend = face->blend; + + + /* if the keyword has a dedicated callback, call it */ + if ( keyword->type == t1_keyword_callback ) + { + keyword->parsing( face, loader ); + error = loader->parser.error; + goto Exit; + } + + /* now, the keyword is either a simple field, or a table of fields; */ + /* we are now going to take care of it */ + switch ( keyword->location ) + { + case t1_keyword_font_info: + dummy_object = &face->type1.font_info; + objects = &dummy_object; + max_objects = 0; + + if ( blend ) + { + objects = (void**)blend->font_infos; + max_objects = blend->num_designs; + } + break; + + case t1_keyword_private: + dummy_object = &face->type1.private_dict; + objects = &dummy_object; + max_objects = 0; + + if ( blend ) + { + objects = (void**)blend->privates; + max_objects = blend->num_designs; + } + break; + + default: + dummy_object = &face->type1; + objects = &dummy_object; + max_objects = 0; + } + + if ( keyword->type == t1_keyword_field_table ) + error = Z1_Load_Field_Table( &loader->parser, keyword->field, + objects, max_objects, 0 ); + else + error = Z1_Load_Field( &loader->parser, keyword->field, + objects, max_objects, 0 ); + + Exit: + return error; + } + + + static + int is_space( char c ) + { + return ( c == ' ' || c == '\t' || c == '\r' || c == '\n' ); + } + + + static + int is_alpha( char c ) + { + return ( isalnum( c ) || + ( c == '.' ) || + ( c == '_' ) ); + } + + + static + void skip_whitespace( Z1_Parser* parser ) + { + FT_Byte* cur = parser->cursor; + + + while ( cur < parser->limit && is_space( *cur ) ) + cur++; + + parser->cursor = cur; + } + + + static + void skip_blackspace( Z1_Parser* parser ) + { + FT_Byte* cur = parser->cursor; + + while ( cur < parser->limit && !is_space( *cur ) ) + cur++; + + parser->cursor = cur; + } + + + static + int read_binary_data( Z1_Parser* parser, + FT_Int* size, + FT_Byte** base ) + { + FT_Byte* cur; + FT_Byte* limit = parser->limit; + + + /* the binary data has the following format */ + /* */ + /* `size' [white*] RD white ....... ND */ + /* */ + + skip_whitespace( parser ); + cur = parser->cursor; + + if ( cur < limit && (FT_Byte)( *cur - '0' ) < 10 ) + { + *size = Z1_ToInt( parser ); + + skip_whitespace( parser ); + skip_blackspace( parser ); /* `RD' or `-|' or something else */ + + /* there is only one whitespace char after the */ + /* `RD' or `-|' token */ + *base = parser->cursor + 1; + + parser->cursor += *size+1; + return 1; + } + + FT_ERROR(( "read_binary_data: invalid size field\n" )); + parser->error = T1_Err_Invalid_File_Format; + return 0; + } + + + /* we will now define the routines used to handle */ + /* the `/Encoding', `/Subrs', and `/CharStrings' */ + /* dictionaries */ + + static + void parse_font_name( T1_Face face, + Z1_Loader* loader ) + { + Z1_Parser* parser = &loader->parser; + FT_Error error; + FT_Memory memory = parser->memory; + FT_Int len; + FT_Byte* cur; + FT_Byte* cur2; + FT_Byte* limit; + + + skip_whitespace( parser ); + + cur = parser->cursor; + limit = parser->limit; + + if ( cur >= limit - 1 || *cur != '/' ) + return; + + cur++; + cur2 = cur; + while ( cur2 < limit && is_alpha( *cur2 ) ) + cur2++; + + len = cur2 - cur; + if ( len > 0 ) + { + if ( ALLOC( face->type1.font_name, len + 1 ) ) + { + parser->error = error; + return; + } + + MEM_Copy( face->type1.font_name, cur, len ); + face->type1.font_name[len] = '\0'; + } + parser->cursor = cur2; + } + + + static + void parse_font_bbox( T1_Face face, + Z1_Loader* loader ) + { + Z1_Parser* parser = &loader->parser; + FT_Short temp[4]; + FT_BBox* bbox = &face->type1.font_bbox; + + + (void)Z1_ToCoordArray( parser, 4, temp ); + bbox->xMin = temp[0]; + bbox->yMin = temp[1]; + bbox->xMax = temp[2]; + bbox->yMax = temp[3]; + } + + + static + void parse_font_matrix( T1_Face face, + Z1_Loader* loader ) + { + Z1_Parser* parser = &loader->parser; + FT_Matrix* matrix = &face->type1.font_matrix; + FT_Fixed temp[4]; + + + (void)Z1_ToFixedArray( parser, 4, temp, 3 ); + matrix->xx = temp[0]; + matrix->yx = temp[1]; + matrix->xy = temp[2]; + matrix->yy = temp[3]; + } + + + static + void parse_encoding( T1_Face face, + Z1_Loader* loader ) + { + Z1_Parser* parser = &loader->parser; + FT_Byte* cur = parser->cursor; + FT_Byte* limit = parser->limit; + + + /* skip whitespace */ + while ( is_space( *cur ) ) + { + cur++; + if ( cur >= limit ) + { + FT_ERROR(( "parse_encoding: out of bounds!\n" )); + parser->error = T1_Err_Invalid_File_Format; + return; + } + } + + /* if we have a number, then the encoding is an array, */ + /* and we must load it now */ + if ( (FT_Byte)( *cur - '0' ) < 10 ) + { + T1_Encoding* encode = &face->type1.encoding; + FT_Int count, n; + Z1_Table* char_table = &loader->encoding_table; + FT_Memory memory = parser->memory; + FT_Error error; + + + /* read the number of entries in the encoding, should be 256 */ + count = Z1_ToInt( parser ); + if ( parser->error ) + return; + + /* we use a Z1_Table to store our charnames */ + encode->num_chars = count; + if ( ALLOC_ARRAY( encode->char_index, count, FT_Short ) || + ALLOC_ARRAY( encode->char_name, count, FT_String* ) || + ( error = Z1_New_Table( char_table, count, memory ) ) != 0 ) + { + parser->error = error; + return; + } + + /* Now, we will need to read a record of the form */ + /* ... charcode /charname ... for each entry in our table */ + /* */ + /* We simply look for a number followed by an immediate */ + /* name. Note that this ignores correctly the sequence */ + /* that is often seen in type1 fonts: */ + /* */ + /* 0 1 255 { 1 index exch /.notdef put } for dup */ + /* */ + /* used to clean the encoding array before anything else. */ + /* */ + /* We stop when we encounter a `def'. */ + + cur = parser->cursor; + limit = parser->limit; + n = 0; + + for ( ; cur < limit; ) + { + FT_Byte c; + + + c = *cur; + + /* we stop when we encounter a `def' */ + if ( c == 'd' && cur + 3 < limit ) + { + if ( cur[1] == 'e' && + cur[2] == 'f' && + is_space(cur[-1]) && + is_space(cur[3]) ) + { + FT_TRACE6(( "encoding end\n" )); + break; + } + } + + /* otherwise, we must find a number before anything else */ + if ( (FT_Byte)( c - '0' ) < 10 ) + { + FT_Int charcode; + + + parser->cursor = cur; + charcode = Z1_ToInt( parser ); + cur = parser->cursor; + + /* skip whitespace */ + while ( cur < limit && is_space( *cur ) ) + cur++; + + if ( cur < limit && *cur == '/' ) + { + /* bingo, we have an immediate name -- it must be a */ + /* character name */ + FT_Byte* cur2 = cur + 1; + FT_Int len; + + + while ( cur2 < limit && is_alpha( *cur2 ) ) + cur2++; + + len = cur2 - cur - 1; + + parser->error = Z1_Add_Table( char_table, charcode, + cur + 1, len + 1 ); + char_table->elements[charcode][len] = '\0'; + if ( parser->error ) + return; + + cur = cur2; + } + } + else + cur++; + } + + face->type1.encoding_type = t1_encoding_array; + parser->cursor = cur; + } + /* Otherwise, we should have either `StandardEncoding' or */ + /* `ExpertEncoding' */ + else + { + if ( cur + 17 < limit && + strncmp( (const char*)cur, "StandardEncoding", 16 ) == 0 ) + face->type1.encoding_type = t1_encoding_standard; + + else if ( cur + 15 < limit && + strncmp( (const char*)cur, "ExpertEncoding", 14 ) == 0 ) + face->type1.encoding_type = t1_encoding_expert; + + else + { + FT_ERROR(( "parse_encoding: invalid token!\n" )); + parser->error = T1_Err_Invalid_File_Format; + } + } + } + + + static + void parse_subrs( T1_Face face, + Z1_Loader* loader ) + { + Z1_Parser* parser = &loader->parser; + Z1_Table* table = &loader->subrs; + FT_Memory memory = parser->memory; + FT_Error error; + FT_Int n; + + + loader->num_subrs = Z1_ToInt( parser ); + if ( parser->error ) + return; + + /* position the parser right before the `dup' of the first subr */ + skip_whitespace( parser ); + skip_blackspace( parser ); /* `array' */ + skip_whitespace( parser ); + + /* initialize subrs array */ + error = Z1_New_Table( table, loader->num_subrs, memory ); + if ( error ) + goto Fail; + + /* the format is simple: */ + /* */ + /* `index' + binary data */ + /* */ + + for ( n = 0; n < loader->num_subrs; n++ ) + { + FT_Int index, size; + FT_Byte* base; + + + /* If the next token isn't `dup', we are also done. This */ + /* happens when there are `holes' in the Subrs array. */ + if ( strncmp( (char*)parser->cursor, "dup", 3 ) != 0 ) + break; + + index = Z1_ToInt( parser ); + + if ( !read_binary_data( parser, &size, &base ) ) + return; + + /* The binary string is followed by one token, e.g. `NP' */ + /* (bound to `noaccess put') or by two separate tokens: */ + /* `noaccess' & `put'. We position the parser right */ + /* before the next `dup', if any. */ + skip_whitespace( parser ); + skip_blackspace( parser ); /* `NP' or `I' or `noaccess' */ + skip_whitespace( parser ); + + if ( strncmp( (char*)parser->cursor, "put", 3 ) == 0 ) + { + skip_blackspace( parser ); /* skip `put' */ + skip_whitespace( parser ); + } + + /* some fonts use a value of -1 for lenIV to indicate that */ + /* the charstrings are unencoded */ + /* */ + /* thanks to Tom Kacvinsky for pointing this out */ + /* */ + if ( face->type1.private_dict.lenIV >= 0 ) + { + Z1_Decrypt( base, size, 4330 ); + size -= face->type1.private_dict.lenIV; + base += face->type1.private_dict.lenIV; + } + + error = Z1_Add_Table( table, index, base, size ); + if ( error ) + goto Fail; + } + return; + + Fail: + parser->error = error; + } + + + static + void parse_charstrings( T1_Face face, + Z1_Loader* loader ) + { + Z1_Parser* parser = &loader->parser; + Z1_Table* code_table = &loader->charstrings; + Z1_Table* name_table = &loader->glyph_names; + FT_Memory memory = parser->memory; + FT_Error error; + + FT_Byte* cur; + FT_Byte* limit = parser->limit; + FT_Int n; + + + loader->num_glyphs = Z1_ToInt( parser ); + if ( parser->error ) + return; + + /* initialize tables */ + error = Z1_New_Table( code_table, loader->num_glyphs, memory ) || + Z1_New_Table( name_table, loader->num_glyphs, memory ); + if ( error ) + goto Fail; + + n = 0; + for (;;) + { + FT_Int size; + FT_Byte* base; + + + /* the format is simple: */ + /* `/glyphname' + binary data */ + /* */ + /* note that we stop when we find a `def' */ + /* */ + skip_whitespace( parser ); + + cur = parser->cursor; + if ( cur >= limit ) + break; + + /* we stop when we find a `def' or `end' keyword */ + if ( *cur == 'd' && + cur + 3 < limit && + cur[1] == 'e' && + cur[2] == 'f' ) + break; + + if ( *cur == 'e' && + cur + 3 < limit && + cur[1] == 'n' && + cur[2] == 'd' ) + break; + + if ( *cur != '/' ) + skip_blackspace( parser ); + else + { + FT_Byte* cur2 = cur + 1; + FT_Int len; + + + while ( cur2 < limit && is_alpha( *cur2 ) ) + cur2++; + len = cur2 - cur - 1; + + error = Z1_Add_Table( name_table, n, cur + 1, len + 1 ); + if ( error ) + goto Fail; + + /* add a trailing zero to the name table */ + name_table->elements[n][len] = '\0'; + + parser->cursor = cur2; + if ( !read_binary_data( parser, &size, &base ) ) + return; + + if ( face->type1.private_dict.lenIV >= 0 ) + { + Z1_Decrypt( base, size, 4330 ); + size -= face->type1.private_dict.lenIV; + base += face->type1.private_dict.lenIV; + } + + error = Z1_Add_Table( code_table, n, base, size ); + if ( error ) + goto Fail; + + n++; + if ( n >= loader->num_glyphs ) + break; + } + } + loader->num_glyphs = n; + return; + + Fail: + parser->error = error; + } + + + static + const Z1_KeyWord t1_keywords[] = + { + +#ifdef FT_FLAT_COMPILE + +#include "z1tokens.h" + +#else + +#include + +#endif + + /* now add the special functions... */ + Z1_KEYWORD_CALLBACK( "FontName", parse_font_name ), + Z1_KEYWORD_CALLBACK( "FontBBox", parse_font_bbox ), + Z1_KEYWORD_CALLBACK( "FontMatrix", parse_font_matrix ), + Z1_KEYWORD_CALLBACK( "Encoding", parse_encoding ), + Z1_KEYWORD_CALLBACK( "Subrs", parse_subrs ), + Z1_KEYWORD_CALLBACK( "CharStrings", parse_charstrings ), + +#ifndef Z1_CONFIG_OPTION_NO_MM_SUPPORT + Z1_KEYWORD_CALLBACK( "BlendDesignPositions", parse_blend_design_positions ), + Z1_KEYWORD_CALLBACK( "BlendDesignMap", parse_blend_design_map ), + Z1_KEYWORD_CALLBACK( "BlendAxisTypes", parse_blend_axis_types ), + Z1_KEYWORD_CALLBACK( "WeightVector", parse_weight_vector ), + Z1_KEYWORD_CALLBACK( "shareddict", parse_shared_dict ), +#endif + + Z1_KEYWORD_CALLBACK( 0, 0 ) + }; + + + static + FT_Error parse_dict( T1_Face face, + Z1_Loader* loader, + FT_Byte* base, + FT_Long size ) + { + Z1_Parser* parser = &loader->parser; + + + parser->cursor = base; + parser->limit = base + size; + parser->error = 0; + + { + FT_Byte* cur = base; + FT_Byte* limit = cur + size; + + + for ( ; cur < limit; cur++ ) + { + /* look for `FontDirectory', which causes problems on some fonts */ + if ( *cur == 'F' && cur + 25 < limit && + strncmp( (char*)cur, "FontDirectory", 13 ) == 0 ) + { + FT_Byte* cur2; + + + /* skip the `FontDirectory' keyword */ + cur += 13; + cur2 = cur; + + /* lookup the `known' keyword */ + while ( cur < limit && *cur != 'k' && + strncmp( (char*)cur, "known", 5 ) ) + cur++; + + if ( cur < limit ) + { + Z1_Token_Rec token; + + + /* skip the `known' keyword and the token following it */ + cur += 5; + loader->parser.cursor = cur; + Z1_ToToken( &loader->parser, &token ); + + /* if the last token was an array, skip it! */ + if ( token.type == t1_token_array ) + cur2 = parser->cursor; + } + cur = cur2; + } + /* look for immediates */ + else if ( *cur == '/' && cur + 2 < limit ) + { + FT_Byte* cur2; + FT_Int len; + + + cur++; + cur2 = cur; + while ( cur2 < limit && is_alpha( *cur2 ) ) + cur2++; + + len = cur2 - cur; + if ( len > 0 && len < 22 ) + { + if ( !loader->fontdata ) + { + if ( strncmp( (char*)cur, "FontInfo", 8 ) == 0 ) + loader->fontdata = 1; + } + else + { + /* now, compare the immediate name to the keyword table */ + Z1_KeyWord* keyword = (Z1_KeyWord*)t1_keywords; + + + for (;;) + { + FT_Byte* name; + + + name = (FT_Byte*)keyword->name; + if ( !name ) + break; + + if ( cur[0] == name[0] && + len == (FT_Int)strlen( (const char*)name ) ) + { + FT_Int n; + + + for ( n = 1; n < len; n++ ) + if ( cur[n] != name[n] ) + break; + + if ( n >= len ) + { + /* we found it -- run the parsing callback! */ + parser->cursor = cur2; + skip_whitespace( parser ); + parser->error = t1_load_keyword( face, loader, keyword ); + if ( parser->error ) + return parser->error; + + cur = parser->cursor; + break; + } + } + keyword++; + } + } + } + } + } + } + return parser->error; + } + + + static + void t1_init_loader( Z1_Loader* loader, + T1_Face face ) + { + FT_UNUSED( face ); + + MEM_Set( loader, 0, sizeof ( *loader ) ); + loader->num_glyphs = 0; + loader->num_chars = 0; + + /* initialize the tables -- simply set their `init' field to 0 */ + loader->encoding_table.init = 0; + loader->charstrings.init = 0; + loader->glyph_names.init = 0; + loader->subrs.init = 0; + loader->fontdata = 0; + } + + + static + void t1_done_loader( Z1_Loader* loader ) + { + Z1_Parser* parser = &loader->parser; + + + /* finalize tables */ + Z1_Release_Table( &loader->encoding_table ); + Z1_Release_Table( &loader->charstrings ); + Z1_Release_Table( &loader->glyph_names ); + Z1_Release_Table( &loader->subrs ); + + /* finalize parser */ + Z1_Done_Parser( parser ); + } + + + LOCAL_FUNC + FT_Error Z1_Open_Face( T1_Face face ) + { + Z1_Loader loader; + Z1_Parser* parser; + T1_Font* type1 = &face->type1; + FT_Error error; + + + t1_init_loader( &loader, face ); + + /* default lenIV */ + type1->private_dict.lenIV = 4; + + parser = &loader.parser; + error = Z1_New_Parser( parser, face->root.stream, face->root.memory ); + if ( error ) + goto Exit; + + error = parse_dict( face, &loader, parser->base_dict, parser->base_len ); + if ( error ) + goto Exit; + + error = Z1_Get_Private_Dict( parser ); + if ( error ) + goto Exit; + + error = parse_dict( face, &loader, parser->private_dict, + parser->private_len ); + if ( error ) + goto Exit; + + /* now, propagate the subrs, charstrings, and glyphnames tables */ + /* to the Type1 data */ + type1->num_glyphs = loader.num_glyphs; + + if ( !loader.subrs.init ) + { + FT_ERROR(( "Z1_Open_Face: no subrs array in face!\n" )); + error = T1_Err_Invalid_File_Format; + } + + if ( !loader.charstrings.init ) + { + FT_ERROR(( "Z1_Open_Face: no charstrings array in face!\n" )); + error = T1_Err_Invalid_File_Format; + } + + loader.subrs.init = 0; + type1->num_subrs = loader.num_subrs; + type1->subrs_block = loader.subrs.block; + type1->subrs = loader.subrs.elements; + type1->subrs_len = loader.subrs.lengths; + + loader.charstrings.init = 0; + type1->charstrings_block = loader.charstrings.block; + type1->charstrings = loader.charstrings.elements; + type1->charstrings_len = loader.charstrings.lengths; + + /* we copy the glyph names `block' and `elements' fields; */ + /* the `lengths' field must be released later */ + type1->glyph_names_block = loader.glyph_names.block; + type1->glyph_names = (FT_String**)loader.glyph_names.elements; + loader.glyph_names.block = 0; + loader.glyph_names.elements = 0; + + /* we must now build type1.encoding when we have a custom */ + /* array.. */ + if ( type1->encoding_type == t1_encoding_array ) + { + FT_Int charcode, index, min_char, max_char; + FT_Byte* char_name; + FT_Byte* glyph_name; + + + /* OK, we do the following: for each element in the encoding */ + /* table, look up the index of the glyph having the same name */ + /* the index is then stored in type1.encoding.char_index, and */ + /* a the name to type1.encoding.char_name */ + + min_char = +32000; + max_char = -32000; + + charcode = 0; + for ( ; charcode < loader.encoding_table.num_elems; charcode++ ) + { + type1->encoding.char_index[charcode] = 0; + type1->encoding.char_name [charcode] = ".notdef"; + + char_name = loader.encoding_table.elements[charcode]; + if ( char_name ) + for ( index = 0; index < type1->num_glyphs; index++ ) + { + glyph_name = (FT_Byte*)type1->glyph_names[index]; + if ( strcmp( (const char*)char_name, + (const char*)glyph_name ) == 0 ) + { + type1->encoding.char_index[charcode] = index; + type1->encoding.char_name [charcode] = (char*)glyph_name; + + if (charcode < min_char) min_char = charcode; + if (charcode > max_char) max_char = charcode; + break; + } + } + } + type1->encoding.code_first = min_char; + type1->encoding.code_last = max_char; + type1->encoding.num_chars = loader.num_chars; + } + + Exit: + t1_done_loader( &loader ); + return error; + } + + +/* END */ diff --git a/src/freetype/type1z/z1load.h b/src/freetype/type1z/z1load.h new file mode 100644 index 0000000000..672b5531b6 --- /dev/null +++ b/src/freetype/type1z/z1load.h @@ -0,0 +1,93 @@ +/***************************************************************************/ +/* */ +/* z1load.h */ +/* */ +/* Experimental Type 1 font loader (specification). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef Z1LOAD_H +#define Z1LOAD_H + +#include +#include +#include + + +#ifdef FT_FLAT_COMPILE + +#include "z1parse.h" + +#else + +#include + +#endif + + +#ifdef __cplusplus + extern "C" { +#endif + + typedef struct Z1_Loader_ + { + Z1_Parser parser; /* parser used to read the stream */ + + FT_Int num_chars; /* number of characters in encoding */ + Z1_Table encoding_table; /* Z1_Table used to store the */ + /* encoding character names */ + + FT_Int num_glyphs; + Z1_Table glyph_names; + Z1_Table charstrings; + + FT_Int num_subrs; + Z1_Table subrs; + FT_Bool fontdata; + + } Z1_Loader; + + + LOCAL_DEF + FT_Error Z1_Open_Face( T1_Face face ); + +#ifndef Z1_CONFIG_OPTION_NO_MM_SUPPORT + + LOCAL_DEF + FT_Error Z1_Get_Multi_Master( T1_Face face, + FT_Multi_Master* master ); + + LOCAL_DEF + FT_Error Z1_Set_MM_Blend( T1_Face face, + FT_UInt num_coords, + FT_Fixed* coords ); + + LOCAL_DEF + FT_Error Z1_Set_MM_Design( T1_Face face, + FT_UInt num_coords, + FT_Long* coords ); + + LOCAL_DEF + void Z1_Done_Blend( T1_Face face ); + +#endif /* !Z1_CONFIG_OPTION_NO_MM_SUPPORT */ + + +#ifdef __cplusplus + } +#endif + +#endif /* Z1LOAD_H */ + + +/* END */ diff --git a/src/freetype/type1z/z1objs.c b/src/freetype/type1z/z1objs.c new file mode 100644 index 0000000000..e452bb5edd --- /dev/null +++ b/src/freetype/type1z/z1objs.c @@ -0,0 +1,398 @@ +/***************************************************************************/ +/* */ +/* z1objs.c */ +/* */ +/* Experimental Type 1 objects manager (body). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#include +#include + + +#ifdef FT_FLAT_COMPILE + +#include "z1gload.h" +#include "z1load.h" +#include "z1afm.h" + +#else + +#include +#include +#include + +#endif + + +#include + + + /*************************************************************************/ + /* */ + /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ + /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ + /* messages during execution. */ + /* */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_z1objs + + + /*************************************************************************/ + /* */ + /* FACE FUNCTIONS */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* */ + /* Z1_Done_Face */ + /* */ + /* */ + /* The face object destructor. */ + /* */ + /* */ + /* face :: A typeless pointer to the face object to destroy. */ + /* */ + LOCAL_FUNC + void Z1_Done_Face( T1_Face face ) + { + FT_Memory memory; + T1_Font* type1 = &face->type1; + + + if ( face ) + { + memory = face->root.memory; + +#ifndef Z1_CONFIG_OPTION_NO_MM_SUPPORT + /* release multiple masters information */ + Z1_Done_Blend( face ); + face->blend = 0; +#endif + + /* release font info strings */ + { + T1_FontInfo* info = &type1->font_info; + + + FREE( info->version ); + FREE( info->notice ); + FREE( info->full_name ); + FREE( info->family_name ); + FREE( info->weight ); + } + + /* release top dictionary */ + FREE( type1->charstrings_len ); + FREE( type1->charstrings ); + FREE( type1->glyph_names ); + + FREE( type1->subrs ); + FREE( type1->subrs_len ); + + FREE( type1->subrs_block ); + FREE( type1->charstrings_block ); + FREE( type1->glyph_names_block ); + + FREE( type1->encoding.char_index ); + FREE( type1->font_name ); + +#ifndef Z1_CONFIG_OPTION_NO_AFM + /* release afm data if present */ + if ( face->afm_data ) + Z1_Done_AFM( memory, (Z1_AFM*)face->afm_data ); +#endif + + /* release unicode map, if any */ + FREE( face->unicode_map.maps ); + face->unicode_map.num_maps = 0; + + face->root.family_name = 0; + face->root.style_name = 0; + } + } + + + /*************************************************************************/ + /* */ + /* */ + /* Z1_Init_Face */ + /* */ + /* */ + /* The face object constructor. */ + /* */ + /* */ + /* stream :: input stream where to load font data. */ + /* */ + /* face_index :: The index of the font face in the resource. */ + /* */ + /* num_params :: Number of additional generic parameters. Ignored. */ + /* */ + /* params :: Additional generic parameters. Ignored. */ + /* */ + /* */ + /* face :: The face record to build. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + LOCAL_FUNC + FT_Error Z1_Init_Face( FT_Stream stream, + T1_Face face, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ) + { + FT_Error error; + PSNames_Interface* psnames; + + FT_UNUSED( num_params ); + FT_UNUSED( params ); + FT_UNUSED( face_index ); + FT_UNUSED( stream ); + + + face->root.num_faces = 1; + + psnames = (PSNames_Interface*)face->psnames; + if ( !psnames ) + { + psnames = (PSNames_Interface*) + FT_Get_Module_Interface( FT_FACE_LIBRARY( face ), "psnames" ); + + face->psnames = psnames; + } + + /* open the tokenizer, this will also check the font format */ + error = Z1_Open_Face( face ); + if ( error ) + goto Exit; + + /* if we just wanted to check the format, leave successfully now */ + if ( face_index < 0 ) + goto Exit; + + /* check the face index */ + if ( face_index != 0 ) + { + FT_ERROR(( "Z1_Init_Face: invalid face index\n" )); + error = T1_Err_Invalid_Argument; + goto Exit; + } + + /* Now, load the font program into the face object */ + + /* Init the face object fields */ + /* Now set up root face fields */ + { + FT_Face root = (FT_Face)&face->root; + + + root->num_glyphs = face->type1.num_glyphs; + root->num_charmaps = 1; + + root->face_index = face_index; + root->face_flags = FT_FACE_FLAG_SCALABLE; + + root->face_flags |= FT_FACE_FLAG_HORIZONTAL; + + root->face_flags |= FT_FACE_FLAG_GLYPH_NAMES; + + if ( face->type1.font_info.is_fixed_pitch ) + root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH; + + if ( face->blend ) + root->face_flags |= FT_FACE_FLAG_MULTIPLE_MASTERS; + + /* XXX: TODO -- add kerning with .afm support */ + + /* get style name -- be careful, some broken fonts only */ + /* have a `/FontName' dictionary entry! */ + root->family_name = face->type1.font_info.family_name; + if ( root->family_name ) + { + char* full = face->type1.font_info.full_name; + char* family = root->family_name; + + + while ( *family && *full == *family ) + { + family++; + full++; + } + + root->style_name = ( *full == ' ' ? full + 1 + : (char *)"Regular" ); + } + else + { + /* do we have a `/FontName'? */ + if ( face->type1.font_name ) + { + root->family_name = face->type1.font_name; + root->style_name = "Regular"; + } + } + + /* no embedded bitmap support */ + root->num_fixed_sizes = 0; + root->available_sizes = 0; + + root->bbox = face->type1.font_bbox; + root->units_per_EM = 1000; + root->ascender = (FT_Short)face->type1.font_bbox.yMax; + root->descender = -(FT_Short)face->type1.font_bbox.yMin; + root->height = ( ( root->ascender + root->descender ) * 12 ) / 10; + + /* now compute the maximum advance width */ + + root->max_advance_width = face->type1.private_dict.standard_width[0]; + + /* compute max advance width for proportional fonts */ + if ( !face->type1.font_info.is_fixed_pitch ) + { + FT_Int max_advance; + + + error = Z1_Compute_Max_Advance( face, &max_advance ); + + /* in case of error, keep the standard width */ + if ( !error ) + root->max_advance_width = max_advance; + else + error = 0; /* clear error */ + } + + root->max_advance_height = root->height; + + root->underline_position = face->type1.font_info.underline_position; + root->underline_thickness = face->type1.font_info.underline_thickness; + + root->max_points = 0; + root->max_contours = 0; + } + + /* charmap support -- synthetize unicode charmap if possible */ + { + FT_Face root = &face->root; + FT_CharMap charmap = face->charmaprecs; + + + /* synthesize a Unicode charmap if there is support in the `PSNames' */ + /* module */ + if ( face->psnames ) + { + PSNames_Interface* psnames = (PSNames_Interface*)face->psnames; + + + if ( psnames->unicode_value ) + { + error = psnames->build_unicodes( + root->memory, + face->type1.num_glyphs, + (const char**)face->type1.glyph_names, + &face->unicode_map ); + if ( !error ) + { + root->charmap = charmap; + charmap->face = (FT_Face)face; + charmap->encoding = ft_encoding_unicode; + charmap->platform_id = 3; + charmap->encoding_id = 1; + charmap++; + } + + /* simply clear the error in case of failure (which really) */ + /* means that out of memory or no unicode glyph names */ + error = FT_Err_Ok; + } + } + + /* now, support either the standard, expert, or custom encoding */ + charmap->face = (FT_Face)face; + charmap->platform_id = 7; /* a new platform id for Adobe fonts? */ + + switch ( face->type1.encoding_type ) + { + case t1_encoding_standard: + charmap->encoding = ft_encoding_adobe_standard; + charmap->encoding_id = 0; + break; + + case t1_encoding_expert: + charmap->encoding = ft_encoding_adobe_expert; + charmap->encoding_id = 1; + break; + + default: + charmap->encoding = ft_encoding_adobe_custom; + charmap->encoding_id = 2; + break; + } + + root->charmaps = face->charmaps; + root->num_charmaps = charmap - face->charmaprecs + 1; + face->charmaps[0] = &face->charmaprecs[0]; + face->charmaps[1] = &face->charmaprecs[1]; + } + + Exit: + return error; + } + + + /*************************************************************************/ + /* */ + /* */ + /* Z1_Init_Driver */ + /* */ + /* */ + /* Initializes a given Type 1 driver object. */ + /* */ + /* */ + /* driver :: A handle to the target driver object. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + LOCAL_FUNC + FT_Error Z1_Init_Driver( Z1_Driver driver ) + { + FT_UNUSED( driver ); + + return T1_Err_Ok; + } + + + /*************************************************************************/ + /* */ + /* */ + /* Z1_Done_Driver */ + /* */ + /* */ + /* Finalizes a given Type 1 driver. */ + /* */ + /* */ + /* driver :: A handle to the target Type 1 driver. */ + /* */ + LOCAL_DEF + void Z1_Done_Driver( Z1_Driver driver ) + { + FT_UNUSED( driver ); + } + + +/* END */ diff --git a/src/freetype/type1z/z1objs.h b/src/freetype/type1z/z1objs.h new file mode 100644 index 0000000000..c655a67318 --- /dev/null +++ b/src/freetype/type1z/z1objs.h @@ -0,0 +1,161 @@ +/***************************************************************************/ +/* */ +/* z1objs.h */ +/* */ +/* Experimental Type 1 objects manager (specification). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef Z1OBJS_H +#define Z1OBJS_H + +#include +#include +#include +#include + +#ifdef __cplusplus + extern "C" { +#endif + + /* The following structures must be defined by the hinter */ + typedef struct Z1_Size_Hints_ Z1_Size_Hints; + typedef struct Z1_Glyph_Hints_ Z1_Glyph_Hints; + + + /*************************************************************************/ + /* */ + /* */ + /* Z1_Driver */ + /* */ + /* */ + /* A handle to a Type 1 driver object. */ + /* */ + typedef struct Z1_DriverRec_ *Z1_Driver; + + + /*************************************************************************/ + /* */ + /* */ + /* Z1_Size */ + /* */ + /* */ + /* A handle to a Type 1 size object. */ + /* */ + typedef struct Z1_SizeRec_* Z1_Size; + + + /*************************************************************************/ + /* */ + /* */ + /* Z1_GlyphSlot */ + /* */ + /* */ + /* A handle to a Type 1 glyph slot object. */ + /* */ + typedef struct Z1_GlyphSlotRec_* Z1_GlyphSlot; + + + /*************************************************************************/ + /* */ + /* */ + /* Z1_CharMap */ + /* */ + /* */ + /* A handle to a Type 1 character mapping object. */ + /* */ + /* */ + /* The Type 1 format doesn't use a charmap but an encoding table. */ + /* The driver is responsible for making up charmap objects */ + /* corresponding to these tables. */ + /* */ + typedef struct Z1_CharMapRec_* Z1_CharMap; + + + /*************************************************************************/ + /* */ + /* HERE BEGINS THE TYPE1 SPECIFIC STUFF */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* */ + /* Z1_SizeRec */ + /* */ + /* */ + /* Type 1 size record. */ + /* */ + typedef struct Z1_SizeRec_ + { + FT_SizeRec root; + FT_Bool valid; + Z1_Size_Hints* hints; /* defined in the hinter. This allows */ + /* us to experiment with different */ + /* hinting schemes without having to */ + /* change `z1objs' each time. */ + } Z1_SizeRec; + + + /*************************************************************************/ + /* */ + /* */ + /* Z1_GlyphSlotRec */ + /* */ + /* */ + /* Type 1 glyph slot record. */ + /* */ + typedef struct Z1_GlyphSlotRec_ + { + FT_GlyphSlotRec root; + + FT_Bool hint; + FT_Bool scaled; + + FT_Int max_points; + FT_Int max_contours; + + FT_Fixed x_scale; + FT_Fixed y_scale; + + Z1_Glyph_Hints* hints; /* defined in the hinter */ + + } Z1_GlyphSlotRec; + + + LOCAL_DEF + FT_Error Z1_Init_Face( FT_Stream stream, + T1_Face face, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ); + + LOCAL_DEF + void Z1_Done_Face( T1_Face face ); + + LOCAL_DEF + FT_Error Z1_Init_Driver( Z1_Driver driver ); + + LOCAL_DEF + void Z1_Done_Driver( Z1_Driver driver ); + + +#ifdef __cplusplus + } +#endif + +#endif /* Z1OBJS_H */ + + +/* END */ diff --git a/src/freetype/type1z/z1parse.c b/src/freetype/type1z/z1parse.c new file mode 100644 index 0000000000..9bc2913874 --- /dev/null +++ b/src/freetype/type1z/z1parse.c @@ -0,0 +1,1398 @@ +/***************************************************************************/ +/* */ +/* z1parse.c */ +/* */ +/* Experimental Type 1 parser (body). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + + /*************************************************************************/ + /* */ + /* The Type 1 parser is in charge of the following: */ + /* */ + /* - provide an implementation of a growing sequence of objects called */ + /* a `Z1_Table' (used to build various tables needed by the loader). */ + /* */ + /* - opening .pfb and .pfa files to extract their top-level and private */ + /* dictionaries. */ + /* */ + /* - read numbers, arrays & strings from any dictionary. */ + /* */ + /* See `z1load.c' to see how data is loaded from the font file. */ + /* */ + /*************************************************************************/ + + +#include +#include +#include +#include +#include + + +#ifdef FT_FLAT_COMPILE + +#include "z1parse.h" + +#else + +#include + +#endif + + +#include /* for strncmp() */ + + + /*************************************************************************/ + /* */ + /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ + /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ + /* messages during execution. */ + /* */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_z1parse + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** IMPLEMENTATION OF Z1_TABLE OBJECT *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* */ + /* Z1_New_Table */ + /* */ + /* */ + /* Initialises a Z1_Table. */ + /* */ + /* */ + /* table :: The address of the target table. */ + /* */ + /* */ + /* count :: The table size = the maximum number of elements. */ + /* */ + /* memory :: The memory object to use for all subsequent */ + /* reallocations. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + LOCAL_FUNC + FT_Error Z1_New_Table( Z1_Table* table, + FT_Int count, + FT_Memory memory ) + { + FT_Error error; + + + table->memory = memory; + if ( ALLOC_ARRAY( table->elements, count, FT_Byte* ) || + ALLOC_ARRAY( table->lengths, count, FT_Byte* ) ) + goto Exit; + + table->max_elems = count; + table->init = 0xdeadbeef; + table->num_elems = 0; + table->block = 0; + table->capacity = 0; + table->cursor = 0; + + Exit: + if ( error ) + FREE( table->elements ); + + return error; + } + + + static + void shift_elements( Z1_Table* table, + FT_Byte* old_base ) + { + FT_Long delta = table->block - old_base; + FT_Byte** offset = table->elements; + FT_Byte** limit = offset + table->max_elems; + + + if ( delta ) + for ( ; offset < limit; offset++ ) + { + if ( offset[0] ) + offset[0] += delta; + } + } + + + static + FT_Error reallocate_t1_table( Z1_Table* table, + FT_Int new_size ) + { + FT_Memory memory = table->memory; + FT_Byte* old_base = table->block; + FT_Error error; + + + /* reallocate the base block */ + if ( REALLOC( table->block, table->capacity, new_size ) ) + return error; + + table->capacity = new_size; + + /* shift all offsets if necessary */ + if ( old_base ) + shift_elements( table, old_base ); + + return T1_Err_Ok; + } + + + /*************************************************************************/ + /* */ + /* */ + /* Z1_Add_Table */ + /* */ + /* */ + /* Adds an object to a Z1_Table, possibly growing its memory block. */ + /* */ + /* */ + /* table :: The target table. */ + /* */ + /* */ + /* index :: The index of the object in the table. */ + /* */ + /* object :: The address of the object to copy in memory. */ + /* */ + /* length :: The length in bytes of the source object. */ + /* */ + /* */ + /* FreeType error code. 0 means success. An error is returned if a */ + /* reallocation fails. */ + /* */ + LOCAL_FUNC + FT_Error Z1_Add_Table( Z1_Table* table, + FT_Int index, + void* object, + FT_Int length ) + { + if ( index < 0 || index > table->max_elems ) + { + FT_ERROR(( "Z1_Add_Table: invalid index\n" )); + return T1_Err_Syntax_Error; + } + + /* grow the base block if needed */ + if ( table->cursor + length > table->capacity ) + { + FT_Error error; + FT_Int new_size = table->capacity; + + + while ( new_size < table->cursor + length ) + new_size += 1024; + + error = reallocate_t1_table( table, new_size ); + if ( error ) + return error; + } + + /* add the object to the base block and adjust offset */ + table->elements[index] = table->block + table->cursor; + table->lengths [index] = length; + MEM_Copy( table->block + table->cursor, object, length ); + + table->cursor += length; + return T1_Err_Ok; + } + + +#if 0 + + /*************************************************************************/ + /* */ + /* */ + /* Z1_Done_Table */ + /* */ + /* */ + /* Finalizes a Z1_Table (i.e., reallocate it to its current cursor). */ + /* */ + /* */ + /* table :: The target table. */ + /* */ + /* */ + /* This function does NOT release the heap's memory block. It is up */ + /* to the caller to clean it, or reference it in its own structures. */ + /* */ + LOCAL_FUNC + void Z1_Done_Table( Z1_Table* table ) + { + FT_Memory memory = table->memory; + FT_Error error; + FT_Byte* old_base; + + + /* should never fail, as rec.cursor <= rec.size */ + old_base = table->block; + if ( !old_base ) + return; + + (void)REALLOC( table->block, table->capacity, table->cursor ); + table->capacity = table->cursor; + + if ( old_base != table->block ) + shift_elements( table, old_base ); + } + +#endif /* 0 */ + + + LOCAL_FUNC + void Z1_Release_Table( Z1_Table* table ) + { + FT_Memory memory = table->memory; + + + if ( table->init == (FT_Long)0xDEADBEEF ) + { + FREE( table->block ); + FREE( table->elements ); + FREE( table->lengths ); + table->init = 0; + } + } + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** INPUT STREAM PARSER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + +#define IS_Z1_WHITESPACE( c ) ( (c) == ' ' || (c) == '\t' ) +#define IS_Z1_LINESPACE( c ) ( (c) == '\r' || (c) == '\n' ) + +#define IS_Z1_SPACE( c ) ( IS_Z1_WHITESPACE( c ) || IS_Z1_LINESPACE( c ) ) + + + LOCAL_FUNC + void Z1_Skip_Spaces( Z1_Parser* parser ) + { + FT_Byte* cur = parser->cursor; + FT_Byte* limit = parser->limit; + + + while ( cur < limit ) + { + FT_Byte c = *cur; + + + if ( !IS_Z1_SPACE( c ) ) + break; + cur++; + } + parser->cursor = cur; + } + + + LOCAL_FUNC + void Z1_ToToken( Z1_Parser* parser, + Z1_Token_Rec* token ) + { + FT_Byte* cur; + FT_Byte* limit; + FT_Byte starter, ender; + FT_Int embed; + + + token->type = t1_token_none; + token->start = 0; + token->limit = 0; + + /* first of all, skip space */ + Z1_Skip_Spaces( parser ); + + cur = parser->cursor; + limit = parser->limit; + + if ( cur < limit ) + { + switch ( *cur ) + { + /************* check for strings ***********************/ + case '(': + token->type = t1_token_string; + ender = ')'; + goto Lookup_Ender; + + /************* check for programs/array ****************/ + case '{': + token->type = t1_token_array; + ender = '}'; + goto Lookup_Ender; + + /************* check for table/array ******************/ + case '[': + token->type = t1_token_array; + ender = ']'; + + Lookup_Ender: + embed = 1; + starter = *cur++; + token->start = cur; + while ( cur < limit ) + { + if ( *cur == starter ) + embed++; + else if ( *cur == ender ) + { + embed--; + if ( embed <= 0 ) + { + token->limit = cur++; + break; + } + } + cur++; + } + break; + + /* **************** otherwise, it's any token **********/ + default: + token->start = cur++; + token->type = t1_token_any; + while ( cur < limit && !IS_Z1_SPACE( *cur ) ) + cur++; + + token->limit = cur; + } + + if ( !token->limit ) + { + token->start = 0; + token->type = t1_token_none; + } + + parser->cursor = cur; + } + } + + + LOCAL_FUNC + void Z1_ToTokenArray( Z1_Parser* parser, + Z1_Token_Rec* tokens, + FT_UInt max_tokens, + FT_Int* pnum_tokens ) + { + Z1_Token_Rec master; + + + *pnum_tokens = -1; + + Z1_ToToken( parser, &master ); + if ( master.type == t1_token_array ) + { + FT_Byte* old_cursor = parser->cursor; + FT_Byte* old_limit = parser->limit; + Z1_Token_Rec* cur = tokens; + Z1_Token_Rec* limit = cur + max_tokens; + + + parser->cursor = master.start; + parser->limit = master.limit; + + while ( parser->cursor < parser->limit ) + { + Z1_Token_Rec token; + + + Z1_ToToken( parser, &token ); + if ( !token.type ) + break; + + if ( cur < limit ) + *cur = token; + + cur++; + } + + *pnum_tokens = cur - tokens; + + parser->cursor = old_cursor; + parser->limit = old_limit; + } + } + + + static + FT_Long t1_toint( FT_Byte** cursor, + FT_Byte* limit ) + { + FT_Long result = 0; + FT_Byte* cur = *cursor; + FT_Byte c, d; + + + for ( ; cur < limit; cur++ ) + { + c = *cur; + d = (FT_Byte)( c - '0' ); + if ( d < 10 ) + break; + + if ( c == '-' ) + { + cur++; + break; + } + } + + if ( cur < limit ) + { + do + { + d = (FT_Byte)( cur[0] - '0' ); + if ( d >= 10 ) + break; + + result = result * 10 + d; + cur++; + + } while ( cur < limit ); + + if ( c == '-' ) + result = -result; + } + + *cursor = cur; + return result; + } + + + static + FT_Long t1_tofixed( FT_Byte** cursor, + FT_Byte* limit, + FT_Long power_ten ) + { + FT_Byte* cur = *cursor; + FT_Long num, divider, result; + FT_Int sign = 0; + FT_Byte d; + + + if ( cur >= limit ) + return 0; + + /* first of all, read the integer part */ + result = t1_toint( &cur, limit ) << 16; + num = 0; + divider = 1; + + if ( result < 0 ) + { + sign = 1; + result = -result; + } + + if ( cur >= limit ) + goto Exit; + + /* read decimal part, if any */ + if ( *cur == '.' && cur + 1 < limit ) + { + cur++; + + for (;;) + { + d = (FT_Byte)( *cur - '0' ); + if ( d >= 10 ) + break; + + if ( divider < 10000000L ) + { + num = num * 10 + d; + divider *= 10; + } + + cur++; + if ( cur >= limit ) + break; + } + } + + /* read exponent, if any */ + if ( cur + 1 < limit && ( *cur == 'e' || *cur == 'E' ) ) + { + cur++; + power_ten += t1_toint( &cur, limit ); + } + + Exit: + /* raise to power of ten if needed */ + while ( power_ten > 0 ) + { + result = result * 10; + num = num * 10; + power_ten--; + } + + while ( power_ten < 0 ) + { + result = result / 10; + divider = divider * 10; + power_ten++; + } + + if ( num ) + result += FT_DivFix( num, divider ); + + if ( sign ) + result = -result; + + *cursor = cur; + return result; + } + + + static + FT_Int t1_tocoordarray( FT_Byte** cursor, + FT_Byte* limit, + FT_Int max_coords, + FT_Short* coords ) + { + FT_Byte* cur = *cursor; + FT_Int count = 0; + FT_Byte c, ender; + + + if ( cur >= limit ) + goto Exit; + + /* check for the beginning of an array. If not, only one number will */ + /* be read */ + c = *cur; + ender = 0; + + if ( c == '[' ) + ender = ']'; + + if ( c == '{' ) + ender = '}'; + + if ( ender ) + cur++; + + /* now, read the coordinates */ + for ( ; cur < limit; ) + { + /* skip whitespace in front of data */ + for (;;) + { + c = *cur; + if ( c != ' ' && c != '\t' ) + break; + + cur++; + if ( cur >= limit ) + goto Exit; + } + + if ( count >= max_coords || c == ender ) + break; + + coords[count] = (FT_Short)( t1_tofixed( &cur, limit, 0 ) >> 16 ); + count++; + + if ( !ender ) + break; + } + + Exit: + *cursor = cur; + return count; + } + + + static + FT_Int t1_tofixedarray( FT_Byte** cursor, + FT_Byte* limit, + FT_Int max_values, + FT_Fixed* values, + FT_Int power_ten ) + { + FT_Byte* cur = *cursor; + FT_Int count = 0; + FT_Byte c, ender; + + + if ( cur >= limit ) goto Exit; + + /* check for the beginning of an array. If not, only one number will */ + /* be read */ + c = *cur; + ender = 0; + + if ( c == '[' ) + ender = ']'; + + if ( c == '{' ) + ender = '}'; + + if ( ender ) + cur++; + + /* now, read the values */ + for ( ; cur < limit; ) + { + /* skip whitespace in front of data */ + for (;;) + { + c = *cur; + if ( c != ' ' && c != '\t' ) + break; + + cur++; + if ( cur >= limit ) + goto Exit; + } + + if ( count >= max_values || c == ender ) + break; + + values[count] = t1_tofixed( &cur, limit, power_ten ); + count++; + + if ( !ender ) + break; + } + + Exit: + *cursor = cur; + return count; + } + + +#if 0 + + static + FT_String* t1_tostring( FT_Byte** cursor, + FT_Byte* limit, + FT_Memory memory ) + { + FT_Byte* cur = *cursor; + FT_Int len = 0; + FT_Int count; + FT_String* result; + FT_Error error; + + + /* XXX: some stupid fonts have a `Notice' or `Copyright' string */ + /* that simply doesn't begin with an opening parenthesis, even */ + /* though they have a closing one! E.g. "amuncial.pfb" */ + /* */ + /* We must deal with these ill-fated cases there. Note that */ + /* these fonts didn't work with the old Type 1 driver as the */ + /* notice/copyright was not recognized as a valid string token */ + /* and made the old token parser commit errors. */ + + while ( cur < limit && ( *cur == ' ' || *cur == '\t' ) ) + cur++; + if ( cur + 1 >= limit ) + return 0; + + if ( *cur == '(' ) + cur++; /* skip the opening parenthesis, if there is one */ + + *cursor = cur; + count = 0; + + /* then, count its length */ + for ( ; cur < limit; cur++ ) + { + if ( *cur == '(' ) + count++; + + else if ( *cur == ')' ) + { + count--; + if ( count < 0 ) + break; + } + } + + len = cur - *cursor; + if ( cur >= limit || ALLOC( result, len + 1 ) ) + return 0; + + /* now copy the string */ + MEM_Copy( result, *cursor, len ); + result[len] = '\0'; + *cursor = cur; + return result; + } + +#endif /* 0 */ + + + static + int t1_tobool( FT_Byte** cursor, + FT_Byte* limit ) + { + FT_Byte* cur = *cursor; + FT_Bool result = 0; + + + /* return 1 if we find `true', 0 otherwise */ + if ( cur + 3 < limit && + cur[0] == 't' && + cur[1] == 'r' && + cur[2] == 'u' && + cur[3] == 'e' ) + { + result = 1; + cur += 5; + } + else if ( cur + 4 < limit && + cur[0] == 'f' && + cur[1] == 'a' && + cur[2] == 'l' && + cur[3] == 's' && + cur[4] == 'e' ) + { + result = 0; + cur += 6; + } + + *cursor = cur; + return result; + } + + + /* Load a simple field (i.e. non-table) into the current list of objects */ + LOCAL_FUNC + FT_Error Z1_Load_Field( Z1_Parser* parser, + const Z1_Field_Rec* field, + void** objects, + FT_UInt max_objects, + FT_ULong* pflags ) + { + Z1_Token_Rec token; + FT_Byte* cur; + FT_Byte* limit; + FT_UInt count; + FT_UInt index; + FT_Error error; + + + Z1_ToToken( parser, &token ); + if ( !token.type ) + goto Fail; + + count = 1; + index = 0; + cur = token.start; + limit = token.limit; + + if ( token.type == t1_token_array ) + { + /* if this is an array, and we have no blend, an error occurs */ + if ( max_objects == 0 ) + goto Fail; + + count = max_objects; + index = 1; + } + + for ( ; count > 0; count--, index++ ) + { + FT_Byte* q = (FT_Byte*)objects[index] + field->offset; + FT_Long val; + FT_String* string; + + switch ( field->type ) + { + case t1_field_bool: + val = t1_tobool( &cur, limit ); + goto Store_Integer; + + case t1_field_fixed: + val = t1_tofixed( &cur, limit, 3 ); + goto Store_Integer; + + case t1_field_integer: + val = t1_toint( &cur, limit ); + + Store_Integer: + switch ( field->size ) + { + case 1: + *(FT_Byte*)q = (FT_Byte)val; + break; + + case 2: + *(FT_UShort*)q = (FT_UShort)val; + break; + + case 4: + *(FT_UInt32*)q = (FT_UInt32)val; + break; + + default: /* for 64-bit systems */ + *(FT_Long*)q = val; + } + break; + + case t1_field_string: + { + FT_Memory memory = parser->memory; + FT_UInt len = limit-cur; + + if ( ALLOC( string, len + 1 ) ) + goto Exit; + + MEM_Copy( string, cur, len ); + string[len] = 0; + + *(FT_String**)q = string; + } + break; + + default: + /* an error occured */ + goto Fail; + } + } + + if ( pflags ) + *pflags |= 1L << field->flag_bit; + + error = FT_Err_Ok; + + Exit: + return error; + + Fail: + error = T1_Err_Invalid_File_Format; + goto Exit; + } + + +#define T1_MAX_TABLE_ELEMENTS 32 + + + LOCAL_FUNC + FT_Error Z1_Load_Field_Table( Z1_Parser* parser, + const Z1_Field_Rec* field, + void** objects, + FT_UInt max_objects, + FT_ULong* pflags ) + { + Z1_Token_Rec elements[T1_MAX_TABLE_ELEMENTS]; + Z1_Token_Rec* token; + FT_Int num_elements; + FT_Error error = 0; + FT_Byte* old_cursor; + FT_Byte* old_limit; + Z1_Field_Rec fieldrec = *(Z1_Field_Rec*)field; + + + Z1_ToTokenArray( parser, elements, 32, &num_elements ); + if ( num_elements < 0 ) + goto Fail; + + if ( num_elements > T1_MAX_TABLE_ELEMENTS ) + num_elements = T1_MAX_TABLE_ELEMENTS; + + old_cursor = parser->cursor; + old_limit = parser->limit; + + /* we store the elements count */ + *(FT_Byte*)( (FT_Byte*)objects[0] + field->count_offset ) = num_elements; + + /* we now load each element, adjusting the field.offset on each one */ + token = elements; + for ( ; num_elements > 0; num_elements--, token++ ) + { + parser->cursor = token->start; + parser->limit = token->limit; + Z1_Load_Field( parser, &fieldrec, objects, max_objects, 0 ); + fieldrec.offset += fieldrec.size; + } + + if ( pflags ) + *pflags |= 1L << field->flag_bit; + + parser->cursor = old_cursor; + parser->limit = old_limit; + + Exit: + return error; + + Fail: + error = T1_Err_Invalid_File_Format; + goto Exit; + } + + + LOCAL_FUNC + FT_Long Z1_ToInt ( Z1_Parser* parser ) + { + return t1_toint( &parser->cursor, parser->limit ); + } + + + LOCAL_FUNC + FT_Long Z1_ToFixed( Z1_Parser* parser, + FT_Int power_ten ) + { + return t1_tofixed( &parser->cursor, parser->limit, power_ten ); + } + + + LOCAL_FUNC + FT_Int Z1_ToCoordArray( Z1_Parser* parser, + FT_Int max_coords, + FT_Short* coords ) + { + return t1_tocoordarray( &parser->cursor, parser->limit, + max_coords, coords ); + } + + + LOCAL_FUNC + FT_Int Z1_ToFixedArray( Z1_Parser* parser, + FT_Int max_values, + FT_Fixed* values, + FT_Int power_ten ) + { + return t1_tofixedarray( &parser->cursor, parser->limit, + max_values, values, power_ten ); + } + + +#if 0 + + LOCAL_FUNC + FT_String* Z1_ToString( Z1_Parser* parser ) + { + return t1_tostring( &parser->cursor, parser->limit, parser->memory ); + } + + + LOCAL_FUNC + FT_Bool Z1_ToBool( Z1_Parser* parser ) + { + return t1_tobool( &parser->cursor, parser->limit ); + } + +#endif /* 0 */ + + + static + FT_Error read_pfb_tag( FT_Stream stream, + FT_UShort* tag, + FT_Long* size ) + { + FT_Error error; + + + if ( READ_UShort( *tag ) ) + goto Exit; + + if ( *tag == 0x8001 || *tag == 0x8002 ) + { + FT_Long asize; + + + if ( READ_ULong( asize ) ) + goto Exit; + + /* swap between big and little endianness */ + *size = ( ( asize & 0xFF000000L ) >> 24 ) | + ( ( asize & 0x00FF0000L ) >> 8 ) | + ( ( asize & 0x0000FF00L ) << 8 ) | + ( ( asize & 0x000000FFL ) << 24 ); + } + + Exit: + return error; + } + + + LOCAL_FUNC + FT_Error Z1_New_Parser( Z1_Parser* parser, + FT_Stream stream, + FT_Memory memory ) + { + FT_Error error; + FT_UShort tag; + FT_Long size; + + + parser->stream = stream; + parser->memory = memory; + parser->base_len = 0; + parser->base_dict = 0; + parser->private_len = 0; + parser->private_dict = 0; + parser->in_pfb = 0; + parser->in_memory = 0; + parser->single_block = 0; + + parser->cursor = 0; + parser->limit = 0; + + /******************************************************************/ + /* */ + /* Here a short summary of what is going on: */ + /* */ + /* When creating a new Type 1 parser, we try to locate and load */ + /* the base dictionary if this is possible (i.e. for PFB */ + /* files). Otherwise, we load the whole font into memory. */ + /* */ + /* When `loading' the base dictionary, we only setup pointers */ + /* in the case of a memory-based stream. Otherwise, we */ + /* allocate and load the base dictionary in it. */ + /* */ + /* parser->in_pfb is set if we are in a binary (".pfb") font. */ + /* parser->in_memory is set if we have a memory stream. */ + /* */ + + /* try to compute the size of the base dictionary; */ + /* look for a Postscript binary file tag, i.e 0x8001 */ + if ( FILE_Seek( 0L ) ) + goto Exit; + + error = read_pfb_tag( stream, &tag, &size ); + if ( error ) + goto Exit; + + if ( tag != 0x8001 ) + { + /* assume that this is a PFA file for now; an error will */ + /* be produced later when more things are checked */ + (void)FILE_Seek( 0L ); + size = stream->size; + } + else + parser->in_pfb = 1; + + /* now, try to load `size' bytes of the `base' dictionary we */ + /* found previously */ + + /* if it is a memory-based resource, set up pointers */ + if ( !stream->read ) + { + parser->base_dict = (FT_Byte*)stream->base + stream->pos; + parser->base_len = size; + parser->in_memory = 1; + + /* check that the `size' field is valid */ + if ( FILE_Skip( size ) ) + goto Exit; + } + else + { + /* read segment in memory */ + if ( ALLOC( parser->base_dict, size ) || + FILE_Read( parser->base_dict, size ) ) + goto Exit; + parser->base_len = size; + } + + /* Now check font format; we must see `%!PS-AdobeFont-1' */ + /* or `%!FontType' */ + { + if ( size <= 16 || + ( strncmp( (const char*)parser->base_dict, + "%!PS-AdobeFont-1", 16 ) && + strncmp( (const char*)parser->base_dict, + "%!FontType", 10 ) ) ) + { + FT_TRACE2(( "[not a Type1 font]\n" )); + error = FT_Err_Unknown_File_Format; + } + else + { + parser->cursor = parser->base_dict; + parser->limit = parser->cursor + parser->base_len; + } + } + + Exit: + if ( error && !parser->in_memory ) + FREE( parser->base_dict ); + + return error; + } + + + LOCAL_FUNC + void Z1_Done_Parser( Z1_Parser* parser ) + { + FT_Memory memory = parser->memory; + + + /* always free the private dictionary */ + FREE( parser->private_dict ); + + /* free the base dictionary only when we have a disk stream */ + if ( !parser->in_memory ) + FREE( parser->base_dict ); + } + + + /* return the value of an hexadecimal digit */ + static + int hexa_value( char c ) + { + unsigned int d; + + + d = (unsigned int)( c - '0' ); + if ( d <= 9 ) + return (int)d; + + d = (unsigned int)( c - 'a' ); + if ( d <= 5 ) + return (int)( d + 10 ); + + d = (unsigned int)( c - 'A' ); + if ( d <= 5 ) + return (int)( d + 10 ); + + return -1; + } + + + LOCAL_FUNC + void Z1_Decrypt( FT_Byte* buffer, + FT_Int length, + FT_UShort seed ) + { + while ( length > 0 ) + { + FT_Byte plain; + + + plain = ( *buffer ^ ( seed >> 8 ) ); + seed = ( *buffer + seed ) * 52845 + 22719; + *buffer++ = plain; + length--; + } + } + + + LOCAL_FUNC + FT_Error Z1_Get_Private_Dict( Z1_Parser* parser ) + { + FT_Stream stream = parser->stream; + FT_Memory memory = parser->memory; + FT_Error error = 0; + FT_Long size; + + + if ( parser->in_pfb ) + { + /* in the case of the PFB format, the private dictionary can be */ + /* made of several segments. We thus first read the number of */ + /* segments to compute the total size of the private dictionary */ + /* then re-read them into memory. */ + FT_Long start_pos = FILE_Pos(); + FT_UShort tag; + FT_Long size; + + + parser->private_len = 0; + for (;;) + { + error = read_pfb_tag( stream, &tag, &size ); + if ( error ) + goto Fail; + + if ( tag != 0x8002 ) + break; + + parser->private_len += size; + + if ( FILE_Skip( size ) ) + goto Fail; + } + + /* Check that we have a private dictionary there */ + /* and allocate private dictionary buffer */ + if ( parser->private_len == 0 ) + { + FT_ERROR(( "Z1_Get_Private_Dict:" )); + FT_ERROR(( " invalid private dictionary section\n" )); + error = T1_Err_Invalid_File_Format; + goto Fail; + } + + if ( FILE_Seek( start_pos ) || + ALLOC( parser->private_dict, parser->private_len ) ) + goto Fail; + + parser->private_len = 0; + for (;;) + { + error = read_pfb_tag( stream, &tag, &size ); + if ( error || tag != 0x8002 ) + { + error = FT_Err_Ok; + break; + } + + if ( FILE_Read( parser->private_dict + parser->private_len, size ) ) + goto Fail; + + parser->private_len += size; + } + } + else + { + /* we have already `loaded' the whole PFA font file into memory; */ + /* if this is a memory resource, allocate a new block to hold */ + /* the private dict. Otherwise, simply overwrite into the base */ + /* dictionary block in the heap. */ + + /* first of all, look at the `eexec' keyword */ + FT_Byte* cur = parser->base_dict; + FT_Byte* limit = cur + parser->base_len; + FT_Byte c; + + + for (;;) + { + c = cur[0]; + if ( c == 'e' && cur + 9 < limit ) /* 9 = 5 letters for `eexec' + */ + /* newline + 4 chars */ + { + if ( cur[1] == 'e' && cur[2] == 'x' && + cur[3] == 'e' && cur[4] == 'c' ) + { + cur += 6; /* we skip the newling after the `eexec' */ + + /* XXX: Some fonts use DOS-linefeeds, i.e. \r\n; we need to */ + /* skip the extra \n if we find it */ + if ( cur[0] == '\n' ) + cur++; + + break; + } + } + cur++; + if ( cur >= limit ) + { + FT_ERROR(( "Z1_Get_Private_Dict:" )); + FT_ERROR(( " could not find `eexec' keyword\n" )); + error = T1_Err_Invalid_File_Format; + goto Exit; + } + } + + /* now determine where to write the _encrypted_ binary private */ + /* dictionary. We overwrite the base dictionary for disk-based */ + /* resources and allocate a new block otherwise */ + + size = parser->base_len - ( cur - parser->base_dict); + + if ( parser->in_memory ) + { + /* note that we allocate one more byte to put a terminating `0' */ + if ( ALLOC( parser->private_dict, size + 1 ) ) + goto Fail; + parser->private_len = size; + } + else + { + parser->single_block = 1; + parser->private_dict = parser->base_dict; + parser->private_len = size; + parser->base_dict = 0; + parser->base_len = 0; + } + + /* now determine whether the private dictionary is encoded in binary */ + /* or hexadecimal ASCII format -- decode it accordingly */ + + /* we need to access the next 4 bytes (after the final \r following */ + /* the `eexec' keyword); if they all are hexadecimal digits, then */ + /* we have a case of ASCII storage */ + + if ( ( hexa_value( cur[0] ) | hexa_value( cur[1] ) | + hexa_value( cur[2] ) | hexa_value( cur[3] ) ) < 0 ) + + /* binary encoding -- `simply' copy the private dict */ + MEM_Copy( parser->private_dict, cur, size ); + + else + { + /* ASCII hexadecimal encoding */ + + FT_Byte* write; + FT_Int count; + + + write = parser->private_dict; + count = 0; + + for ( ;cur < limit; cur++ ) + { + int hex1; + + + /* check for newline */ + if ( cur[0] == '\r' || cur[0] == '\n' ) + continue; + + /* exit if we have a non-hexadecimal digit that isn't a newline */ + hex1 = hexa_value( cur[0] ); + if ( hex1 < 0 || cur + 1 >= limit ) + break; + + /* otherwise, store byte */ + *write++ = ( hex1 << 4 ) | hexa_value( cur[1] ); + count++; + cur++; + } + + /* put a safeguard */ + parser->private_len = write - parser->private_dict; + *write++ = 0; + } + } + + /* we now decrypt the encoded binary private dictionary */ + Z1_Decrypt( parser->private_dict, parser->private_len, 55665 ); + parser->cursor = parser->private_dict; + parser->limit = parser->cursor + parser->private_len; + + Fail: + Exit: + return error; + } + + +/* END */ diff --git a/src/freetype/type1z/z1parse.h b/src/freetype/type1z/z1parse.h new file mode 100644 index 0000000000..d0b6a6503e --- /dev/null +++ b/src/freetype/type1z/z1parse.h @@ -0,0 +1,363 @@ +/***************************************************************************/ +/* */ +/* z1parse.h */ +/* */ +/* Experimental Type 1 parser (specification). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef Z1PARSE_H +#define Z1PARSE_H + +#include + +#ifdef __cplusplus + extern "C" { +#endif + + + /* simple enumeration type used to identify token types */ + typedef enum Z1_Token_Type_ + { + t1_token_none = 0, + t1_token_any, + t1_token_string, + t1_token_array, + + /* do not remove */ + t1_token_max + + } Z1_Token_Type; + + + /* a simple structure used to identify tokens */ + typedef struct Z1_Token_Rec_ + { + FT_Byte* start; /* first character of token in input stream */ + FT_Byte* limit; /* first character after the token */ + Z1_Token_Type type; /* type of token.. */ + + } Z1_Token_Rec; + + + /* enumeration type used to identify object fields */ + typedef enum Z1_Field_Type_ + { + t1_field_none = 0, + t1_field_bool, + t1_field_integer, + t1_field_fixed, + t1_field_string, + t1_field_integer_array, + t1_field_fixed_array, + + /* do not remove */ + t1_field_max + + } Z1_Field_Type; + + + /* structure type used to model object fields */ + typedef struct Z1_Field_Rec_ + { + Z1_Field_Type type; /* type of field */ + FT_UInt offset; /* offset of field in object */ + FT_UInt size; /* size of field in bytes */ + FT_UInt array_max; /* maximum number of elements for array */ + FT_UInt count_offset; /* offset of element count for arrays */ + FT_Int flag_bit; /* bit number for field flag */ + + } Z1_Field_Rec; + + +#define Z1_FIELD_REF( s, f ) ( ((s*)0)->f ) + +#define Z1_FIELD_BOOL( _ftype, _fname ) \ + { \ + t1_field_bool, \ + (FT_UInt)(char*)&Z1_FIELD_REF( _ftype, _fname ), \ + sizeof ( Z1_FIELD_REF( _ftype, _fname ) ), \ + 0, 0, 0 \ + } + +#define Z1_FIELD_NUM( _ftype, _fname ) \ + { \ + t1_field_integer, \ + (FT_UInt)(char*)&Z1_FIELD_REF( _ftype, _fname ), \ + sizeof ( Z1_FIELD_REF( _ftype, _fname ) ), \ + 0, 0, 0 \ + } + +#define Z1_FIELD_FIXED( _ftype, _fname, _power ) \ + { \ + t1_field_fixed, \ + (FT_UInt)(char*)&Z1_FIELD_REF( _ftype, _fname ), \ + sizeof ( Z1_FIELD_REF( _ftype, _fname ) ), \ + 0, 0, 0 \ + } + +#define Z1_FIELD_STRING( _ftype, _fname ) \ + { \ + t1_field_string, \ + (FT_UInt)(char*)&Z1_FIELD_REF( _ftype, _fname ), \ + sizeof ( Z1_FIELD_REF( _ftype, _fname ) ), \ + 0, 0, 0 \ + } + +#define Z1_FIELD_NUM_ARRAY( _ftype, _fname, _fcount, _fmax ) \ + { \ + t1_field_integer, \ + (FT_UInt)(char*)&Z1_FIELD_REF( _ftype, _fname ), \ + sizeof ( Z1_FIELD_REF( _ftype, _fname )[0] ), \ + _fmax, \ + (FT_UInt)(char*)&Z1_FIELD_REF( _ftype, _fcount ), \ + 0 \ + } + +#define Z1_FIELD_FIXED_ARRAY( _ftype, _fname, _fcount, _fmax ) \ + { \ + t1_field_fixed, \ + (FT_UInt)(char*)&Z1_FIELD_REF( _ftype, _fname ), \ + sizeof ( Z1_FIELD_REF( _ftype, _fname )[0] ), \ + _fmax, \ + (FT_UInt)(char*)&Z1_FIELD_REF( _ftype, _fcount ), \ + 0 \ + } + +#define Z1_FIELD_NUM_ARRAY2( _ftype, _fname, _fmax ) \ + { \ + t1_field_integer, \ + (FT_UInt)(char*)&Z1_FIELD_REF( _ftype, _fname ), \ + sizeof ( Z1_FIELD_REF( _ftype, _fname )[0] ), \ + _fmax, \ + 0, 0 \ + } + +#define Z1_FIELD_FIXED_ARRAY2( _ftype, _fname, _fmax ) \ + { \ + t1_field_fixed, \ + (FT_UInt)(char*)&Z1_FIELD_REF( _ftype, _fname ), \ + sizeof ( Z1_FIELD_REF( _ftype, _fname )[0] ), \ + _fmax, \ + 0, 0 \ + } + + + /*************************************************************************/ + /* */ + /* */ + /* Z1_Table */ + /* */ + /* */ + /* A Z1_Table is a simple object used to store an array of objects in */ + /* a single memory block. */ + /* */ + /* */ + /* block :: The address in memory of the growheap's block. This */ + /* can change between two object adds, due to the use of */ + /* reallocation. */ + /* */ + /* cursor :: The current top of the grow heap within its block. */ + /* */ + /* capacity :: The current size of the heap block. Increments in */ + /* 1kByte blocks. */ + /* */ + /* init :: A boolean. Set when the table has been initialized */ + /* (the table user should set this field). */ + /* */ + /* max_elems :: The maximum number of elements in the table. */ + /* */ + /* num_elems :: The current number of elements in the table. */ + /* */ + /* elements :: A table of element addresses within the block. */ + /* */ + /* lengths :: A table of element sizes within the block. */ + /* */ + /* memory :: The memory object used for memory operations */ + /* (allocation/reallocation). */ + /* */ + typedef struct Z1_Table_ + { + FT_Byte* block; /* current memory block */ + FT_Int cursor; /* current cursor in memory block */ + FT_Int capacity; /* current size of memory block */ + FT_Long init; + + FT_Int max_elems; + FT_Int num_elems; + FT_Byte** elements; /* addresses of table elements */ + FT_Int* lengths; /* lengths of table elements */ + + FT_Memory memory; + + } Z1_Table; + + + /*************************************************************************/ + /* */ + /* */ + /* Z1_Parser */ + /* */ + /* */ + /* A Z1_Parser is an object used to parse a Type 1 fonts very */ + /* quickly. */ + /* */ + /* */ + /* stream :: The current input stream. */ + /* */ + /* memory :: The current memory object. */ + /* */ + /* base_dict :: A pointer to the top-level dictionary. */ + /* */ + /* base_len :: The length in bytes of the top dictionary. */ + /* */ + /* private_dict :: A pointer to the private dictionary. */ + /* */ + /* private_len :: The length in bytes of the private dictionary. */ + /* */ + /* in_pfb :: A boolean. Indicates that we are handling a PFB */ + /* file. */ + /* */ + /* in_memory :: A boolean. Indicates a memory-based stream. */ + /* */ + /* single_block :: A boolean. Indicates that the private dictionary */ + /* is stored in lieu of the base dictionary. */ + /* */ + /* cursor :: The current parser cursor. */ + /* */ + /* limit :: The current parser limit (first byte after the */ + /* current dictionary). */ + /* */ + /* error :: The current parsing error. */ + /* */ + typedef struct Z1_Parser_ + { + FT_Stream stream; + FT_Memory memory; + + FT_Byte* base_dict; + FT_Int base_len; + + FT_Byte* private_dict; + FT_Int private_len; + + FT_Byte in_pfb; + FT_Byte in_memory; + FT_Byte single_block; + + FT_Byte* cursor; + FT_Byte* limit; + FT_Error error; + + } Z1_Parser; + + + LOCAL_DEF + FT_Error Z1_New_Table( Z1_Table* table, + FT_Int count, + FT_Memory memory ); + + + LOCAL_DEF + FT_Error Z1_Add_Table( Z1_Table* table, + FT_Int index, + void* object, + FT_Int length ); + +#if 0 + LOCAL_DEF + void Z1_Done_Table( Z1_Table* table ); +#endif + + LOCAL_DEF + void Z1_Release_Table( Z1_Table* table ); + + LOCAL_DEF + FT_Long Z1_ToInt( Z1_Parser* parser ); + + LOCAL_DEF + FT_Long Z1_ToFixed( Z1_Parser* parser, + FT_Int power_ten ); + + LOCAL_DEF + FT_Int Z1_ToCoordArray( Z1_Parser* parser, + FT_Int max_coords, + FT_Short* coords ); + + LOCAL_DEF + FT_Int Z1_ToFixedArray( Z1_Parser* parser, + FT_Int max_values, + FT_Fixed* values, + FT_Int power_ten ); + +#if 0 + LOCAL_DEF + FT_String* Z1_ToString( Z1_Parser* parser ); + + LOCAL_DEF + FT_Bool Z1_ToBool( Z1_Parser* parser ); +#endif + + + LOCAL_DEF + void Z1_Skip_Spaces( Z1_Parser* parser ); + + LOCAL_DEF + void Z1_ToToken( Z1_Parser* parser, + Z1_Token_Rec* token ); + + LOCAL_FUNC + void Z1_ToTokenArray( Z1_Parser* parser, + Z1_Token_Rec* tokens, + FT_UInt max_tokens, + FT_Int* pnum_tokens ); + + LOCAL_DEF + FT_Error Z1_Load_Field( Z1_Parser* parser, + const Z1_Field_Rec* field, + void** objects, + FT_UInt max_objects, + FT_ULong* pflags ); + + LOCAL_DEF + FT_Error Z1_Load_Field_Table( Z1_Parser* parser, + const Z1_Field_Rec* field, + void** objects, + FT_UInt max_objects, + FT_ULong* pflags ); + + + LOCAL_DEF + FT_Error Z1_New_Parser( Z1_Parser* parser, + FT_Stream stream, + FT_Memory memory ); + + LOCAL_DEF + FT_Error Z1_Get_Private_Dict( Z1_Parser* parser ); + + LOCAL_DEF + void Z1_Decrypt( FT_Byte* buffer, + FT_Int length, + FT_UShort seed ); + + LOCAL_DEF + void Z1_Done_Parser( Z1_Parser* parser ); + +#ifdef __cplusplus + } +#endif + +#endif /* Z1PARSE_H */ + + +/* END */ diff --git a/src/freetype/type1z/z1tokens.h b/src/freetype/type1z/z1tokens.h new file mode 100644 index 0000000000..73c0228e53 --- /dev/null +++ b/src/freetype/type1z/z1tokens.h @@ -0,0 +1,132 @@ +/***************************************************************************/ +/* */ +/* z1tokens.h */ +/* */ +/* Experimental Type 1 tokenizer (specification). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#undef T1TYPE +#define T1TYPE T1_FontInfo + + Z1_FONTINFO_STRING( "version", version ) + Z1_FONTINFO_STRING( "Notice", notice ) + Z1_FONTINFO_STRING( "FullName", full_name ) + Z1_FONTINFO_STRING( "FamilyName", family_name ) + Z1_FONTINFO_STRING( "Weight", weight ) + + Z1_FONTINFO_NUM ( "ItalicAngle", italic_angle ) + Z1_FONTINFO_BOOL ( "isFixedPitch", is_fixed_pitch ) + Z1_FONTINFO_NUM ( "UnderlinePosition", underline_position ) + Z1_FONTINFO_NUM ( "UnderlineThickness", underline_thickness ) + + +#undef T1TYPE +#define T1TYPE T1_Private + + Z1_PRIVATE_NUM ( "UniqueID", unique_id ) + Z1_PRIVATE_NUM ( "lenIV", lenIV ) + Z1_PRIVATE_NUM ( "LanguageGroup", language_group ) + Z1_PRIVATE_NUM ( "password", password ) + + Z1_PRIVATE_FIXED ( "BlueScale", blue_scale ) + Z1_PRIVATE_NUM ( "BlueShift", blue_shift ) + Z1_PRIVATE_NUM ( "BlueFuzz", blue_fuzz ) + + Z1_PRIVATE_NUM_TABLE ( "BlueValues", blue_values, 14, num_blue_values ) + Z1_PRIVATE_NUM_TABLE ( "OtherBlues", other_blues, 10, num_other_blues ) + Z1_PRIVATE_NUM_TABLE ( "FamilyBlues", family_blues, 14, num_family_blues ) + Z1_PRIVATE_NUM_TABLE ( "FamilyOtherBlues", family_other_blues, 10, \ + num_family_other_blues ) + + Z1_PRIVATE_NUM_TABLE2( "StdHW", standard_width, 1 ) + Z1_PRIVATE_NUM_TABLE2( "StdVW", standard_height, 1 ) + Z1_PRIVATE_NUM_TABLE2( "MinFeature", min_feature, 2 ) + + Z1_PRIVATE_NUM_TABLE ( "StemSnapH", snap_widths, 12, num_snap_widths ) + Z1_PRIVATE_NUM_TABLE ( "StemSnapV", snap_heights, 12, num_snap_heights ) + + +#undef T1TYPE +#define T1TYPE T1_Font + + Z1_TOPDICT_NUM( "PaintType", paint_type ) + Z1_TOPDICT_NUM( "FontType", font_type ) + Z1_TOPDICT_NUM( "StrokeWidth", stroke_width ) + + +#if 0 + + /* define the font info dictionary parsing callbacks */ +#undef FACE +#define FACE (face->type1.font_info) + + PARSE_STRING( "version", version ) + PARSE_STRING( "Notice", notice ) + PARSE_STRING( "FullName", full_name ) + PARSE_STRING( "FamilyName", family_name ) + PARSE_STRING( "Weight", weight ) + + PARSE_INT ( "ItalicAngle", italic_angle ) + PARSE_BOOL ( "isFixedPitch", is_fixed_pitch ) + PARSE_NUM ( "UnderlinePosition", underline_position, FT_Short ) + PARSE_NUM ( "UnderlineThickness", underline_thickness, FT_UShort ) + + + /* define the private dict parsing callbacks */ +#undef FACE +#define FACE (face->type1.private_dict) + + PARSE_INT ("UniqueID", unique_id ) + PARSE_INT ("lenIV", lenIV ) + + PARSE_COORDS ( "BlueValues", num_blues, 14, blue_values) + PARSE_COORDS ( "OtherBlues", num_other_blues, 10, other_blues) + + PARSE_COORDS ( "FamilyBlues", num_family_blues, 14, family_blues ) + PARSE_COORDS ( "FamilyOtherBlues", num_family_other_blues, 10, + family_other_blues ) + + PARSE_FIXED ( "BlueScale", blue_scale ) + PARSE_INT ( "BlueShift", blue_shift ) + + PARSE_INT ( "BlueFuzz", blue_fuzz ) + + PARSE_COORDS2( "StdHW", 1, standard_width ) + PARSE_COORDS2( "StdVW", 1, standard_height ) + + PARSE_COORDS ( "StemSnapH", num_snap_widths, 12, stem_snap_widths ) + PARSE_COORDS ( "StemSnapV", num_snap_heights, 12, stem_snap_heights ) + + PARSE_INT ( "LanguageGroup", language_group ) + PARSE_INT ( "password", password ) + PARSE_COORDS2( "MinFeature", 2, min_feature ) + + + /* define the top-level dictionary parsing callbacks */ +#undef FACE +#define FACE (face->type1) + +/*PARSE_STRING ( "FontName", font_name ) -- handled by special routine */ + PARSE_NUM ( "PaintType", paint_type, FT_Byte ) + PARSE_NUM ( "FontType", font_type, FT_Byte ) + PARSE_FIXEDS2( "FontMatrix", 4, font_matrix ) +/*PARSE_COORDS2( "FontBBox", 4, font_bbox ) -- handled by special routine */ + PARSE_INT ( "StrokeWidth", stroke_width ) + +#undef FACE + +#endif /* 0 */ + + +/* END */ diff --git a/src/freetype/unix/ftsystem.c b/src/freetype/unix/ftsystem.c new file mode 100644 index 0000000000..9ecd95c7dc --- /dev/null +++ b/src/freetype/unix/ftsystem.c @@ -0,0 +1,306 @@ +/***************************************************************************/ +/* */ +/* ftsystem.c */ +/* */ +/* Unix-specific FreeType low-level system interface (body). */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#include +#include +#include +#include +#include + +#include +#include +#include + + + /* memory-mapping includes and definitions */ +#ifdef HAVE_UNISTD_H +#include +#endif + +#include +#ifndef MAP_FILE +#define MAP_FILE 0x00 +#endif + + /*************************************************************************/ + /* */ + /* The prototype for munmap() is not provided on SunOS. This needs to */ + /* have a check added later to see if the GNU C library is being used. */ + /* If so, then this prototype is not needed. */ + /* */ +#if defined( __sun__ ) && !defined( SVR4 ) && !defined( __SVR4 ) + extern int munmap( caddr_t addr, + int len ); +#endif + +#include + +#ifdef HAVE_FCNTL_H +#include +#endif + +#include +#include +#include + + + /*************************************************************************/ + /* */ + /* MEMORY MANAGEMENT INTERFACE */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* */ + /* ft_alloc */ + /* */ + /* */ + /* The memory allocation function. */ + /* */ + /* */ + /* memory :: A pointer to the memory object. */ + /* size :: The requested size in bytes. */ + /* */ + /* */ + /* block :: The address of newly allocated block. */ + /* */ + static + void* ft_alloc( FT_Memory memory, + long size ) + { + FT_UNUSED( memory ); + + return malloc( size ); + } + + + /*************************************************************************/ + /* */ + /* */ + /* ft_realloc */ + /* */ + /* */ + /* The memory reallocation function. */ + /* */ + /* */ + /* memory :: A pointer to the memory object. */ + /* */ + /* cur_size :: The current size of the allocated memory block. */ + /* */ + /* new_size :: The newly requested size in bytes. */ + /* */ + /* block :: The current address of the block in memory. */ + /* */ + /* */ + /* The address of the reallocated memory block. */ + /* */ + static + void* ft_realloc( FT_Memory memory, + long cur_size, + long new_size, + void* block ) + { + FT_UNUSED( memory ); + FT_UNUSED( cur_size ); + + return realloc( block, new_size ); + } + + + /*************************************************************************/ + /* */ + /* */ + /* ft_free */ + /* */ + /* */ + /* The memory release function. */ + /* */ + /* */ + /* memory :: A pointer to the memory object. */ + /* */ + /* block :: The address of block in memory to be freed. */ + /* */ + static + void ft_free( FT_Memory memory, + void* block ) + { + FT_UNUSED( memory ); + + free( block ); + } + + + /*************************************************************************/ + /* */ + /* RESOURCE MANAGEMENT INTERFACE */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ + /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ + /* messages during execution. */ + /* */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_io + + /* We use the macro STREAM_FILE for convenience to extract the */ + /* system-specific stream handle from a given FreeType stream object */ +#define STREAM_FILE( stream ) ( (FILE*)stream->descriptor.pointer ) + + + /*************************************************************************/ + /* */ + /* */ + /* ft_close_stream */ + /* */ + /* */ + /* The function to close a stream. */ + /* */ + /* */ + /* stream :: A pointer to the stream object. */ + /* */ + static + void ft_close_stream( FT_Stream stream ) + { + munmap ( stream->descriptor.pointer, stream->size ); + + stream->descriptor.pointer = NULL; + stream->size = 0; + stream->base = 0; + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_New_Stream */ + /* */ + /* */ + /* Creates a new stream object. */ + /* */ + /* */ + /* filepathname :: The name of the stream (usually a file) to be */ + /* opened. */ + /* */ + /* stream :: A pointer to the stream object. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT_FUNC( FT_Error ) FT_New_Stream( const char* filepathname, + FT_Stream stream ) + { + int file; + struct stat stat_buf; + + + if ( !stream ) + return FT_Err_Invalid_Stream_Handle; + + /* open the file */ + file = open( filepathname, O_RDONLY ); + if ( file < 0 ) + { + FT_ERROR(( "FT_New_Stream:" )); + FT_ERROR(( " could not open `%s'\n", filepathname )); + return FT_Err_Cannot_Open_Resource; + } + + if ( fstat( file, &stat_buf ) < 0 ) + { + FT_ERROR(( "FT_New_Stream:" )); + FT_ERROR(( " could not `fstat' file `%s'\n", filepathname )); + goto Fail_Map; + } + + stream->size = stat_buf.st_size; + stream->pos = 0; + stream->base = mmap( NULL, + stream->size, + PROT_READ, + MAP_FILE | MAP_PRIVATE, + file, + 0 ); + + if ( (long)stream->base == -1 ) + { + FT_ERROR(( "FT_New_Stream:" )); + FT_ERROR(( " could not `mmap' file `%s'\n", filepathname )); + goto Fail_Map; + } + + close( file ); + + stream->descriptor.pointer = stream->base; + stream->pathname.pointer = (char*)filepathname; + + stream->close = ft_close_stream; + stream->read = 0; + + FT_TRACE1(( "FT_New_Stream:" )); + FT_TRACE1(( " opened `%s' (%d bytes) successfully\n", + filepathname, stream->size )); + + return FT_Err_Ok; + + Fail_Map: + close( file ); + + stream->base = NULL; + stream->size = 0; + stream->pos = 0; + + return FT_Err_Cannot_Open_Stream; + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_New_Memory */ + /* */ + /* */ + /* Creates a new memory object. */ + /* */ + /* */ + /* A pointer to the new memory object. 0 in case of error. */ + /* */ + FT_EXPORT_FUNC( FT_Memory ) FT_New_Memory( void ) + { + FT_Memory memory; + + + memory = (FT_Memory)malloc( sizeof ( *memory ) ); + if ( memory ) + { + memory->user = 0; + memory->alloc = ft_alloc; + memory->realloc = ft_realloc; + memory->free = ft_free; + } + + return memory; + } + + +/* END */ diff --git a/src/freetype/winfonts/module.mk b/src/freetype/winfonts/module.mk new file mode 100644 index 0000000000..5c12eb6ee8 --- /dev/null +++ b/src/freetype/winfonts/module.mk @@ -0,0 +1,6 @@ +make_module_list: add_windows_driver + +add_windows_driver: + $(OPEN_DRIVER)winfnt_driver_class$(CLOSE_DRIVER) + $(ECHO_DRIVER)winfnt $(ECHO_DRIVER_DESC)Windows bitmap fonts with extension *.fnt or *.fon$(ECHO_DRIVER_DONE) + diff --git a/src/freetype/winfonts/rules.mk b/src/freetype/winfonts/rules.mk new file mode 100644 index 0000000000..8396894d97 --- /dev/null +++ b/src/freetype/winfonts/rules.mk @@ -0,0 +1,64 @@ +# +# FreeType 2 Windows FNT/FON driver configuration rules +# + + +# Copyright 1996-2000 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +# Windows driver directory +# +FNT_DIR := $(SRC_)winfonts +FNT_DIR_ := $(FNT_DIR)$(SEP) + + +FNT_COMPILE := $(FT_COMPILE) + + +# Windows driver sources (i.e., C files) +# +FNT_DRV_SRC := $(FNT_DIR_)winfnt.c + +# Windows driver headers +# +FNT_DRV_H := $(FNT_DRV_SRC:%.c=%.h) + + +# Windows driver object(s) +# +# FNT_DRV_OBJ_M is used during `multi' builds +# FNT_DRV_OBJ_S is used during `single' builds +# +FNT_DRV_OBJ_M := $(FNT_DRV_SRC:$(FNT_DIR_)%.c=$(OBJ_)%.$O) +FNT_DRV_OBJ_S := $(OBJ_)winfnt.$O + +# Windows driver source file for single build +# +FNT_DRV_SRC_S := $(FNT_DIR_)winfnt.c + + +# Windows driver - single object +# +$(FNT_DRV_OBJ_S): $(FNT_DRV_SRC_S) $(FNT_DRV_SRC) $(FREETYPE_H) $(FNT_DRV_H) + $(FNT_COMPILE) $T$@ $(FNT_DRV_SRC_S) + + +# Windows driver - multiple objects +# +$(OBJ_)%.$O: $(FNT_DIR_)%.c $(FREETYPE_H) $(FNT_DRV_H) + $(FNT_COMPILE) $T$@ $< + + +# update main driver object lists +# +DRV_OBJS_S += $(FNT_DRV_OBJ_S) +DRV_OBJS_M += $(FNT_DRV_OBJ_M) + +# EOF diff --git a/src/freetype/winfonts/winfnt.c b/src/freetype/winfonts/winfnt.c new file mode 100644 index 0000000000..470440a2ca --- /dev/null +++ b/src/freetype/winfonts/winfnt.c @@ -0,0 +1,623 @@ +/***************************************************************************/ +/* */ +/* winfnt.c */ +/* */ +/* FreeType font driver for Windows FNT/FON files */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifdef FT_FLAT_COMPILE + +#include "winfnt.h" + +#else + +#include + +#endif + + +#include +#include +#include +#include + + + /*************************************************************************/ + /* */ + /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ + /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ + /* messages during execution. */ + /* */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_winfnt + + + static + const FT_Frame_Field winmz_header_fields[] = + { + FT_FRAME_START( 64 ), + FT_FRAME_USHORT_LE ( WinMZ_Header, magic ), + FT_FRAME_SKIP_BYTES( 29 * 2 ), + FT_FRAME_ULONG_LE ( WinMZ_Header, lfanew ), + FT_FRAME_END + }; + + static + const FT_Frame_Field winne_header_fields[] = + { + FT_FRAME_START( 40 ), + FT_FRAME_USHORT_LE ( WinNE_Header, magic ), + FT_FRAME_SKIP_BYTES( 34 ), + FT_FRAME_USHORT_LE ( WinNE_Header, resource_tab_offset ), + FT_FRAME_USHORT_LE ( WinNE_Header, rname_tab_offset ), + FT_FRAME_END + }; + + static + const FT_Frame_Field winfnt_header_fields[] = + { + FT_FRAME_START( 134 ), + FT_FRAME_USHORT_LE( WinFNT_Header, version ), + FT_FRAME_ULONG_LE ( WinFNT_Header, file_size ), + FT_FRAME_BYTES ( WinFNT_Header, copyright, 60 ), + FT_FRAME_USHORT_LE( WinFNT_Header, file_type ), + FT_FRAME_USHORT_LE( WinFNT_Header, nominal_point_size ), + FT_FRAME_USHORT_LE( WinFNT_Header, vertical_resolution ), + FT_FRAME_USHORT_LE( WinFNT_Header, horizontal_resolution ), + FT_FRAME_USHORT_LE( WinFNT_Header, ascent ), + FT_FRAME_USHORT_LE( WinFNT_Header, internal_leading ), + FT_FRAME_USHORT_LE( WinFNT_Header, external_leading ), + FT_FRAME_BYTE ( WinFNT_Header, italic ), + FT_FRAME_BYTE ( WinFNT_Header, underline ), + FT_FRAME_BYTE ( WinFNT_Header, strike_out ), + FT_FRAME_USHORT_LE( WinFNT_Header, weight ), + FT_FRAME_BYTE ( WinFNT_Header, charset ), + FT_FRAME_USHORT_LE( WinFNT_Header, pixel_width ), + FT_FRAME_USHORT_LE( WinFNT_Header, pixel_height ), + FT_FRAME_BYTE ( WinFNT_Header, pitch_and_family ), + FT_FRAME_USHORT_LE( WinFNT_Header, avg_width ), + FT_FRAME_USHORT_LE( WinFNT_Header, max_width ), + FT_FRAME_BYTE ( WinFNT_Header, first_char ), + FT_FRAME_BYTE ( WinFNT_Header, last_char ), + FT_FRAME_BYTE ( WinFNT_Header, default_char ), + FT_FRAME_BYTE ( WinFNT_Header, break_char ), + FT_FRAME_USHORT_LE( WinFNT_Header, bytes_per_row ), + FT_FRAME_ULONG_LE ( WinFNT_Header, device_offset ), + FT_FRAME_ULONG_LE ( WinFNT_Header, face_name_offset ), + FT_FRAME_ULONG_LE ( WinFNT_Header, bits_pointer ), + FT_FRAME_ULONG_LE ( WinFNT_Header, bits_offset ), + FT_FRAME_BYTE ( WinFNT_Header, reserved ), + FT_FRAME_ULONG_LE ( WinFNT_Header, flags ), + FT_FRAME_USHORT_LE( WinFNT_Header, A_space ), + FT_FRAME_USHORT_LE( WinFNT_Header, B_space ), + FT_FRAME_USHORT_LE( WinFNT_Header, C_space ), + FT_FRAME_USHORT_LE( WinFNT_Header, color_table_offset ), + FT_FRAME_BYTES ( WinFNT_Header, reserved, 4 ), + FT_FRAME_END + }; + + + static + void fnt_done_font( FT_Stream stream, + FNT_Font* font ) + { + if ( font->fnt_frame ) + RELEASE_Frame( font->fnt_frame ); + + font->fnt_size = 0; + font->fnt_frame = 0; + } + + + static + FT_Error fnt_load_font( FT_Stream stream, + FNT_Font* font ) + { + FT_Error error; + WinFNT_Header* header = &font->header; + + + /* first of all, read the FNT header */ + if ( FILE_Seek( font->offset ) || + READ_Fields( winfnt_header_fields, header ) ) + goto Exit; + + /* check header */ + if ( header->version != 0x200 && + header->version != 0x300 ) + { + FT_TRACE2(( "[not a valid FNT file]\n" )); + error = FT_Err_Unknown_File_Format; + goto Exit; + } + + if ( header->file_type & 1 ) + { + FT_TRACE2(( "can't handle vector FNT fonts\n" )); + error = FT_Err_Unknown_File_Format; + goto Exit; + } + + /* small fixup -- some fonts have the `pixel_width' field set to 0 */ + if ( header->pixel_width == 0 ) + header->pixel_width = header->pixel_height; + + /* this is a FNT file/table, we now extract its frame */ + if ( FILE_Seek( font->offset ) || + EXTRACT_Frame( header->file_size, font->fnt_frame ) ) + goto Exit; + + Exit: + return error; + } + + + static + void fnt_done_fonts( FNT_Face face ) + { + FT_Memory memory = FT_FACE(face)->memory; + FT_Stream stream = FT_FACE(face)->stream; + FNT_Font* cur = face->fonts; + FNT_Font* limit = cur + face->num_fonts; + + + for ( ; cur < limit; cur++ ) + fnt_done_font( stream, cur ); + + FREE( face->fonts ); + face->num_fonts = 0; + } + + static + FT_Error fnt_get_dll_fonts( FNT_Face face ) + { + FT_Error error; + FT_Stream stream = FT_FACE(face)->stream; + FT_Memory memory = FT_FACE(face)->memory; + WinMZ_Header mz_header; + + + face->fonts = 0; + face->num_fonts = 0; + + /* does it begin with a MZ header? */ + if ( FILE_Seek( 0 ) || + READ_Fields( winmz_header_fields, &mz_header ) ) + goto Exit; + + error = FT_Err_Unknown_File_Format; + if ( mz_header.magic == WINFNT_MZ_MAGIC ) + { + /* yes, now look for a NE header in the file */ + WinNE_Header ne_header; + + + if ( FILE_Seek( mz_header.lfanew ) || + READ_Fields( winne_header_fields, &ne_header ) ) + goto Exit; + + error = FT_Err_Unknown_File_Format; + if ( ne_header.magic == WINFNT_NE_MAGIC ) + { + /* good, now look in the resource table for each FNT resource */ + FT_ULong res_offset = mz_header.lfanew + + ne_header.resource_tab_offset; + + FT_UShort size_shift; + FT_UShort font_count = 0; + FT_ULong font_offset = 0; + + + if ( FILE_Seek( res_offset ) || + ACCESS_Frame( ne_header.rname_tab_offset - + ne_header.resource_tab_offset ) ) + goto Exit; + + size_shift = GET_UShortLE(); + + for (;;) + { + FT_UShort type_id, count; + + + type_id = GET_UShortLE(); + if ( !type_id ) + break; + + count = GET_UShortLE(); + + if ( type_id == 0x8008 ) + { + font_count = count; + font_offset = FILE_Pos() + 4 + ( stream->cursor - stream->limit ); + break; + } + + stream->cursor += 4 + count * 12; + } + FORGET_Frame(); + + if ( !font_count || !font_offset ) + { + FT_TRACE2(( "this file doesn't contain any FNT resources!\n" )); + error = FT_Err_Unknown_File_Format; + goto Exit; + } + + if ( FILE_Seek( font_offset ) || + ALLOC_ARRAY( face->fonts, font_count, FNT_Font ) ) + goto Exit; + + face->num_fonts = font_count; + + if ( ACCESS_Frame( (FT_Long)font_count * 12 ) ) + goto Exit; + + /* now read the offset and position of each FNT font */ + { + FNT_Font* cur = face->fonts; + FNT_Font* limit = cur + font_count; + + + for ( ; cur < limit; cur++ ) + { + cur->offset = (FT_ULong)GET_UShortLE() << size_shift; + cur->fnt_size = (FT_ULong)GET_UShortLE() << size_shift; + cur->size_shift = size_shift; + stream->cursor += 8; + } + } + FORGET_Frame(); + + /* finally, try to load each font there */ + { + FNT_Font* cur = face->fonts; + FNT_Font* limit = cur + font_count; + + + for ( ; cur < limit; cur++ ) + { + error = fnt_load_font( stream, cur ); + if ( error ) + goto Fail; + } + } + } + } + + Fail: + if ( error ) + fnt_done_fonts( face ); + + Exit: + return error; + } + + + static + void FNT_Done_Face( FNT_Face face ) + { + FT_Memory memory = FT_FACE_MEMORY( face ); + + + fnt_done_fonts( face ); + + FREE( face->root.available_sizes ); + face->root.num_fixed_sizes = 0; + } + + + static + FT_Error FNT_Init_Face( FT_Stream stream, + FNT_Face face, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ) + { + FT_Error error; + FT_Memory memory = FT_FACE_MEMORY( face ); + + FT_UNUSED( num_params ); + FT_UNUSED( params ); + FT_UNUSED( face_index ); + + + /* try to load several fonts from a DLL */ + error = fnt_get_dll_fonts( face ); + if ( error ) + { + /* this didn't work, now try to load a single FNT font */ + FT_Memory memory = FT_FACE_MEMORY( face ); + FNT_Font* font; + + if ( ALLOC( face->fonts, sizeof ( *face->fonts ) ) ) + goto Exit; + + face->num_fonts = 1; + font = face->fonts; + + font->offset = 0; + font->fnt_size = stream->size; + + error = fnt_load_font( stream, font ); + if ( error ) + goto Fail; + } + + /* all right, one or more fonts were loaded; we now need to */ + /* fill the root FT_Face fields with relevant information */ + { + FT_Face root = FT_FACE( face ); + FNT_Font* fonts = face->fonts; + FNT_Font* limit = fonts + face->num_fonts; + FNT_Font* cur; + + + root->num_faces = 1; + root->face_flags = FT_FACE_FLAG_FIXED_SIZES | + FT_FACE_FLAG_HORIZONTAL; + + if ( fonts->header.avg_width == fonts->header.max_width ) + root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH; + + if ( fonts->header.italic ) + root->style_flags |= FT_STYLE_FLAG_ITALIC; + + if ( fonts->header.weight >= 800 ) + root->style_flags |= FT_STYLE_FLAG_BOLD; + + /* Setup the `fixed_sizes' array */ + if ( ALLOC_ARRAY( root->available_sizes, face->num_fonts, + FT_Bitmap_Size ) ) + goto Fail; + + root->num_fixed_sizes = face->num_fonts; + + { + FT_Bitmap_Size* size = root->available_sizes; + + + for ( cur = fonts; cur < limit; cur++, size++ ) + { + size->width = cur->header.pixel_width; + size->height = cur->header.pixel_height; + } + } + + /* Setup the `charmaps' array */ + root->charmaps = &face->charmap_handle; + root->num_charmaps = 1; + + face->charmap.encoding = ft_encoding_unicode; + face->charmap.platform_id = 3; + face->charmap.encoding_id = 1; + face->charmap.face = root; + + face->charmap_handle = &face->charmap; + + root->charmap = face->charmap_handle; + + /* setup remaining flags */ + root->num_glyphs = fonts->header.last_char - + fonts->header.first_char + 1; + + root->family_name = (FT_String*)fonts->fnt_frame + + fonts->header.face_name_offset; + root->style_name = "Regular"; + + if ( root->style_flags & FT_STYLE_FLAG_BOLD ) + { + if ( root->style_flags & FT_STYLE_FLAG_ITALIC ) + root->style_name = "Bold Italic"; + else + root->style_name = "Bold"; + } + else if ( root->style_flags & FT_STYLE_FLAG_ITALIC ) + root->style_name = "Italic"; + } + + Fail: + if ( error ) + FNT_Done_Face( face ); + + Exit: + return error; + } + + + static + FT_Error FNT_Set_Pixel_Size( FNT_Size size ) + { + /* look up a font corresponding to the current pixel size */ + FNT_Face face = (FNT_Face)FT_SIZE_FACE( size ); + FNT_Font* cur = face->fonts; + FNT_Font* limit = cur + face->num_fonts; + + + size->font = 0; + for ( ; cur < limit; cur++ ) + { + /* we only compare the character height, as fonts used some strange */ + /* values */ + if ( cur->header.pixel_height == size->root.metrics.y_ppem ) + { + size->font = cur; + + size->root.metrics.ascender = cur->header.ascent * 64; + size->root.metrics.descender = ( cur->header.pixel_height - + cur->header.ascent ) * 64; + size->root.metrics.height = cur->header.pixel_height * 64; + break; + } + } + + return ( size->font ? FT_Err_Ok : FT_Err_Invalid_Argument ); + } + + + static + FT_UInt FNT_Get_Char_Index( FT_CharMap charmap, + FT_ULong char_code ) + { + FT_UInt result = char_code; + + + if ( charmap ) + { + FNT_Font* font = ((FNT_Face)charmap->face)->fonts; + FT_UInt first = font->header.first_char; + FT_UInt count = font->header.last_char - first + 1; + + + char_code -= first; + if ( char_code < count ) + result = char_code + 1; + else + result = 0; + } + + return result; + } + + + static + FT_Error FNT_Load_Glyph( FT_GlyphSlot slot, + FNT_Size size, + FT_UInt glyph_index, + FT_Int load_flags ) + { + FNT_Font* font = size->font; + FT_Error error = 0; + FT_Byte* p; + FT_Int len; + FT_Bitmap* bitmap = &slot->bitmap; + FT_ULong offset; + FT_Bool new_format; + + FT_UNUSED( slot ); + FT_UNUSED( load_flags ); + + + if ( !font ) + { + error = FT_Err_Invalid_Argument; + goto Exit; + } + + if ( glyph_index > 0 ) + glyph_index--; + else + glyph_index = font->header.default_char - font->header.first_char; + + new_format = font->header.version == 0x300; + len = new_format ? 6 : 4; + + /* jump to glyph entry */ + p = font->fnt_frame + 118 + len * glyph_index; + + bitmap->width = NEXT_ShortLE(p); + + if ( new_format ) + offset = NEXT_ULongLE(p); + else + offset = NEXT_UShortLE(p); + + /* jump to glyph data */ + p = font->fnt_frame + /* font->header.bits_offset */ + offset; + + /* allocate and build bitmap */ + { + FT_Memory memory = FT_FACE_MEMORY( slot->face ); + FT_Int pitch = ( bitmap->width + 7 ) >> 3; + FT_Byte* column; + FT_Byte* write; + + + bitmap->pitch = pitch; + bitmap->rows = font->header.pixel_height; + bitmap->pixel_mode = ft_pixel_mode_mono; + + if ( ALLOC( bitmap->buffer, pitch * bitmap->rows ) ) + goto Exit; + + column = (FT_Byte*)bitmap->buffer; + + for ( ; pitch > 0; pitch--, column++ ) + { + FT_Byte* limit = p + bitmap->rows; + + + for ( write = column; p < limit; p++, write += bitmap->pitch ) + write[0] = p[0]; + } + } + + slot->flags = ft_glyph_own_bitmap; + slot->bitmap_left = 0; + slot->bitmap_top = font->header.ascent; + slot->format = ft_glyph_format_bitmap; + + /* now set up metrics */ + slot->metrics.horiAdvance = bitmap->width << 6; + slot->metrics.horiBearingX = 0; + slot->metrics.horiBearingY = slot->bitmap_top << 6; + + slot->linearHoriAdvance = (FT_Fixed)bitmap->width << 16; + + Exit: + return error; + } + + + const FT_Driver_Class winfnt_driver_class = + { + { + ft_module_font_driver, + sizeof ( FT_DriverRec ), + + "winfonts", + 0x10000L, + 0x20000L, + + 0, + + (FT_Module_Constructor)0, + (FT_Module_Destructor) 0, + (FT_Module_Requester) 0 + }, + + sizeof( FNT_FaceRec ), + sizeof( FNT_SizeRec ), + sizeof( FT_GlyphSlotRec ), + + (FTDriver_initFace) FNT_Init_Face, + (FTDriver_doneFace) FNT_Done_Face, + (FTDriver_initSize) 0, + (FTDriver_doneSize) 0, + (FTDriver_initGlyphSlot)0, + (FTDriver_doneGlyphSlot)0, + + (FTDriver_setCharSizes) FNT_Set_Pixel_Size, + (FTDriver_setPixelSizes)FNT_Set_Pixel_Size, + + (FTDriver_loadGlyph) FNT_Load_Glyph, + (FTDriver_getCharIndex) FNT_Get_Char_Index, + + (FTDriver_getKerning) 0, + (FTDriver_attachFile) 0, + (FTDriver_getAdvances) 0 + }; + + +/* END */ diff --git a/src/freetype/winfonts/winfnt.h b/src/freetype/winfonts/winfnt.h new file mode 100644 index 0000000000..eaf308b875 --- /dev/null +++ b/src/freetype/winfonts/winfnt.h @@ -0,0 +1,150 @@ +/***************************************************************************/ +/* */ +/* winfnt.h */ +/* */ +/* FreeType font driver for Windows FNT/FON files */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef WINFNT_H +#define WINFNT_H + +#include + + + typedef struct WinMZ_Header_ + { + FT_UShort magic; + /* skipped content */ + FT_UShort lfanew; + + } WinMZ_Header; + + + typedef struct WinNE_Header_ + { + FT_UShort magic; + /* skipped content */ + FT_UShort resource_tab_offset; + FT_UShort rname_tab_offset; + + } WinNE_Header; + + + typedef struct WinNameInfo_ + { + FT_UShort offset; + FT_UShort length; + FT_UShort flags; + FT_UShort id; + FT_UShort handle; + FT_UShort usage; + + } WinNameInfo; + + + typedef struct WinResourceInfo_ + { + FT_UShort type_id; + FT_UShort count; + + } WinResourceInfo; + + +#define WINFNT_MZ_MAGIC 0x5A4D +#define WINFNT_NE_MAGIC 0x454E + + + typedef struct WinFNT_Header_ + { + FT_UShort version; + FT_ULong file_size; + FT_Byte copyright[60]; + FT_UShort file_type; + FT_UShort nominal_point_size; + FT_UShort vertical_resolution; + FT_UShort horizontal_resolution; + FT_UShort ascent; + FT_UShort internal_leading; + FT_UShort external_leading; + FT_Byte italic; + FT_Byte underline; + FT_Byte strike_out; + FT_UShort weight; + FT_Byte charset; + FT_UShort pixel_width; + FT_UShort pixel_height; + FT_Byte pitch_and_family; + FT_UShort avg_width; + FT_UShort max_width; + FT_Byte first_char; + FT_Byte last_char; + FT_Byte default_char; + FT_Byte break_char; + FT_UShort bytes_per_row; + FT_ULong device_offset; + FT_ULong face_name_offset; + FT_ULong bits_pointer; + FT_ULong bits_offset; + FT_Byte reserved; + FT_ULong flags; + FT_UShort A_space; + FT_UShort B_space; + FT_UShort C_space; + FT_UShort color_table_offset; + FT_Byte reserved2[4]; + + } WinFNT_Header; + + + typedef struct FNT_Font_ + { + FT_ULong offset; + FT_Int size_shift; + + WinFNT_Header header; + + FT_Byte* fnt_frame; + FT_ULong fnt_size; + + } FNT_Font; + + + typedef struct FNT_SizeRec_ + { + FT_SizeRec root; + FNT_Font* font; + + } FNT_SizeRec, *FNT_Size; + + + typedef struct FNT_FaceRec_ + { + FT_FaceRec root; + + FT_UInt num_fonts; + FNT_Font* fonts; + + FT_CharMap charmap_handle; + FT_CharMapRec charmap; /* a single charmap per face */ + + } FNT_FaceRec, *FNT_Face; + + + FT_EXPORT_VAR( const FT_Driver_Class ) winfnt_driver_class; + + +#endif /* WINFNT_H */ + + +/* END */