void Print_Type( FT_Face face ) { FT_Module module; printf( "font type entries\n" ); module = &face->driver->root; printf( " FreeType driver: %s\n", module->clazz->module_name ); /* Is it better to dump all sfnt tag names? */ printf( " sfnt wrapped: %s\n", FT_IS_SFNT( face ) ? (char *)"yes" : (char *)"no" ); /* isScalable? */ comma_flag = 0; printf( " type: " ); if ( FT_IS_SCALABLE( face ) ) { Print_Comma( "scalable" ); if ( FT_HAS_MULTIPLE_MASTERS( face ) ) Print_Comma( "multiple masters" ); } if ( FT_HAS_FIXED_SIZES( face ) ) Print_Comma( "fixed size" ); printf( "\n" ); /* Direction */ comma_flag = 0; printf( " direction: " ); if ( FT_HAS_HORIZONTAL( face ) ) Print_Comma( "horizontal" ); if ( FT_HAS_VERTICAL( face ) ) Print_Comma( "vertical" ); printf( "\n" ); printf( " fixed width: %s\n", FT_IS_FIXED_WIDTH( face ) ? (char *)"yes" : (char *)"no" ); printf( " glyph names: %s\n", FT_HAS_GLYPH_NAMES( face ) ? (char *)"yes" : (char *)"no" ); if ( FT_IS_SCALABLE( face ) ) { printf( " EM size: %d\n", face->units_per_EM ); printf( " global BBox: (%ld,%ld):(%ld,%ld)\n", face->bbox.xMin, face->bbox.yMin, face->bbox.xMax, face->bbox.yMax ); printf( " ascent: %d\n", face->ascender ); printf( " descent: %d\n", face->descender ); printf( " text height: %d\n", face->height ); } }
static int glnames( GLYPH *glyph_list ) { #define MAX_NAMELEN 1024 #ifdef XP_PSTEXT char buf[1024]; long i; FT_Error error; #ifdef XP_ONLY_BLOCKS extern unsigned long xp_font_block_offset; extern FTFontPtr xp_xtf; int bc; /* block counter */ /* FixMe: This code should use PsOut_Get_FreeType_Glyph_Name() instead of * duplicating the code */ for( bc = xp_font_block_offset ; bc < (xp_font_block_offset+256) ; bc++ ) { /* Remap X11 font index to FreeType font index */ i = FTRemap(face, &xp_xtf->mapping, bc); if( i >= face->num_glyphs ) continue; #else for(i=0; i < face->num_glyphs; i++) { #endif /* XP_ONLY_BLOCKS */ if( FT_Has_PS_Glyph_Names(face) ) { error = FT_Get_Glyph_Name(face, i, buf, MAX_NAMELEN); } else { error = -1; } if( error ) { /* Check for unicode mapping * See Adobe document "Unicode and Glyph Names" * (http://partners.adobe.com/asn/tech/type/unicodegn.jsp) */ if( (xp_xtf->mapping.mapping->type == FONT_ENCODING_UNICODE) && (i < 0xFFFE) ) { sprintf(buf, "uni%04lx", i); } else { sprintf(buf, "ch%02lx", i); } } glyph_list[i].name = strdup(buf); if(ISDBG(FT)) fprintf(stderr, "%d has name %s\n", i, buf); if (glyph_list[i].name == NULL) { fprintf (stderr, "****malloc failed %s line %d\n", __FILE__, __LINE__); exit(255); } } return 0; #else char bf[1024]; long i; if( ! FT_HAS_GLYPH_NAMES(face) ) { WARNING_1 fprintf(stderr, "Font has no glyph names\n"); return 1; } for(i=0; i < face->num_glyphs; i++) { if( FT_Get_Glyph_Name(face, i, bf, MAX_NAMELEN) || bf[0]==0 ) { sprintf(bf, "_g_%d", i); WARNING_2 fprintf(stderr, "Glyph No. %d has no postscript name, becomes %s\n", i, bf); } glyph_list[i].name = strdup(bf); if(ISDBG(FT)) fprintf(stderr, "%d has name %s\n", i, bf); if (glyph_list[i].name == NULL) { fprintf (stderr, "****malloc failed %s line %d\n", __FILE__, __LINE__); exit(255); } } return 0; #endif /* XP_PSTEXT */ } /* * Get the metrics of the glyphs. */ static void glmetrics( GLYPH *glyph_list ) { GLYPH *g; int i; FT_Glyph_Metrics *met; FT_BBox bbox; FT_Glyph gly; #ifdef XP_ONLY_BLOCKS extern unsigned long xp_font_block_offset; extern FTFontPtr xp_xtf; int bc; /* block counter */ for( bc = xp_font_block_offset ; bc < (xp_font_block_offset+256) ; bc++ ) { /* Remap X11 font index to FreeType font index */ i = FTRemap(face, &xp_xtf->mapping, bc); if( i >= face->num_glyphs ) continue; #else for(i=0; i < face->num_glyphs; i++) { #endif /* XP_ONLY_BLOCKS */ g = &(glyph_list[i]); if( FT_Load_Glyph(face, i, FT_LOAD_NO_BITMAP|FT_LOAD_NO_SCALE) ) { fprintf(stderr, "Can't load glyph %s, skipped\n", g->name); continue; } met = &face->glyph->metrics; if(FT_HAS_HORIZONTAL(face)) { g->width = met->horiAdvance; g->lsb = met->horiBearingX; } else { WARNING_2 fprintf(stderr, "Glyph %s has no horizontal metrics, guessed them\n", g->name); g->width = met->width; g->lsb = 0; } if( FT_Get_Glyph(face->glyph, &gly) ) { fprintf(stderr, "Can't access glyph %s bbox, skipped\n", g->name); continue; } FT_Glyph_Get_CBox(gly, ft_glyph_bbox_unscaled, &bbox); g->xMin = bbox.xMin; g->yMin = bbox.yMin; g->xMax = bbox.xMax; g->yMax = bbox.yMax; g->ttf_pathlen = face->glyph->outline.n_points; } } /* * Get the original encoding of the font. * Returns 1 for if the original encoding is Unicode, 2 if the * original encoding is other 16-bit, 0 if 8-bit. */ static int glenc( GLYPH *glyph_list, int *encoding, int *unimap ) { #ifdef XP_PSTEXT int i, e; unsigned code; extern FTFontPtr xp_xtf; extern unsigned long xp_font_block_offset; enc_found = 1; enc_type = 0; for(i=0; i<ENCTABSZ; i++) { if(encoding[i] != -1) continue; /* Remap X11 font index to FreeType font index */ code = FTRemap(face, &xp_xtf->mapping, xp_font_block_offset+i); if(code == 0) continue; /* .notdef */ encoding[i] = code; } return enc_type; #else int i, e; unsigned code; if(ISDBG(FT)) for(e=0; e < face->num_charmaps; e++) { fprintf(stderr, "found encoding pid=%d eid=%d\n", face->charmaps[e]->platform_id, face->charmaps[e]->encoding_id); } if(enc_found) goto populate_map; enc_type = 0; /* first check for an explicit PID/EID */ if(force_pid != -1) { for(e=0; e < face->num_charmaps; e++) { if(face->charmaps[e]->platform_id == force_pid && face->charmaps[e]->encoding_id == force_eid) { WARNING_1 fprintf(stderr, "Found Encoding PID=%d/EID=%d\n", force_pid, force_eid); if( FT_Set_Charmap(face, face->charmaps[e]) ) { fprintf(stderr, "**** Cannot set charmap in FreeType ****\n"); exit(1); } enc_type = 1; goto populate_map; } } fprintf(stderr, "*** TTF encoding table PID=%d/EID=%d not found\n", force_pid, force_eid); exit(1); } /* next check for a direct Adobe mapping */ if(!forcemap) { for(e=0; e < face->num_charmaps; e++) { if(face->charmaps[e]->encoding == ft_encoding_adobe_custom) { WARNING_1 fputs("Found Adobe Custom Encoding\n", stderr); if( FT_Set_Charmap(face, face->charmaps[e]) ) { fprintf(stderr, "**** Cannot set charmap in FreeType ****\n"); exit(1); } goto populate_map; } } } for(e=0; e < face->num_charmaps; e++) { if(face->charmaps[e]->platform_id == 3) { switch(face->charmaps[e]->encoding_id) { case 0: WARNING_1 fputs("Found Symbol Encoding\n", stderr); break; case 1: WARNING_1 fputs("Found Unicode Encoding\n", stderr); enc_type = 1; break; default: WARNING_1 { fprintf(stderr, "****MS Encoding ID %d not supported****\n", face->charmaps[e]->encoding_id); fputs("Treating it like Symbol encoding\n", stderr); } break; } break; } } if(e >= face->num_charmaps) { WARNING_1 fputs("No Microsoft encoding, using first encoding available\n", stderr); e = 0; } if( FT_Set_Charmap(face, face->charmaps[e]) ) { fprintf(stderr, "**** Cannot set charmap in FreeType ****\n"); exit(1); } populate_map: enc_found = 1; for(i=0; i<ENCTABSZ; i++) { if(encoding[i] != -1) continue; if(enc_type == 1 || forcemap) { code = unimap[i]; if(code == (unsigned) -1) continue; } else code = i; code = FT_Get_Char_Index(face, code); if(0 && ISDBG(FT)) fprintf(stderr, "code of %3d is %3d\n", i, code); if(code == 0) continue; /* .notdef */ encoding[i] = code; } return enc_type; #endif /* XP_PSTEXT */ }
void font_instance::LoadGlyph(int glyph_id) { if ( pFont == NULL ) { return; } InitTheFace(); #ifndef USE_PANGO_WIN32 if ( !FT_IS_SCALABLE(theFace) ) { return; // bitmap font } #endif if ( id_to_no.find(glyph_id) == id_to_no.end() ) { Geom::PathBuilder path_builder; if ( nbGlyph >= maxGlyph ) { maxGlyph=2*nbGlyph+1; glyphs=(font_glyph*)realloc(glyphs,maxGlyph*sizeof(font_glyph)); } font_glyph n_g; n_g.pathvector=NULL; n_g.bbox[0]=n_g.bbox[1]=n_g.bbox[2]=n_g.bbox[3]=0; n_g.h_advance = 0; n_g.v_advance = 0; n_g.h_width = 0; n_g.v_width = 0; bool doAdd=false; #ifdef USE_PANGO_WIN32 #ifndef GGO_UNHINTED // For compatibility with old SDKs. #define GGO_UNHINTED 0x0100 #endif MAT2 identity = {{0,1},{0,0},{0,0},{0,1}}; OUTLINETEXTMETRIC otm; GetOutlineTextMetrics(daddy->hScreenDC, sizeof(otm), &otm); GLYPHMETRICS metrics; DWORD bufferSize=GetGlyphOutline (daddy->hScreenDC, glyph_id, GGO_GLYPH_INDEX | GGO_NATIVE | GGO_UNHINTED, &metrics, 0, NULL, &identity); double scale=1.0/daddy->fontSize; n_g.h_advance=metrics.gmCellIncX*scale; n_g.v_advance=otm.otmTextMetrics.tmHeight*scale; n_g.h_width=metrics.gmBlackBoxX*scale; n_g.v_width=metrics.gmBlackBoxY*scale; if ( bufferSize == GDI_ERROR) { // shit happened } else if ( bufferSize == 0) { // character has no visual representation, but is valid (eg whitespace) doAdd=true; } else { char *buffer = new char[bufferSize]; if ( GetGlyphOutline (daddy->hScreenDC, glyph_id, GGO_GLYPH_INDEX | GGO_NATIVE | GGO_UNHINTED, &metrics, bufferSize, buffer, &identity) <= 0 ) { // shit happened } else { // Platform SDK is rubbish, read KB87115 instead DWORD polyOffset=0; while ( polyOffset < bufferSize ) { TTPOLYGONHEADER const *polyHeader=(TTPOLYGONHEADER const *)(buffer+polyOffset); if (polyOffset+polyHeader->cb > bufferSize) break; if (polyHeader->dwType == TT_POLYGON_TYPE) { path_builder.moveTo(pointfx_to_nrpoint(polyHeader->pfxStart, scale)); DWORD curveOffset=polyOffset+sizeof(TTPOLYGONHEADER); while ( curveOffset < polyOffset+polyHeader->cb ) { TTPOLYCURVE const *polyCurve=(TTPOLYCURVE const *)(buffer+curveOffset); POINTFX const *p=polyCurve->apfx; POINTFX const *endp=p+polyCurve->cpfx; switch (polyCurve->wType) { case TT_PRIM_LINE: while ( p != endp ) path_builder.lineTo(pointfx_to_nrpoint(*p++, scale)); break; case TT_PRIM_QSPLINE: { g_assert(polyCurve->cpfx >= 2); // The list of points specifies one or more control points and ends with the end point. // The intermediate points (on the curve) are the points between the control points. Geom::Point this_control = pointfx_to_nrpoint(*p++, scale); while ( p+1 != endp ) { // Process all "midpoints" (all points except the last) Geom::Point new_control = pointfx_to_nrpoint(*p++, scale); path_builder.quadTo(this_control, (new_control+this_control)/2); this_control = new_control; } Geom::Point end = pointfx_to_nrpoint(*p++, scale); path_builder.quadTo(this_control, end); } break; case 3: // TT_PRIM_CSPLINE g_assert(polyCurve->cpfx % 3 == 0); while ( p != endp ) { path_builder.curveTo(pointfx_to_nrpoint(p[0], scale), pointfx_to_nrpoint(p[1], scale), pointfx_to_nrpoint(p[2], scale)); p += 3; } break; } curveOffset += sizeof(TTPOLYCURVE)+sizeof(POINTFX)*(polyCurve->cpfx-1); } } polyOffset += polyHeader->cb; } doAdd=true; } delete [] buffer; } #else if (FT_Load_Glyph (theFace, glyph_id, FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP)) { // shit happened } else { if ( FT_HAS_HORIZONTAL(theFace) ) { n_g.h_advance=((double)theFace->glyph->metrics.horiAdvance)/((double)theFace->units_per_EM); n_g.h_width=((double)theFace->glyph->metrics.width)/((double)theFace->units_per_EM); } else { n_g.h_width=n_g.h_advance=((double)(theFace->bbox.xMax-theFace->bbox.xMin))/((double)theFace->units_per_EM); } if ( FT_HAS_VERTICAL(theFace) ) { n_g.v_advance=((double)theFace->glyph->metrics.vertAdvance)/((double)theFace->units_per_EM); n_g.v_width=((double)theFace->glyph->metrics.height)/((double)theFace->units_per_EM); } else { n_g.v_width=n_g.v_advance=((double)theFace->height)/((double)theFace->units_per_EM); } if ( theFace->glyph->format == ft_glyph_format_outline ) { FT_Outline_Funcs ft2_outline_funcs = { ft2_move_to, ft2_line_to, ft2_conic_to, ft2_cubic_to, 0, 0 }; FT2GeomData user(path_builder, 1.0/((double)theFace->units_per_EM)); FT_Outline_Decompose (&theFace->glyph->outline, &ft2_outline_funcs, &user); } doAdd=true; } #endif path_builder.finish(); if ( doAdd ) { Geom::PathVector pv = path_builder.peek(); // close all paths for (Geom::PathVector::iterator i = pv.begin(); i != pv.end(); ++i) { i->close(); } if ( !pv.empty() ) { n_g.pathvector = new Geom::PathVector(pv); Geom::OptRect bounds = bounds_exact(*n_g.pathvector); if (bounds) { n_g.bbox[0] = bounds->left(); n_g.bbox[1] = bounds->top(); n_g.bbox[2] = bounds->right(); n_g.bbox[3] = bounds->bottom(); } } glyphs[nbGlyph]=n_g; id_to_no[glyph_id]=nbGlyph; nbGlyph++; } } else { } }