📄 ahglyph.c
字号:
/***************************************************************************//* *//* 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 <autohint/ahglyph.h>#include <autohint/ahangles.h>#include <autohint/ahglobal.h>#endif#include <stdio.h>#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; } /* this function is used by ah_get_orientation (see below) to test */ /* the fill direction of a given bbox extrema */ static int ah_test_extrema( FT_Outline* outline, int n ) { FT_Vector *prev, *cur, *next; FT_Pos product; FT_Int first, last, c; /* 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 ? 2 : 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 ah_get_orientation( FT_Outline* outline ) { FT_BBox box; FT_BBox indices; int n, last; indices.xMin = -1; indices.yMin = -1; indices.xMax = -1; indices.yMax = -1; box.xMin = box.yMin = 32767; box.xMax = box.yMax = -32768; /* is it empty? */ if ( outline->n_contours < 1 ) return 1; last = outline->contours[outline->n_contours - 1]; for ( n = 0; n <= last; n++ ) { FT_Pos x, y; x = outline->points[n].x; if ( x < box.xMin ) { box.xMin = x; indices.xMin = n; } if ( x > box.xMax ) { box.xMax = x; indices.xMax = n; } y = outline->points[n].y; if ( y < box.yMin ) { box.yMin = y; indices.yMin = n; } if ( y > box.yMax ) { box.yMax = y; indices.yMax = n; } } /* test orientation of the xmin */ n = ah_test_extrema( outline, indices.xMin ); if ( n ) goto Exit; n = ah_test_extrema( outline, indices.yMin ); if ( n ) goto Exit; n = ah_test_extrema( outline, indices.xMax ); if ( n ) goto Exit; n = ah_test_extrema( outline, indices.yMax ); if ( !n ) n = 1; Exit: return n; } /*************************************************************************/ /* */ /* <Function> */ /* ah_outline_new */ /* */ /* <Description> */ /* Creates a new and empty AH_Outline object. */ /* */ FT_LOCAL_DEF 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; } /*************************************************************************/ /* */ /* <Function> */ /* ah_outline_done */ /* */ /* <Description> */ /* Destroys a given AH_Outline object. */ /* */ FT_LOCAL_DEF 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 ); } /*************************************************************************/ /* */ /* <Function> */ /* ah_outline_save */ /* */ /* <Description> */ /* Saves the content of a given AH_Outline object into a face's glyph */ /* slot. */ /* */ FT_LOCAL_DEF void ah_outline_save( AH_Outline* outline, AH_Loader* gloader ) { AH_Point* point = outline->points; AH_Point* 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 < 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; } } /*************************************************************************/ /* */ /* <Function> */ /* ah_outline_load */ /* */ /* <Description> */ /* Loads an unscaled outline from a glyph slot into an AH_Outline */ /* object. */ /* */ FT_LOCAL_DEF 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, reallocate the points, segments & edges arrays if needed -- */ /* note that we reserved two additional point positions, used to */ /* hint metrics appropriately */ /* */ if ( num_points + 2 > outline->max_points ) { FT_Int news = ( num_points + 2 + 7 ) & -8; FT_Int max = outline->max_points; if ( REALLOC_ARRAY( outline->points, max, news, AH_Point ) || REALLOC_ARRAY( outline->horz_edges, max * 2, news * 2, AH_Edge ) || REALLOC_ARRAY( outline->horz_segments, max * 2, news * 2, AH_Segment ) ) goto Exit; /* readjust some pointers */ outline->vert_edges = outline->horz_edges + news; outline->vert_segments = outline->horz_segments + news; 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;#if 1 /* We can't rely on the value of `FT_Outline.flags' to know the fill */ /* direction used for a glyph, given that some fonts are broken (e.g. */ /* the Arphic ones). We thus recompute it each time we need to. */ /* */ outline->vert_major_dir = ah_dir_up; outline->horz_major_dir = ah_dir_left; if ( ah_get_orientation( source ) > 1 ) { outline->vert_major_dir = ah_dir_down; outline->horz_major_dir = ah_dir_right; }#else /* 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; }#endif /* 1 */ outline->x_scale = face->size->metrics.x_scale; outline->y_scale = face->size->metrics.y_scale; points = outline->points; if ( outline->num_points == 0 ) goto Exit; { /* do one thing at a time -- it is easier to understand, and */ /* the code is clearer */ AH_Point* point; AH_Point* point_limit = points + 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 = points; point < 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 < 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 < point_limit; point++ ) { point->prev = prev; if ( point < end ) { point->next = point + 1; prev = point; } else { point->next = first; contour_index++; if ( point + 1 < point_limit ) { end = points + source->contours[contour_index]; first = point + 1; prev = end; } } } } /* set-up the contours array */ { AH_Point** contour = outline->contours; AH_Point** contour_limit = contour + outline->num_contours; short* end = source->contours; short index = 0; for ( ; contour < contour_limit; contour++, end++ ) { contour[0] = points + index; index = end[0] + 1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -