af_direction_compute( FT_Pos dx, FT_Pos dy ) { AF_Direction dir; FT_Pos ax = FT_ABS( dx ); FT_Pos ay = FT_ABS( dy ); dir = AF_DIR_NONE; /* atan(1/12) == 4.7 degrees */ /* test for vertical direction */ if ( ax * 12 < ay ) { dir = dy > 0 ? AF_DIR_UP : AF_DIR_DOWN; } /* test for horizontal direction */ else if ( ay * 12 < ax ) { dir = dx > 0 ? AF_DIR_RIGHT : AF_DIR_LEFT; } return dir; }
static void find_way(t_filler *f) { int i; int j; int minx; int miny; i = -1; minx = INT_MAX / 2; miny = INT_MAX / 2; while (++i < f->grid.hig && (j = -1)) while (++j < f->grid.wid) if (f->grid.g[i][j] == f->itschars[0] || f->grid.g[i][j] == f->itschars[1]) if (FT_ABS(f->y - i) + FT_ABS(f->x - j) < FT_ABS(miny - i) + FT_ABS(minx - j) && ((minx = j) || 1)) miny = i; if (minx == INT_MAX / 2) f->way = LEFT | UP; else if (minx <= f->x && miny <= f->x) f->way = LEFT | UP; else if (minx <= f->x) f->way = LEFT | DOWN; else if (miny <= f->x) f->way = RIGHT | UP; else f->way = RIGHT | DOWN; }
static void BBox_Cubic_Check( FT_Pos p1, FT_Pos p2, FT_Pos p3, FT_Pos p4, FT_Pos* min, FT_Pos* max ) { FT_Pos nmin, nmax; FT_Int shift; /* This function is only called when a control off-point is outside */ /* the bbox that contains all on-points. It finds a local extremum */ /* within the segment using iterative bisection of the segment. */ /* The fixed-point arithmetic of bisection is inherently stable */ /* but may loose accuracy in the two lowest bits. To compensate, */ /* we upscale the segment if there is room. Large values may need */ /* to be downscaled to avoid overflows during bisection. */ /* The control off-point outside the bbox is likely to have the top */ /* absolute value among arguments. */ shift = 27 - FT_MSB( FT_ABS( p2 ) | FT_ABS( p3 ) ); if ( shift > 0 ) { /* upscaling too much just wastes time */ if ( shift > 2 ) shift = 2; p1 <<= shift; p2 <<= shift; p3 <<= shift; p4 <<= shift; nmin = *min << shift; nmax = *max << shift; } else { p1 >>= -shift; p2 >>= -shift; p3 >>= -shift; p4 >>= -shift; nmin = *min >> -shift; nmax = *max >> -shift; } nmax = update_cubic_max( p1, p2, p3, p4, nmax ); /* now flip the signs to update the minimum */ nmin = -update_cubic_max( -p1, -p2, -p3, -p4, -nmin ); if ( shift > 0 ) { nmin >>= shift; nmax >>= shift; }
void my_burning_ship(t_win *win, t_frac *f) { int i; int x; int y; double tmp; y = -1; while (++y < FOL_HIG && (x = -1)) while (++x < FOL_WID) { f->cr = x / f->zoomx + f->x; f->ci = y / f->zoomy + f->y; f->zr = f->cr_ref; f->zi = f->ci_ref; i = -1; while (++i < (int)f->max_iter && f->zr * f->zr + f->zi * f->zi < 10) { tmp = f->zr; f->zr = f->zr * f->zr - f->zi * f->zi - f->cr; f->zi = 2 * FT_ABS(f->zi * tmp) - f->ci; } *(int *)(win->buf + (FOL_HIG - y - 1) * win->line + (FOL_WID - x - 1) * 4) = get_color(f, win->col, i, f->max_iter); } }
cid_parse_font_matrix( CID_Face face, CID_Parser* parser ) { CID_FaceDict dict; FT_Face root = (FT_Face)&face->root; FT_Fixed temp[6]; FT_Fixed temp_scale; if ( parser->num_dict >= 0 && parser->num_dict < face->cid.num_dicts ) { FT_Matrix* matrix; FT_Vector* offset; FT_Int result; dict = face->cid.font_dicts + parser->num_dict; matrix = &dict->font_matrix; offset = &dict->font_offset; result = cid_parser_to_fixed_array( parser, 6, temp, 3 ); if ( result < 6 ) return FT_THROW( Invalid_File_Format ); temp_scale = FT_ABS( temp[3] ); if ( temp_scale == 0 ) { FT_ERROR(( "cid_parse_font_matrix: invalid font matrix\n" )); return FT_THROW( Invalid_File_Format ); } /* Set Units per EM based on FontMatrix values. We set the value to */ /* 1000 / temp_scale, because temp_scale was already multiplied by */ /* 1000 (in t1_tofixed, from psobjs.c). */ root->units_per_EM = (FT_UShort)FT_DivFix( 1000, temp_scale ); /* we need to scale the values by 1.0/temp[3] */ if ( temp_scale != 0x10000L ) { temp[0] = FT_DivFix( temp[0], temp_scale ); temp[1] = FT_DivFix( temp[1], temp_scale ); temp[2] = FT_DivFix( temp[2], temp_scale ); temp[4] = FT_DivFix( temp[4], temp_scale ); temp[5] = FT_DivFix( temp[5], temp_scale ); temp[3] = temp[3] < 0 ? -0x10000L : 0x10000L; } matrix->xx = temp[0]; matrix->yx = temp[1]; matrix->xy = temp[2]; matrix->yy = temp[3]; /* note that the font offsets are expressed in integer font units */ offset->x = temp[4] >> 16; offset->y = temp[5] >> 16; }
cid_parse_font_matrix( CID_Face face, CID_Parser* parser ) { CID_FaceDict dict; FT_Face root = (FT_Face)&face->root; FT_Fixed temp[6]; FT_Fixed temp_scale; if ( parser->num_dict >= 0 && parser->num_dict < face->cid.num_dicts ) { FT_Matrix* matrix; FT_Vector* offset; FT_Int result; dict = face->cid.font_dicts + parser->num_dict; matrix = &dict->font_matrix; offset = &dict->font_offset; /* input is scaled by 1000 to accommodate default FontMatrix */ result = cid_parser_to_fixed_array( parser, 6, temp, 3 ); if ( result < 6 ) return FT_THROW( Invalid_File_Format ); temp_scale = FT_ABS( temp[3] ); if ( temp_scale == 0 ) { FT_ERROR(( "cid_parse_font_matrix: invalid font matrix\n" )); return FT_THROW( Invalid_File_Format ); } /* atypical case */ if ( temp_scale != 0x10000L ) { /* set units per EM based on FontMatrix values */ root->units_per_EM = (FT_UShort)FT_DivFix( 1000, temp_scale ); temp[0] = FT_DivFix( temp[0], temp_scale ); temp[1] = FT_DivFix( temp[1], temp_scale ); temp[2] = FT_DivFix( temp[2], temp_scale ); temp[4] = FT_DivFix( temp[4], temp_scale ); temp[5] = FT_DivFix( temp[5], temp_scale ); temp[3] = temp[3] < 0 ? -0x10000L : 0x10000L; } matrix->xx = temp[0]; matrix->yx = temp[1]; matrix->xy = temp[2]; matrix->yy = temp[3]; /* note that the font offsets are expressed in integer font units */ offset->x = temp[4] >> 16; offset->y = temp[5] >> 16; }
static void t42_parse_font_matrix( T42_Face face, T42_Loader loader ) { T42_Parser parser = &loader->parser; FT_Matrix* matrix = &face->type1.font_matrix; FT_Vector* offset = &face->type1.font_offset; FT_Face root = (FT_Face)&face->root; FT_Fixed temp[6]; FT_Fixed temp_scale; FT_Int result; result = T1_ToFixedArray( parser, 6, temp, 3 ); if ( result < 6 ) { parser->root.error = FT_THROW( Invalid_File_Format ); return; } temp_scale = FT_ABS( temp[3] ); if ( temp_scale == 0 ) { FT_ERROR(( "t1_parse_font_matrix: invalid font matrix\n" )); parser->root.error = FT_THROW( Invalid_File_Format ); return; } /* Set Units per EM based on FontMatrix values. We set the value to */ /* 1000 / temp_scale, because temp_scale was already multiplied by */ /* 1000 (in t1_tofixed, from psobjs.c). */ root->units_per_EM = (FT_UShort)FT_DivFix( 1000, temp_scale ); /* we need to scale the values by 1.0/temp_scale */ if ( temp_scale != 0x10000L ) { temp[0] = FT_DivFix( temp[0], temp_scale ); temp[1] = FT_DivFix( temp[1], temp_scale ); temp[2] = FT_DivFix( temp[2], temp_scale ); temp[4] = FT_DivFix( temp[4], temp_scale ); temp[5] = FT_DivFix( temp[5], temp_scale ); temp[3] = temp[3] < 0 ? -0x10000L : 0x10000L; } matrix->xx = temp[0]; matrix->yx = temp[1]; matrix->xy = temp[2]; matrix->yy = temp[3]; /* note that the offsets must be expressed in integer font units */ offset->x = temp[4] >> 16; offset->y = temp[5] >> 16; }
parse_font_matrix( CID_Face face, CID_Parser* parser ) { FT_Matrix* matrix; FT_Vector* offset; CID_FaceDict dict; FT_Face root = (FT_Face)&face->root; FT_Fixed temp[6]; FT_Fixed temp_scale; if ( parser->num_dict >= 0 ) { dict = face->cid.font_dicts + parser->num_dict; matrix = &dict->font_matrix; offset = &dict->font_offset; (void)cid_parser_to_fixed_array( parser, 6, temp, 3 ); temp_scale = FT_ABS( temp[3] ); /* Set units per EM based on FontMatrix values. We set the value to */ /* `1000/temp_scale', because temp_scale was already multiplied by */ /* 1000 (in `t1_tofixed', from psobjs.c). */ root->units_per_EM = (FT_UShort)( FT_DivFix( 0x10000L, FT_DivFix( temp_scale, 1000 ) ) ); /* we need to scale the values by 1.0/temp[3] */ if ( temp_scale != 0x10000L ) { temp[0] = FT_DivFix( temp[0], temp_scale ); temp[1] = FT_DivFix( temp[1], temp_scale ); temp[2] = FT_DivFix( temp[2], temp_scale ); temp[4] = FT_DivFix( temp[4], temp_scale ); temp[5] = FT_DivFix( temp[5], temp_scale ); temp[3] = 0x10000L; } matrix->xx = temp[0]; matrix->yx = temp[1]; matrix->xy = temp[2]; matrix->yy = temp[3]; /* note that the font offsets are expressed in integer font units */ offset->x = temp[4] >> 16; offset->y = temp[5] >> 16; }
static void t42_parse_font_matrix( T42_Face face, T42_Loader loader ) { T42_Parser parser = &loader->parser; FT_Matrix* matrix = &face->type1.font_matrix; FT_Vector* offset = &face->type1.font_offset; FT_Face root = (FT_Face)&face->root; FT_Fixed temp[6]; FT_Fixed temp_scale; (void)T1_ToFixedArray( parser, 6, temp, 3 ); temp_scale = FT_ABS( temp[3] ); /* Set Units per EM based on FontMatrix values. We set the value to */ /* 1000 / temp_scale, because temp_scale was already multiplied by */ /* 1000 (in t1_tofixed, from psobjs.c). */ root->units_per_EM = (FT_UShort)( FT_DivFix( 1000 * 0x10000L, temp_scale ) >> 16 ); /* we need to scale the values by 1.0/temp_scale */ if ( temp_scale != 0x10000L ) { temp[0] = FT_DivFix( temp[0], temp_scale ); temp[1] = FT_DivFix( temp[1], temp_scale ); temp[2] = FT_DivFix( temp[2], temp_scale ); temp[4] = FT_DivFix( temp[4], temp_scale ); temp[5] = FT_DivFix( temp[5], temp_scale ); temp[3] = 0x10000L; } matrix->xx = temp[0]; matrix->yx = temp[1]; matrix->xy = temp[2]; matrix->yy = temp[3]; /* note that the offsets must be expressed in integer font units */ offset->x = temp[4] >> 16; offset->y = temp[5] >> 16; }
ftc_inode_weight( FTC_Node ftcinode, FTC_Cache ftccache ) { FTC_INode inode = (FTC_INode)ftcinode; FT_Offset size = 0; FT_Glyph glyph = inode->glyph; FT_UNUSED( ftccache ); switch ( glyph->format ) { case FT_GLYPH_FORMAT_BITMAP: { FT_BitmapGlyph bitg; bitg = (FT_BitmapGlyph)glyph; size = bitg->bitmap.rows * (FT_Offset)FT_ABS( bitg->bitmap.pitch ) + sizeof ( *bitg ); } break; case FT_GLYPH_FORMAT_OUTLINE: { FT_OutlineGlyph outg; outg = (FT_OutlineGlyph)glyph; size = (FT_Offset)outg->outline.n_points * ( sizeof ( FT_Vector ) + sizeof ( FT_Byte ) ) + (FT_Offset)outg->outline.n_contours * sizeof ( FT_Short ) + sizeof ( *outg ); } break; default: ; } size += sizeof ( *inode ); return size; }
FT_Outline_Get_Orientation( FT_Outline* outline ) { FT_BBox cbox; FT_Int xshift, yshift; FT_Vector* points; FT_Vector v_prev, v_cur; FT_Int c, n, first; FT_Pos area = 0; if ( !outline || outline->n_points <= 0 ) return FT_ORIENTATION_TRUETYPE; /* We use the nonzero winding rule to find the orientation. */ /* Since glyph outlines behave much more `regular' than arbitrary */ /* cubic or quadratic curves, this test deals with the polygon */ /* only that is spanned up by the control points. */ FT_Outline_Get_CBox( outline, &cbox ); /* Handle collapsed outlines to avoid undefined FT_MSB. */ if ( cbox.xMin == cbox.xMax || cbox.yMin == cbox.yMax ) return FT_ORIENTATION_NONE; xshift = FT_MSB( (FT_UInt32)( FT_ABS( cbox.xMax ) | FT_ABS( cbox.xMin ) ) ) - 14; xshift = FT_MAX( xshift, 0 ); yshift = FT_MSB( (FT_UInt32)( cbox.yMax - cbox.yMin ) ) - 14; yshift = FT_MAX( yshift, 0 ); points = outline->points; first = 0; for ( c = 0; c < outline->n_contours; c++ ) { FT_Int last = outline->contours[c]; v_prev.x = points[last].x >> xshift; v_prev.y = points[last].y >> yshift; for ( n = first; n <= last; n++ ) { v_cur.x = points[n].x >> xshift; v_cur.y = points[n].y >> yshift; area = ADD_LONG( area, ( v_cur.y - v_prev.y ) * ( v_cur.x + v_prev.x ) ); v_prev = v_cur; } first = last + 1; } if ( area > 0 ) return FT_ORIENTATION_POSTSCRIPT; else if ( area < 0 ) return FT_ORIENTATION_TRUETYPE; else return FT_ORIENTATION_NONE; }
cff_face_init( FT_Stream stream, FT_Face cffface, /* CFF_Face */ FT_Int face_index, FT_Int num_params, FT_Parameter* params ) { CFF_Face face = (CFF_Face)cffface; FT_Error error; SFNT_Service sfnt; FT_Service_PsCMaps psnames; PSHinter_Service pshinter; FT_Bool pure_cff = 1; FT_Bool sfnt_format = 0; FT_Library library = cffface->driver->root.library; sfnt = (SFNT_Service)FT_Get_Module_Interface( library, "sfnt" ); if ( !sfnt ) { FT_ERROR(( "cff_face_init: cannot access `sfnt' module\n" )); error = FT_THROW( Missing_Module ); goto Exit; } FT_FACE_FIND_GLOBAL_SERVICE( face, psnames, POSTSCRIPT_CMAPS ); pshinter = (PSHinter_Service)FT_Get_Module_Interface( library, "pshinter" ); FT_TRACE2(( "CFF driver\n" )); /* create input stream from resource */ if ( FT_STREAM_SEEK( 0 ) ) goto Exit; /* check whether we have a valid OpenType file */ error = sfnt->init_face( stream, face, face_index, num_params, params ); if ( !error ) { if ( face->format_tag != TTAG_OTTO ) /* `OTTO'; OpenType/CFF font */ { FT_TRACE2(( " not an OpenType/CFF font\n" )); error = FT_THROW( Unknown_File_Format ); goto Exit; } /* if we are performing a simple font format check, exit immediately */ if ( face_index < 0 ) return FT_Err_Ok; sfnt_format = 1; /* now, the font can be either an OpenType/CFF font, or an SVG CEF */ /* font; in the latter 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 explicitly */ error = sfnt->load_cmap( face, stream ); if ( error ) goto Exit; } /* 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 */ if ( FT_STREAM_SEEK( 0 ) ) goto Exit; error = FT_Err_Ok; } /* now load and parse the CFF table in the file */ { CFF_Font cff = NULL; CFF_FontRecDict dict; FT_Memory memory = cffface->memory; FT_Int32 flags; FT_UInt i; if ( FT_NEW( cff ) ) goto Exit; face->extra.data = cff; error = cff_font_load( library, stream, face_index, cff, pure_cff ); if ( error ) goto Exit; cff->pshinter = pshinter; cff->psnames = psnames; cffface->face_index = face_index; /* Complement the root flags with some interesting information. */ /* Note that this is only necessary for pure CFF and CEF fonts; */ /* SFNT based fonts use the `name' table instead. */ cffface->num_glyphs = cff->num_glyphs; dict = &cff->top_font.font_dict; /* we need the `PSNames' module for CFF and CEF formats */ /* which aren't CID-keyed */ if ( dict->cid_registry == 0xFFFFU && !psnames ) { FT_ERROR(( "cff_face_init:" " cannot open CFF & CEF fonts\n" " " " without the `PSNames' module\n" )); error = FT_THROW( Missing_Module ); goto Exit; } #ifdef FT_DEBUG_LEVEL_TRACE { FT_UInt idx; FT_String* s; FT_TRACE4(( "SIDs\n" )); /* dump string index, including default strings for convenience */ for ( idx = 0; idx < cff->num_strings + 390; idx++ ) { s = cff_index_get_sid_string( cff, idx ); if ( s ) FT_TRACE4((" %5d %s\n", idx, s )); } } #endif /* FT_DEBUG_LEVEL_TRACE */ if ( !dict->has_font_matrix ) dict->units_per_em = pure_cff ? 1000 : face->root.units_per_EM; /* Normalize the font matrix so that `matrix->xx' is 1; the */ /* scaling is done with `units_per_em' then (at this point, */ /* it already contains the scaling factor, but without */ /* normalization of the matrix). */ /* */ /* Note that the offsets must be expressed in integer font */ /* units. */ { FT_Matrix* matrix = &dict->font_matrix; FT_Vector* offset = &dict->font_offset; FT_ULong* upm = &dict->units_per_em; FT_Fixed temp = FT_ABS( matrix->yy ); if ( temp != 0x10000L ) { *upm = FT_DivFix( *upm, temp ); matrix->xx = FT_DivFix( matrix->xx, temp ); matrix->yx = FT_DivFix( matrix->yx, temp ); matrix->xy = FT_DivFix( matrix->xy, temp ); matrix->yy = FT_DivFix( matrix->yy, temp ); offset->x = FT_DivFix( offset->x, temp ); offset->y = FT_DivFix( offset->y, temp ); } offset->x >>= 16; offset->y >>= 16; } for ( i = cff->num_subfonts; i > 0; i-- ) { CFF_FontRecDict sub = &cff->subfonts[i - 1]->font_dict; CFF_FontRecDict top = &cff->top_font.font_dict; FT_Matrix* matrix; FT_Vector* offset; FT_ULong* upm; FT_Fixed temp; if ( sub->has_font_matrix ) { FT_Long scaling; /* if we have a top-level matrix, */ /* concatenate the subfont matrix */ if ( top->has_font_matrix ) { if ( top->units_per_em > 1 && sub->units_per_em > 1 ) scaling = FT_MIN( top->units_per_em, sub->units_per_em ); else scaling = 1; FT_Matrix_Multiply_Scaled( &top->font_matrix, &sub->font_matrix, scaling ); FT_Vector_Transform_Scaled( &sub->font_offset, &top->font_matrix, scaling ); sub->units_per_em = FT_MulDiv( sub->units_per_em, top->units_per_em, scaling ); } } else { sub->font_matrix = top->font_matrix; sub->font_offset = top->font_offset; sub->units_per_em = top->units_per_em; } matrix = &sub->font_matrix; offset = &sub->font_offset; upm = &sub->units_per_em; temp = FT_ABS( matrix->yy ); if ( temp != 0x10000L ) { *upm = FT_DivFix( *upm, temp ); matrix->xx = FT_DivFix( matrix->xx, temp ); matrix->yx = FT_DivFix( matrix->yx, temp ); matrix->xy = FT_DivFix( matrix->xy, temp ); matrix->yy = FT_DivFix( matrix->yy, temp ); offset->x = FT_DivFix( offset->x, temp ); offset->y = FT_DivFix( offset->y, temp ); } offset->x >>= 16; offset->y >>= 16; } if ( pure_cff ) { char* style_name = NULL; /* set up num_faces */ cffface->num_faces = cff->num_faces; /* compute number of glyphs */ if ( dict->cid_registry != 0xFFFFU ) cffface->num_glyphs = cff->charset.max_cid + 1; else cffface->num_glyphs = cff->charstrings_index.count; /* set global bbox, as well as EM size */ cffface->bbox.xMin = dict->font_bbox.xMin >> 16; cffface->bbox.yMin = dict->font_bbox.yMin >> 16; /* no `U' suffix here to 0xFFFF! */ cffface->bbox.xMax = ( dict->font_bbox.xMax + 0xFFFF ) >> 16; cffface->bbox.yMax = ( dict->font_bbox.yMax + 0xFFFF ) >> 16; cffface->units_per_EM = (FT_UShort)( dict->units_per_em ); cffface->ascender = (FT_Short)( cffface->bbox.yMax ); cffface->descender = (FT_Short)( cffface->bbox.yMin ); cffface->height = (FT_Short)( ( cffface->units_per_EM * 12 ) / 10 ); if ( cffface->height < cffface->ascender - cffface->descender ) cffface->height = (FT_Short)( cffface->ascender - cffface->descender ); cffface->underline_position = (FT_Short)( dict->underline_position >> 16 ); cffface->underline_thickness = (FT_Short)( dict->underline_thickness >> 16 ); /* retrieve font family & style name */ cffface->family_name = cff_index_get_name( cff, face_index ); if ( cffface->family_name ) { char* full = cff_index_get_sid_string( cff, dict->full_name ); char* fullp = full; char* family = cffface->family_name; char* family_name = NULL; remove_subset_prefix( cffface->family_name ); if ( dict->family_name ) { family_name = cff_index_get_sid_string( cff, dict->family_name ); if ( family_name ) family = family_name; } /* We try to extract the style name from the full name. */ /* We need to ignore spaces and dashes during the search. */ if ( full && family ) { while ( *fullp ) { /* skip common characters at the start of both strings */ if ( *fullp == *family ) { family++; fullp++; continue; } /* ignore spaces and dashes in full name during comparison */ if ( *fullp == ' ' || *fullp == '-' ) { fullp++; continue; } /* ignore spaces and dashes in family name during comparison */ if ( *family == ' ' || *family == '-' ) { family++; continue; } if ( !*family && *fullp ) { /* The full name begins with the same characters as the */ /* family name, with spaces and dashes removed. In this */ /* case, the remaining string in `fullp' will be used as */ /* the style name. */ style_name = cff_strcpy( memory, fullp ); /* remove the style part from the family name (if present) */ remove_style( cffface->family_name, style_name ); } break; } } } else { char *cid_font_name = cff_index_get_sid_string( cff, dict->cid_font_name ); /* do we have a `/FontName' for a CID-keyed font? */ if ( cid_font_name ) cffface->family_name = cff_strcpy( memory, cid_font_name ); } if ( style_name ) cffface->style_name = style_name; else /* assume "Regular" style if we don't know better */ cffface->style_name = cff_strcpy( memory, (char *)"Regular" ); /*******************************************************************/ /* */ /* Compute face flags. */ /* */ flags = FT_FACE_FLAG_SCALABLE | /* scalable outlines */ FT_FACE_FLAG_HORIZONTAL | /* horizontal data */ FT_FACE_FLAG_HINTER; /* has native hinter */ if ( sfnt_format ) flags |= FT_FACE_FLAG_SFNT; /* fixed width font? */ if ( dict->is_fixed_pitch ) flags |= FT_FACE_FLAG_FIXED_WIDTH; /* XXX: 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 cffface->face_flags |= flags; /*******************************************************************/ /* */ /* Compute style flags. */ /* */ flags = 0; if ( dict->italic_angle ) flags |= FT_STYLE_FLAG_ITALIC; { char *weight = cff_index_get_sid_string( cff, dict->weight ); if ( weight ) if ( !ft_strcmp( weight, "Bold" ) || !ft_strcmp( weight, "Black" ) ) flags |= FT_STYLE_FLAG_BOLD; } /* double check */ if ( !(flags & FT_STYLE_FLAG_BOLD) && cffface->style_name ) if ( !ft_strncmp( cffface->style_name, "Bold", 4 ) || !ft_strncmp( cffface->style_name, "Black", 5 ) ) flags |= FT_STYLE_FLAG_BOLD; cffface->style_flags = flags; } #ifndef FT_CONFIG_OPTION_NO_GLYPH_NAMES /* CID-keyed CFF fonts don't have glyph names -- the SFNT loader */ /* has unset this flag because of the 3.0 `post' table. */ if ( dict->cid_registry == 0xFFFFU ) cffface->face_flags |= FT_FACE_FLAG_GLYPH_NAMES; #endif if ( dict->cid_registry != 0xFFFFU && pure_cff ) cffface->face_flags |= FT_FACE_FLAG_CID_KEYED; /*******************************************************************/ /* */ /* Compute char maps. */ /* */ /* Try to synthesize a Unicode charmap if there is none available */ /* already. If an OpenType font contains a Unicode "cmap", we */ /* will use it, whatever be in the CFF part of the file. */ { FT_CharMapRec cmaprec; FT_CharMap cmap; FT_UInt nn; CFF_Encoding encoding = &cff->encoding; for ( nn = 0; nn < (FT_UInt)cffface->num_charmaps; nn++ ) { cmap = cffface->charmaps[nn]; /* Windows Unicode? */ if ( cmap->platform_id == TT_PLATFORM_MICROSOFT && cmap->encoding_id == TT_MS_ID_UNICODE_CS ) goto Skip_Unicode; /* Apple Unicode platform id? */ if ( cmap->platform_id == TT_PLATFORM_APPLE_UNICODE ) goto Skip_Unicode; /* Apple Unicode */ } /* since CID-keyed fonts don't contain glyph names, we can't */ /* construct a cmap */ if ( pure_cff && cff->top_font.font_dict.cid_registry != 0xFFFFU ) goto Exit; #ifdef FT_MAX_CHARMAP_CACHEABLE if ( nn + 1 > FT_MAX_CHARMAP_CACHEABLE ) { FT_ERROR(( "cff_face_init: no Unicode cmap is found, " "and too many subtables (%d) to add synthesized cmap\n", nn )); goto Exit; } #endif /* we didn't find a Unicode charmap -- synthesize one */ cmaprec.face = cffface; cmaprec.platform_id = TT_PLATFORM_MICROSOFT; cmaprec.encoding_id = TT_MS_ID_UNICODE_CS; cmaprec.encoding = FT_ENCODING_UNICODE; nn = (FT_UInt)cffface->num_charmaps; error = FT_CMap_New( &CFF_CMAP_UNICODE_CLASS_REC_GET, NULL, &cmaprec, NULL ); if ( error && FT_ERR_NEQ( error, No_Unicode_Glyph_Name ) ) goto Exit; error = FT_Err_Ok; /* if no Unicode charmap was previously selected, select this one */ if ( cffface->charmap == NULL && nn != (FT_UInt)cffface->num_charmaps ) cffface->charmap = cffface->charmaps[nn]; Skip_Unicode: #ifdef FT_MAX_CHARMAP_CACHEABLE if ( nn > FT_MAX_CHARMAP_CACHEABLE ) { FT_ERROR(( "cff_face_init: Unicode cmap is found, " "but too many preceding subtables (%d) to access\n", nn - 1 )); goto Exit; } #endif if ( encoding->count > 0 ) { FT_CMap_Class clazz; cmaprec.face = cffface; cmaprec.platform_id = TT_PLATFORM_ADOBE; /* Adobe platform id */ if ( encoding->offset == 0 ) { cmaprec.encoding_id = TT_ADOBE_ID_STANDARD; cmaprec.encoding = FT_ENCODING_ADOBE_STANDARD; clazz = &CFF_CMAP_ENCODING_CLASS_REC_GET; } else if ( encoding->offset == 1 ) { cmaprec.encoding_id = TT_ADOBE_ID_EXPERT; cmaprec.encoding = FT_ENCODING_ADOBE_EXPERT; clazz = &CFF_CMAP_ENCODING_CLASS_REC_GET; } else { cmaprec.encoding_id = TT_ADOBE_ID_CUSTOM; cmaprec.encoding = FT_ENCODING_ADOBE_CUSTOM; clazz = &CFF_CMAP_ENCODING_CLASS_REC_GET; } error = FT_CMap_New( clazz, NULL, &cmaprec, NULL ); } } } Exit: return error; }
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 ( FT_ABS( last->out_dir ) == major_dir && FT_ABS( point->out_dir ) == major_dir ) { /* we are already on an edge, try to locate its start */ last = point; for (;;) { point = point->prev; if ( FT_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_FLAG_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 && FT_ABS( point->out_dir ) == major_dir ) { /* this is the start of a new segment! */ segment_dir = point->out_dir; /* clear all segment fields */ FT_ZERO( 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; segment->score = 32000; segment->link = NULL; on_edge = 1; #ifdef AH_HINT_METRICS if ( point == max_point ) max_point = 0; if ( point == min_point ) min_point = 0; #endif } 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 point_limit = point + outline->num_points; FT_Pos min_pos = 32000; FT_Pos max_pos = -32000; min_point = 0; max_point = 0; /* compute minimum and maximum points */ for ( ; point < 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 */ FT_ZERO( segment ); segment->dir = segment_dir; segment->flags = AH_EDGE_NORMAL; segment->first = min_point; segment->last = min_point; segment->pos = min_pos; segment->score = 32000; segment->link = NULL; num_segments++; segment++; } /* insert maximum segment */ if ( max_point ) { /* clear all segment fields */ FT_ZERO( segment ); segment->dir = segment_dir; segment->flags = AH_EDGE_NORMAL; segment->first = max_point; segment->last = max_point; segment->pos = max_pos; segment->score = 32000; segment->link = NULL; 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 ); }
static void BBox_Cubic_Check( FT_Pos y1, FT_Pos y2, FT_Pos y3, FT_Pos y4, FT_Pos* min, FT_Pos* max ) { /* always compare first and last points */ if ( y1 < *min ) *min = y1; else if ( y1 > *max ) *max = y1; if ( y4 < *min ) *min = y4; else if ( y4 > *max ) *max = y4; /* now, try to see if there are split points here */ if ( y1 <= y4 ) { /* flat or ascending arc test */ if ( y1 <= y2 && y2 <= y4 && y1 <= y3 && y3 <= y4 ) return; } else /* y1 > y4 */ { /* descending arc test */ if ( y1 >= y2 && y2 >= y4 && y1 >= y3 && y3 >= y4 ) return; } /* There are some split points. Find them. */ /* We already made sure that a, b, and c below cannot be all zero. */ { FT_Pos a = y4 - 3*y3 + 3*y2 - y1; FT_Pos b = y3 - 2*y2 + y1; FT_Pos c = y2 - y1; FT_Pos d; FT_Fixed t; FT_Int shift; /* We need to solve `ax^2+2bx+c' here, without floating points! */ /* The trick is to normalize to a different representation in order */ /* to use our 16.16 fixed-point routines. */ /* */ /* We compute FT_MulFix(b,b) and FT_MulFix(a,c) after normalization. */ /* These values must fit into a single 16.16 value. */ /* */ /* We normalize a, b, and c to `8.16' fixed-point values to ensure */ /* that their product is held in a `16.16' value including the sign. */ /* Necessarily, we need to shift `a', `b', and `c' so that the most */ /* significant bit of their absolute values is at position 22. */ /* */ /* This also means that we are using 23 bits of precision to compute */ /* the zeros, independently of the range of the original polynomial */ /* coefficients. */ /* */ /* This algorithm should ensure reasonably accurate values for the */ /* zeros. Note that they are only expressed with 16 bits when */ /* computing the extrema (the zeros need to be in 0..1 exclusive */ /* to be considered part of the arc). */ shift = FT_MSB( FT_ABS( a ) | FT_ABS( b ) | FT_ABS( c ) ); if ( shift > 22 ) { shift -= 22; /* this loses some bits of precision, but we use 23 of them */ /* for the computation anyway */ a >>= shift; b >>= shift; c >>= shift; } else {
static FT_Pos af_cjk_compute_stem_width( AF_GlyphHints hints, AF_Dimension dim, FT_Pos width, AF_Edge_Flags base_flags, AF_Edge_Flags stem_flags ) { AF_LatinMetrics metrics = (AF_LatinMetrics) hints->metrics; AF_LatinAxis axis = & metrics->axis[dim]; FT_Pos dist = width; FT_Int sign = 0; FT_Int vertical = ( dim == AF_DIMENSION_VERT ); FT_UNUSED( base_flags ); FT_UNUSED( stem_flags ); if ( !AF_LATIN_HINTS_DO_STEM_ADJUST( hints ) ) return width; if ( dist < 0 ) { dist = -width; sign = 1; } if ( ( vertical && !AF_LATIN_HINTS_DO_VERT_SNAP( hints ) ) || ( !vertical && !AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) ) ) { /* smooth hinting process: very lightly quantize the stem width */ if ( axis->width_count > 0 ) { if ( FT_ABS( dist - axis->widths[0].cur ) < 40 ) { dist = axis->widths[0].cur; if ( dist < 48 ) dist = 48; goto Done_Width; } } if ( dist < 54 ) dist += ( 54 - dist ) / 2 ; else if ( dist < 3 * 64 ) { FT_Pos delta; delta = dist & 63; dist &= -64; if ( delta < 10 ) dist += delta; else if ( delta < 22 ) dist += 10; else if ( delta < 42 ) dist += delta; else if ( delta < 54 ) dist += 54; else dist += delta; } } else { /* strong hinting process: snap the stem width to integer pixels */ dist = af_cjk_snap_width( axis->widths, axis->width_count, dist ); if ( vertical ) { /* in the case of vertical hinting, always round */ /* the stem heights to integer pixels */ if ( dist >= 64 ) dist = ( dist + 16 ) & ~63; else dist = 64; } else { if ( AF_LATIN_HINTS_DO_MONO( hints ) ) { /* monochrome horizontal hinting: snap widths to integer pixels */ /* with a different threshold */ if ( dist < 64 ) dist = 64; else dist = ( dist + 32 ) & ~63; } 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 + 22 ) & ~63; else /* round otherwise to prevent color fringes in LCD mode */ dist = ( dist + 32 ) & ~63; } } }
static FT_Pos af_hint_normal_stem( AF_GlyphHints hints, AF_Edge edge, AF_Edge edge2, FT_Pos anchor, AF_Dimension dim ) { FT_Pos org_len, cur_len, org_center; FT_Pos cur_pos1, cur_pos2; FT_Pos d_off1, u_off1, d_off2, u_off2, delta; FT_Pos offset; FT_Pos threshold = 64; if ( !AF_LATIN_HINTS_DO_STEM_ADJUST( hints ) ) { if ( ( edge->flags & AF_EDGE_ROUND ) && ( edge2->flags & AF_EDGE_ROUND ) ) { if ( dim == AF_DIMENSION_VERT ) threshold = 64 - AF_LIGHT_MODE_MAX_HORZ_GAP; else threshold = 64 - AF_LIGHT_MODE_MAX_VERT_GAP; } else { if ( dim == AF_DIMENSION_VERT ) threshold = 64 - AF_LIGHT_MODE_MAX_HORZ_GAP / 3; else threshold = 64 - AF_LIGHT_MODE_MAX_VERT_GAP / 3; } } org_len = edge2->opos - edge->opos; cur_len = af_cjk_compute_stem_width( hints, dim, org_len, (AF_Edge_Flags)edge->flags, (AF_Edge_Flags)edge2->flags ); org_center = ( edge->opos + edge2->opos ) / 2 + anchor; cur_pos1 = org_center - cur_len / 2; cur_pos2 = cur_pos1 + cur_len; d_off1 = cur_pos1 - FT_PIX_FLOOR( cur_pos1 ); d_off2 = cur_pos2 - FT_PIX_FLOOR( cur_pos2 ); u_off1 = 64 - d_off1; u_off2 = 64 - d_off2; delta = 0; if ( d_off1 == 0 || d_off2 == 0 ) goto Exit; if ( cur_len <= threshold ) { if ( d_off2 < cur_len ) { if ( u_off1 <= d_off2 ) delta = u_off1; else delta = -d_off2; } goto Exit; } if ( threshold < 64 ) { if ( d_off1 >= threshold || u_off1 >= threshold || d_off2 >= threshold || u_off2 >= threshold ) goto Exit; } offset = cur_len % 64; if ( offset < 32 ) { if ( u_off1 <= offset || d_off2 <= offset ) goto Exit; } else offset = 64 - threshold; d_off1 = threshold - u_off1; u_off1 = u_off1 - offset; u_off2 = threshold - d_off2; d_off2 = d_off2 - offset; if ( d_off1 <= u_off1 ) u_off1 = -d_off1; if ( d_off2 <= u_off2 ) u_off2 = -d_off2; if ( FT_ABS( u_off1 ) <= FT_ABS( u_off2 ) ) delta = u_off1; else delta = u_off2; Exit: #if 1 if ( !AF_LATIN_HINTS_DO_STEM_ADJUST( hints ) ) { if ( delta > AF_LIGHT_MODE_MAX_DELTA_ABS ) delta = AF_LIGHT_MODE_MAX_DELTA_ABS; else if ( delta < -AF_LIGHT_MODE_MAX_DELTA_ABS ) delta = -AF_LIGHT_MODE_MAX_DELTA_ABS; } #endif cur_pos1 += delta; if ( edge->opos < edge2->opos ) { edge->pos = cur_pos1; edge2->pos = cur_pos1 + cur_len; } else { edge->pos = cur_pos1 + cur_len; edge2->pos = cur_pos1; } return delta; }
static void af_cjk_hint_edges( AF_GlyphHints hints, AF_Dimension dim ) { AF_AxisHints axis = &hints->axis[dim]; AF_Edge edges = axis->edges; AF_Edge edge_limit = edges + axis->num_edges; FT_Int n_edges; AF_Edge edge; AF_Edge anchor = 0; FT_Pos delta = 0; FT_Int skipped = 0; /* now we align all stem edges. */ for ( edge = edges; edge < edge_limit; edge++ ) { AF_Edge edge2; if ( edge->flags & AF_EDGE_DONE ) continue; /* skip all non-stem edges */ edge2 = edge->link; if ( !edge2 ) { skipped++; continue; } /* now align the stem */ if ( edge2 < edge ) { af_cjk_align_linked_edge( hints, dim, edge2, edge ); edge->flags |= AF_EDGE_DONE; continue; } if ( dim != AF_DIMENSION_VERT && !anchor ) { #if 0 if ( fixedpitch ) { AF_Edge left = edge; AF_Edge right = edge_limit - 1; AF_EdgeRec left1, left2, right1, right2; FT_Pos target, center1, center2; FT_Pos delta1, delta2, d1, d2; while ( right > left && !right->link ) right--; left1 = *left; left2 = *left->link; right1 = *right->link; right2 = *right; delta = ( ( ( hinter->pp2.x + 32 ) & -64 ) - hinter->pp2.x ) / 2; target = left->opos + ( right->opos - left->opos ) / 2 + delta - 16; delta1 = delta; delta1 += af_hint_normal_stem( hints, left, left->link, delta1, 0 ); if ( left->link != right ) af_hint_normal_stem( hints, right->link, right, delta1, 0 ); center1 = left->pos + ( right->pos - left->pos ) / 2; if ( center1 >= target ) delta2 = delta - 32; else delta2 = delta + 32; delta2 += af_hint_normal_stem( hints, &left1, &left2, delta2, 0 ); if ( delta1 != delta2 ) { if ( left->link != right ) af_hint_normal_stem( hints, &right1, &right2, delta2, 0 ); center2 = left1.pos + ( right2.pos - left1.pos ) / 2; d1 = center1 - target; d2 = center2 - target; if ( FT_ABS( d2 ) < FT_ABS( d1 ) ) { left->pos = left1.pos; left->link->pos = left2.pos; if ( left->link != right ) { right->link->pos = right1.pos; right->pos = right2.pos; } delta1 = delta2; } } delta = delta1; right->link->flags |= AF_EDGE_DONE; right->flags |= AF_EDGE_DONE; } else #endif /* 0 */ delta = af_hint_normal_stem( hints, edge, edge2, 0, AF_DIMENSION_HORZ ); } else af_hint_normal_stem( hints, edge, edge2, delta, dim ); #if 0 FT_PRINTF( "stem (%d,%d) adjusted (%.1f,%.1f)\n", edge - edges, edge2 - edges, ( edge->pos - edge->opos ) / 64.0, ( edge2->pos - edge2->opos ) / 64.0 ); #endif anchor = edge; edge->flags |= AF_EDGE_DONE; edge2->flags |= AF_EDGE_DONE; } /* make sure that lowercase m's maintain their symmetry */ /* In general, lowercase m's have six vertical edges if they are sans */ /* serif, or twelve if they are with serifs. This implementation is */ /* based on that assumption, and seems to work very well with most */ /* faces. However, if for a certain face this assumption is not */ /* true, the m is just rendered like before. In addition, any stem */ /* correction will only be applied to symmetrical glyphs (even if the */ /* glyph is not an m), so the potential for unwanted distortion is */ /* relatively low. */ /* We don't handle horizontal edges since we can't easily assure that */ /* the third (lowest) stem aligns with the base line; it might end up */ /* one pixel higher or lower. */ n_edges = edge_limit - edges; if ( dim == AF_DIMENSION_HORZ && ( n_edges == 6 || n_edges == 12 ) ) { AF_Edge edge1, edge2, edge3; FT_Pos dist1, dist2, span; if ( n_edges == 6 ) { edge1 = edges; edge2 = edges + 2; edge3 = edges + 4; } else { edge1 = edges + 1; edge2 = edges + 5; edge3 = edges + 9; } dist1 = edge2->opos - edge1->opos; dist2 = edge3->opos - edge2->opos; span = dist1 - dist2; if ( span < 0 ) span = -span; if ( edge1->link == edge1 + 1 && edge2->link == edge2 + 1 && edge3->link == edge3 + 1 && span < 8 ) { delta = edge3->pos - ( 2 * edge2->pos - edge1->pos ); edge3->pos -= delta; if ( edge3->link ) edge3->link->pos -= delta; /* move the serifs along with the stem */ if ( n_edges == 12 ) { ( edges + 8 )->pos -= delta; ( edges + 11 )->pos -= delta; } edge3->flags |= AF_EDGE_DONE; if ( edge3->link ) edge3->link->flags |= AF_EDGE_DONE; } } if ( !skipped ) return; /* * now hint the remaining edges (serifs and single) in order * to complete our processing */ for ( edge = edges; edge < edge_limit; edge++ ) { if ( edge->flags & AF_EDGE_DONE ) continue; if ( edge->serif ) { af_cjk_align_serif_edge( hints, edge->serif, edge ); edge->flags |= AF_EDGE_DONE; skipped--; } } if ( !skipped ) return; for ( edge = edges; edge < edge_limit; edge++ ) { AF_Edge before, after; if ( edge->flags & AF_EDGE_DONE ) continue; before = after = edge; while ( --before >= edges ) if ( before->flags & AF_EDGE_DONE ) break; while ( ++after < edge_limit ) if ( after->flags & AF_EDGE_DONE ) break; if ( before >= edges || after < edge_limit ) { if ( before < edges ) af_cjk_align_serif_edge( hints, after, edge ); else if ( after >= edge_limit ) af_cjk_align_serif_edge( hints, before, edge ); else { if ( after->fpos == before->fpos ) edge->pos = before->pos; else edge->pos = before->pos + FT_MulDiv( edge->fpos - before->fpos, after->pos - before->pos, after->fpos - before->fpos ); } } } }
/* * This function tries to load a small bitmap within a given FTC_SNode. * Note that it returns a non-zero error code _only_ in the case of * out-of-memory condition. For all other errors (e.g., corresponding * to a bad font file), this function will mark the sbit as `unavailable' * and return a value of 0. * * You should also read the comment within the @ftc_snode_compare * function below to see how out-of-memory is handled during a lookup. */ static FT_Error ftc_snode_load( FTC_SNode snode, FTC_Manager manager, FT_UInt gindex, FT_ULong *asize ) { FT_Error error; FTC_GNode gnode = FTC_GNODE( snode ); FTC_Family family = gnode->family; FT_Memory memory = manager->memory; FT_Face face; FTC_SBit sbit; FTC_SFamilyClass clazz; if ( (FT_UInt)(gindex - gnode->gindex) >= snode->count ) { FT_ERROR(( "ftc_snode_load: invalid glyph index" )); return FT_THROW( Invalid_Argument ); } sbit = snode->sbits + ( gindex - gnode->gindex ); clazz = (FTC_SFamilyClass)family->clazz; sbit->buffer = 0; error = clazz->family_load_glyph( family, gindex, manager, &face ); if ( error ) goto BadGlyph; { FT_Int temp; FT_GlyphSlot slot = face->glyph; FT_Bitmap* bitmap = &slot->bitmap; FT_Pos xadvance, yadvance; /* FT_GlyphSlot->advance.{x|y} */ if ( slot->format != FT_GLYPH_FORMAT_BITMAP ) { FT_TRACE0(( "ftc_snode_load:" " glyph loaded didn't return a bitmap\n" )); goto BadGlyph; } /* Check whether our values fit into 8-bit containers! */ /* If this is not the case, our bitmap is too large */ /* and we will leave it as `missing' with sbit.buffer = 0 */ #define CHECK_CHAR( d ) ( temp = (FT_Char)d, (FT_Int) temp == (FT_Int) d ) #define CHECK_BYTE( d ) ( temp = (FT_Byte)d, (FT_UInt)temp == (FT_UInt)d ) /* horizontal advance in pixels */ xadvance = ( slot->advance.x + 32 ) >> 6; yadvance = ( slot->advance.y + 32 ) >> 6; if ( !CHECK_BYTE( bitmap->rows ) || !CHECK_BYTE( bitmap->width ) || !CHECK_CHAR( bitmap->pitch ) || !CHECK_CHAR( slot->bitmap_left ) || !CHECK_CHAR( slot->bitmap_top ) || !CHECK_CHAR( xadvance ) || !CHECK_CHAR( yadvance ) ) { FT_TRACE2(( "ftc_snode_load:" " glyph too large for small bitmap cache\n")); goto BadGlyph; } sbit->width = (FT_Byte)bitmap->width; sbit->height = (FT_Byte)bitmap->rows; sbit->pitch = (FT_Char)bitmap->pitch; sbit->left = (FT_Char)slot->bitmap_left; sbit->top = (FT_Char)slot->bitmap_top; sbit->xadvance = (FT_Char)xadvance; sbit->yadvance = (FT_Char)yadvance; sbit->format = (FT_Byte)bitmap->pixel_mode; sbit->max_grays = (FT_Byte)(bitmap->num_grays - 1); /* copy the bitmap into a new buffer -- ignore error */ error = ftc_sbit_copy_bitmap( sbit, bitmap, memory ); /* now, compute size */ if ( asize ) *asize = (FT_ULong)FT_ABS( sbit->pitch ) * sbit->height; } /* glyph loading successful */ /* ignore the errors that might have occurred -- */ /* we mark unloaded glyphs with `sbit.buffer == 0' */ /* and `width == 255', `height == 0' */ /* */ if ( error && FT_ERR_NEQ( error, Out_Of_Memory ) ) { BadGlyph: sbit->width = 255; sbit->height = 0; sbit->buffer = NULL; error = FT_Err_Ok; if ( asize ) *asize = 0; } return error; }
cff_face_init( FT_Stream stream, FT_Face cffface, /* CFF_Face */ FT_Int face_index, FT_Int num_params, FT_Parameter* params ) { CFF_Face face = (CFF_Face)cffface; FT_Error error; SFNT_Service sfnt; FT_Service_PsCMaps psnames; PSHinter_Service pshinter; FT_Bool pure_cff = 1; FT_Bool sfnt_format = 0; #if 0 FT_FACE_FIND_GLOBAL_SERVICE( face, sfnt, SFNT ); FT_FACE_FIND_GLOBAL_SERVICE( face, psnames, POSTSCRIPT_NAMES ); FT_FACE_FIND_GLOBAL_SERVICE( face, pshinter, POSTSCRIPT_HINTER ); if ( !sfnt ) goto Bad_Format; #else sfnt = (SFNT_Service)FT_Get_Module_Interface( cffface->driver->root.library, "sfnt" ); if ( !sfnt ) goto Bad_Format; FT_FACE_FIND_GLOBAL_SERVICE( face, psnames, POSTSCRIPT_CMAPS ); pshinter = (PSHinter_Service)FT_Get_Module_Interface( cffface->driver->root.library, "pshinter" ); #endif /* create input stream from resource */ if ( FT_STREAM_SEEK( 0 ) ) goto Exit; /* check whether 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 CFF_Err_Ok; /* UNDOCUMENTED! A CFF in an SFNT can have only a single font. */ if ( face_index > 0 ) { FT_ERROR(( "cff_face_init: invalid face index\n" )); error = CFF_Err_Invalid_Argument; goto Exit; } sfnt_format = 1; /* now, the font can be either an OpenType/CFF font, or an SVG CEF */ /* font; in the latter 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 explicitly */ error = sfnt->load_cmap( face, stream ); if ( error ) goto Exit; /* XXX: we don't load the GPOS table, as OpenType Layout */ /* support will be added later to a layout library on top of */ /* FreeType 2 */ } /* 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 */ if ( FT_STREAM_SEEK( 0 ) ) goto Exit; error = CFF_Err_Ok; } /* now load and parse the CFF table in the file */ { CFF_Font cff; CFF_FontRecDict dict; FT_Memory memory = cffface->memory; FT_Int32 flags; FT_UInt i; if ( FT_NEW( cff ) ) goto Exit; face->extra.data = cff; error = cff_font_load( stream, face_index, cff ); if ( error ) goto Exit; cff->pshinter = pshinter; cff->psnames = (void*)psnames; /* Complement the root flags with some interesting information. */ /* Note that this is only necessary for pure CFF and CEF fonts; */ /* SFNT based fonts use the `name' table instead. */ cffface->num_glyphs = cff->num_glyphs; dict = &cff->top_font.font_dict; /* we need the `PSNames' module for CFF and CEF formats */ /* which aren't CID-keyed */ if ( dict->cid_registry == 0xFFFFU && !psnames ) { FT_ERROR(( "cff_face_init:" )); FT_ERROR(( " cannot open CFF & CEF fonts\n" )); FT_ERROR(( " " )); FT_ERROR(( " without the `PSNames' module\n" )); goto Bad_Format; } if ( pure_cff ) { char* style_name = NULL; /* set up num_faces */ cffface->num_faces = cff->num_faces; /* compute number of glyphs */ if ( dict->cid_registry != 0xFFFFU ) cffface->num_glyphs = cff->charset.max_cid; else cffface->num_glyphs = cff->charstrings_index.count; /* set global bbox, as well as EM size */ cffface->bbox.xMin = dict->font_bbox.xMin >> 16; cffface->bbox.yMin = dict->font_bbox.yMin >> 16; cffface->bbox.xMax = ( dict->font_bbox.xMax + 0xFFFFU ) >> 16; cffface->bbox.yMax = ( dict->font_bbox.yMax + 0xFFFFU ) >> 16; if ( !dict->units_per_em ) dict->units_per_em = 1000; cffface->units_per_EM = dict->units_per_em; cffface->ascender = (FT_Short)( cffface->bbox.yMax ); cffface->descender = (FT_Short)( cffface->bbox.yMin ); cffface->height = (FT_Short)( ( cffface->units_per_EM * 12 ) / 10 ); if ( cffface->height < cffface->ascender - cffface->descender ) cffface->height = (FT_Short)( cffface->ascender - cffface->descender ); cffface->underline_position = (FT_Short)( dict->underline_position >> 16 ); cffface->underline_thickness = (FT_Short)( dict->underline_thickness >> 16 ); /* retrieve font family & style name */ cffface->family_name = cff_index_get_name( &cff->name_index, face_index ); if ( cffface->family_name ) { char* full = cff_index_get_sid_string( &cff->string_index, dict->full_name, psnames ); char* fullp = full; char* family = cffface->family_name; char* family_name = 0; if ( dict->family_name ) { family_name = cff_index_get_sid_string( &cff->string_index, dict->family_name, psnames); if ( family_name ) family = family_name; } /* We try to extract the style name from the full name. */ /* We need to ignore spaces and dashes during the search. */ if ( full && family ) { while ( *fullp ) { /* skip common characters at the start of both strings */ if ( *fullp == *family ) { family++; fullp++; continue; } /* ignore spaces and dashes in full name during comparison */ if ( *fullp == ' ' || *fullp == '-' ) { fullp++; continue; } /* ignore spaces and dashes in family name during comparison */ if ( *family == ' ' || *family == '-' ) { family++; continue; } if ( !*family && *fullp ) { /* The full name begins with the same characters as the */ /* family name, with spaces and dashes removed. In this */ /* case, the remaining string in `fullp' will be used as */ /* the style name. */ style_name = cff_strcpy( memory, fullp ); } break; } if ( family_name ) FT_FREE( family_name ); FT_FREE( full ); } } else { char *cid_font_name = cff_index_get_sid_string( &cff->string_index, dict->cid_font_name, psnames ); /* do we have a `/FontName' for a CID-keyed font? */ if ( cid_font_name ) cffface->family_name = cid_font_name; } if ( style_name ) cffface->style_name = style_name; else /* assume "Regular" style if we don't know better */ cffface->style_name = cff_strcpy( memory, (char *)"Regular" ); /*******************************************************************/ /* */ /* Compute face flags. */ /* */ flags = FT_FACE_FLAG_SCALABLE | /* scalable outlines */ FT_FACE_FLAG_HORIZONTAL | /* horizontal data */ FT_FACE_FLAG_HINTER; /* has native hinter */ if ( sfnt_format ) flags |= FT_FACE_FLAG_SFNT; /* fixed width font? */ if ( dict->is_fixed_pitch ) flags |= FT_FACE_FLAG_FIXED_WIDTH; /* XXX: 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 cffface->face_flags = flags; /*******************************************************************/ /* */ /* Compute style flags. */ /* */ flags = 0; if ( dict->italic_angle ) flags |= FT_STYLE_FLAG_ITALIC; { char *weight = cff_index_get_sid_string( &cff->string_index, dict->weight, psnames ); if ( weight ) if ( !ft_strcmp( weight, "Bold" ) || !ft_strcmp( weight, "Black" ) ) flags |= FT_STYLE_FLAG_BOLD; FT_FREE( weight ); } /* double check */ if ( !(flags & FT_STYLE_FLAG_BOLD) && cffface->style_name ) if ( !ft_strncmp( cffface->style_name, "Bold", 4 ) || !ft_strncmp( cffface->style_name, "Black", 5 ) ) flags |= FT_STYLE_FLAG_BOLD; cffface->style_flags = flags; } else { if ( !dict->units_per_em ) dict->units_per_em = face->root.units_per_EM; } /* Normalize the font matrix so that `matrix->xx' is 1; the */ /* scaling is done with `units_per_em' then (at this point, */ /* it already contains the scaling factor, but without */ /* normalization of the matrix). */ /* */ /* Note that the offsets must be expressed in integer font */ /* units. */ { FT_Matrix* matrix = &dict->font_matrix; FT_Vector* offset = &dict->font_offset; FT_ULong* upm = &dict->units_per_em; FT_Fixed temp = FT_ABS( matrix->yy ); if ( temp != 0x10000L ) { *upm = FT_DivFix( *upm, temp ); matrix->xx = FT_DivFix( matrix->xx, temp ); matrix->yx = FT_DivFix( matrix->yx, temp ); matrix->xy = FT_DivFix( matrix->xy, temp ); matrix->yy = FT_DivFix( matrix->yy, temp ); offset->x = FT_DivFix( offset->x, temp ); offset->y = FT_DivFix( offset->y, temp ); } offset->x >>= 16; offset->y >>= 16; } for ( i = cff->num_subfonts; i > 0; i-- ) { CFF_FontRecDict sub = &cff->subfonts[i - 1]->font_dict; CFF_FontRecDict top = &cff->top_font.font_dict; FT_Matrix* matrix; FT_Vector* offset; FT_ULong* upm; FT_Fixed temp; if ( sub->units_per_em ) { FT_Int scaling; if ( top->units_per_em > 1 && sub->units_per_em > 1 ) scaling = FT_MIN( top->units_per_em, sub->units_per_em ); else scaling = 1; FT_Matrix_Multiply_Scaled( &top->font_matrix, &sub->font_matrix, scaling ); FT_Vector_Transform_Scaled( &sub->font_offset, &top->font_matrix, scaling ); sub->units_per_em = FT_MulDiv( sub->units_per_em, top->units_per_em, scaling ); } else { sub->font_matrix = top->font_matrix; sub->font_offset = top->font_offset; sub->units_per_em = top->units_per_em; } matrix = &sub->font_matrix; offset = &sub->font_offset; upm = &sub->units_per_em; temp = FT_ABS( matrix->yy ); if ( temp != 0x10000L ) { *upm = FT_DivFix( *upm, temp ); /* if *upm is larger than 100*1000 we divide by 1000 -- */ /* this can happen if e.g. there is no top-font FontMatrix */ /* and the subfont FontMatrix already contains the complete */ /* scaling for the subfont (see section 5.11 of the PLRM) */ /* 100 is a heuristic value */ if ( *upm > 100L * 1000L ) *upm = ( *upm + 500 ) / 1000; matrix->xx = FT_DivFix( matrix->xx, temp ); matrix->yx = FT_DivFix( matrix->yx, temp ); matrix->xy = FT_DivFix( matrix->xy, temp ); matrix->yy = FT_DivFix( matrix->yy, temp ); offset->x = FT_DivFix( offset->x, temp ); offset->y = FT_DivFix( offset->y, temp ); } offset->x >>= 16; offset->y >>= 16; } #ifndef FT_CONFIG_OPTION_NO_GLYPH_NAMES /* CID-keyed CFF fonts don't have glyph names -- the SFNT loader */ /* has unset this flag because of the 3.0 `post' table. */ if ( dict->cid_registry == 0xFFFFU ) cffface->face_flags |= FT_FACE_FLAG_GLYPH_NAMES; #endif if ( dict->cid_registry != 0xFFFFU ) cffface->face_flags |= FT_FACE_FLAG_CID_KEYED; /*******************************************************************/ /* */ /* Compute char maps. */ /* */ /* Try to synthetize a Unicode charmap if there is none available */ /* already. If an OpenType font contains a Unicode "cmap", we */ /* will use it, whatever be in the CFF part of the file. */ { FT_CharMapRec cmaprec; FT_CharMap cmap; FT_UInt nn; CFF_Encoding encoding = &cff->encoding; for ( nn = 0; nn < (FT_UInt)cffface->num_charmaps; nn++ ) { cmap = cffface->charmaps[nn]; /* Windows Unicode (3,1)? */ if ( cmap->platform_id == 3 && cmap->encoding_id == 1 ) goto Skip_Unicode; /* Deprecated Unicode platform id? */ if ( cmap->platform_id == 0 ) goto Skip_Unicode; /* Standard Unicode (deprecated) */ } /* since CID-keyed fonts don't contain glyph names, we can't */ /* construct a cmap */ if ( pure_cff && cff->top_font.font_dict.cid_registry != 0xFFFFU ) goto Exit; /* we didn't find a Unicode charmap -- synthesize one */ cmaprec.face = cffface; cmaprec.platform_id = 3; cmaprec.encoding_id = 1; cmaprec.encoding = FT_ENCODING_UNICODE; nn = (FT_UInt)cffface->num_charmaps; FT_CMap_New( &cff_cmap_unicode_class_rec, NULL, &cmaprec, NULL ); /* if no Unicode charmap was previously selected, select this one */ if ( cffface->charmap == NULL && nn != (FT_UInt)cffface->num_charmaps ) cffface->charmap = cffface->charmaps[nn]; Skip_Unicode: if ( encoding->count > 0 ) { FT_CMap_Class clazz; cmaprec.face = cffface; cmaprec.platform_id = 7; /* Adobe platform id */ if ( encoding->offset == 0 ) { cmaprec.encoding_id = TT_ADOBE_ID_STANDARD; cmaprec.encoding = FT_ENCODING_ADOBE_STANDARD; clazz = &cff_cmap_encoding_class_rec; } else if ( encoding->offset == 1 ) { cmaprec.encoding_id = TT_ADOBE_ID_EXPERT; cmaprec.encoding = FT_ENCODING_ADOBE_EXPERT; clazz = &cff_cmap_encoding_class_rec; } else { cmaprec.encoding_id = TT_ADOBE_ID_CUSTOM; cmaprec.encoding = FT_ENCODING_ADOBE_CUSTOM; clazz = &cff_cmap_encoding_class_rec; } FT_CMap_New( clazz, NULL, &cmaprec, NULL ); } } }
static FT_Error ft_bitmap_assure_buffer( FT_Memory memory, FT_Bitmap* bitmap, FT_UInt xpixels, FT_UInt ypixels ) { FT_Error error; unsigned int pitch; unsigned int new_pitch; FT_UInt bpp; FT_UInt width, height; unsigned char* buffer = NULL; width = bitmap->width; height = bitmap->rows; pitch = (unsigned int)FT_ABS( bitmap->pitch ); switch ( bitmap->pixel_mode ) { case FT_PIXEL_MODE_MONO: bpp = 1; new_pitch = ( width + xpixels + 7 ) >> 3; break; case FT_PIXEL_MODE_GRAY2: bpp = 2; new_pitch = ( width + xpixels + 3 ) >> 2; break; case FT_PIXEL_MODE_GRAY4: bpp = 4; new_pitch = ( width + xpixels + 1 ) >> 1; break; case FT_PIXEL_MODE_GRAY: case FT_PIXEL_MODE_LCD: case FT_PIXEL_MODE_LCD_V: bpp = 8; new_pitch = width + xpixels; break; default: return FT_THROW( Invalid_Glyph_Format ); } /* if no need to allocate memory */ if ( ypixels == 0 && new_pitch <= pitch ) { /* zero the padding */ FT_UInt bit_width = pitch * 8; FT_UInt bit_last = ( width + xpixels ) * bpp; if ( bit_last < bit_width ) { FT_Byte* line = bitmap->buffer + ( bit_last >> 3 ); FT_Byte* end = bitmap->buffer + pitch; FT_UInt shift = bit_last & 7; FT_UInt mask = 0xFF00U >> shift; FT_UInt count = height; for ( ; count > 0; count--, line += pitch, end += pitch ) { FT_Byte* write = line; if ( shift > 0 ) { write[0] = (FT_Byte)( write[0] & mask ); write++; } if ( write < end ) FT_MEM_ZERO( write, end - write ); } }
af_latin_hints_compute_segments( AF_GlyphHints hints, AF_Dimension dim ) { AF_AxisHints axis = &hints->axis[dim]; FT_Memory memory = hints->memory; FT_Error error = AF_Err_Ok; AF_Segment segment = NULL; AF_SegmentRec seg0; AF_Point* contour = hints->contours; AF_Point* contour_limit = contour + hints->num_contours; AF_Direction major_dir, segment_dir; FT_ZERO( &seg0 ); seg0.score = 32000; seg0.flags = AF_EDGE_NORMAL; major_dir = (AF_Direction)FT_ABS( axis->major_dir ); segment_dir = major_dir; axis->num_segments = 0; /* set up (u,v) in each point */ if ( dim == AF_DIMENSION_HORZ ) { AF_Point point = hints->points; AF_Point limit = point + hints->num_points; for ( ; point < limit; point++ ) { point->u = point->fx; point->v = point->fy; } } else { AF_Point point = hints->points; AF_Point limit = point + hints->num_points; for ( ; point < limit; point++ ) { point->u = point->fy; point->v = point->fx; } } /* do each contour separately */ for ( ; contour < contour_limit; contour++ ) { AF_Point point = contour[0]; AF_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; if ( point == last ) /* skip singletons -- just in case */ continue; if ( FT_ABS( last->out_dir ) == major_dir && FT_ABS( point->out_dir ) == major_dir ) { /* we are already on an edge, try to locate its start */ last = point; for (;;) { point = point->prev; if ( FT_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 = (FT_Short)( ( min_pos + max_pos ) >> 1 ); /* a segment is round