static FT_Error tt_size_request( FT_Size size, FT_Size_Request req ) { TT_Size ttsize = (TT_Size)size; FT_Error error = TT_Err_Ok; #ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS if ( FT_HAS_FIXED_SIZES( size->face ) ) { TT_Face ttface = (TT_Face)size->face; SFNT_Service sfnt = (SFNT_Service) ttface->sfnt; FT_ULong strike_index; error = sfnt->set_sbit_strike( ttface, req, &strike_index ); if ( error ) ttsize->strike_index = 0xFFFFFFFFUL; else return tt_size_select( size, strike_index ); } #endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ FT_Request_Metrics( size->face, req ); if ( FT_IS_SCALABLE( size->face ) ) { error = tt_size_reset( ttsize ); ttsize->root.metrics = ttsize->metrics; } return error; }
bool initFaceSize(Font font, const unsigned int size, const unsigned int res = 72) { FT_Face fontFace = font->ftFace; FT_Size fontSize; if (FT_Select_Charmap(fontFace, FT_ENCODING_UNICODE) || FT_Set_Char_Size(fontFace, 0L, size * 64, res, res)) return false; font->charSize = size; fontSize = font->ftSize = fontFace->size; if(FT_IS_SCALABLE((fontFace))) { font->glyphWidth = (fontFace->bbox.xMax-fontFace->bbox.xMin) * ((float)(fontSize->metrics.x_ppem)/(float)(fontFace->units_per_EM)); font->glyphHeight = (fontFace->bbox.yMax-fontFace->bbox.yMin) * ((float)fontSize->metrics.y_ppem/(float)fontFace->units_per_EM); } else { font->glyphWidth = static_cast<float>(fontSize->metrics.max_advance)/64.0f; font->glyphHeight = static_cast<float>(fontSize->metrics.height)/64.0f; } return true; }
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 { } }
sfnt_load_face(FT_Stream stream, TT_Face face, FT_Int face_index, FT_Int num_params, FT_Parameter * params) { FT_Error error; #ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES FT_Error psnames_error; #endif FT_Bool has_outline; FT_Bool is_apple_sbit; FT_Bool ignore_preferred_family = FALSE; FT_Bool ignore_preferred_subfamily = FALSE; SFNT_Service sfnt = (SFNT_Service)face->sfnt; FT_UNUSED(face_index); /* Check parameters */ { FT_Int i; for (i = 0; i < num_params; i++) { if (params[i].tag == FT_PARAM_TAG_IGNORE_PREFERRED_FAMILY) ignore_preferred_family = TRUE; else if (params[i].tag == FT_PARAM_TAG_IGNORE_PREFERRED_SUBFAMILY) ignore_preferred_subfamily = TRUE; } } /* Load tables */ /* We now support two SFNT-based bitmapped font formats. They */ /* are recognized easily as they do not include a `glyf' */ /* table. */ /* */ /* The first format comes from Apple, and uses a table named */ /* `bhed' instead of `head' to store the font header (using */ /* the same format). It also doesn't include horizontal and */ /* vertical metrics tables (i.e. `hhea' and `vhea' tables are */ /* missing). */ /* */ /* The other format comes from Microsoft, and is used with */ /* WinCE/PocketPC. It looks like a standard TTF, except that */ /* it doesn't contain outlines. */ /* */ FT_TRACE2(("sfnt_load_face: %08p\n\n", face)); /* do we have outlines in there? */ #ifdef FT_CONFIG_OPTION_INCREMENTAL has_outline = FT_BOOL(face->root.internal->incremental_interface != 0 || tt_face_lookup_table(face, TTAG_glyf) != 0 || tt_face_lookup_table(face, TTAG_CFF) != 0); #else has_outline = FT_BOOL(tt_face_lookup_table(face, TTAG_glyf) != 0 || tt_face_lookup_table(face, TTAG_CFF) != 0); #endif is_apple_sbit = 0; /* if this font doesn't contain outlines, we try to load */ /* a `bhed' table */ if (!has_outline && sfnt->load_bhed) { LOAD_(bhed); is_apple_sbit = FT_BOOL(!error); } /* load the font header (`head' table) if this isn't an Apple */ /* sbit font file */ if (!is_apple_sbit) { LOAD_(head); if (error) goto Exit; } if (face->header.Units_Per_EM == 0) { error = SFNT_Err_Invalid_Table; goto Exit; } /* the following tables are often not present in embedded TrueType */ /* fonts within PDF documents, so don't check for them. */ LOAD_(maxp); LOAD_(cmap); /* the following tables are optional in PCL fonts -- */ /* don't check for errors */ LOAD_(name); LOAD_(post); #ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES psnames_error = error; #endif /* do not load the metrics headers and tables if this is an Apple */ /* sbit font file */ if (!is_apple_sbit) { /* load the `hhea' and `hmtx' tables */ LOADM_(hhea, 0); if (!error) { LOADM_(hmtx, 0); if (error == SFNT_Err_Table_Missing) { error = SFNT_Err_Hmtx_Table_Missing; #ifdef FT_CONFIG_OPTION_INCREMENTAL /* If this is an incrementally loaded font and there are */ /* overriding metrics, tolerate a missing `hmtx' table. */ if (face->root.internal->incremental_interface && face->root.internal->incremental_interface->funcs-> get_glyph_metrics) { face->horizontal.number_Of_HMetrics = 0; error = SFNT_Err_Ok; } #endif } } else if (error == SFNT_Err_Table_Missing) { /* No `hhea' table necessary for SFNT Mac fonts. */ if (face->format_tag == TTAG_true) { FT_TRACE2(("This is an SFNT Mac font.\n")); has_outline = 0; error = SFNT_Err_Ok; } else { error = SFNT_Err_Horiz_Header_Missing; #ifdef FT_CONFIG_OPTION_INCREMENTAL /* If this is an incrementally loaded font and there are */ /* overriding metrics, tolerate a missing `hhea' table. */ if (face->root.internal->incremental_interface && face->root.internal->incremental_interface->funcs-> get_glyph_metrics) { face->horizontal.number_Of_HMetrics = 0; error = SFNT_Err_Ok; } #endif } } if (error) goto Exit; /* try to load the `vhea' and `vmtx' tables */ LOADM_(hhea, 1); if (!error) { LOADM_(hmtx, 1); if (!error) face->vertical_info = 1; } if (error && error != SFNT_Err_Table_Missing) goto Exit; LOAD_(os2); if (error) { if (error != SFNT_Err_Table_Missing) goto Exit; face->os2.version = 0xFFFFU; } } /* the optional tables */ /* embedded bitmap support */ if (sfnt->load_eblc) { LOAD_(eblc); if (error) { /* a font which contains neither bitmaps nor outlines is */ /* still valid (although rather useless in most cases); */ /* however, you can find such stripped fonts in PDFs */ if (error == SFNT_Err_Table_Missing) error = SFNT_Err_Ok; else goto Exit; } } LOAD_(pclt); if (error) { if (error != SFNT_Err_Table_Missing) goto Exit; face->pclt.Version = 0; } /* consider the kerning and gasp tables as optional */ LOAD_(gasp); LOAD_(kern); face->root.num_glyphs = face->max_profile.numGlyphs; /* Bit 8 of the `fsSelection' field in the `OS/2' table denotes */ /* a WWS-only font face. `WWS' stands for `weight', width', and */ /* `slope', a term used by Microsoft's Windows Presentation */ /* Foundation (WPF). This flag has been introduced in version */ /* 1.5 of the OpenType specification (May 2008). */ face->root.family_name = NULL; face->root.style_name = NULL; if (face->os2.version != 0xFFFFU && face->os2.fsSelection & 256) { if (!ignore_preferred_family) GET_NAME(PREFERRED_FAMILY, &face->root.family_name); if (!face->root.family_name) GET_NAME(FONT_FAMILY, &face->root.family_name); if (!ignore_preferred_subfamily) GET_NAME(PREFERRED_SUBFAMILY, &face->root.style_name); if (!face->root.style_name) GET_NAME(FONT_SUBFAMILY, &face->root.style_name); } else { GET_NAME(WWS_FAMILY, &face->root.family_name); if (!face->root.family_name && !ignore_preferred_family) GET_NAME(PREFERRED_FAMILY, &face->root.family_name); if (!face->root.family_name) GET_NAME(FONT_FAMILY, &face->root.family_name); GET_NAME(WWS_SUBFAMILY, &face->root.style_name); if (!face->root.style_name && !ignore_preferred_subfamily) GET_NAME(PREFERRED_SUBFAMILY, &face->root.style_name); if (!face->root.style_name) GET_NAME(FONT_SUBFAMILY, &face->root.style_name); } /* now set up root fields */ { FT_Face root = &face->root; FT_Long flags = root->face_flags; /*********************************************************************/ /* */ /* Compute face flags. */ /* */ if (has_outline == TRUE) flags |= FT_FACE_FLAG_SCALABLE; /* scalable outlines */ /* The sfnt driver only supports bitmap fonts natively, thus we */ /* don't set FT_FACE_FLAG_HINTER. */ flags |= FT_FACE_FLAG_SFNT | /* SFNT file format */ FT_FACE_FLAG_HORIZONTAL; /* horizontal data */ #ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES if (psnames_error == SFNT_Err_Ok && face->postscript.FormatType != 0x00030000L) flags |= FT_FACE_FLAG_GLYPH_NAMES; #endif /* fixed width font? */ if (face->postscript.isFixedPitch) flags |= FT_FACE_FLAG_FIXED_WIDTH; /* vertical information? */ if (face->vertical_info) flags |= FT_FACE_FLAG_VERTICAL; /* kerning available ? */ if (TT_FACE_HAS_KERNING(face)) flags |= FT_FACE_FLAG_KERNING; #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT /* Don't bother to load the tables unless somebody asks for them. */ /* No need to do work which will (probably) not be used. */ if (tt_face_lookup_table(face, TTAG_glyf) != 0 && tt_face_lookup_table(face, TTAG_fvar) != 0 && tt_face_lookup_table(face, TTAG_gvar) != 0) flags |= FT_FACE_FLAG_MULTIPLE_MASTERS; #endif root->face_flags = flags; /*********************************************************************/ /* */ /* Compute style flags. */ /* */ flags = 0; if (has_outline == TRUE && face->os2.version != 0xFFFFU) { /* We have an OS/2 table; use the `fsSelection' field. Bit 9 */ /* indicates an oblique font face. This flag has been */ /* introduced in version 1.5 of the OpenType specification. */ if (face->os2.fsSelection & 512) /* bit 9 */ flags |= FT_STYLE_FLAG_ITALIC; else if (face->os2.fsSelection & 1) /* bit 0 */ flags |= FT_STYLE_FLAG_ITALIC; if (face->os2.fsSelection & 32) /* bit 5 */ flags |= FT_STYLE_FLAG_BOLD; } else { /* this is an old Mac font, use the header field */ if (face->header.Mac_Style & 1) flags |= FT_STYLE_FLAG_BOLD; if (face->header.Mac_Style & 2) flags |= FT_STYLE_FLAG_ITALIC; } root->style_flags = flags; /*********************************************************************/ /* */ /* Polish the charmaps. */ /* */ /* Try to set the charmap encoding according to the platform & */ /* encoding ID of each charmap. */ /* */ tt_face_build_cmaps(face); /* ignore errors */ /* set the encoding fields */ { FT_Int m; for (m = 0; m < root->num_charmaps; m++) { FT_CharMap charmap = root->charmaps[m]; charmap->encoding = sfnt_find_encoding(charmap->platform_id, charmap->encoding_id); #if 0 if (root->charmap == NULL && charmap->encoding == FT_ENCODING_UNICODE) { /* set 'root->charmap' to the first Unicode encoding we find */ root->charmap = charmap; } #endif } } #ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS /* * Now allocate the root array of FT_Bitmap_Size records and * populate them. Unfortunately, it isn't possible to indicate bit * depths in the FT_Bitmap_Size record. This is a design error. */ { FT_UInt i, count; #ifndef FT_CONFIG_OPTION_OLD_INTERNALS count = face->sbit_num_strikes; #else count = (FT_UInt)face->num_sbit_strikes; #endif if (count > 0) { FT_Memory memory = face->root.stream->memory; FT_UShort em_size = face->header.Units_Per_EM; FT_Short avgwidth = face->os2.xAvgCharWidth; FT_Size_Metrics metrics; if (em_size == 0 || face->os2.version == 0xFFFFU) { avgwidth = 0; em_size = 1; } if (FT_NEW_ARRAY(root->available_sizes, count)) goto Exit; for (i = 0; i < count; i++) { FT_Bitmap_Size *bsize = root->available_sizes + i; error = sfnt->load_strike_metrics(face, i, &metrics); if (error) goto Exit; bsize->height = (FT_Short)(metrics.height >> 6); bsize->width = (FT_Short)( (avgwidth * metrics.x_ppem + em_size / 2) / em_size); bsize->x_ppem = metrics.x_ppem << 6; bsize->y_ppem = metrics.y_ppem << 6; /* assume 72dpi */ bsize->size = metrics.y_ppem << 6; } root->face_flags |= FT_FACE_FLAG_FIXED_SIZES; root->num_fixed_sizes = (FT_Int)count; } } #endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ /* a font with no bitmaps and no outlines is scalable; */ /* it has only empty glyphs then */ if (!FT_HAS_FIXED_SIZES(root) && !FT_IS_SCALABLE(root)) root->face_flags |= FT_FACE_FLAG_SCALABLE; /*********************************************************************/ /* */ /* Set up metrics. */ /* */ if (FT_IS_SCALABLE(root)) { /* XXX What about if outline header is missing */ /* (e.g. sfnt wrapped bitmap)? */ root->bbox.xMin = face->header.xMin; root->bbox.yMin = face->header.yMin; root->bbox.xMax = face->header.xMax; root->bbox.yMax = face->header.yMax; root->units_per_EM = face->header.Units_Per_EM; /* XXX: Computing the ascender/descender/height is very different */ /* from what the specification tells you. Apparently, we */ /* must be careful because */ /* */ /* - not all fonts have an OS/2 table; in this case, we take */ /* the values in the horizontal header. However, these */ /* values very often are not reliable. */ /* */ /* - otherwise, the correct typographic values are in the */ /* sTypoAscender, sTypoDescender & sTypoLineGap fields. */ /* */ /* However, certain fonts have these fields set to 0. */ /* Rather, they have usWinAscent & usWinDescent correctly */ /* set (but with different values). */ /* */ /* As an example, Arial Narrow is implemented through four */ /* files ARIALN.TTF, ARIALNI.TTF, ARIALNB.TTF & ARIALNBI.TTF */ /* */ /* Strangely, all fonts have the same values in their */ /* sTypoXXX fields, except ARIALNB which sets them to 0. */ /* */ /* On the other hand, they all have different */ /* usWinAscent/Descent values -- as a conclusion, the OS/2 */ /* table cannot be used to compute the text height reliably! */ /* */ /* The ascender/descender/height are computed from the OS/2 table */ /* when found. Otherwise, they're taken from the horizontal */ /* header. */ /* */ root->ascender = face->horizontal.Ascender; root->descender = face->horizontal.Descender; root->height = (FT_Short)(root->ascender - root->descender + face->horizontal.Line_Gap); #if 0 /* if the line_gap is 0, we add an extra 15% to the text height -- */ /* this computation is based on various versions of Times New Roman */ if (face->horizontal.Line_Gap == 0) root->height = (FT_Short)((root->height * 115 + 50) / 100); #endif /* 0 */ #if 0 /* some fonts have the OS/2 "sTypoAscender", "sTypoDescender" & */ /* "sTypoLineGap" fields set to 0, like ARIALNB.TTF */ if (face->os2.version != 0xFFFFU && root->ascender) { FT_Int height; root->ascender = face->os2.sTypoAscender; root->descender = -face->os2.sTypoDescender; height = root->ascender + root->descender + face->os2.sTypoLineGap; if (height > root->height) root->height = height; } #endif /* 0 */ root->max_advance_width = face->horizontal.advance_Width_Max; root->max_advance_height = (FT_Short)(face->vertical_info ? face->vertical.advance_Height_Max : root->height); /* See http://www.microsoft.com/OpenType/OTSpec/post.htm -- */ /* Adjust underline position from top edge to centre of */ /* stroke to convert TrueType meaning to FreeType meaning. */ root->underline_position = face->postscript.underlinePosition - face->postscript.underlineThickness / 2; root->underline_thickness = face->postscript.underlineThickness; } }
EFontFT2::EFontFT2(const EEntry *entry, eint32 faceIndex) : EFontEngine(), fFilename(NULL), fFaceIndex(-1), nFaces(-1), fFace(NULL), fScalable(false), fForceFontAliasing(false) { EPath aPath; if(entry == NULL || entry->Exists() == false || entry->GetPath(&aPath) != E_OK) return; EString filename = aPath.Path(); #ifdef _WIN32 filename.ReplaceAll("/", "\\"); #endif SetRenderMode(E_FONT_RENDER_PIXMAP); EAutolock <ELocker> autolock(&etk_ft2_font_locker); if(!_etk_ft2_initialized_) return; FT_Error error = FT_New_Face(_etk_ft2_library_, filename.String(), faceIndex, &fFace); if(error || !fFace) { ETK_DEBUG("[FONT]: %s --- CAN NOT load face[%s:%d].", __PRETTY_FUNCTION__, aPath.Path(), faceIndex); return; } if(FT_Select_Charmap(fFace, FT_ENCODING_UNICODE)) { // ETK_DEBUG("[FONT]: %s --- font[%s] don't support ENCODING_UNICODE.", __PRETTY_FUNCTION__, aPath.Path()); if(FT_Select_Charmap(fFace, FT_ENCODING_NONE)) { // ETK_WARNING("[FONT]: %s --- font[%s] don't support unicode at all.", __PRETTY_FUNCTION__, aPath.Path()); FT_Done_Face(fFace); fFace = NULL; return; } } fFilename = EStrdup(filename.String()); fFaceIndex = faceIndex; nFaces = fFace->num_faces; EString family = fFace->family_name; if(family.Length() <= 0) { family = aPath.Leaf(); eint32 cFound; if((cFound = family.FindFirst('.')) >= 0) family.Remove(cFound, -1); if(family.Length() < 0) family = "Unknown"; } SetFamily(family.String()); EString style = fFace->style_name; if(style.Length() <= 0) { if((fFace->style_flags & FT_STYLE_FLAG_BOLD) && (fFace->style_flags & FT_STYLE_FLAG_ITALIC)) style = "Bold Italic"; else if(fFace->style_flags & FT_STYLE_FLAG_BOLD) style = "Bold"; else if(fFace->style_flags & FT_STYLE_FLAG_ITALIC) style = "Italic"; else style = "Regular"; } SetStyle(style.String()); if(FT_IS_SCALABLE(fFace)) fScalable = true; if(fFace->num_fixed_sizes > 0) { float *sizes = new float[(int)fFace->num_fixed_sizes]; for(int i = 0; i < fFace->num_fixed_sizes; i++) sizes[i] = (float)(fFace->available_sizes[i].height); SetFixedSize(sizes, (eint32)fFace->num_fixed_sizes); delete[] sizes; } FT_Done_Face(fFace); fFace = NULL; }
static FT_Error Load_Glyph(TTF_Font * font, Uint16 ch, c_glyph * cached, int want) { FT_Face face; FT_Error error; FT_GlyphSlot glyph; FT_Glyph_Metrics *metrics; FT_Outline *outline; if(!font || !font->face) { return FT_Err_Invalid_Handle; } face = font->face; /* Load the glyph */ if(!cached->index) { cached->index = FT_Get_Char_Index(face, ch); } error = FT_Load_Glyph(face, cached->index, FT_LOAD_DEFAULT); if(error) { return error; } /* Get our glyph shortcuts */ glyph = face->glyph; metrics = &glyph->metrics; outline = &glyph->outline; /* Get the glyph metrics if desired */ if((want & CACHED_METRICS) && !(cached->stored & CACHED_METRICS)) { if(FT_IS_SCALABLE(face)) { /* Get the bounding box */ cached->minx = FT_FLOOR(metrics->horiBearingX); cached->maxx = cached->minx + FT_CEIL(metrics->width); cached->maxy = FT_FLOOR(metrics->horiBearingY); cached->miny = cached->maxy - FT_CEIL(metrics->height); cached->yoffset = font->ascent - cached->maxy; cached->advance = FT_CEIL(metrics->horiAdvance); } else { /* Get the bounding box for non-scalable format. * Again, freetype2 fills in many of the font metrics * with the value of 0, so some of the values we * need must be calculated differently with certain * assumptions about non-scalable formats. * */ cached->minx = FT_FLOOR(metrics->horiBearingX); cached->maxx = cached->minx + FT_CEIL(metrics->horiAdvance); cached->maxy = FT_FLOOR(metrics->horiBearingY); cached->miny = cached->maxy - FT_CEIL(face->available_sizes[font->font_size_family].height); cached->yoffset = 0; cached->advance = FT_CEIL(metrics->horiAdvance); } /* Adjust for bold and italic text */ if(font->style & TTF_STYLE_BOLD) { cached->maxx += font->glyph_overhang; } if(font->style & TTF_STYLE_ITALIC) { cached->maxx += (int) ceil(font->glyph_italics); } cached->stored |= CACHED_METRICS; } if(((want & CACHED_BITMAP) && !(cached->stored & CACHED_BITMAP)) || ((want & CACHED_PIXMAP) && !(cached->stored & CACHED_PIXMAP))) { int mono = (want & CACHED_BITMAP); int i; FT_Bitmap *src; FT_Bitmap *dst; /* Handle the italic style */ if(font->style & TTF_STYLE_ITALIC) { FT_Matrix shear; shear.xx = 1 << 16; shear.xy = (int) (font->glyph_italics * (1 << 16)) / font->height; shear.yx = 0; shear.yy = 1 << 16; FT_Outline_Transform(outline, &shear); } /* Render the glyph */ if(mono) { error = FT_Render_Glyph(glyph, ft_render_mode_mono); } else { error = FT_Render_Glyph(glyph, ft_render_mode_normal); } if(error) { return error; } /* Copy over information to cache */ src = &glyph->bitmap; if(mono) { dst = &cached->bitmap; } else { dst = &cached->pixmap; } memcpy(dst, src, sizeof(*dst)); /* FT_Render_Glyph() and .fon fonts always generate a * two-color (black and white) glyphslot surface, even * when rendered in ft_render_mode_normal. This is probably * a freetype2 bug because it is inconsistent with the * freetype2 documentation under FT_Render_Mode section. * */ if(mono || !FT_IS_SCALABLE(face)) { dst->pitch *= 8; } /* Adjust for bold and italic text */ if(font->style & TTF_STYLE_BOLD) { int bump = font->glyph_overhang; dst->pitch += bump; dst->width += bump; } if(font->style & TTF_STYLE_ITALIC) { int bump = (int) ceil(font->glyph_italics); dst->pitch += bump; dst->width += bump; } if(dst->rows != 0) { dst->buffer = (unsigned char *) malloc(dst->pitch * dst->rows); if(!dst->buffer) { return FT_Err_Out_Of_Memory; } memset(dst->buffer, 0, dst->pitch * dst->rows); for(i = 0; i < src->rows; i++) { int soffset = i * src->pitch; int doffset = i * dst->pitch; if(mono) { unsigned char *srcp = src->buffer + soffset; unsigned char *dstp = dst->buffer + doffset; int j; for(j = 0; j < src->width; j += 8) { unsigned char ch = *srcp++; *dstp++ = (ch & 0x80) >> 7; ch <<= 1; *dstp++ = (ch & 0x80) >> 7; ch <<= 1; *dstp++ = (ch & 0x80) >> 7; ch <<= 1; *dstp++ = (ch & 0x80) >> 7; ch <<= 1; *dstp++ = (ch & 0x80) >> 7; ch <<= 1; *dstp++ = (ch & 0x80) >> 7; ch <<= 1; *dstp++ = (ch & 0x80) >> 7; ch <<= 1; *dstp++ = (ch & 0x80) >> 7; } } else if(!FT_IS_SCALABLE(face)) { /* This special case wouldn't * be here if the FT_Render_Glyph() * function wasn't buggy when it tried * to render a .fon font with 256 * shades of gray. Instead, it * returns a black and white surface * and we have to translate it back * to a 256 gray shaded surface. * */ unsigned char *srcp = src->buffer + soffset; unsigned char *dstp = dst->buffer + doffset; unsigned char ch; int j, k; for(j = 0; j < src->width; j += 8) { ch = *srcp++; for(k = 0; k < 8; ++k) { if((ch & 0x80) >> 7) { *dstp++ = NUM_GRAYS - 1; } else { *dstp++ = 0x00; } ch <<= 1; } }
bool TTFFont::load(Common::SeekableReadStream &stream, int size, bool monochrome, const uint32 *mapping) { if (!g_ttf.isInitialized()) return false; _size = stream.size(); if (!_size) return false; _ttfFile = new uint8[_size]; assert(_ttfFile); if (stream.read(_ttfFile, _size) != _size) { delete[] _ttfFile; _ttfFile = 0; return false; } if (!g_ttf.loadFont(_ttfFile, _size, _face)) { delete[] _ttfFile; _ttfFile = 0; return false; } // We only support scalable fonts. if (!FT_IS_SCALABLE(_face)) { delete[] _ttfFile; _ttfFile = 0; g_ttf.closeFont(_face); return false; } // Check whether we have kerning support _hasKerning = (FT_HAS_KERNING(_face) != 0); if (FT_Set_Char_Size(_face, 0, size * 64, 0, 0)) { delete[] _ttfFile; _ttfFile = 0; return false; } _monochrome = monochrome; FT_Fixed yScale = _face->size->metrics.y_scale; _ascent = ftCeil26_6(FT_MulFix(_face->ascender, yScale)); _descent = ftCeil26_6(FT_MulFix(_face->descender, yScale)); _width = ftCeil26_6(FT_MulFix(_face->max_advance_width, _face->size->metrics.x_scale)); _height = _ascent - _descent + 1; if (!mapping) { // Load all ISO-8859-1 characters. for (uint i = 0; i < 256; ++i) { if (!cacheGlyph(_glyphs[i], _glyphSlots[i], i)) _glyphSlots[i] = 0; } } else { for (uint i = 0; i < 256; ++i) { const uint32 unicode = mapping[i] & 0x7FFFFFFF; const bool isRequired = (mapping[i] & 0x80000000) != 0; // Check whether loading an important glyph fails and error out if // that is the case. if (!cacheGlyph(_glyphs[i], _glyphSlots[i], unicode)) { _glyphSlots[i] = 0; if (isRequired) return false; } } } _initialized = (_glyphs.size() != 0); return _initialized; }
//------------------------------------------------------------------------ bool font_engine_freetype_base::load_font(const char* font_name, unsigned face_index, glyph_rendering ren_type, const char* font_mem, const long font_mem_size) { bool ret = false; if(m_library_initialized) { m_last_error = 0; int idx = find_face(font_name); if(idx >= 0) { m_cur_face = m_faces[idx]; m_name = m_face_names[idx]; } else { if(m_num_faces >= m_max_faces) { delete [] m_face_names[0]; FT_Done_Face(m_faces[0]); memcpy(m_faces, m_faces + 1, (m_max_faces - 1) * sizeof(FT_Face)); memcpy(m_face_names, m_face_names + 1, (m_max_faces - 1) * sizeof(char*)); m_num_faces = m_max_faces - 1; } if (font_mem && font_mem_size) { m_last_error = FT_New_Memory_Face(m_library, (const FT_Byte*)font_mem, font_mem_size, face_index, &m_faces[m_num_faces]); } else { m_last_error = FT_New_Face(m_library, font_name, face_index, &m_faces[m_num_faces]); } if(m_last_error == 0) { m_face_names[m_num_faces] = new char [strlen(font_name) + 1]; strcpy(m_face_names[m_num_faces], font_name); m_cur_face = m_faces[m_num_faces]; m_name = m_face_names[m_num_faces]; ++m_num_faces; } else { m_face_names[m_num_faces] = 0; m_cur_face = 0; m_name = 0; } } if(m_last_error == 0) { ret = true; switch(ren_type) { case glyph_ren_native_mono: m_glyph_rendering = glyph_ren_native_mono; break; case glyph_ren_native_gray8: m_glyph_rendering = glyph_ren_native_gray8; break; case glyph_ren_outline: if(FT_IS_SCALABLE(m_cur_face)) { m_glyph_rendering = glyph_ren_outline; } else { m_glyph_rendering = glyph_ren_native_gray8; } break; case glyph_ren_agg_mono: if(FT_IS_SCALABLE(m_cur_face)) { m_glyph_rendering = glyph_ren_agg_mono; } else { m_glyph_rendering = glyph_ren_native_mono; } break; case glyph_ren_agg_gray8: if(FT_IS_SCALABLE(m_cur_face)) { m_glyph_rendering = glyph_ren_agg_gray8; } else { m_glyph_rendering = glyph_ren_native_gray8; } break; } update_signature(); } } return ret; }
font::font( FT_Face face, std::string fam, std::string style, double pixsize ) : script::font( std::move( fam ), std::move( style ), pixsize ), _face( face ) { auto err = FT_Select_Charmap( _face, FT_ENCODING_UNICODE ); if ( err ) { std::cerr << "ERROR selecting UNICODE charmap: [" << FT_Errors[err].code << "] " << FT_Errors[err].message << std::endl; if ( _face->charmaps ) { err = FT_Set_Charmap( _face, _face->charmaps[0] ); if ( err ) throw std::runtime_error( errorstr( err ) ); } else throw std::runtime_error( "Unable to select any character map" ); } std::cout << "Need to add global DPI accessor somehow (multiple screens?)" << std::endl; static const int theDPI = 95; if ( FT_IS_SCALABLE( _face ) ) { err = FT_Set_Char_Size( _face, static_cast<int>( pixsize * 64.0 ), 0, theDPI, theDPI ); if ( err ) throw std::runtime_error( "Unable to set character size" ); } else if ( _face->num_fixed_sizes > 1 ) { int targsize = static_cast<int>( pixsize ); int bestSize[2]; bestSize[0] = bestSize[1] = targsize; int i; for ( i = 0; i != _face->num_fixed_sizes; ++i ) { if ( _face->available_sizes[i].width == targsize ) { bestSize[1] = _face->available_sizes[i].height; break; } else if ( _face->available_sizes[i].width > targsize && bestSize[0] > _face->available_sizes[i].width ) { bestSize[0] = _face->available_sizes[i].width; bestSize[1] = _face->available_sizes[i].height; } } if ( i == _face->num_fixed_sizes ) _size = bestSize[0]; // otherwise we have to use FT_Set_Pixel_Sizes err = FT_Set_Pixel_Sizes( _face, static_cast<FT_UInt>( bestSize[0] ), static_cast<FT_UInt>( bestSize[1] ) ); if ( err ) throw std::runtime_error( "Unable to set fixed character size" ); } _extents.ascent = static_cast<double>( _face->size->metrics.ascender ) / 64.0; _extents.descent = static_cast<double>( _face->size->metrics.descender ) / 64.0; if ( FT_IS_SCALABLE( _face ) ) { double scaleX = ( static_cast<double>( _face->size->metrics.x_ppem ) / static_cast<double>( _face->units_per_EM ) ); double scaleY = ( static_cast<double>( _face->size->metrics.y_ppem ) / static_cast<double>( _face->units_per_EM ) ); _extents.width = std::ceil( static_cast<double>( _face->bbox.xMax - _face->bbox.xMin ) * scaleX ); _extents.height = static_cast<double>( _face->size->metrics.height ) / 64.0; // was: std::ceil( static_cast<double>( _face->bbox.yMax - _face->bbox.yMin ) * scaleY ); _extents.max_x_advance = static_cast<double>( _face->max_advance_width ) * scaleX; _extents.max_y_advance = static_cast<double>( _face->max_advance_height ) * scaleY; } else { _extents.width = static_cast<double>( _face->size->metrics.max_advance ) / 64.0; _extents.height = static_cast<double>( _face->size->metrics.height ) / 64.0; _extents.max_x_advance = static_cast<double>( _face->size->metrics.max_advance ) / 64.0; _extents.max_y_advance = 0.0; } }
TTF_Font* TTF_OpenFontIndexRW( FILE* src, int freesrc, int ptsize, long index ) { TTF_Font* font; FT_Error error; FT_Face face; FT_Fixed scale; FT_Stream stream; FT_CharMap found; int position, i; if ( ! TTF_initialized ) { TTF_SetError( "Library not initialized" ); return NULL; } /* Check to make sure we can seek in this stream */ position = ftell(src); if ( position < 0 ) { TTF_SetError( "Can't seek in stream" ); return NULL; } font = (TTF_Font*) malloc(sizeof *font); if ( font == NULL ) { TTF_SetError( "Out of memory" ); return NULL; } memset(font, 0, sizeof(*font)); font->src = src; font->freesrc = freesrc; stream = (FT_Stream)malloc(sizeof(*stream)); if ( stream == NULL ) { TTF_SetError( "Out of memory" ); TTF_CloseFont( font ); return NULL; } memset(stream, 0, sizeof(*stream)); stream->read = ft_read; stream->descriptor.pointer = src; stream->pos = (unsigned long)position; fseek(src, 0, SEEK_END); stream->size = (unsigned long)(ftell(src) - position); fseek(src, position, SEEK_SET); font->args.flags = FT_OPEN_STREAM; font->args.stream = stream; error = FT_Open_Face( library, &font->args, index, &font->face ); if( error ) { TTF_SetFTError( "Couldn't load font file", error ); TTF_CloseFont( font ); return NULL; } face = font->face; /* Set charmap for loaded font */ found = 0; for (i = 0; i < face->num_charmaps; i++) { FT_CharMap charmap = face->charmaps[i]; /* Windows Unicode */ if ((charmap->platform_id == 3 && charmap->encoding_id == 1) /* Windows Symbol */ || (charmap->platform_id == 3 && charmap->encoding_id == 0) /* ISO Unicode */ || (charmap->platform_id == 2 && charmap->encoding_id == 1) /* Apple Unicode */ || (charmap->platform_id == 0)) { found = charmap; break; } } if ( found ) { /* If this fails, continue using the default charmap */ FT_Set_Charmap(face, found); } /* Make sure that our font face is scalable (global metrics) */ if ( FT_IS_SCALABLE(face) ) { /* Set the character size and use default DPI (72) */ error = FT_Set_Char_Size( font->face, 0, ptsize * 64, 0, 0 ); if( error ) { TTF_SetFTError( "Couldn't set font size", error ); TTF_CloseFont( font ); return NULL; } /* Get the scalable font metrics for this font */ scale = face->size->metrics.y_scale; font->ascent = FT_CEIL(FT_MulFix(face->ascender, scale)); font->descent = FT_CEIL(FT_MulFix(face->descender, scale)); font->height = font->ascent - font->descent + /* baseline */ 1; font->lineskip = FT_CEIL(FT_MulFix(face->height, scale)); font->underline_offset = FT_FLOOR( FT_MulFix(face->underline_position, scale)); font->underline_height = FT_FLOOR( FT_MulFix(face->underline_thickness, scale)); } else { /* Non-scalable font case. ptsize determines which family * or series of fonts to grab from the non-scalable format. * It is not the point size of the font. * */ if ( ptsize >= font->face->num_fixed_sizes ) ptsize = font->face->num_fixed_sizes - 1; font->font_size_family = ptsize; error = FT_Set_Pixel_Sizes( face, face->available_sizes[ptsize].height, face->available_sizes[ptsize].width ); /* With non-scalale fonts, Freetype2 likes to fill many of the * font metrics with the value of 0. The size of the * non-scalable fonts must be determined differently * or sometimes cannot be determined. * */ font->ascent = face->available_sizes[ptsize].height; font->descent = 0; font->height = face->available_sizes[ptsize].height; font->lineskip = FT_CEIL(font->ascent); font->underline_offset = FT_FLOOR(face->underline_position); font->underline_height = FT_FLOOR(face->underline_thickness); } if ( font->underline_height < 1 ) { font->underline_height = 1; } #ifdef DEBUG_FONTS printf("Font metrics:\n"); printf("\tascent = %d, descent = %d\n", font->ascent, font->descent); printf("\theight = %d, lineskip = %d\n", font->height, font->lineskip); printf("\tunderline_offset = %d, underline_height = %d\n", font->underline_offset, font->underline_height); printf("\tunderline_top_row = %d, strikethrough_top_row = %d\n", TTF_underline_top_row(font), TTF_strikethrough_top_row(font)); #endif /* Initialize the font face style */ font->face_style = TTF_STYLE_NORMAL; if ( font->face->style_flags & FT_STYLE_FLAG_BOLD ) { font->face_style |= TTF_STYLE_BOLD; } if ( font->face->style_flags & FT_STYLE_FLAG_ITALIC ) { font->face_style |= TTF_STYLE_ITALIC; } /* Set the default font style */ font->style = font->face_style; font->outline = 0; font->kerning = 1; font->glyph_overhang = face->size->metrics.y_ppem / 10; /* x offset = cos(((90.0-12)/360)*2*M_PI), or 12 degree angle */ font->glyph_italics = 0.207f; font->glyph_italics *= font->height; return font; }
BOOL KG3DFontTexture::Initialize(LPCSTR szName, float fPixel, DWORD dwStyle) { static FT_Long const DEFAULT_FACE_INDEX = 0; int nRetCode = false; int nResult = false; KG3DFTFontLibrary* pFontLibrary = NULL; FT_Face pFontFace = NULL; FT_Error nError = 0; FT_F26Dot6 FontSize = 0; BOOL bUnicode = FALSE; UINT uEncoding = FT_ENCODING_UNICODE; if (dwStyle & KG3DUI_TEXT_STYLE_MONO) { m_InitParams.dwRenderMode = FT_RENDER_MODE_MONO; m_InitParams.dwLoadFlag = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH | FT_LOAD_NO_HINTING; } else { m_InitParams.dwRenderMode = FT_RENDER_MODE_LIGHT; m_InitParams.dwLoadFlag = FT_LOAD_TARGET_LIGHT | FT_LOAD_MONOCHROME; } _tcsncpy(m_InitParams.szName, szName, _countof(m_InitParams.szName)); m_InitParams.szName[_countof(m_InitParams.szName) - 1] = _T('\0'); m_InitParams.fPixel = fPixel; m_InitParams.dwStyle = dwStyle; pFontLibrary = KG3DFTFontLibrary::Instance(); KGLOG_PROCESS_ERROR(pFontLibrary); nRetCode = s_FontFacePool.Load(pFontLibrary->m_library, m_InitParams.szName, DEFAULT_FACE_INDEX, &pFontFace); KGLOG_PROCESS_ERROR(nRetCode); ASSERT(pFontFace); nRetCode = FT_IS_SCALABLE(pFontFace); KGLOG_PROCESS_ERROR(nRetCode); KGLOG_PROCESS_ERROR(pFontFace->charmap); for (int i = 0; i < pFontFace->num_charmaps; ++i) { if (FT_Encoding(FT_ENCODING_UNICODE) == pFontFace->charmaps[i]->encoding) { bUnicode = TRUE; break; } } if (!bUnicode) { uEncoding = pFontFace->charmaps[0]->encoding; bUnicode = uEncoding == FT_ENCODING_UNICODE; } nError = FT_Select_Charmap(pFontFace, FT_Encoding(uEncoding)); KGLOG_PROCESS_ERROR(nError == 0); FontSize = FontFixMul(fPixel); nError = FT_Set_Char_Size(pFontFace, FontSize, 0, 0, 0); KGLOG_PROCESS_ERROR(nError == 0); LoadAlphaAdjustTable(szName, (INT)fPixel); m_pFontFace = pFontFace; pFontFace = NULL; m_dwEffect = dwStyle & ~KG3DUI_TEXT_STYLE_VERTICAL; m_bVertical = dwStyle & KG3DUI_TEXT_STYLE_VERTICAL; if (m_bVertical) m_InitParams.dwLoadFlag |= FT_LOAD_VERTICAL_LAYOUT; m_uMipmapLevel = (dwStyle & KG3DUI_TEXT_STYLE_MIPMAP) ? 8 : 1; if (FT_IS_SCALABLE(m_pFontFace)) { m_fontWidth = (m_pFontFace->bbox.xMax - m_pFontFace->bbox.xMin) * ((FLOAT)(m_pFontFace->size->metrics.x_ppem) / (FLOAT)(m_pFontFace->units_per_EM)); m_fontHeight = (m_pFontFace->bbox.yMax - m_pFontFace->bbox.yMin) * ((FLOAT)m_pFontFace->size->metrics.y_ppem / (FLOAT)m_pFontFace->units_per_EM); } else { m_fontWidth = FontFixDiv(m_pFontFace->size->metrics.max_advance); m_fontHeight = FontFixDiv(m_pFontFace->size->metrics.height); } m_fontWidth = ceil(m_fontWidth); m_fontHeight = ceil(m_fontHeight); m_fontAscender = FontFixDiv(m_pFontFace->size->metrics.ascender); m_fontDescender = FontFixDiv(m_pFontFace->size->metrics.descender); m_fontAscender = ceil(m_fontAscender); m_fontDescender = ceil(m_fontDescender); nResult = true; Exit0: if (!nResult) { if (pFontFace) { nRetCode = s_FontFacePool.Unload(pFontFace); KGLOG_CHECK_ERROR(nRetCode); pFontFace = NULL; } CleanUp(); } return nResult; }
bool SkScalerContext_CairoFT::computeShapeMatrix(const SkMatrix& m) { // Compute a shape matrix compatible with Cairo's _compute_transform. // Finds major/minor scales and uses them to normalize the transform. double scaleX = m.getScaleX(); double skewX = m.getSkewX(); double skewY = m.getSkewY(); double scaleY = m.getScaleY(); double det = scaleX * scaleY - skewY * skewX; if (!std::isfinite(det)) { fScaleX = fRec.fTextSize * fRec.fPreScaleX; fScaleY = fRec.fTextSize; fHaveShape = false; return false; } double major = det != 0.0 ? hypot(scaleX, skewY) : 0.0; double minor = major != 0.0 ? fabs(det) / major : 0.0; // Limit scales to be above 1pt. major = SkTMax(major, 1.0); minor = SkTMax(minor, 1.0); // If the font is not scalable, then choose the best available size. CairoLockedFTFace faceLock(fScaledFont); FT_Face face = faceLock.getFace(); if (face && !FT_IS_SCALABLE(face)) { double bestDist = DBL_MAX; FT_Int bestSize = -1; for (FT_Int i = 0; i < face->num_fixed_sizes; i++) { // Distance is positive if strike is larger than desired size, // or negative if smaller. If previously a found smaller strike, // then prefer a larger strike. Otherwise, minimize distance. double dist = face->available_sizes[i].y_ppem / 64.0 - minor; if (bestDist < 0 ? dist >= bestDist : fabs(dist) <= bestDist) { bestDist = dist; bestSize = i; } } if (bestSize < 0) { fScaleX = fRec.fTextSize * fRec.fPreScaleX; fScaleY = fRec.fTextSize; fHaveShape = false; return false; } major = face->available_sizes[bestSize].x_ppem / 64.0; minor = face->available_sizes[bestSize].y_ppem / 64.0; fHaveShape = true; } else { fHaveShape = !m.isScaleTranslate(); } fScaleX = SkDoubleToScalar(major); fScaleY = SkDoubleToScalar(minor); if (fHaveShape) { // Normalize the transform and convert to fixed-point. double invScaleX = 65536.0 / major; double invScaleY = 65536.0 / minor; fShapeMatrix.xx = (FT_Fixed)(scaleX * invScaleX); fShapeMatrix.yx = -(FT_Fixed)(skewY * invScaleX); fShapeMatrix.xy = -(FT_Fixed)(skewX * invScaleY); fShapeMatrix.yy = (FT_Fixed)(scaleY * invScaleY); } return true; }
int main(int argc, char** argv) { FT_Face face; long max_bytes = CACHE_SIZE * 1024; char* test_string = NULL; int size = FACE_SIZE; int max_iter = 0; double max_time = BENCH_TIME; int compare_cached = 0; int i; while ( 1 ) { int opt; opt = getopt( argc, argv, "Cc:f:m:pr:s:t:b:" ); if ( opt == -1 ) break; switch ( opt ) { case 'C': compare_cached = 1; break; case 'c': max_iter = atoi( optarg ); break; case 'f': load_flags = strtol( optarg, NULL, 16 ); break; case 'm': max_bytes = atoi( optarg ); max_bytes *= 1024; break; case 'p': preload = 1; break; case 'r': render_mode = (FT_Render_Mode)atoi( optarg ); if ( render_mode >= FT_RENDER_MODE_MAX ) render_mode = FT_RENDER_MODE_NORMAL; break; case 's': size = atoi( optarg ); if ( size <= 0 ) size = 1; else if ( size > 500 ) size = 500; break; case 't': max_time = atof( optarg ); break; case 'b': test_string = optarg; break; default: usage(); break; } } argc -= optind; argv += optind; if ( argc != 1 ) usage(); if ( FT_Init_FreeType( &lib ) ) { fprintf( stderr, "could not initialize font library\n" ); return 1; } filename = *argv; if ( get_face( &face ) ) goto Exit; if ( FT_IS_SCALABLE( face ) ) { if ( FT_Set_Pixel_Sizes( face, size, size ) ) { fprintf( stderr, "failed to set pixel size to %d\n", size ); return 1; } } else size = face->available_sizes[0].width; FTC_Manager_New( lib, 0, 0, max_bytes, face_requester, face, &cache_man ); font_type.face_id = (FTC_FaceID) 1; font_type.width = (short) size; font_type.height = (short) size; font_type.flags = load_flags; for ( i = 0; i < N_FT_BENCH; i++ ) { btest_t test; FT_ULong flags; if ( !TEST( 'a' + i ) ) continue; test.title = NULL; test.bench = NULL; test.cache_first = 0; test.user_data = NULL; switch ( i ) { case FT_BENCH_LOAD_GLYPH: test.title = "Load"; test.bench = test_load; benchmark( face, &test, max_iter, max_time ); if ( compare_cached ) { test.cache_first = 1; test.title = "Load (image cached)"; test.bench = test_image_cache; benchmark( face, &test, max_iter, max_time ); test.title = "Load (sbit cached)"; test.bench = test_sbit_cache; benchmark( face, &test, max_iter, max_time ); } break; case FT_BENCH_LOAD_ADVANCES: test.user_data = &flags; test.title = "Load_Advances (Normal)"; test.bench = test_load_advances; flags = FT_LOAD_DEFAULT; benchmark( face, &test, max_iter, max_time ); test.title = "Load_Advances (Fast)"; test.bench = test_load_advances; flags = FT_LOAD_TARGET_LIGHT; benchmark( face, &test, max_iter, max_time ); break; case FT_BENCH_RENDER: test.title = "Render"; test.bench = test_render; benchmark( face, &test, max_iter, max_time ); break; case FT_BENCH_GET_GLYPH: test.title = "Get_Glyph"; test.bench = test_get_glyph; benchmark( face, &test, max_iter, max_time ); break; case FT_BENCH_GET_CBOX: test.title = "Get_CBox"; test.bench = test_get_cbox; benchmark( face, &test, max_iter, max_time ); break; case FT_BENCH_CMAP: { bcharset_t charset; get_charset( face, &charset ); if ( charset.code ) { test.user_data = (void*)&charset; test.title = "Get_Char_Index"; test.bench = test_get_char_index; benchmark( face, &test, max_iter, max_time ); if ( compare_cached ) { test.cache_first = 1; test.title = "Get_Char_Index (cached)"; test.bench = test_cmap_cache; benchmark( face, &test, max_iter, max_time ); } free( charset.code ); } } break; case FT_BENCH_CMAP_ITER: test.title = "Iterate CMap"; test.bench = test_cmap_iter; benchmark( face, &test, max_iter, max_time ); break; case FT_BENCH_NEW_FACE: test.title = "New_Face"; test.bench = test_new_face; benchmark( face, &test, max_iter, max_time ); break; case FT_BENCH_EMBOLDEN: test.title = "Embolden"; test.bench = test_embolden; benchmark( face, &test, max_iter, max_time ); break; } } Exit: /* The following is a bit subtle: When we call FTC_Manager_Done, this * normally destroys all FT_Face objects that the cache might have created * by calling the face requester. * * However, this little benchmark uses a tricky face requester that * doesn't create a new FT_Face through FT_New_Face but simply pass a * pointer to the one that was previously created. * * If the cache manager has been used before, the call to FTC_Manager_Done * discards our single FT_Face. * * In the case where no cache manager is in place, or if no test was run, * the call to FT_Done_FreeType releases any remaining FT_Face object * anyway. */ if ( cache_man ) FTC_Manager_Done( cache_man ); FT_Done_FreeType( lib ); return 0; }
QGlyph render(QChar ch) { selectThisSize(); int index = ch.unicode(); if ( !unicode(index) ) index = 0; QGlyph result; FT_Error err; err=FT_Load_Glyph(myface,index,FT_LOAD_DEFAULT); if(err) qFatal("Load glyph error %x",err); int width,height,pitch,size = 0; FT_Glyph glyph; err=FT_Get_Glyph( myface->glyph, &glyph ); if(err) qFatal("Get glyph error %x",err); FT_BBox bbox; FT_Glyph_Get_CBox(glyph, ft_glyph_bbox_gridfit, &bbox); FT_Vector origin; origin.x = -bbox.xMin; origin.y = -bbox.yMin; if ( FT_IS_SCALABLE(myface) ) { err=FT_Glyph_To_Bitmap(&glyph, smooth ? ft_render_mode_normal : ft_render_mode_mono, &origin, 1); // destroy original glyph if(err) qWarning("Get bitmap error %d",err); } if ( !err ) { FT_Bitmap bm = ((FT_BitmapGlyph)glyph)->bitmap; pitch = bm.pitch; size=pitch*bm.rows; result.data = new uchar[size]; // XXX memory manage me width=bm.width; height=bm.rows; if ( size ) { memcpy( result.data, bm.buffer, size ); } else { result.data = new uchar[0]; // XXX memory manage me } } else { result.data = new uchar[0]; // XXX memory manage me } result.metrics = new QGlyphMetrics; memset((char*)result.metrics, 0, sizeof(QGlyphMetrics)); result.metrics->bearingx=myface->glyph->metrics.horiBearingX/64; result.metrics->advance=myface->glyph->metrics.horiAdvance/64; result.metrics->bearingy=myface->glyph->metrics.horiBearingY/64; result.metrics->linestep=pitch; result.metrics->width=width; result.metrics->height=height; FT_Done_Glyph( glyph ); return result; }
bool IsScalable() const override { return FT_IS_SCALABLE(m_face) != 0; }
void XeTeXFontInst::initialize(const char* pathname, int index, int &status) { TT_Postscript *postTable; TT_OS2* os2Table; FT_Error error; hb_face_t *hbFace; if (!gFreeTypeLibrary) { error = FT_Init_FreeType(&gFreeTypeLibrary); if (error) { fprintf(stderr, "FreeType initialization failed! (%d)\n", error); exit(1); } } error = FT_New_Face(gFreeTypeLibrary, pathname, index, &m_ftFace); if (error) { status = 1; return; } if (!FT_IS_SCALABLE(m_ftFace)) { status = 1; return; } /* for non-sfnt-packaged fonts (presumably Type 1), see if there is an AFM file we can attach */ if (index == 0 && !FT_IS_SFNT(m_ftFace)) { char* afm = xstrdup (xbasename (pathname)); char* p = strrchr (afm, '.'); if (p != NULL && strlen(p) == 4 && tolower(*(p+1)) == 'p' && tolower(*(p+2)) == 'f') strcpy(p, ".afm"); char *fullafm = kpse_find_file (afm, kpse_afm_format, 0); free (afm); if (fullafm) { FT_Attach_File(m_ftFace, fullafm); free (fullafm); } } m_filename = xstrdup(pathname); m_index = index; m_unitsPerEM = m_ftFace->units_per_EM; m_ascent = unitsToPoints(m_ftFace->ascender); m_descent = unitsToPoints(m_ftFace->descender); postTable = (TT_Postscript *) getFontTable(ft_sfnt_post); if (postTable != NULL) { m_italicAngle = Fix2D(postTable->italicAngle); } os2Table = (TT_OS2*) getFontTable(ft_sfnt_os2); if (os2Table) { m_capHeight = unitsToPoints(os2Table->sCapHeight); m_xHeight = unitsToPoints(os2Table->sxHeight); } // Set up HarfBuzz font hbFace = hb_face_create_for_tables(_get_table, m_ftFace, NULL); hb_face_set_index(hbFace, index); hb_face_set_upem(hbFace, m_unitsPerEM); m_hbFont = hb_font_create(hbFace); hb_face_destroy(hbFace); if (hbFontFuncs == NULL) hbFontFuncs = _get_font_funcs(); hb_font_set_funcs(m_hbFont, hbFontFuncs, m_ftFace, NULL); hb_font_set_scale(m_hbFont, m_unitsPerEM, m_unitsPerEM); // We don’t want device tables adjustments hb_font_set_ppem(m_hbFont, 0, 0); return; }
bool TTFFont::load(Common::SeekableReadStream &stream, int size, uint dpi, TTFRenderMode renderMode, const uint32 *mapping) { if (!g_ttf.isInitialized()) return false; _size = stream.size(); if (!_size) return false; _ttfFile = new uint8[_size]; assert(_ttfFile); if (stream.read(_ttfFile, _size) != _size) { delete[] _ttfFile; _ttfFile = 0; return false; } if (!g_ttf.loadFont(_ttfFile, _size, _face)) { delete[] _ttfFile; _ttfFile = 0; return false; } // We only support scalable fonts. if (!FT_IS_SCALABLE(_face)) { delete[] _ttfFile; _ttfFile = 0; g_ttf.closeFont(_face); return false; } // Check whether we have kerning support _hasKerning = (FT_HAS_KERNING(_face) != 0); if (FT_Set_Char_Size(_face, 0, size * 64, dpi, dpi)) { delete[] _ttfFile; _ttfFile = 0; return false; } switch (renderMode) { case kTTFRenderModeNormal: _loadFlags = FT_LOAD_TARGET_NORMAL; _renderMode = FT_RENDER_MODE_NORMAL; break; case kTTFRenderModeLight: _loadFlags = FT_LOAD_TARGET_LIGHT; _renderMode = FT_RENDER_MODE_LIGHT; break; case kTTFRenderModeMonochrome: _loadFlags = FT_LOAD_TARGET_MONO; _renderMode = FT_RENDER_MODE_MONO; break; } FT_Fixed yScale = _face->size->metrics.y_scale; _ascent = ftCeil26_6(FT_MulFix(_face->ascender, yScale)); _descent = ftCeil26_6(FT_MulFix(_face->descender, yScale)); _width = ftCeil26_6(FT_MulFix(_face->max_advance_width, _face->size->metrics.x_scale)); _height = _ascent - _descent + 1; if (!mapping) { // Allow loading of all unicode characters. _allowLateCaching = true; // Load all ISO-8859-1 characters. for (uint i = 0; i < 256; ++i) { if (!cacheGlyph(_glyphs[i], i)) { _glyphs.erase(i); } } } else { // We have a fixed map of characters do not load more later. _allowLateCaching = false; for (uint i = 0; i < 256; ++i) { const uint32 unicode = mapping[i] & 0x7FFFFFFF; const bool isRequired = (mapping[i] & 0x80000000) != 0; // Check whether loading an important glyph fails and error out if // that is the case. if (!cacheGlyph(_glyphs[i], unicode)) { _glyphs.erase(i); if (isRequired) return false; } } } _initialized = (_glyphs.size() != 0); return _initialized; }
static GdkPixmap * create_text_pixmap(GtkWidget *drawing_area, FT_Face face) { gint i, pixmap_width, pixmap_height, pos_y, textlen; GdkPixmap *pixmap = NULL; const gchar *text; Display *xdisplay; Drawable xdrawable; Visual *xvisual; Colormap xcolormap; XftDraw *draw; XftColor colour; XGlyphInfo extents; XftFont *font; gint *sizes = NULL, n_sizes, alpha_size; FcCharSet *charset = NULL; cairo_t *cr; GdkWindow *window = gtk_widget_get_window (drawing_area); text = pango_language_get_sample_string(NULL); if (! check_font_contain_text (face, text)) { pango_language_get_sample_string (pango_language_from_string ("en_US")); } textlen = strlen(text); /* create the XftDraw */ xdisplay = GDK_PIXMAP_XDISPLAY(window); #if GTK_CHECK_VERSION(3, 0, 0) xvisual = GDK_VISUAL_XVISUAL(gdk_window_get_visual(window)); #else xvisual = GDK_VISUAL_XVISUAL(gdk_drawable_get_visual(window)); #endif xcolormap = GDK_COLORMAP_XCOLORMAP(gdk_drawable_get_colormap(window)); XftColorAllocName(xdisplay, xvisual, xcolormap, "black", &colour); /* work out what sizes to render */ if (FT_IS_SCALABLE(face)) { n_sizes = 8; sizes = g_new(gint, n_sizes); sizes[0] = 8; sizes[1] = 10; sizes[2] = 12; sizes[3] = 18; sizes[4] = 24; sizes[5] = 36; sizes[6] = 48; sizes[7] = 72; alpha_size = 24; } else { /* use fixed sizes */ n_sizes = face->num_fixed_sizes; sizes = g_new(gint, n_sizes); alpha_size = 0; for (i = 0; i < face->num_fixed_sizes; i++) { sizes[i] = face->available_sizes[i].height; /* work out which font size to render */ if (face->available_sizes[i].height <= 24) alpha_size = face->available_sizes[i].height; } } /* calculate size of pixmap to use (with 4 pixels padding) ... */ pixmap_width = 8; pixmap_height = 8; font = get_font(xdisplay, face, alpha_size, charset); charset = FcCharSetCopy (font->charset); XftTextExtentsUtf8(xdisplay, font, (guchar *)lowercase_text, strlen(lowercase_text), &extents); pixmap_height += extents.height + 4; pixmap_width = MAX(pixmap_width, 8 + extents.width); XftTextExtentsUtf8(xdisplay, font, (guchar *)uppercase_text, strlen(uppercase_text), &extents); pixmap_height += extents.height + 4; pixmap_width = MAX(pixmap_width, 8 + extents.width); XftTextExtentsUtf8(xdisplay, font, (guchar *)punctuation_text, strlen(punctuation_text), &extents); pixmap_height += extents.height + 4; pixmap_width = MAX(pixmap_width, 8 + extents.width); XftFontClose(xdisplay, font); pixmap_height += 8; for (i = 0; i < n_sizes; i++) { font = get_font(xdisplay, face, sizes[i], charset); if (!font) continue; XftTextExtentsUtf8(xdisplay, font, (guchar *)text, textlen, &extents); pixmap_height += extents.height + 4; pixmap_width = MAX(pixmap_width, 8 + extents.width); XftFontClose(xdisplay, font); } /* create pixmap */ gtk_widget_set_size_request(drawing_area, pixmap_width, pixmap_height); pixmap = gdk_pixmap_new(window, pixmap_width, pixmap_height, -1); if (!pixmap) goto end; cr = gdk_cairo_create (pixmap); cairo_set_source_rgb (cr, 1, 1, 1); cairo_paint (cr); cairo_destroy (cr); xdrawable = GDK_DRAWABLE_XID(pixmap); draw = XftDrawCreate(xdisplay, xdrawable, xvisual, xcolormap); /* draw text */ pos_y = 4; font = get_font(xdisplay, face, alpha_size, charset); draw_string(xdisplay, draw, font, &colour, lowercase_text, &pos_y); draw_string(xdisplay, draw, font, &colour, uppercase_text, &pos_y); draw_string(xdisplay, draw, font, &colour, punctuation_text, &pos_y); XftFontClose(xdisplay, font); pos_y += 8; for (i = 0; i < n_sizes; i++) { font = get_font(xdisplay, face, sizes[i], charset); if (!font) continue; draw_string(xdisplay, draw, font, &colour, text, &pos_y); XftFontClose(xdisplay, font); } g_signal_connect(drawing_area, "expose-event", G_CALLBACK(expose_event), pixmap); end: g_free(sizes); FcCharSetDestroy (charset); return pixmap; }
bool gfx_font_adapter::prepare_glyph(unsigned int code) { if (m_impl->font) { m_impl->cur_glyph_index = FT_Get_Char_Index(m_impl->font, code); int error = FT_Load_Glyph(m_impl->font, m_impl->cur_glyph_index, m_impl->hinting ? FT_LOAD_DEFAULT : FT_LOAD_NO_HINTING); bool is_sys_bitmap = false; if (m_impl->font->glyph->format == FT_GLYPH_FORMAT_BITMAP) is_sys_bitmap = true; if (error == 0) { if (m_impl->antialias && !is_sys_bitmap) { if (m_impl->weight == 500) { int strength = 1 << 5; FT_Outline_Embolden(&(m_impl->font->glyph->outline), strength); } else if (m_impl->weight == 700) { int strength = 1 << 6; FT_Outline_Embolden(&(m_impl->font->glyph->outline), strength); } else if (m_impl->weight == 900) { int strength = 1 << 7; FT_Outline_Embolden(&(m_impl->font->glyph->outline), strength); } // outline text m_impl->cur_data_type = glyph_type_outline; m_impl->cur_font_path.remove_all(); if (decompose_ft_outline(m_impl->font->glyph->outline, m_impl->flip_y, m_impl->matrix, m_impl->cur_font_path)) { m_impl->cur_bound_rect = get_bounding_rect(m_impl->cur_font_path); m_impl->cur_data_size = m_impl->cur_font_path.total_byte_size()+sizeof(unsigned int);//count data m_impl->cur_advance_x = FLT_TO_SCALAR(int26p6_to_flt(m_impl->font->glyph->advance.x)); m_impl->cur_advance_y = FLT_TO_SCALAR(int26p6_to_flt(m_impl->font->glyph->advance.y)); m_impl->matrix.transform(&m_impl->cur_advance_x, &m_impl->cur_advance_y); return true; } } else { m_impl->cur_data_type = glyph_type_mono; if (is_sys_bitmap || !FT_IS_SCALABLE(m_impl->font) || m_impl->matrix.is_identity()) { gfx_scanline_bin sl; error = FT_Render_Glyph(m_impl->font->glyph, FT_RENDER_MODE_MONO); if (error == 0) { decompose_ft_bitmap_mono(m_impl->font->glyph->bitmap, m_impl->font->glyph->bitmap_left, m_impl->flip_y ? -m_impl->font->glyph->bitmap_top : m_impl->font->glyph->bitmap_top, m_impl->flip_y, sl, m_impl->cur_font_scanlines_bin); m_impl->cur_bound_rect = rect(m_impl->cur_font_scanlines_bin.min_x(), m_impl->cur_font_scanlines_bin.min_y(), m_impl->cur_font_scanlines_bin.max_x() + 1, m_impl->cur_font_scanlines_bin.max_y() + 1); m_impl->cur_data_size = m_impl->cur_font_scanlines_bin.byte_size(); m_impl->cur_advance_x = FLT_TO_SCALAR(int26p6_to_flt(m_impl->font->glyph->advance.x)); m_impl->cur_advance_y = FLT_TO_SCALAR(int26p6_to_flt(m_impl->font->glyph->advance.y)); return true; } } else { if (m_impl->weight == 500) { int strength = 1 << 5; FT_Outline_Embolden(&(m_impl->font->glyph->outline), strength); } else if (m_impl->weight == 700) { int strength = 1 << 6; FT_Outline_Embolden(&(m_impl->font->glyph->outline), strength); } else if (m_impl->weight == 900) { int strength = 1 << 7; FT_Outline_Embolden(&(m_impl->font->glyph->outline), strength); } m_impl->cur_font_path.remove_all(); if (decompose_ft_outline(m_impl->font->glyph->outline, m_impl->flip_y, m_impl->matrix, m_impl->cur_font_path)) { gfx_rasterizer_scanline_aa<> rasterizer; picasso::conv_curve curves(m_impl->cur_font_path); curves.approximation_scale(4.0); rasterizer.add_path(curves); gfx_scanline_bin sl; m_impl->cur_font_scanlines_bin.prepare(); // Remove all gfx_render_scanlines(rasterizer, sl, m_impl->cur_font_scanlines_bin); m_impl->cur_bound_rect = rect(m_impl->cur_font_scanlines_bin.min_x(), m_impl->cur_font_scanlines_bin.min_y(), m_impl->cur_font_scanlines_bin.max_x() + 1, m_impl->cur_font_scanlines_bin.max_y() + 1); m_impl->cur_data_size = m_impl->cur_font_scanlines_bin.byte_size(); m_impl->cur_advance_x = FLT_TO_SCALAR(int26p6_to_flt(m_impl->font->glyph->advance.x)); m_impl->cur_advance_y = FLT_TO_SCALAR(int26p6_to_flt(m_impl->font->glyph->advance.y)); m_impl->matrix.transform(&m_impl->cur_advance_x, &m_impl->cur_advance_y); return true; } } } } } return false; }
static FT_Error Load_Glyph( TTF_Font* font, Uint16 ch, c_glyph* cached, int want ) { FT_Face face; FT_Error error; FT_GlyphSlot glyph; FT_Glyph_Metrics* metrics; FT_Outline* outline; if ( !font || !font->face ) { return FT_Err_Invalid_Handle; } face = font->face; /* Load the glyph */ if ( ! cached->index ) { cached->index = FT_Get_Char_Index( face, ch ); } error = FT_Load_Glyph( face, cached->index, FT_LOAD_DEFAULT ); if( error ) { return error; } /* Get our glyph shortcuts */ glyph = face->glyph; metrics = &glyph->metrics; outline = &glyph->outline; /* Get the glyph metrics if desired */ if ( (want & CACHED_METRICS) && !(cached->stored & CACHED_METRICS) ) { if ( FT_IS_SCALABLE( face ) ) { /* Get the bounding box */ cached->minx = FT_FLOOR(metrics->horiBearingX); cached->maxx = cached->minx + FT_CEIL(metrics->width); cached->maxy = FT_FLOOR(metrics->horiBearingY); cached->miny = cached->maxy - FT_CEIL(metrics->height); cached->yoffset = font->ascent - cached->maxy; cached->advance = FT_CEIL(metrics->horiAdvance); } else { /* Get the bounding box for non-scalable format. * Again, freetype2 fills in many of the font metrics * with the value of 0, so some of the values we * need must be calculated differently with certain * assumptions about non-scalable formats. * */ cached->minx = FT_FLOOR(metrics->horiBearingX); cached->maxx = cached->minx + FT_CEIL(metrics->horiAdvance); cached->maxy = FT_FLOOR(metrics->horiBearingY); cached->miny = cached->maxy - FT_CEIL(face->available_sizes[font->font_size_family].height); cached->yoffset = 0; cached->advance = FT_CEIL(metrics->horiAdvance); } /* Adjust for bold and italic text */ if( font->style & TTF_STYLE_BOLD ) { cached->maxx += font->glyph_overhang; } if( font->style & TTF_STYLE_ITALIC ) { cached->maxx += (int)ceil(font->glyph_italics); } cached->stored |= CACHED_METRICS; } if ( ((want & CACHED_BITMAP) && !(cached->stored & CACHED_BITMAP)) || ((want & CACHED_PIXMAP) && !(cached->stored & CACHED_PIXMAP)) ) { int mono = (want & CACHED_BITMAP); int i; FT_Bitmap* src; FT_Bitmap* dst; /* Handle the italic style */ if( font->style & TTF_STYLE_ITALIC ) { FT_Matrix shear; shear.xx = 1 << 16; shear.xy = (int) ( font->glyph_italics * ( 1 << 16 ) ) / font->height; shear.yx = 0; shear.yy = 1 << 16; FT_Outline_Transform( outline, &shear ); } /* Render the glyph */ if ( mono ) { error = FT_Render_Glyph( glyph, ft_render_mode_mono ); } else { error = FT_Render_Glyph( glyph, ft_render_mode_normal ); } if( error ) { return error; } /* Copy over information to cache */ src = &glyph->bitmap; if ( mono ) { dst = &cached->bitmap; } else { dst = &cached->pixmap; } memcpy( dst, src, sizeof( *dst ) ); /* FT_Render_Glyph() and .fon fonts always generate a * two-color (black and white) glyphslot surface, even * when rendered in ft_render_mode_normal. */ /* FT_IS_SCALABLE() means that the font is in outline format, * but does not imply that outline is rendered as 8-bit * grayscale, because embedded bitmap/graymap is preferred * (see FT_LOAD_DEFAULT section of FreeType2 API Reference). * FT_Render_Glyph() canreturn two-color bitmap or 4/16/256- * color graymap according to the format of embedded bitmap/ * graymap. */ if ( glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO ) { dst->pitch *= 8; } else if ( glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY2 ) { dst->pitch *= 4; } else if ( glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY4 ) { dst->pitch *= 2; } /* Adjust for bold and italic text */ if( font->style & TTF_STYLE_BOLD ) { int bump = font->glyph_overhang; dst->pitch += bump; dst->width += bump; } if( font->style & TTF_STYLE_ITALIC ) { int bump = (int)ceil(font->glyph_italics); dst->pitch += bump; dst->width += bump; } if (dst->rows != 0) { dst->buffer = (unsigned char *)malloc( dst->pitch * dst->rows ); if( !dst->buffer ) { return FT_Err_Out_Of_Memory; } memset( dst->buffer, 0, dst->pitch * dst->rows ); for( i = 0; i < src->rows; i++ ) { int soffset = i * src->pitch; int doffset = i * dst->pitch; if ( mono ) { unsigned char *srcp = src->buffer + soffset; unsigned char *dstp = dst->buffer + doffset; int j; if ( glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO ) { for ( j = 0; j < src->width; j += 8 ) { unsigned char ch = *srcp++; *dstp++ = (ch&0x80) >> 7; ch <<= 1; *dstp++ = (ch&0x80) >> 7; ch <<= 1; *dstp++ = (ch&0x80) >> 7; ch <<= 1; *dstp++ = (ch&0x80) >> 7; ch <<= 1; *dstp++ = (ch&0x80) >> 7; ch <<= 1; *dstp++ = (ch&0x80) >> 7; ch <<= 1; *dstp++ = (ch&0x80) >> 7; ch <<= 1; *dstp++ = (ch&0x80) >> 7; } } else if ( glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY2 ) { for ( j = 0; j < src->width; j += 4 ) { unsigned char ch = *srcp++; *dstp++ = (((ch&0xA0) >> 6) >= 0x2) ? 1 : 0; ch <<= 2; *dstp++ = (((ch&0xA0) >> 6) >= 0x2) ? 1 : 0; ch <<= 2; *dstp++ = (((ch&0xA0) >> 6) >= 0x2) ? 1 : 0; ch <<= 2; *dstp++ = (((ch&0xA0) >> 6) >= 0x2) ? 1 : 0; } } else if ( glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY4 ) { for ( j = 0; j < src->width; j += 2 ) { unsigned char ch = *srcp++; *dstp++ = (((ch&0xF0) >> 4) >= 0x8) ? 1 : 0; ch <<= 4; *dstp++ = (((ch&0xF0) >> 4) >= 0x8) ? 1 : 0; } } else { for ( j = 0; j < src->width; j++ ) {
void FontRenderer::rasterize() { clear_bitmaps(); if (!m_ft_face) { return; } qDebug() << " begin rasterize_font "; if (m_config->italic()!=0) { FT_Matrix matrix; const float angle = (-M_PI*m_config->italic()) / 180.0f; matrix.xx = (FT_Fixed)( cos( angle ) * 0x10000L ); matrix.xy = (FT_Fixed)(-sin( angle ) * 0x10000L ); matrix.yx = (FT_Fixed)( 0/*sin( angle )*/ * 0x10000L ); matrix.yy = (FT_Fixed)( 1/*cos( angle )*/ * 0x10000L ); FT_Set_Transform(m_ft_face,&matrix,0); } else { FT_Set_Transform(m_ft_face,0,0); } /// fill metrics if (FT_IS_SCALABLE(m_ft_face)) { m_rendered.metrics.ascender = m_ft_face->size->metrics.ascender / 64; m_rendered.metrics.descender = m_ft_face->size->metrics.descender/ 64; m_rendered.metrics.height = m_ft_face->size->metrics.height/ 64; } else { m_rendered.metrics.ascender = m_ft_face->ascender; m_rendered.metrics.descender = m_ft_face->descender; m_rendered.metrics.height = m_ft_face->height; } bool use_kerning = FT_HAS_KERNING( m_ft_face ); const ushort* chars = m_config->characters().utf16(); size_t amount = 0; while (chars[amount]!=0) amount++; int error = 0; for (size_t i=0;i<amount;i++) { int glyph_index = FT_Get_Char_Index( m_ft_face, chars[i] ); if (glyph_index==0 && !m_config->renderMissing()) continue; FT_Int32 flags = FT_LOAD_DEFAULT; if (!m_config->antialiased()) { flags = flags | FT_LOAD_MONOCHROME | FT_LOAD_TARGET_MONO; } else { flags = flags | FT_LOAD_TARGET_NORMAL; } switch (m_config->hinting()) { case FontConfig::HintingDisable: flags = flags | FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT; break; case FontConfig::HintingForceFreetypeAuto: flags = flags | FT_LOAD_FORCE_AUTOHINT; break; case FontConfig::HintingDisableFreetypeAuto: flags = flags | FT_LOAD_NO_AUTOHINT; break; default: break; } error = FT_Load_Glyph( m_ft_face, glyph_index, flags ); if ( error ) continue; if (m_config->bold()!=0) { FT_Pos strength = m_config->size()*m_config->bold(); if ( m_ft_face->glyph->format == FT_GLYPH_FORMAT_OUTLINE ) FT_Outline_Embolden( &m_ft_face->glyph->outline, strength ); } if (m_ft_face->glyph->format!=FT_GLYPH_FORMAT_BITMAP) { error = FT_Render_Glyph( m_ft_face->glyph, m_config->antialiased() ? FT_RENDER_MODE_NORMAL:FT_RENDER_MODE_MONO ); } if ( error ) continue; if (append_bitmap(chars[i])) { if (use_kerning) append_kerning(chars[i],chars,amount); } } imagesChanged(m_chars); imagesChanged(); }
TTF_Font * TTF_OpenFontIndexRW(SDL_RWops * src, int freesrc, int ptsize, long index) { TTF_Font *font; FT_Error error; FT_Face face; FT_Fixed scale; FT_Stream stream; int position; if(!TTF_initialized) { TTF_SetError("Library not initialized"); return NULL; } /* Check to make sure we can seek in this stream */ position = SDL_RWtell(src); if(position < 0) { TTF_SetError("Can't seek in stream"); return NULL; } font = (TTF_Font *) malloc(sizeof *font); if(font == NULL) { TTF_SetError("Out of memory"); return NULL; } memset(font, 0, sizeof(*font)); font->src = src; font->freesrc = freesrc; stream = (FT_Stream) malloc(sizeof(*stream)); if(stream == NULL) { TTF_SetError("Out of memory"); TTF_CloseFont(font); return NULL; } memset(stream, 0, sizeof(*stream)); /* 090303 Chase - Newer FT2 version sets this internally so we don't have to. (Can't anyway, Don't have a definition for FT_Library) */ // stream->memory = library->memory; stream->read = RWread; stream->descriptor.pointer = src; stream->pos = (unsigned long) position; SDL_RWseek(src, 0, SEEK_END); stream->size = (unsigned long) (SDL_RWtell(src) - position); SDL_RWseek(src, position, SEEK_SET); font->args.flags = FT_OPEN_STREAM; font->args.stream = stream; error = FT_Open_Face(library, &font->args, index, &font->face); if(error) { TTF_SetFTError("Couldn't load font file", error); TTF_CloseFont(font); return NULL; } face = font->face; /* Make sure that our font face is scalable (global metrics) */ if(FT_IS_SCALABLE(face)) { /* Set the character size and use default DPI (72) */ error = FT_Set_Char_Size(font->face, 0, ptsize * 64, 0, 0); if(error) { TTF_SetFTError("Couldn't set font size", error); TTF_CloseFont(font); return NULL; } /* Get the scalable font metrics for this font */ scale = face->size->metrics.y_scale; font->ascent = FT_CEIL(FT_MulFix(face->bbox.yMax, scale)); font->descent = FT_CEIL(FT_MulFix(face->bbox.yMin, scale)); font->height = font->ascent - font->descent + /* baseline */ 1; font->lineskip = FT_CEIL(FT_MulFix(face->height, scale)); font->underline_offset = FT_FLOOR(FT_MulFix(face->underline_position, scale)); font->underline_height = FT_FLOOR(FT_MulFix(face->underline_thickness, scale)); } else { /* Non-scalable font case. ptsize determines which family * or series of fonts to grab from the non-scalable format. * It is not the point size of the font. * */ if(ptsize >= font->face->num_fixed_sizes) ptsize = font->face->num_fixed_sizes - 1; font->font_size_family = ptsize; error = FT_Set_Pixel_Sizes(face, face->available_sizes[ptsize].height, face->available_sizes[ptsize].width); /* With non-scalale fonts, Freetype2 likes to fill many of the * font metrics with the value of 0. The size of the * non-scalable fonts must be determined differently * or sometimes cannot be determined. * */ font->ascent = face->available_sizes[ptsize].height; font->descent = 0; font->height = face->available_sizes[ptsize].height; font->lineskip = FT_CEIL(font->ascent); font->underline_offset = FT_FLOOR(face->underline_position); font->underline_height = FT_FLOOR(face->underline_thickness); } if(font->underline_height < 1) { font->underline_height = 1; } #ifdef DEBUG_FONTS printf("Font metrics:\n"); printf("\tascent = %d, descent = %d\n", font->ascent, font->descent); printf("\theight = %d, lineskip = %d\n", font->height, font->lineskip); printf("\tunderline_offset = %d, underline_height = %d\n", font->underline_offset, font->underline_height); #endif /* Set the default font style */ font->style = TTF_STYLE_NORMAL; font->glyph_overhang = face->size->metrics.y_ppem / 10; /* x offset = cos(((90.0-12)/360)*2*M_PI), or 12 degree angle */ font->glyph_italics = 0.207f; font->glyph_italics *= font->height; return font; }
// // _checkLicenses(); // void FontFace::_checkLicenses(void){ // // Assign the default: // _licenseData = UnknownLicense::pData; std::string licenseString; /////////////////////////////////////// // // Handle both (1) TrueType/OpenType // and (2) Type1 fonts // /////////////////////////////////////// if(FT_IS_SFNT(_face)){ /////////////////////////////// // // TrueType / OpenType CASE: // /////////////////////////////// FT_UInt count=FT_Get_Sfnt_Name_Count(_face); FT_SfntName fontName; // // Check both the COPYRIGHT (TTF) and LICENSE (OPENTYPE) fields: // for(unsigned j=0;j<count;j++){ FT_Get_Sfnt_Name(_face,j,&fontName); if(fontName.name_id==NID_LICENSE || fontName.name_id==NID_COPYRIGHT){ licenseString = _getStringFromTrueTypeFont(fontName); if(fontName.name_id==NID_COPYRIGHT){ _storeCopyrightSummary(licenseString); } if(_checkAllKnownLicenses(licenseString)){ return; } } if(fontName.name_id==NID_URL_LICENSE){ _licenseURL = _getStringFromTrueTypeFont(fontName); } } // // Get here if not a known license string: // }else if(FT_IS_SCALABLE(_face)){ /////////////////////////////// // // Could be Type 1, Type 42, // CID, or PFR CASES: // /////////////////////////////// PS_FontInfoRec fi; FT_Get_PS_Font_Info(_face,&fi); if(fi.notice){ licenseString = fi.notice; _checkAllKnownLicenses(licenseString); _storeCopyrightSummary(licenseString); } } }
FT2Font::FT2Font(std::string facefile) { _VERBOSE("FT2Font::FT2Font"); clear(Py::Tuple(0)); int error = FT_New_Face( _ft2Library, facefile.c_str(), 0, &face ); if (error == FT_Err_Unknown_File_Format ) { std::ostringstream s; s << "Could not load facefile " << facefile << "; Unknown_File_Format" << std::endl; throw Py::RuntimeError(s.str()); } else if (error == FT_Err_Cannot_Open_Resource) { std::ostringstream s; s << "Could not open facefile " << facefile << "; Cannot_Open_Resource" << std::endl; throw Py::RuntimeError(s.str()); } else if (error == FT_Err_Invalid_File_Format) { std::ostringstream s; s << "Could not open facefile " << facefile << "; Invalid_File_Format" << std::endl; throw Py::RuntimeError(s.str()); } else if (error) { std::ostringstream s; s << "Could not open facefile " << facefile << "; freetype error code " << error<< std::endl; throw Py::RuntimeError(s.str()); } // set a default fontsize 12 pt at 72dpi error = FT_Set_Char_Size( face, 12 * 64, 0, 72, 72 ); //error = FT_Set_Char_Size( face, 20 * 64, 0, 80, 80 ); if (error) { std::ostringstream s; s << "Could not set the fontsize for facefile " << facefile << std::endl; throw Py::RuntimeError(s.str()); } // set some face props as attributes //small memory leak fixed after 2.1.8 const char* ps_name = FT_Get_Postscript_Name( face ); //const char* ps_name = "jdh"; if ( ps_name == NULL ) ps_name = "UNAVAILABLE"; setattr("postscript_name", Py::String(ps_name)); setattr("num_faces", Py::Int(face->num_faces)); setattr("family_name", Py::String(face->family_name)); setattr("style_name", Py::String(face->style_name)); setattr("face_flags", Py::Int(face->face_flags)); setattr("style_flags", Py::Int(face->style_flags)); setattr("num_glyphs", Py::Int(face->num_glyphs)); setattr("num_fixed_sizes", Py::Int(face->num_fixed_sizes)); setattr("num_charmaps", Py::Int(face->num_charmaps)); int scalable = FT_IS_SCALABLE( face ); setattr("scalable", Py::Int(scalable)); if (scalable) { setattr("units_per_EM", Py::Int(face->units_per_EM)); Py::Tuple bbox(4); bbox[0] = Py::Int(face->bbox.xMin); bbox[1] = Py::Int(face->bbox.yMin); bbox[2] = Py::Int(face->bbox.xMax); bbox[3] = Py::Int(face->bbox.yMax); setattr("bbox", bbox); setattr("ascender", Py::Int(face->ascender)); setattr("descender", Py::Int(face->descender)); setattr("height", Py::Int(face->height)); setattr("max_advance_width", Py::Int(face->max_advance_width)); setattr("max_advance_height", Py::Int(face->max_advance_height)); setattr("underline_position", Py::Int(face->underline_position)); setattr("underline_thickness", Py::Int(face->underline_thickness)); } }
TTF_Font* TTF_OpenFontIndex( const char *file, int ptsize, long index ) { TTF_Font* font; FT_Error error; FT_Face face; FT_Fixed scale; extern int strict_font; font = (TTF_Font*) malloc(sizeof *font); if ( font == NULL ) { fprintf(stderr, "Out of memory\n" ); return NULL; } memset( font, 0, sizeof( *font ) ); /* Open the font and create ancillary data */ error = FT_New_Face( library, file, 0, &font->face ); if( error && !strict_font ) error=FT_New_Memory_Face(library, (const FT_Byte*)DroidSans_ttf, DROIDSANS_SIZE, 0, &font->face ); if( error ) { printf( "Couldn't load font file\n"); free( font ); return NULL; } if ( index != 0 ) { if ( font->face->num_faces > index ) { FT_Done_Face( font->face ); error = FT_New_Face( library, file, index, &font->face ); if( error ) { printf( "Couldn't get font face\n"); free( font ); return NULL; } } else { fprintf(stderr, "No such font face\n"); free( font ); return NULL; } } face = font->face; /* Make sure that our font face is scalable (global metrics) */ if ( ! FT_IS_SCALABLE(face) ) { fprintf(stderr,"Font face is not scalable\n"); TTF_CloseFont( font ); return NULL; } /* Set the character size and use default DPI (72) */ error = FT_Set_Char_Size( font->face, 0, ptsize * 64, 0, 0 ); if( error ) { fprintf(stderr, "Couldn't set font size\n"); TTF_CloseFont( font ); return NULL; } /* Get the scalable font metrics for this font */ scale = face->size->metrics.y_scale; font->ascent = FT_CEIL(FT_MulFix(face->bbox.yMax, scale)); font->descent = FT_CEIL(FT_MulFix(face->bbox.yMin, scale)); font->height = font->ascent - font->descent + /* baseline */ 1; font->lineskip = FT_CEIL(FT_MulFix(face->height, scale)); font->underline_offset = FT_FLOOR(FT_MulFix(face->underline_position, scale)); font->underline_height = FT_FLOOR(FT_MulFix(face->underline_thickness, scale)); if ( font->underline_height < 1 ) { font->underline_height = 1; } #ifdef DEBUG_FONTS printf("Font metrics:\n"); printf("\tascent = %d, descent = %d\n", font->ascent, font->descent); printf("\theight = %d, lineskip = %d\n", font->height, font->lineskip); printf("\tunderline_offset = %d, underline_height = %d\n", font->underline_offset, font->underline_height); #endif /* Set the default font style */ font->style = TTF_STYLE_NORMAL; font->glyph_overhang = face->size->metrics.y_ppem / 10; /* x offset = cos(((90.0-12)/360)*2*M_PI), or 12 degree angle */ /*font->glyph_italics = 0.207f; font->glyph_italics *= font->height;*/ return font; }
tt_face_init( FT_Stream stream, FT_Face ttface, /* TT_Face */ FT_Int face_index, FT_Int num_params, FT_Parameter* params ) { FT_Error error; FT_Library library; SFNT_Service sfnt; TT_Face face = (TT_Face)ttface; FT_TRACE2(( "TTF driver\n" )); library = ttface->driver->root.library; sfnt = (SFNT_Service)FT_Get_Module_Interface( library, "sfnt" ); if ( !sfnt ) { FT_ERROR(( "tt_face_init: cannot access `sfnt' module\n" )); error = FT_THROW( Missing_Module ); goto Exit; } /* create input stream from resource */ if ( FT_STREAM_SEEK( 0 ) ) goto Exit; /* check that we have a valid TrueType file */ error = sfnt->init_face( stream, face, face_index, num_params, params ); /* Stream may have changed. */ stream = face->root.stream; if ( error ) goto Exit; /* We must also be able to accept Mac/GX fonts, as well as OT ones. */ /* The 0x00020000 tag is completely undocumented; some fonts from */ /* Arphic made for Chinese Windows 3.1 have this. */ if ( face->format_tag != 0x00010000L && /* MS fonts */ face->format_tag != 0x00020000L && /* CJK fonts for Win 3.1 */ face->format_tag != TTAG_true ) /* Mac fonts */ { FT_TRACE2(( " not a TTF font\n" )); goto Bad_Format; } #ifdef TT_USE_BYTECODE_INTERPRETER ttface->face_flags |= FT_FACE_FLAG_HINTER; #endif /* If we are performing a simple font format check, exit immediately. */ if ( face_index < 0 ) return FT_Err_Ok; /* Load font directory */ error = sfnt->load_face( stream, face, face_index, num_params, params ); if ( error ) goto Exit; if ( tt_check_trickyness( ttface ) ) ttface->face_flags |= FT_FACE_FLAG_TRICKY; error = tt_face_load_hdmx( face, stream ); if ( error ) goto Exit; if ( FT_IS_SCALABLE( ttface ) ) { #ifdef FT_CONFIG_OPTION_INCREMENTAL if ( !ttface->internal->incremental_interface ) error = tt_face_load_loca( face, stream ); if ( !error ) error = tt_face_load_cvt( face, stream ); if ( !error ) error = tt_face_load_fpgm( face, stream ); if ( !error ) error = tt_face_load_prep( face, stream ); /* Check the scalable flag based on `loca'. */ if ( !ttface->internal->incremental_interface && ttface->num_fixed_sizes && face->glyph_locations && tt_check_single_notdef( ttface ) ) { FT_TRACE5(( "tt_face_init:" " Only the `.notdef' glyph has an outline.\n" " " " Resetting scalable flag to FALSE.\n" )); ttface->face_flags &= ~FT_FACE_FLAG_SCALABLE; } #else /* !FT_CONFIG_OPTION_INCREMENTAL */ if ( !error ) error = tt_face_load_loca( face, stream ); if ( !error ) error = tt_face_load_cvt( face, stream ); if ( !error ) error = tt_face_load_fpgm( face, stream ); if ( !error ) error = tt_face_load_prep( face, stream ); /* Check the scalable flag based on `loca'. */ if ( ttface->num_fixed_sizes && face->glyph_locations && tt_check_single_notdef( ttface ) ) { FT_TRACE5(( "tt_face_init:" " Only the `.notdef' glyph has an outline.\n" " " " Resetting scalable flag to FALSE.\n" )); ttface->face_flags &= ~FT_FACE_FLAG_SCALABLE; } #endif /* !FT_CONFIG_OPTION_INCREMENTAL */ } #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT { FT_Int instance_index = face_index >> 16; if ( FT_HAS_MULTIPLE_MASTERS( ttface ) && instance_index > 0 ) { error = TT_Get_MM_Var( face, NULL ); if ( error ) goto Exit; if ( face->blend->mmvar->namedstyle ) { FT_Memory memory = ttface->memory; FT_Var_Named_Style* named_style; FT_String* style_name; /* in `face_index', the instance index starts with value 1 */ named_style = face->blend->mmvar->namedstyle + instance_index - 1; error = sfnt->get_name( face, (FT_UShort)named_style->strid, &style_name ); if ( error ) goto Exit; /* set style name; if already set, replace it */ if ( face->root.style_name ) FT_FREE( face->root.style_name ); face->root.style_name = style_name; /* finally, select the named instance */ error = TT_Set_Var_Design( face, face->blend->mmvar->num_axis, named_style->coords ); if ( error ) goto Exit; } } } #endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */ /* initialize standard glyph loading routines */ TT_Init_Glyph_Loading( face ); Exit: return error; Bad_Format: error = FT_THROW( Unknown_File_Format ); goto Exit; }
BOOL Font::Initialize(LPCTSTR fontName, INT fontSize, UINT fontStyle, UINT fontDpi) { if (KG3DFTFontLibrary::Instance() == NULL) return false; FT_Long const DEFAULT_FACE_INDEX = 0; FT_Face pFontFace = NULL; FT_Error err = 0; err = FT_New_Face(KG3DFTFontLibrary::Instance()->m_library, fontName, DEFAULT_FACE_INDEX, &pFontFace); if (err != 0) { if (err == FT_Err_Unknown_File_Format) _ASSERT(0 && "FT_Err_Unknown_File_Format == err"); m_fontFace = NULL; return FALSE; } else { m_fontGlyphs = pFontFace->num_glyphs; m_fontUploads = pFontFace->num_glyphs; m_fontKerningTable = FT_HAS_KERNING(pFontFace); } // get face caps //if (!FT_HAS_VERTICAL(pFontFace)) if (!FT_IS_SCALABLE(pFontFace)) { _ASSERT(0 && "Sorry, font is not scalable."); return FALSE; } // get face encoding //m_fontFlagDraw = !fontAntialias ? FT_RENDER_MODE_MONO : FT_RENDER_MODE_NORMAL; m_fontEncoding = FT_ENCODING_UNICODE; m_fontUnicode = FALSE; if (NULL != pFontFace->charmap) { for (int i = 0; i < pFontFace->num_charmaps; ++ i) { if (FT_Encoding(m_fontEncoding) == pFontFace->charmaps[i]->encoding) { m_fontUnicode = TRUE; break ; } } if (!m_fontUnicode) { m_fontEncoding = pFontFace->charmaps[0]->encoding; m_fontUnicode = (m_fontEncoding == FT_ENCODING_UNICODE); } err = FT_Select_Charmap(pFontFace, FT_Encoding(m_fontEncoding)); if (0 != err) { _ASSERT(0 && "FT_Select_Charmap"); CleanUp(); return FALSE; } } else { m_fontEncoding = pFontFace->charmap->encoding; m_fontUnicode = (m_fontEncoding == FT_ENCODING_UNICODE); } // set char size err = FT_Set_Char_Size(pFontFace, 0L, FONT_FIXMULT(fontSize), fontDpi, fontDpi); if (0 != err) { // tmd; _ASSERT(0 && "FT_Set_Char_Size"); CleanUp(); return FALSE; } m_fontFace = pFontFace; m_fontPoint = fontSize; m_fontDPI = fontDpi; m_fontEffect = (fontStyle & (~KG3DFONT_STYLE_VERTICAL)); m_fontVertical = fontStyle & KG3DFONT_STYLE_VERTICAL; m_fontFlagLoader = m_fontVertical ? m_fontFlagLoader | FT_LOAD_VERTICAL_LAYOUT : m_fontFlagLoader; return TRUE; }
void gfxFT2LockedFace::GetMetrics(gfxFont::Metrics* aMetrics, PRUint32* aSpaceGlyph) { NS_PRECONDITION(aMetrics != NULL, "aMetrics must not be NULL"); NS_PRECONDITION(aSpaceGlyph != NULL, "aSpaceGlyph must not be NULL"); if (NS_UNLIKELY(!mFace)) { // No face. This unfortunate situation might happen if the font // file is (re)moved at the wrong time. aMetrics->emHeight = mGfxFont->GetStyle()->size; aMetrics->emAscent = 0.8 * aMetrics->emHeight; aMetrics->emDescent = 0.2 * aMetrics->emHeight; aMetrics->maxAscent = aMetrics->emAscent; aMetrics->maxDescent = aMetrics->maxDescent; aMetrics->maxHeight = aMetrics->emHeight; aMetrics->internalLeading = 0.0; aMetrics->externalLeading = 0.2 * aMetrics->emHeight; aSpaceGlyph = 0; aMetrics->spaceWidth = 0.5 * aMetrics->emHeight; aMetrics->maxAdvance = aMetrics->spaceWidth; aMetrics->aveCharWidth = aMetrics->spaceWidth; aMetrics->zeroOrAveCharWidth = aMetrics->spaceWidth; aMetrics->xHeight = 0.5 * aMetrics->emHeight; aMetrics->underlineSize = aMetrics->emHeight / 14.0; aMetrics->underlineOffset = -aMetrics->underlineSize; aMetrics->strikeoutOffset = 0.25 * aMetrics->emHeight; aMetrics->strikeoutSize = aMetrics->underlineSize; aMetrics->superscriptOffset = aMetrics->xHeight; aMetrics->subscriptOffset = aMetrics->xHeight; return; } const FT_Size_Metrics& ftMetrics = mFace->size->metrics; gfxFloat emHeight; // Scale for vertical design metric conversion: pixels per design unit. gfxFloat yScale; if (FT_IS_SCALABLE(mFace)) { // Prefer FT_Size_Metrics::x_scale to x_ppem as x_ppem does not // have subpixel accuracy. // // FT_Size_Metrics::y_scale is in 16.16 fixed point format. Its // (fractional) value is a factor that converts vertical metrics from // design units to units of 1/64 pixels, so that the result may be // interpreted as pixels in 26.6 fixed point format. yScale = FLOAT_FROM_26_6(FLOAT_FROM_16_16(ftMetrics.y_scale)); emHeight = mFace->units_per_EM * yScale; } else { // Not scalable. // FT_Size_Metrics doc says x_scale is "only relevant for scalable // font formats". gfxFloat emUnit = mFace->units_per_EM; emHeight = ftMetrics.y_ppem; yScale = emHeight / emUnit; } TT_OS2 *os2 = static_cast<TT_OS2*>(FT_Get_Sfnt_Table(mFace, ft_sfnt_os2)); aMetrics->maxAscent = FLOAT_FROM_26_6(ftMetrics.ascender); aMetrics->maxDescent = -FLOAT_FROM_26_6(ftMetrics.descender); aMetrics->maxAdvance = FLOAT_FROM_26_6(ftMetrics.max_advance); gfxFloat lineHeight; if (os2 && os2->sTypoAscender) { aMetrics->emAscent = os2->sTypoAscender * yScale; aMetrics->emDescent = -os2->sTypoDescender * yScale; FT_Short typoHeight = os2->sTypoAscender - os2->sTypoDescender + os2->sTypoLineGap; lineHeight = typoHeight * yScale; // maxAscent/maxDescent get used for frame heights, and some fonts // don't have the HHEA table ascent/descent set (bug 279032). if (aMetrics->emAscent > aMetrics->maxAscent) aMetrics->maxAscent = aMetrics->emAscent; if (aMetrics->emDescent > aMetrics->maxDescent) aMetrics->maxDescent = aMetrics->emDescent; } else { aMetrics->emAscent = aMetrics->maxAscent; aMetrics->emDescent = aMetrics->maxDescent; lineHeight = FLOAT_FROM_26_6(ftMetrics.height); } cairo_text_extents_t extents; *aSpaceGlyph = GetCharExtents(' ', &extents); if (*aSpaceGlyph) { aMetrics->spaceWidth = extents.x_advance; } else { aMetrics->spaceWidth = aMetrics->maxAdvance; // guess } aMetrics->zeroOrAveCharWidth = 0.0; if (GetCharExtents('0', &extents)) { aMetrics->zeroOrAveCharWidth = extents.x_advance; } // Prefering a measured x over sxHeight because sxHeight doesn't consider // hinting, but maybe the x extents are not quite right in some fancy // script fonts. CSS 2.1 suggests possibly using the height of an "o", // which would have a more consistent glyph across fonts. if (GetCharExtents('x', &extents) && extents.y_bearing < 0.0) { aMetrics->xHeight = -extents.y_bearing; aMetrics->aveCharWidth = extents.x_advance; } else { if (os2 && os2->sxHeight) { aMetrics->xHeight = os2->sxHeight * yScale; } else { // CSS 2.1, section 4.3.2 Lengths: "In the cases where it is // impossible or impractical to determine the x-height, a value of // 0.5em should be used." aMetrics->xHeight = 0.5 * emHeight; } aMetrics->aveCharWidth = 0.0; // updated below } // aveCharWidth is used for the width of text input elements so be // liberal rather than conservative in the estimate. if (os2 && os2->xAvgCharWidth) { // Round to pixels as this is compared with maxAdvance to guess // whether this is a fixed width font. gfxFloat avgCharWidth = ScaleRoundDesignUnits(os2->xAvgCharWidth, ftMetrics.x_scale); aMetrics->aveCharWidth = NS_MAX(aMetrics->aveCharWidth, avgCharWidth); } aMetrics->aveCharWidth = NS_MAX(aMetrics->aveCharWidth, aMetrics->zeroOrAveCharWidth); if (aMetrics->aveCharWidth == 0.0) { aMetrics->aveCharWidth = aMetrics->spaceWidth; } if (aMetrics->zeroOrAveCharWidth == 0.0) { aMetrics->zeroOrAveCharWidth = aMetrics->aveCharWidth; } // Apparently hinting can mean that max_advance is not always accurate. aMetrics->maxAdvance = NS_MAX(aMetrics->maxAdvance, aMetrics->aveCharWidth); // gfxFont::Metrics::underlineOffset is the position of the top of the // underline. // // FT_FaceRec documentation describes underline_position as "the // center of the underlining stem". This was the original definition // of the PostScript metric, but in the PostScript table of OpenType // fonts the metric is "the top of the underline" // (http://www.microsoft.com/typography/otspec/post.htm), and FreeType // (up to version 2.3.7) doesn't make any adjustment. // // Therefore get the underline position directly from the table // ourselves when this table exists. Use FreeType's metrics for // other (including older PostScript) fonts. if (mFace->underline_position && mFace->underline_thickness) { aMetrics->underlineSize = mFace->underline_thickness * yScale; TT_Postscript *post = static_cast<TT_Postscript*> (FT_Get_Sfnt_Table(mFace, ft_sfnt_post)); if (post && post->underlinePosition) { aMetrics->underlineOffset = post->underlinePosition * yScale; } else { aMetrics->underlineOffset = mFace->underline_position * yScale + 0.5 * aMetrics->underlineSize; } } else { // No underline info. // Imitate Pango. aMetrics->underlineSize = emHeight / 14.0; aMetrics->underlineOffset = -aMetrics->underlineSize; } if (os2 && os2->yStrikeoutSize && os2->yStrikeoutPosition) { aMetrics->strikeoutSize = os2->yStrikeoutSize * yScale; aMetrics->strikeoutOffset = os2->yStrikeoutPosition * yScale; } else { // No strikeout info. aMetrics->strikeoutSize = aMetrics->underlineSize; // Use OpenType spec's suggested position for Roman font. aMetrics->strikeoutOffset = emHeight * 409.0 / 2048.0 + 0.5 * aMetrics->strikeoutSize; } SnapLineToPixels(aMetrics->strikeoutOffset, aMetrics->strikeoutSize); if (os2 && os2->ySuperscriptYOffset) { gfxFloat val = ScaleRoundDesignUnits(os2->ySuperscriptYOffset, ftMetrics.y_scale); aMetrics->superscriptOffset = NS_MAX(1.0, val); } else { aMetrics->superscriptOffset = aMetrics->xHeight; } if (os2 && os2->ySubscriptYOffset) { gfxFloat val = ScaleRoundDesignUnits(os2->ySubscriptYOffset, ftMetrics.y_scale); // some fonts have the incorrect sign. val = fabs(val); aMetrics->subscriptOffset = NS_MAX(1.0, val); } else { aMetrics->subscriptOffset = aMetrics->xHeight; } aMetrics->maxHeight = aMetrics->maxAscent + aMetrics->maxDescent; // Make the line height an integer number of pixels so that lines will be // equally spaced (rather than just being snapped to pixels, some up and // some down). Layout calculates line height from the emHeight + // internalLeading + externalLeading, but first each of these is rounded // to layout units. To ensure that the result is an integer number of // pixels, round each of the components to pixels. aMetrics->emHeight = NS_floor(emHeight + 0.5); // maxHeight will normally be an integer, but round anyway in case // FreeType is configured differently. aMetrics->internalLeading = NS_floor(aMetrics->maxHeight - aMetrics->emHeight + 0.5); // Text input boxes currently don't work well with lineHeight // significantly less than maxHeight (with Verdana, for example). lineHeight = NS_floor(NS_MAX(lineHeight, aMetrics->maxHeight) + 0.5); aMetrics->externalLeading = lineHeight - aMetrics->internalLeading - aMetrics->emHeight; // Ensure emAscent + emDescent == emHeight gfxFloat sum = aMetrics->emAscent + aMetrics->emDescent; aMetrics->emAscent = sum > 0.0 ? aMetrics->emAscent * aMetrics->emHeight / sum : 0.0; aMetrics->emDescent = aMetrics->emHeight - aMetrics->emAscent; }
/** * @brief Initializes a font. * * @param font Font to load (NULL defaults to gl_defFont). * @param fname Name of the font (from inside packfile, NULL defaults to default font). * @param h Height of the font to generate. * @return 0 on success. */ int gl_fontInit( glFont* font, const char *fname, const char *fallback, const unsigned int h ) { FT_Library library; FT_Face face; size_t bufsize; FT_Byte* buf; int i; glFontStash *stsh; char *used_font; /* See if we should override fonts. */ used_font = NULL; if ((strcmp( fallback, FONT_DEFAULT_PATH )==0) && (conf.font_name_default!=NULL)) { used_font = strdup( conf.font_name_default ); } else if ((strcmp( fallback, FONT_MONOSPACE_PATH )==0) && (conf.font_name_monospace!=NULL)) { used_font = strdup( conf.font_name_monospace ); } if (used_font) { buf = (FT_Byte*)nfile_readFile( &bufsize, used_font ); if (buf==NULL) { free(used_font); used_font = NULL; } } /* Try to use system font. */ if (used_font==NULL) { used_font = gl_fontFind( fname ); if (used_font) { buf = (FT_Byte*)nfile_readFile( &bufsize, used_font ); if (buf==NULL) { free(used_font); used_font = NULL; } } } /* Fallback to packaged font. */ if (used_font==NULL) { buf = ndata_read( (fallback!=NULL) ? fallback : FONT_DEFAULT_PATH, &bufsize ); if (buf == NULL) { WARN(_("Unable to read font: %s"), (fallback!=NULL) ? fallback : FONT_DEFAULT_PATH); return -1; } used_font = strdup( fallback ); } /* Get default font if not set. */ if (font == NULL) { font = &gl_defFont; DEBUG( _("Using default font '%s'"), used_font ); } /* Get font stash. */ if (avail_fonts==NULL) avail_fonts = array_create( glFontStash ); stsh = &array_grow( &avail_fonts ); memset( stsh, 0, sizeof(glFontStash) ); font->id = stsh - avail_fonts; font->h = (int)floor((double)h); /* Default sizes. */ stsh->tw = DEFAULT_TEXTURE_SIZE; stsh->th = DEFAULT_TEXTURE_SIZE; stsh->h = font->h; /* Create a FreeType font library. */ if (FT_Init_FreeType(&library)) { WARN(_("FT_Init_FreeType failed with font %s."), (used_font!=NULL) ? used_font : FONT_DEFAULT_PATH ); return -1; } /* Object which freetype uses to store font info. */ if (FT_New_Memory_Face( library, buf, bufsize, 0, &face )) { WARN(_("FT_New_Face failed loading library from %s"), (used_font!=NULL) ? used_font : FONT_DEFAULT_PATH ); return -1; } /* Try to resize. */ if (FT_IS_SCALABLE(face)) { if (FT_Set_Char_Size( face, 0, /* Same as width. */ h << 6, /* In 1/64th of a pixel. */ 96, /* Create at 96 DPI */ 96)) /* Create at 96 DPI */ WARN(_("FT_Set_Char_Size failed.")); } else WARN(_("Font isn't resizable!")); /* Select the character map. */ if (FT_Select_Charmap( face, FT_ENCODING_UNICODE )) WARN(_("FT_Select_Charmap failed to change character mapping.")); /* Initialize the unicode support. */ for (i=0; i<HASH_LUT_SIZE; i++) stsh->lut[i] = -1; stsh->glyphs = array_create( glFontGlyph ); stsh->tex = array_create( glFontTex ); /* Set up font stuff for next glyphs. */ stsh->fontname = strdup( (used_font!=NULL) ? used_font : FONT_DEFAULT_PATH ); stsh->face = face; stsh->library = library; stsh->fontdata = buf; /* Set up VBOs. */ stsh->mvbo = 256; stsh->vbo_tex_data = calloc( 8*stsh->mvbo, sizeof(GLfloat) ); stsh->vbo_vert_data = calloc( 8*stsh->mvbo, sizeof(GLshort) ); stsh->vbo_tex = gl_vboCreateStatic( sizeof(GLfloat)*8*stsh->mvbo, stsh->vbo_tex_data ); stsh->vbo_vert = gl_vboCreateStatic( sizeof(GLshort)*8*stsh->mvbo, stsh->vbo_vert_data ); /* Initializes ASCII. */ for (i=0; i<128; i++) gl_fontGetGlyph( stsh, i ); #if 0 /* We can now free the face and library */ FT_Done_Face(face); FT_Done_FreeType(library); /* Free read buffer. */ free(buf); #endif return 0; }