static TT_Error LoadTrueTypeChar(Font *fnt, int idx, Boolean hint, Boolean quiet) { TT_Error error; int flags; flags = TTLOAD_SCALE_GLYPH; if (hint) flags |= TTLOAD_HINT_GLYPH; error = TT_Load_Glyph(instance, glyph, idx, flags); if (!error) error = TT_Get_Glyph_Big_Metrics(glyph, &metrics); if (!error) error = TT_Get_Glyph_Outline(glyph, &outline); if (!error) { if (fnt->efactor != 1.0 || fnt->slant != 0.0 ) TT_Transform_Outline(&outline, &matrix1); if (fnt->rotate) TT_Transform_Outline(&outline, &matrix2); } if (!error) error = TT_Get_Outline_BBox(&outline, &bbox); /* we need the non- grid-fitted bbox */ if (fnt->rotate) TT_Translate_Outline(&outline, metrics.vertBearingY - bbox.xMin, -fnt->y_offset * ppem * 64); if (!error) error = TT_Get_Outline_BBox(&outline, &bbox); if (!error) SetRasterArea(quiet); return error; }
void readttf(Font *fnt, Boolean quiet, Boolean only_range) { TT_Error error; ttfinfo *ti, *Ti; long Num, index; unsigned int i, j; long k, max_k; unsigned short num_cmap; unsigned short cmap_plat, cmap_enc; int index_array[257]; static Boolean initialized = False; TT_UShort in_string[2]; TTO_GSUB_String in, out; TT_UShort script_index, language_index, feature_index; TT_UShort req_feature_index = 0xFFFF; /* * We allocate a placeholder boundary and the `.notdef' character. */ if (!only_range) { ti = newchar(fnt); ti->charcode = -1; ti->adobename = ".notdef"; ti = newchar(fnt); ti->charcode = -1; ti->adobename = "||"; /* boundary character name */ } /* * Initialize FreeType engine. */ if (!initialized) { if ((error = TT_Init_FreeType(&engine))) oops("Cannot initialize engine (error code = 0x%x).", error); if ((error = TT_Init_Kerning_Extension(engine))) oops("Cannot initialize kerning (error code = 0x%x).", error); if (fnt->PSnames) if ((error = TT_Init_Post_Extension(engine))) oops("Cannot initialize PS name support (error code = 0x%x).", error); if (fnt->rotate) if ((error = TT_Init_GSUB_Extension(engine))) oops("Cannot initialize GSUB support (error code = 0x%x).", error); /* * Load face. */ real_ttfname = TeX_search_ttf_file(&(fnt->ttfname)); if (!real_ttfname) oops("Cannot find `%s'.", fnt->ttfname); if ((error = TT_Open_Face(engine, real_ttfname, &face))) oops("Cannot open `%s'.", real_ttfname); /* * Get face properties and allocate preload arrays. */ TT_Get_Face_Properties(face, &properties); /* * Now we try to open the proper font in a collection. */ if (fnt->fontindex != 0) { if (properties.num_Faces == 1) { warning("This isn't a TrueType collection.\n" "Parameter `-f' is ignored."); fnt->fontindex = 0; fnt->fontindexparam = NULL; } else { TT_Close_Face(face); if ((error = TT_Open_Collection(engine, real_ttfname, fnt->fontindex, &face))) oops("Cannot open font %lu in TrueType Collection `%s'.", fnt->fontindex, real_ttfname); } } /* * Create instance. */ if ((error = TT_New_Instance(face, &instance))) oops("Cannot create instance for `%s' (error code = 0x%x).", real_ttfname, error); /* * We use a dummy glyph size of 10pt. */ if ((error = TT_Set_Instance_CharSize(instance, 10 * 64))) oops("Cannot set character size (error code = 0x%x).", error); matrix1.xx = (TT_Fixed)(floor(fnt->efactor * 1024) * (1L<<16)/1024); matrix1.xy = (TT_Fixed)(floor(fnt->slant * 1024) * (1L<<16)/1024); matrix1.yx = (TT_Fixed)0; matrix1.yy = (TT_Fixed)(1L<<16); if (fnt->rotate) { matrix2.xx = 0; matrix2.yx = 1L << 16; matrix2.xy = -matrix2.yx; matrix2.yy = matrix2.xx; } if ((error = TT_Set_Instance_Transform_Flags( instance, fnt->rotate ? 1 : 0, fnt->efactor != 1.0 ? 1 : 0))) oops("Cannot set transform flags (error code = 0x%x).", error); /* * Create glyph container. */ if ((error = TT_New_Glyph(face, &glyph))) oops("Cannot create glyph container (error code = 0x%x).", error); fnt->units_per_em = properties.header->Units_Per_EM; fnt->fixedpitch = properties.postscript->isFixedPitch; fnt->italicangle = properties.postscript->italicAngle / 65536.0; if (fnt->PSnames != Only) { num_cmap = properties.num_CharMaps; for (i = 0; i < num_cmap; i++) { if ((error = TT_Get_CharMap_ID(face, i, &cmap_plat, &cmap_enc))) oops("Cannot query cmap (error code = 0x%x).", error); if (cmap_plat == fnt->pid && cmap_enc == fnt->eid) break; } if (i == num_cmap) { fprintf(stderr, "%s: ERROR: Invalid platform and/or encoding ID.\n", progname); if (num_cmap == 1) fprintf(stderr, " The only valid PID/EID pair is"); else fprintf(stderr, " Valid PID/EID pairs are:\n"); for (i = 0; i < num_cmap; i++) { TT_Get_CharMap_ID(face, i, &cmap_plat, &cmap_enc); fprintf(stderr, " (%i,%i)\n", cmap_plat, cmap_enc); } fprintf(stderr, "\n"); exit(1); } if ((error = TT_Get_CharMap(face, i, &char_map))) oops("Cannot load cmap (error code = 0x%x).", error); } if (fnt->PSnames) { if ((error = TT_Load_PS_Names(face, &post))) oops("Cannot load TrueType PS names (error code = 0x%x).", error); } else if (cmap_plat == Microsoft_platform && cmap_enc == Microsoft_Unicode_encoding) set_encoding_scheme(encUnicode, fnt); else if (cmap_plat == Macintosh_platform && cmap_enc == Macintosh_encoding) set_encoding_scheme(encMac, fnt); else set_encoding_scheme(encFontSpecific, fnt); if (fnt->rotate) { gsub = &gsub_; error = TT_Load_GSUB_Table(face, gsub, NULL); if (!error) has_gsub = True; else if (error != TT_Err_Table_Missing) warning("Cannot load GSUB table (error code = 0x%x).", error); else warning("No GSUB data available " "for vertical glyph presentation forms."); /* we check for the `vert' feature in Chinese, Japanese, and Korean */ error = TT_GSUB_Select_Script(gsub, SCRIPT_kana, &script_index); if (error) goto check_hani; error = TT_GSUB_Select_Feature(gsub, FEATURE_vert, script_index, 0xFFFF, &feature_index); if (error) { error = TT_GSUB_Select_Language(gsub, LANGUAGE_JAN, script_index, &language_index, &req_feature_index); if (error) goto check_hani; error = TT_GSUB_Select_Feature(gsub, FEATURE_vert, script_index, language_index, &feature_index); if (error) goto check_hani; else goto Done; } else goto Done; check_hani: error = TT_GSUB_Select_Script(gsub, SCRIPT_hani, &script_index); if (error) goto check_hang; error = TT_GSUB_Select_Feature(gsub, FEATURE_vert, script_index, 0xFFFF, &feature_index); if (error) { error = TT_GSUB_Select_Language(gsub, LANGUAGE_CHN, script_index, &language_index, &req_feature_index); if (error) goto check_hang; error = TT_GSUB_Select_Feature(gsub, FEATURE_vert, script_index, language_index, &feature_index); if (error) goto check_hang; else goto Done; } else goto Done; check_hang: error = TT_GSUB_Select_Script(gsub, SCRIPT_hang, &script_index); if (error) goto Done; error = TT_GSUB_Select_Feature(gsub, FEATURE_vert, script_index, 0xFFFF, &feature_index); if (error) { error = TT_GSUB_Select_Language(gsub, LANGUAGE_KOR, script_index, &language_index, &req_feature_index); if (error) goto Done; error = TT_GSUB_Select_Feature(gsub, FEATURE_vert, script_index, language_index, &feature_index); } Done: if (error) { warning("There is no data for vertical typesetting in GSUB table."); has_gsub = False; } if (req_feature_index != 0xFFFF) TT_GSUB_Add_Feature(gsub, req_feature_index, ALL_GLYPHS); TT_GSUB_Add_Feature(gsub, feature_index, ALL_GLYPHS); in.length = 1; in.pos = 0; in.string = in_string; in.properties = NULL; out.pos = 0; out.allocated = 0; out.string = NULL; out.properties = NULL; } initialized = True; } if (!quiet) { if (only_range) printf("\n\n%s:\n", fnt->fullname); printf("\n"); printf("Glyph Code Glyph Name "); printf("Width llx lly urx ury\n"); printf("---------------------------------------"); printf("---------------------------------\n"); } /* * We load only glyphs with a valid cmap entry. Nevertheless, for * the default mapping, we use the first 256 glyphs addressed by * ascending code points, followed by glyphs not in the cmap. * * If we compute a range, we take the character codes given in * the fnt->sf_code array. * * If the -N flag is set, no cmap is used at all. Instead, the * first 256 glyphs (with a valid PS name) are used for the default * mapping. */ if (!only_range) for (i = 0; i < 257; i++) index_array[i] = 0; else for (i = 0; i < 256; i++) fnt->inencptrs[i] = 0; j = 0; if (fnt->PSnames == Only) max_k = properties.num_Glyphs - 1; else max_k = only_range ? 0xFF : 0x16FFFF; for (k = 0; k <= max_k; k++) { char *an; if (fnt->PSnames != Only) { if (only_range) { index = fnt->sf_code[k]; if (index < 0) continue; j = k; } else index = k; Num = TT_Char_Index(char_map, index); /* now we try to get a vertical glyph form */ if (has_gsub) { in_string[0] = Num; error = TT_GSUB_Apply_String(gsub, &in, &out); if (error && error != TTO_Err_Not_Covered) warning("Cannot get the vertical glyph form for glyph index %d.", Num); else Num = out.string[0]; } if (Num < 0) oops("Failure on cmap mapping from %s.", fnt->ttfname); if (Num == 0) continue; if (!only_range) if (Num <= 256) index_array[Num] = 1; } else { Num = k; index = 0; } error = TT_Load_Glyph(instance, glyph, Num, 0); if (!error) error = TT_Get_Glyph_Big_Metrics(glyph, &metrics); if (!error) error = TT_Get_Glyph_Outline(glyph, &outline); if (!error) { if (fnt->efactor != 1.0 || fnt->slant != 0.0 ) TT_Transform_Outline(&outline, &matrix1); if (fnt->rotate) TT_Transform_Outline(&outline, &matrix2); } if (!error) error = TT_Get_Outline_BBox(&outline, &bbox); /* we need the non- grid-fitted bbox */ if (!error) { if (fnt->PSnames) (void)TT_Get_PS_Name(face, Num, &an); else an = code_to_adobename(index); /* ignore characters not usable for typesetting with TeX */ if (strcmp(an, ".notdef") == 0) continue; if (strcmp(an, ".null") == 0) continue; if (strcmp(an, "nonmarkingreturn") == 0) continue; ti = newchar(fnt); ti->charcode = index; ti->glyphindex = Num; ti->adobename = an; ti->llx = bbox.xMin * 1000 / fnt->units_per_em; ti->lly = bbox.yMin * 1000 / fnt->units_per_em; ti->urx = bbox.xMax * 1000 / fnt->units_per_em; ti->ury = bbox.yMax * 1000 / fnt->units_per_em; /* * We must now shift the rotated character both horizontally * and vertically. The vertical amount is 25% by default. */ if (fnt->rotate) { ti->llx += (metrics.vertBearingY - bbox.xMin) * 1000 / fnt->units_per_em; ti->lly -= 1000 * fnt->y_offset; ti->urx += (metrics.vertBearingY - bbox.xMin) * 1000 / fnt->units_per_em; ti->ury -= 1000 * fnt->y_offset; } /* * We need to avoid negative heights or depths. They break accents * in math mode, among other things. */ if (ti->lly > 0) ti->lly = 0; if (ti->ury < 0) ti->ury = 0; if (fnt->rotate) ti->width = metrics.vertAdvance * 1000 / fnt->units_per_em; else ti->width = transform(metrics.horiAdvance * 1000 / fnt->units_per_em, 0, fnt->efactor, fnt->slant); if (!quiet) printf("%5ld %05lx %-25s %5d % 5d,% 5d -- % 5d,% 5d\n", Num, index, ti->adobename, ti->width, ti->llx, ti->lly, ti->urx, ti->ury); if (j < 256) { fnt->inencptrs[j] = ti; ti->incode = j; } j++; } } /* * Now we load glyphs without a cmap entry, provided some slots are * still free -- we skip this if we have to compute a range or use * PS names. */ if (!only_range && !fnt->PSnames) { for (i = 1; i <= properties.num_Glyphs; i++) { char *an; if (index_array[i] == 0) { error = TT_Load_Glyph(instance, glyph, i, 0); if (!error) error = TT_Get_Glyph_Big_Metrics(glyph, &metrics); if (!error) error = TT_Get_Glyph_Outline(glyph, &outline); if (!error) error = TT_Get_Outline_BBox(&outline, &bbox); if (!error) { an = code_to_adobename(i | 0x1000000); ti = newchar(fnt); ti->charcode = i | 0x1000000; ti->glyphindex = i; ti->adobename = an; ti->llx = bbox.xMin * 1000 / fnt->units_per_em; ti->lly = bbox.yMin * 1000 / fnt->units_per_em; ti->urx = bbox.xMax * 1000 / fnt->units_per_em; ti->ury = bbox.yMax * 1000 / fnt->units_per_em; if (ti->lly > 0) ti->lly = 0; if (ti->ury < 0) ti->ury = 0; ti->width = transform(metrics.horiAdvance*1000 / fnt->units_per_em, 0, fnt->efactor, fnt->slant); if (!quiet) printf("%5d %-25s %5d % 5d,% 5d -- % 5d,% 5d\n", i, ti->adobename, ti->width, ti->llx, ti->lly, ti->urx, ti->ury); if (j < 256) { fnt->inencptrs[j] = ti; ti->incode = j; } else break; j++; } } } } /* Finally, we construct a `Germandbls' glyph if necessary */ if (!only_range) { if (NULL == findadobe("Germandbls", fnt->charlist) && NULL != (Ti = findadobe("S", fnt->charlist))) { pcc *np, *nq; ti = newchar(fnt); ti->charcode = properties.num_Glyphs | 0x1000000; ti->glyphindex = properties.num_Glyphs; ti->adobename = "Germandbls"; ti->width = Ti->width << 1; ti->llx = Ti->llx; ti->lly = Ti->lly; ti->urx = Ti->width + Ti->urx; ti->ury = Ti->ury; ti->kerns = Ti->kerns; np = newpcc(); np->partname = "S"; nq = newpcc(); nq->partname = "S"; nq->xoffset = Ti->width; np->next = nq; ti->pccs = np; ti->constructed = True; if (!quiet) printf("* %-25s %5d % 5d,% 5d -- % 5d,% 5d\n", ti->adobename, ti->width, ti->llx, ti->lly, ti->urx, ti->ury); } } /* kerning between subfonts isn't available */ if (!only_range) readttf_kern(fnt); }
Load_TrueType_Glyph( PInstance instance, PGlyph glyph, UShort glyph_index, UShort load_flags ) { enum TPhases_ { Load_Exit, Load_Glyph, Load_Header, Load_Simple, Load_Composite, Load_End }; typedef enum TPhases_ TPhases; DEFINE_ALL_LOCALS; PFace face; UShort num_points; Short num_contours; UShort left_points; Short left_contours; UShort num_elem_points; Long table; UShort load_top; Long k, l; UShort new_flags; Long index; UShort u, v; Long glyph_offset, offset; TT_F26Dot6 x, y, nx, ny; Fixed xx, xy, yx, yy; PExecution_Context exec; PSubglyph_Record subglyph, subglyph2; TGlyph_Zone base_pts; TPhases phase; PByte widths; /* TT_Glyph_Loader_Callback cacheCb; */ /* TT_Outline cached_outline; */ /* first of all, check arguments */ if ( !glyph ) return TT_Err_Invalid_Glyph_Handle; face = glyph->face; if ( !face ) return TT_Err_Invalid_Glyph_Handle; if ( glyph_index >= face->numGlyphs ) return TT_Err_Invalid_Glyph_Index; if ( instance && (load_flags & TTLOAD_SCALE_GLYPH) == 0 ) { instance = 0; load_flags &= ~( TTLOAD_SCALE_GLYPH | TTLOAD_HINT_GLYPH ); } table = TT_LookUp_Table( face, TTAG_glyf ); if ( table < 0 ) { PTRACE0(( "ERROR: There is no glyph table in this font file!\n" )); return TT_Err_Glyf_Table_Missing; } glyph_offset = face->dirTables[table].Offset; /* query new execution context */ if ( instance && instance->debug ) exec = instance->context; else exec = New_Context( face ); if ( !exec ) return TT_Err_Could_Not_Find_Context; Context_Load( exec, face, instance ); if ( instance ) { if ( instance->GS.instruct_control & 2 ) exec->GS = Default_GraphicsState; else exec->GS = instance->GS; /* load default graphics state */ glyph->outline.high_precision = ( instance->metrics.y_ppem < 24 ); } /* save its critical pointers, as they'll be modified during load */ base_pts = exec->pts; /* init variables */ left_points = face->maxPoints; left_contours = face->maxContours; num_points = 0; num_contours = 0; load_top = 0; subglyph = exec->loadStack; Init_Glyph_Component( subglyph, NULL, exec ); subglyph->index = glyph_index; subglyph->is_hinted = load_flags & TTLOAD_HINT_GLYPH; /* when the cvt program has disabled hinting, the argument */ /* is ignored. */ if ( instance && instance->GS.instruct_control & 1 ) subglyph->is_hinted = FALSE; /* now access stream */ if ( USE_Stream( face->stream, stream ) ) goto Fin; /* Main loading loop */ phase = Load_Glyph; index = 0; while ( phase != Load_Exit ) { subglyph = exec->loadStack + load_top; switch ( phase ) { /************************************************************/ /* */ /* Load_Glyph state */ /* */ /* reading a glyph's generic header to determine */ /* whether it's simple or composite */ /* */ /* exit states: Load_Header and Load_End */ case Load_Glyph: /* check glyph index and table */ index = subglyph->index; if ( index < 0 || index >= face->numGlyphs ) { error = TT_Err_Invalid_Glyph_Index; goto Fail; } /* get horizontal metrics */ { Short left_bearing; UShort advance_width; Get_HMetrics( face, (UShort)index, !(load_flags & TTLOAD_IGNORE_GLOBAL_ADVANCE_WIDTH), &left_bearing, &advance_width ); subglyph->metrics.horiBearingX = left_bearing; subglyph->metrics.horiAdvance = advance_width; } phase = Load_Header; /* The cache callback isn't part of the FreeType release yet */ /* It is discarded for the moment.. */ /* */ #if 0 if ( instance ) { /* is the glyph in an outline cache ? */ cacheCb = instance->owner->engine->glCallback; if ( cacheCb && 0 ) /* disabled */ { /* we have a callback */ error = cacheCb( instance->generic, index, &cached_outline, &x, &y ); if ( !error ) { /* no error, then append the outline to the current subglyph */ /* error = Append_Outline( subglyph, &left_points, &left_contours, &cached_outline ); */ phase = Load_End; } } } #endif break; /************************************************************/ /* */ /* Load_Header state */ /* */ /* reading a glyph's generic header to determine */ /* wether it's simple or composite */ /* */ /* exit states: Load_Simple and Load_Composite */ /* */ case Load_Header: /* load glyph */ if ( (TT_UInt)( index + 1 ) < (TT_UInt)face->numLocations && face->glyphLocations[index] == face->glyphLocations[index + 1] ) { /* as described by Frederic Loyer, these are spaces, and */ /* not the unknown glyph. */ num_contours = 0; num_points = 0; subglyph->metrics.bbox.xMin = 0; subglyph->metrics.bbox.xMax = 0; subglyph->metrics.bbox.yMin = 0; subglyph->metrics.bbox.yMax = 0; subglyph->pp1.x = 0; subglyph->pp2.x = subglyph->metrics.horiAdvance; if (load_flags & TTLOAD_SCALE_GLYPH) subglyph->pp2.x = Scale_X( &exec->metrics, subglyph->pp2.x ); exec->glyphSize = 0; phase = Load_End; break; } offset = glyph_offset + face->glyphLocations[index]; /* read first glyph header */ if ( FILE_Seek( offset ) || ACCESS_Frame( 10L ) ) goto Fail_File; num_contours = GET_Short(); subglyph->metrics.bbox.xMin = GET_Short(); subglyph->metrics.bbox.yMin = GET_Short(); subglyph->metrics.bbox.xMax = GET_Short(); subglyph->metrics.bbox.yMax = GET_Short(); FORGET_Frame(); PTRACE6(( "Glyph %ld:\n", index )); PTRACE6(( " # of contours: %d\n", num_contours )); PTRACE6(( " xMin: %4d xMax: %4d\n", subglyph->metrics.bbox.xMin, subglyph->metrics.bbox.xMax )); PTRACE6(( " yMin: %4d yMax: %4d\n", subglyph->metrics.bbox.yMin, subglyph->metrics.bbox.yMax )); if ( num_contours > left_contours ) { PTRACE0(( "ERROR: Too many contours for glyph %ld\n", index )); error = TT_Err_Too_Many_Contours; goto Fail; } subglyph->pp1.x = subglyph->metrics.bbox.xMin - subglyph->metrics.horiBearingX; subglyph->pp1.y = 0; subglyph->pp2.x = subglyph->pp1.x + subglyph->metrics.horiAdvance; if (load_flags & TTLOAD_SCALE_GLYPH) { subglyph->pp1.x = Scale_X( &exec->metrics, subglyph->pp1.x ); subglyph->pp2.x = Scale_X( &exec->metrics, subglyph->pp2.x ); } /* is it a simple glyph ? */ if ( num_contours > 0 ) phase = Load_Simple; else phase = Load_Composite; break; /************************************************************/ /* */ /* Load_Simple state */ /* */ /* reading a simple glyph (num_contours must be set to */ /* the glyph's number of contours.) */ /* */ /* exit states : Load_End */ /* */ case Load_Simple: new_flags = load_flags; /* disable hinting when scaling */ if ( !subglyph->is_hinted ) new_flags &= ~TTLOAD_HINT_GLYPH; error = Load_Simple_Glyph( exec, stream, num_contours, left_contours, left_points, new_flags, subglyph ); if ( error ) goto Fail; /* Note: We could have put the simple loader source there */ /* but the code is fat enough already :-) */ num_points = exec->pts.n_points - 2; phase = Load_End; break; /************************************************************/ /* */ /* Load_Composite state */ /* */ /* reading a composite glyph header a pushing a new */ /* load element on the stack. */ /* */ /* exit states: Load_Glyph */ /* */ case Load_Composite: /* create a new element on the stack */ load_top++; if ( load_top > face->maxComponents ) { error = TT_Err_Invalid_Composite; goto Fail; } subglyph2 = exec->loadStack + load_top; Init_Glyph_Component( subglyph2, subglyph, NULL ); subglyph2->is_hinted = subglyph->is_hinted; /* now read composite header */ if ( ACCESS_Frame( 4L ) ) goto Fail_File; subglyph->element_flag = new_flags = GET_UShort(); subglyph2->index = GET_UShort(); FORGET_Frame(); k = 1 + 1; if ( new_flags & ARGS_ARE_WORDS ) k *= 2; if ( new_flags & WE_HAVE_A_SCALE ) k += 2; else if ( new_flags & WE_HAVE_AN_XY_SCALE ) k += 4; else if ( new_flags & WE_HAVE_A_2X2 ) k += 8; if ( ACCESS_Frame( k ) ) goto Fail_File; if ( new_flags & ARGS_ARE_WORDS ) { k = GET_Short(); l = GET_Short(); } else { k = GET_Char(); l = GET_Char(); } subglyph->arg1 = k; subglyph->arg2 = l; if ( new_flags & ARGS_ARE_XY_VALUES ) { subglyph->transform.ox = k; subglyph->transform.oy = l; } xx = 1L << 16; xy = 0; yx = 0; yy = 1L << 16; if ( new_flags & WE_HAVE_A_SCALE ) { xx = (Fixed)GET_Short() << 2; yy = xx; subglyph2->is_scaled = TRUE; } else if ( new_flags & WE_HAVE_AN_XY_SCALE ) { xx = (Fixed)GET_Short() << 2; yy = (Fixed)GET_Short() << 2; subglyph2->is_scaled = TRUE; } else if ( new_flags & WE_HAVE_A_2X2 ) { xx = (Fixed)GET_Short() << 2; xy = (Fixed)GET_Short() << 2; yx = (Fixed)GET_Short() << 2; yy = (Fixed)GET_Short() << 2; subglyph2->is_scaled = TRUE; } FORGET_Frame(); subglyph->transform.xx = xx; subglyph->transform.xy = xy; subglyph->transform.yx = yx; subglyph->transform.yy = yy; k = TT_MulFix( xx, yy ) - TT_MulFix( xy, yx ); /* disable hinting in case of scaling/slanting */ if ( ABS( k ) != (1L << 16) ) subglyph2->is_hinted = FALSE; subglyph->file_offset = FILE_Pos(); phase = Load_Glyph; break; /************************************************************/ /* */ /* Load_End state */ /* */ /* after loading a glyph, apply transformation and offset */ /* where necessary, pops element and continue or */ /* stop process. */ /* */ /* exit states : Load_Composite and Load_Exit */ /* */ case Load_End: if ( load_top > 0 ) { subglyph2 = subglyph; load_top--; subglyph = exec->loadStack + load_top; /* check advance width and left side bearing */ if ( !subglyph->preserve_pps && subglyph->element_flag & USE_MY_METRICS ) { subglyph->metrics.horiBearingX = subglyph2->metrics.horiBearingX; subglyph->metrics.horiAdvance = subglyph2->metrics.horiAdvance; subglyph->pp1 = subglyph2->pp1; subglyph->pp2 = subglyph2->pp2; subglyph->preserve_pps = TRUE; } /* apply scale */ if ( subglyph2->is_scaled ) { TT_Vector* cur = subglyph2->zone.cur; TT_Vector* org = subglyph2->zone.org; for ( u = 0; u < num_points; u++ ) { nx = TT_MulFix( cur->x, subglyph->transform.xx ) + TT_MulFix( cur->y, subglyph->transform.yx ); ny = TT_MulFix( cur->x, subglyph->transform.xy ) + TT_MulFix( cur->y, subglyph->transform.yy ); cur->x = nx; cur->y = ny; nx = TT_MulFix( org->x, subglyph->transform.xx ) + TT_MulFix( org->y, subglyph->transform.yx ); ny = TT_MulFix( org->x, subglyph->transform.xy ) + TT_MulFix( org->y, subglyph->transform.yy ); org->x = nx; org->y = ny; cur++; org++; } } /* adjust counts */ num_elem_points = subglyph->zone.n_points; for ( k = 0; k < num_contours; k++ ) subglyph2->zone.contours[k] += num_elem_points; subglyph->zone.n_points += num_points; subglyph->zone.n_contours += num_contours; left_points -= num_points; left_contours -= num_contours; if ( !(subglyph->element_flag & ARGS_ARE_XY_VALUES) ) { /* move second glyph according to control points */ /* the attach points are relative to the specific component */ u = (UShort)subglyph->arg1; v = (UShort)subglyph->arg2; if ( u >= num_elem_points || v >= num_points ) { error = TT_Err_Invalid_Composite; goto Fail; } /* adjust count */ v += num_elem_points; x = subglyph->zone.cur[u].x - subglyph->zone.cur[v].x; y = subglyph->zone.cur[u].y - subglyph->zone.cur[v].y; } else { /* apply offset */ x = subglyph->transform.ox; y = subglyph->transform.oy; if ( load_flags & TTLOAD_SCALE_GLYPH ) { x = Scale_X( &exec->metrics, x ); y = Scale_Y( &exec->metrics, y ); if ( subglyph->element_flag & ROUND_XY_TO_GRID ) { x = (x+32) & -64; y = (y+32) & -64; } } } translate_array( num_points, subglyph2->zone.cur, x, y ); cur_to_org( num_points, &subglyph2->zone ); num_points = subglyph->zone.n_points; num_contours = subglyph->zone.n_contours; /* check for last component */ if ( FILE_Seek( subglyph->file_offset ) ) goto Fail_File; if ( subglyph->element_flag & MORE_COMPONENTS ) phase = Load_Composite; else { error = Load_Composite_End( num_points, num_contours, exec, subglyph, load_flags, stream ); if ( error ) goto Fail; phase = Load_End; } } else phase = Load_Exit; break; case Load_Exit: break; } } /* finally, copy the points arrays to the glyph object */ exec->pts = base_pts; for ( u = 0; u < num_points + 2; u++ ) { glyph->outline.points[u] = exec->pts.cur[u]; glyph->outline.flags [u] = exec->pts.touch[u]; } for ( k = 0; k < num_contours; k++ ) glyph->outline.contours[k] = exec->pts.contours[k]; glyph->outline.n_points = num_points; glyph->outline.n_contours = num_contours; glyph->outline.second_pass = TRUE; /* translate array so that (0,0) is the glyph's origin */ translate_array( num_points + 2, glyph->outline.points, -subglyph->pp1.x, 0 ); TT_Get_Outline_BBox( &glyph->outline, &glyph->metrics.bbox ); if ( subglyph->is_hinted ) { /* grid-fit the bounding box */ glyph->metrics.bbox.xMin &= -64; glyph->metrics.bbox.yMin &= -64; glyph->metrics.bbox.xMax = (glyph->metrics.bbox.xMax+63) & -64; glyph->metrics.bbox.yMax = (glyph->metrics.bbox.yMax+63) & -64; } /* get the device-independent scaled horizontal metrics */ /* take care of fixed-pitch fonts... */ { TT_Pos left_bearing; TT_Pos advance; left_bearing = subglyph->metrics.horiBearingX; advance = subglyph->metrics.horiAdvance; if ( face->postscript.isFixedPitch ) advance = face->horizontalHeader.advance_Width_Max; if ( load_flags & TTLOAD_SCALE_GLYPH ) { left_bearing = Scale_X( &exec->metrics, left_bearing ); advance = Scale_X( &exec->metrics, advance ); } glyph->metrics.linearHoriBearingX = left_bearing; glyph->metrics.linearHoriAdvance = advance; } glyph->metrics.horiBearingX = glyph->metrics.bbox.xMin; glyph->metrics.horiBearingY = glyph->metrics.bbox.yMax; glyph->metrics.horiAdvance = subglyph->pp2.x - subglyph->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' ... */ { Short top_bearing; /* vertical top side bearing (EM units) */ UShort advance_height; /* vertical advance height (EM units) */ TT_Pos left; /* scaled vertical left side bearing */ TT_Pos orig_top; /* scaled original vertical top side bearing */ TT_Pos top; /* scaled vertical top side bearing */ TT_Pos advance; /* scaled vertical advance height */ /* Get the unscaled `tsb' and `ah' values */ if ( face->verticalInfo && face->verticalHeader.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_Horizontal_Header*)&face->verticalHeader, 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... */ /* */ /* NOTE2: The sTypoDescender is negative, which is why */ /* we compute the baseline-to-baseline distance */ /* here with : */ /* ascender - descender + linegap */ /* */ /* XXX What happens here with these Apple fonts without OS/2 table ? */ top_bearing = (Short) (face->os2.sTypoLineGap / 2); advance_height = (UShort)(face->os2.sTypoAscender - face->os2.sTypoDescender + face->os2.sTypoLineGap); } /* We must adjust the top_bearing value from the bounding box */ /* given in the glyph header to te bounding box calculated with */ /* TT_Get_Outline_BBox() */ /* scale the metrics */ if ( load_flags & TTLOAD_SCALE_GLYPH ) { orig_top = Scale_Y( &exec->metrics, top_bearing ); top = Scale_Y( &exec->metrics, top_bearing + subglyph->metrics.bbox.yMax ) - glyph->metrics.bbox.yMax; advance = Scale_Y( &exec->metrics, advance_height ); } else { orig_top = top_bearing; top = top_bearing + subglyph->metrics.bbox.yMax - glyph->metrics.bbox.yMax; advance = advance_height; } glyph->metrics.linearVertBearingY = orig_top; glyph->metrics.linearVertAdvance = advance; /* XXX : for now, we have no better algo for the lsb, but it should */ /* work ok.. */ /* */ left = ( glyph->metrics.bbox.xMin - glyph->metrics.bbox.xMax ) / 2; /* grid-fit them if necessary */ if ( subglyph->is_hinted ) { 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 ( !exec->face->postscript.isFixedPitch && instance && subglyph->is_hinted ) { widths = Get_Advance_Widths( exec->face, exec->instance->metrics.x_ppem ); if ( widths ) glyph->metrics.horiAdvance = widths[glyph_index] << 6; } glyph->outline.dropout_mode = (Char)exec->GS.scan_type; error = TT_Err_Ok; Fail_File: Fail: DONE_Stream( stream ); Fin: /* reset the execution context */ exec->pts = base_pts; if ( !instance || !instance->debug ) Done_Context( exec ); return error; }