// load all glyphs static void LoadGlyphs(GFont2D& Font, const FT_Face Face, const GReal Scale) { GInt32 i, j; j = (GInt32)Face->num_glyphs; for (i = 0; i < j; i++) LoadGlyph(Font, Face, i, Scale); }
CTextRenderer::CGlyph* CTextRenderer::GetGlyph(CGlyphCache* pCache, CGlyphId GlyphId) { CTextRenderer::CGlyph* pGlyph = FindGlyph(pCache, GlyphId); //Load Glyph if(!pGlyph) pGlyph = LoadGlyph(pCache, GlyphId); //Update timer if(pGlyph) pGlyph->m_RenderTick = m_RenderTick; return pGlyph; }
Geom::PathVector* font_instance::PathVector(int glyph_id) { int no = -1; if ( id_to_no.find(glyph_id) == id_to_no.end() ) { LoadGlyph(glyph_id); if ( id_to_no.find(glyph_id) == id_to_no.end() ) { // didn't load } else { no = id_to_no[glyph_id]; } } else { no = id_to_no[glyph_id]; } if ( no < 0 ) return NULL; return glyphs[no].pathvector; }
// Get the given character's glyph Font::Glyph& Font::GetGlyph( char ch, unsigned int size ) { GlyphTable& glyphTable = _pages[ size ].Glyphs; // If the character already exists auto search = glyphTable.find( ch ); if ( search != glyphTable.end() ) { // Return its glyph return search->second; } else { // Otherwise we need to add the glyph Glyph glyph = LoadGlyph( ch, size ); return glyphTable.insert( std::make_pair( ch, glyph ) ).first->second; } }
Geom::OptRect font_instance::BBox(int glyph_id) { int no = -1; if ( id_to_no.find(glyph_id) == id_to_no.end() ) { LoadGlyph(glyph_id); if ( id_to_no.find(glyph_id) == id_to_no.end() ) { // didn't load } else { no = id_to_no[glyph_id]; } } else { no = id_to_no[glyph_id]; } if ( no < 0 ) { return Geom::OptRect(); } else { Geom::Point rmin(glyphs[no].bbox[0],glyphs[no].bbox[1]); Geom::Point rmax(glyphs[no].bbox[2],glyphs[no].bbox[3]); return Geom::Rect(rmin, rmax); } }
const Glyph& Font::GetGlyph(Uint32 codePoint, unsigned int characterSize, bool bold) const { // Get the page corresponding to the character size GlyphTable& glyphs = myPages[characterSize].Glyphs; // Build the key by combining the code point and the bold flag Uint32 key = ((bold ? 1 : 0) << 31) | codePoint; // Search the glyph into the cache GlyphTable::const_iterator it = glyphs.find(key); if (it != glyphs.end()) { // Found: just return it return it->second; } else { // Not found: we have to load it Glyph glyph = LoadGlyph(codePoint, characterSize, bold); return glyphs.insert(std::make_pair(key, glyph)).first->second; } }
double font_instance::Advance(int glyph_id,bool vertical) { int no = -1; if ( id_to_no.find(glyph_id) == id_to_no.end() ) { LoadGlyph(glyph_id); if ( id_to_no.find(glyph_id) == id_to_no.end() ) { // didn't load } else { no=id_to_no[glyph_id]; } } else { no = id_to_no[glyph_id]; } if ( no >= 0 ) { if ( vertical ) { return glyphs[no].v_advance; } else { return glyphs[no].h_advance; } } return 0; }
SDL_Surface* TTF_RenderASCII(TTF_Font* font, const char* text, int textlen, SDL_Color fg, SDL_Color bg, int style) { if (textlen <= 0) E_Exit("TTF: Draw text called with invalid length"); SDL_Surface* surface = SDL_CreateRGBSurface(SDL_SWSURFACE, textlen*font->width, font->height, 8, 0, 0, 0, 0); // Create the target surface if (surface == NULL) E_Exit("TTF: Draw string couldn't create surface"); SDL_Palette* palette = surface->format->palette; // Fill the palette with NUM_GRAYS levels of shading from bg to fg int rdiff = fg.r-bg.r; int gdiff = fg.g-bg.g; int bdiff = fg.b-bg.b; for (int i = 0; i < NUM_GRAYS; ++i) { palette->colors[i].r = bg.r+(i*rdiff)/(NUM_GRAYS-1); palette->colors[i].g = bg.g+(i*gdiff)/(NUM_GRAYS-1); palette->colors[i].b = bg.b+(i*bdiff)/(NUM_GRAYS-1); } int prevChar = 256; for (int xPos = 0; xPos < textlen; xPos++) // Load and render each character { if (text[xPos] == prevChar) // If it's the same as the previous, just copy { // Could be futher optimzed counting repeated characters Uint8* dst = (Uint8*)surface->pixels+xPos*font->width; // and using a "smart" copy procedure for (int row = 0; row < font->height; row++) // but updating the window is no hotspot { memcpy(dst, dst-font->width, font->width); dst += surface->pitch; } } else { prevChar = text[xPos]; c_glyph *glyph = LoadGlyph(font, prevChar); if (!glyph) E_Exit("TTF: Couldn't load glyph"); FT_Bitmap* pixmap = &glyph->pixmap; int width = pixmap->width; if (width > font->width) width = font->width; int xstart = xPos*font->width; for (int row = 0; row < pixmap->rows; ++row) { if (row+glyph->yoffset < 0 || row+glyph->yoffset >= surface->h) // Make sure we don't go either over, or under the limit continue; Uint8* dst = (Uint8*)surface->pixels+(row+glyph->yoffset)*surface->pitch+xstart+glyph->minx; Uint8* src = pixmap->buffer+row*pixmap->pitch; for (int col = width; col > 0; --col) *dst++ |= *src++; } } } if (style&TTF_STYLE_UNDERLINE) // Add underline memset((Uint8 *)surface->pixels+(font->ascent-font->underline_offset-1)*surface->pitch, NUM_GRAYS-1, font->underline_height*surface->pitch); if (style&TTF_STYLE_STRIKETHROUGH) // Add strikethrough memset((Uint8 *)surface->pixels+(font->height/2)*surface->pitch, NUM_GRAYS-1, font->underline_height*surface->pitch); return surface; }
//----------------------------------------------------------------------------- // Load a TrueType font into memory. We care about the curves that define // the letter shapes, and about the mappings that determine which glyph goes // with which character. //----------------------------------------------------------------------------- bool TtfFont::LoadFontFromFile(bool nameOnly) { if(loaded) return true; int i; fh = fopen(fontFile, "rb"); if(!fh) { return false; } try { // First, load the Offset Table DWORD version = GetDWORD(); WORD numTables = GetWORD(); WORD searchRange = GetWORD(); WORD entrySelector = GetWORD(); WORD rangeShift = GetWORD(); // Now load the Table Directory; our goal in doing this will be to // find the addresses of the tables that we will need. DWORD glyfAddr = -1, glyfLen; DWORD cmapAddr = -1, cmapLen; DWORD headAddr = -1, headLen; DWORD locaAddr = -1, locaLen; DWORD maxpAddr = -1, maxpLen; DWORD nameAddr = -1, nameLen; DWORD hmtxAddr = -1, hmtxLen; DWORD hheaAddr = -1, hheaLen; for(i = 0; i < numTables; i++) { char tag[5] = "xxxx"; tag[0] = GetBYTE(); tag[1] = GetBYTE(); tag[2] = GetBYTE(); tag[3] = GetBYTE(); DWORD checksum = GetDWORD(); DWORD offset = GetDWORD(); DWORD length = GetDWORD(); if(strcmp(tag, "glyf")==0) { glyfAddr = offset; glyfLen = length; } else if(strcmp(tag, "cmap")==0) { cmapAddr = offset; cmapLen = length; } else if(strcmp(tag, "head")==0) { headAddr = offset; headLen = length; } else if(strcmp(tag, "loca")==0) { locaAddr = offset; locaLen = length; } else if(strcmp(tag, "maxp")==0) { maxpAddr = offset; maxpLen = length; } else if(strcmp(tag, "name")==0) { nameAddr = offset; nameLen = length; } else if(strcmp(tag, "hhea")==0) { hheaAddr = offset; hheaLen = length; } else if(strcmp(tag, "hmtx")==0) { hmtxAddr = offset; hmtxLen = length; } } if(glyfAddr == -1 || cmapAddr == -1 || headAddr == -1 || locaAddr == -1 || maxpAddr == -1 || hmtxAddr == -1 || nameAddr == -1 || hheaAddr == -1) { throw "missing table addr"; } // Load the name table. This gives us display names for the font, which // we need when we're giving the user a list to choose from. fseek(fh, nameAddr, SEEK_SET); WORD nameFormat = GetWORD(); WORD nameCount = GetWORD(); WORD nameStringOffset = GetWORD(); // And now we're at the name records. Go through those till we find // one that we want. int displayNameOffset, displayNameLength; for(i = 0; i < nameCount; i++) { WORD platformID = GetWORD(); WORD encodingID = GetWORD(); WORD languageID = GetWORD(); WORD nameId = GetWORD(); WORD length = GetWORD(); WORD offset = GetWORD(); if(nameId == 4) { displayNameOffset = offset; displayNameLength = length; break; } } if(nameOnly && i >= nameCount) { throw "no name"; } if(nameOnly) { // Find the display name, and store it in the provided buffer. fseek(fh, nameAddr+nameStringOffset+displayNameOffset, SEEK_SET); int c = 0; for(i = 0; i < displayNameLength; i++) { BYTE b = GetBYTE(); if(b && c < (sizeof(name.str) - 2)) { name.str[c++] = b; } } name.str[c++] = '\0'; fclose(fh); return true; } // Load the head table; we need this to determine the format of the // loca table, 16- or 32-bit entries fseek(fh, headAddr, SEEK_SET); DWORD headVersion = GetDWORD(); DWORD headFontRevision = GetDWORD(); DWORD headCheckSumAdj = GetDWORD(); DWORD headMagicNumber = GetDWORD(); WORD headFlags = GetWORD(); WORD headUnitsPerEm = GetWORD(); (void)GetDWORD(); // created time (void)GetDWORD(); (void)GetDWORD(); // modified time (void)GetDWORD(); WORD headXmin = GetWORD(); WORD headYmin = GetWORD(); WORD headXmax = GetWORD(); WORD headYmax = GetWORD(); WORD headMacStyle = GetWORD(); WORD headLowestRecPPEM = GetWORD(); WORD headFontDirectionHint = GetWORD(); WORD headIndexToLocFormat = GetWORD(); WORD headGlyphDataFormat = GetWORD(); if(headMagicNumber != 0x5F0F3CF5) { throw "bad magic number"; } // Load the hhea table, which contains the number of entries in the // horizontal metrics (hmtx) table. fseek(fh, hheaAddr, SEEK_SET); DWORD hheaVersion = GetDWORD(); WORD hheaAscender = GetWORD(); WORD hheaDescender = GetWORD(); WORD hheaLineGap = GetWORD(); WORD hheaAdvanceWidthMax = GetWORD(); WORD hheaMinLsb = GetWORD(); WORD hheaMinRsb = GetWORD(); WORD hheaXMaxExtent = GetWORD(); WORD hheaCaretSlopeRise = GetWORD(); WORD hheaCaretSlopeRun = GetWORD(); WORD hheaCaretOffset = GetWORD(); (void)GetWORD(); (void)GetWORD(); (void)GetWORD(); (void)GetWORD(); WORD hheaMetricDataFormat = GetWORD(); WORD hheaNumberOfMetrics = GetWORD(); // Load the maxp table, which determines (among other things) the number // of glyphs in the font fseek(fh, maxpAddr, SEEK_SET); DWORD maxpVersion = GetDWORD(); WORD maxpNumGlyphs = GetWORD(); WORD maxpMaxPoints = GetWORD(); WORD maxpMaxContours = GetWORD(); WORD maxpMaxComponentPoints = GetWORD(); WORD maxpMaxComponentContours = GetWORD(); WORD maxpMaxZones = GetWORD(); WORD maxpMaxTwilightPoints = GetWORD(); WORD maxpMaxStorage = GetWORD(); WORD maxpMaxFunctionDefs = GetWORD(); WORD maxpMaxInstructionDefs = GetWORD(); WORD maxpMaxStackElements = GetWORD(); WORD maxpMaxSizeOfInstructions = GetWORD(); WORD maxpMaxComponentElements = GetWORD(); WORD maxpMaxComponentDepth = GetWORD(); glyphs = maxpNumGlyphs; glyph = (Glyph *)MemAlloc(glyphs*sizeof(glyph[0])); // Load the hmtx table, which gives the horizontal metrics (spacing // and advance width) of the font. fseek(fh, hmtxAddr, SEEK_SET); WORD hmtxAdvanceWidth; SWORD hmtxLsb; for(i = 0; i < min(glyphs, hheaNumberOfMetrics); i++) { hmtxAdvanceWidth = GetWORD(); hmtxLsb = (SWORD)GetWORD(); glyph[i].leftSideBearing = hmtxLsb; glyph[i].advanceWidth = hmtxAdvanceWidth; } // The last entry in the table applies to all subsequent glyphs also. for(; i < glyphs; i++) { glyph[i].leftSideBearing = hmtxLsb; glyph[i].advanceWidth = hmtxAdvanceWidth; } // Load the cmap table, which determines the mapping of characters to // glyphs. fseek(fh, cmapAddr, SEEK_SET); DWORD usedTableAddr = -1; WORD cmapVersion = GetWORD(); WORD cmapTableCount = GetWORD(); for(i = 0; i < cmapTableCount; i++) { WORD platformId = GetWORD(); WORD encodingId = GetWORD(); DWORD offset = GetDWORD(); if(platformId == 3 && encodingId == 1) { // The Windows Unicode mapping is our preference usedTableAddr = cmapAddr + offset; } } if(usedTableAddr == -1) { throw "no used table addr"; } // So we can load the desired subtable; in this case, Windows Unicode, // which is us. fseek(fh, usedTableAddr, SEEK_SET); WORD mapFormat = GetWORD(); WORD mapLength = GetWORD(); WORD mapVersion = GetWORD(); WORD mapSegCountX2 = GetWORD(); WORD mapSearchRange = GetWORD(); WORD mapEntrySelector = GetWORD(); WORD mapRangeShift = GetWORD(); if(mapFormat != 4) { // Required to use format 4 per spec throw "not format 4"; } int segCount = mapSegCountX2 / 2; WORD *endChar = (WORD *)AllocTemporary(segCount*sizeof(WORD)); WORD *startChar = (WORD *)AllocTemporary(segCount*sizeof(WORD)); WORD *idDelta = (WORD *)AllocTemporary(segCount*sizeof(WORD)); WORD *idRangeOffset = (WORD *)AllocTemporary(segCount*sizeof(WORD)); DWORD *filePos = (DWORD *)AllocTemporary(segCount*sizeof(DWORD)); for(i = 0; i < segCount; i++) { endChar[i] = GetWORD(); } WORD mapReservedPad = GetWORD(); for(i = 0; i < segCount; i++) { startChar[i] = GetWORD(); } for(i = 0; i < segCount; i++) { idDelta[i] = GetWORD(); } for(i = 0; i < segCount; i++) { filePos[i] = ftell(fh); idRangeOffset[i] = GetWORD(); } // So first, null out the glyph table in our in-memory representation // of the font; any character for which cmap does not provide a glyph // corresponds to -1 for(i = 0; i < arraylen(useGlyph); i++) { useGlyph[i] = 0; } for(i = 0; i < segCount; i++) { WORD v = idDelta[i]; if(idRangeOffset[i] == 0) { int j; for(j = startChar[i]; j <= endChar[i]; j++) { if(j > 0 && j < arraylen(useGlyph)) { // Don't create a reference to a glyph that we won't // store because it's bigger than the table. if((WORD)(j + v) < glyphs) { // Arithmetic is modulo 2^16 useGlyph[j] = (WORD)(j + v); } } } } else { int j; for(j = startChar[i]; j <= endChar[i]; j++) { if(j > 0 && j < arraylen(useGlyph)) { int fp = filePos[i]; fp += (j - startChar[i])*sizeof(WORD); fp += idRangeOffset[i]; fseek(fh, fp, SEEK_SET); useGlyph[j] = GetWORD(); } } } } // Load the loca table. This contains the offsets of each glyph, // relative to the beginning of the glyf table. fseek(fh, locaAddr, SEEK_SET); DWORD *glyphOffsets = (DWORD *)AllocTemporary(glyphs*sizeof(DWORD)); for(i = 0; i < glyphs; i++) { if(headIndexToLocFormat == 1) { // long offsets, 32 bits glyphOffsets[i] = GetDWORD(); } else if(headIndexToLocFormat == 0) { // short offsets, 16 bits but divided by 2 glyphOffsets[i] = GetWORD()*2; } else { throw "bad headIndexToLocFormat"; } } scale = 1024; // Load the glyf table. This contains the actual representations of the // letter forms, as piecewise linear or quadratic outlines. for(i = 0; i < glyphs; i++) { fseek(fh, glyfAddr + glyphOffsets[i], SEEK_SET); LoadGlyph(i); } } catch (char *s) { dbp("failed: '%s'", s); fclose(fh); return false; } fclose(fh); loaded = true; return true; }