GlyphMetrics GlyphCache::get_metrics(FontEngine *font_engine, const CanvasPtr &canvas, unsigned int glyph) { Font_TextureGlyph *gptr = get_glyph(canvas, font_engine, glyph); if (gptr) { return gptr->metrics; } return GlyphMetrics(); }
GlyphMetrics Font::measure_text(Canvas &canvas, const std::string &string) { if (impl) return impl->measure_text(canvas, string); return GlyphMetrics(); }
GlyphMetrics Font::get_metrics(Canvas &canvas, unsigned int glyph) { if (impl) return impl->get_metrics(canvas, glyph); return GlyphMetrics(); }
void Draw::DrawText(int x, int y, int angle, const wchar *text, Font font, Color ink, int n, const int *dx) { #if defined(flagWINGL) || defined(flagLINUXGL) if(IsNull(ink)) return; DrawTextOp(x, y, angle, text, font, ink, n, dx); #else if(IsNull(ink)) return; if(n < 0) n = wstrlen(text); Std(font); double sina = 0; double cosa = 1; int posx = 0; if(angle) Draw::SinCos(angle, sina, cosa); Font font0 = font; if(GetInfo() & DRAWTEXTLINES) font.Underline(false).Strikeout(false); for(int i = 0; i < n; i++) { wchar chr = text[i]; GlyphInfo gi = GetGlyphInfo(font, chr); if(gi.IsNormal()) if(angle) DrawTextOp(int(x + cosa * posx), int(y - sina * posx), angle, &chr, font, ink, 1, NULL); else { int c = 1; int dd = 0; while(i + c < n && c < 1000) { GlyphInfo gi2 = GetGlyphInfo(font, text[i + c]); if(!gi2.IsNormal()) break; dd += dx ? dx[c - 1] : gi.width; c++; gi = gi2; } DrawTextOp(x + posx, y, 0, text + i, font, ink, c, dx); posx += dd; i += c - 1; if(dx) dx += c - 1; } else if(gi.IsReplaced()) { Font fnt = font; fnt.Face(gi.lspc); fnt.Height(gi.rspc); if(angle) DrawTextOp(int(x + cosa * posx), int(y - sina * (font.GetAscent() - fnt.GetAscent() + posx)), angle, &chr, fnt, ink, 1, NULL); else DrawTextOp(x + posx, y + font.GetAscent() - fnt.GetAscent(), 0, &chr, fnt, ink, 1, NULL); GlyphMetrics(gi, font, chr); } else if(gi.IsComposed()) { ComposedGlyph cg; Compose(font, chr, cg); if(angle) { DrawTextOp(int(x + cosa * posx), int(y - sina * posx), angle, &cg.basic_char, font, ink, 1, NULL); DrawTextOp(int(x + cosa * (posx + cg.mark_pos.x)), int(y - sina * (cg.mark_pos.y + posx)), angle, &cg.mark_char, cg.mark_font, ink, 1, NULL); } else { DrawTextOp(x + posx, y, 0, &cg.basic_char, font, ink, 1, NULL); DrawTextOp(x + cg.mark_pos.x + posx, y + cg.mark_pos.y, 0, &cg.mark_char, cg.mark_font, ink, 1, NULL); } GlyphMetrics(gi, font, chr); } else { Font fnt = Arial(font.GetHeight()); wchar chr = 0x25a1; gi = GetGlyphInfo(fnt, chr); if(!gi.IsNormal()) { chr = ' '; gi = GetGlyphInfo(fnt, chr); } if(angle) DrawTextOp(int(x + cosa * posx), int(y - sina * posx), angle, &chr, fnt, ink, 1, NULL); else DrawTextOp(x + posx, y, 0, &chr, fnt, ink, 1, NULL); } posx += dx ? *dx++ : gi.width; } if((GetInfo() & DRAWTEXTLINES) && (font0.IsUnderline() || font0.IsStrikeout())) { int hg = abs(font0.GetCy()); if(hg == 0) hg = 10; int thickness = max(hg / 20, 1); int ascent = font0.GetAscent(); Size offset = Point(0, ascent); if(angle) { offset.cx = fround(ascent * sina); offset.cy = fround(ascent * cosa); } x += offset.cx; y += offset.cy; if(font0.IsUnderline()) { int p = max(hg / 15, int(font0.Info().GetDescent() > 0)); DrawLine( int(x + p * sina), int(y + p * cosa), int(x + posx * cosa + p * sina), int(y - posx * sina + p * cosa), thickness, ink ); } if(font0.IsStrikeout()) { int p = -ascent / 3; DrawLine( int(x + p * sina), int(y + p * cosa), int(x + posx * cosa + p * sina), int(y - posx * sina + p * cosa), thickness, ink ); } } #endif }
void Draw::DrawText(int x, int y, int angle, const wchar *text, Font font, Color ink, int n, const int *dx) { #ifdef flagWINGL if(IsNull(ink)) return; DrawTextOp(x, y, angle, text, font, ink, n, dx); #else if(IsNull(ink)) return; if(n < 0) n = wstrlen(text); Std(font); double sina; double cosa; int d = 0; if(angle) Draw::SinCos(angle, sina, cosa); for(int i = 0; i < n; i++) { wchar chr = text[i]; GlyphInfo gi = GetGlyphInfo(font, chr); if(gi.IsNormal()) if(angle) DrawTextOp(int(x + cosa * d), int(y - sina * d), angle, &chr, font, ink, 1, NULL); else { int c = 1; int dd = 0; while(i + c < n) { GlyphInfo gi2 = GetGlyphInfo(font, text[i + c]); if(!gi2.IsNormal()) break; dd += dx ? dx[c] : gi.width; c++; gi = gi2; } DrawTextOp(x + d, y, 0, text + i, font, ink, c, dx); d += dd; i += c - 1; if(dx) dx += c - 1; } else if(gi.IsReplaced()) { Font fnt = font; fnt.Face(gi.lspc); fnt.Height(gi.rspc); if(angle) DrawTextOp(int(x + cosa * d), int(y - sina * (font.GetAscent() - fnt.GetAscent() + d)), angle, &chr, fnt, ink, 1, NULL); else DrawTextOp(x + d, y + font.GetAscent() - fnt.GetAscent(), 0, &chr, fnt, ink, 1, NULL); GlyphMetrics(gi, font, chr); } else if(gi.IsComposed()) { ComposedGlyph cg; Compose(font, chr, cg); if(angle) { DrawTextOp(int(x + cosa * d), int(y - sina * d), angle, &cg.basic_char, font, ink, 1, NULL); DrawTextOp(int(x + cosa * (d + cg.mark_pos.x)), int(y - sina * (cg.mark_pos.y + d)), angle, &cg.mark_char, cg.mark_font, ink, 1, NULL); } else { DrawTextOp(x + d, y, 0, &cg.basic_char, font, ink, 1, NULL); DrawTextOp(x + cg.mark_pos.x + d, y + cg.mark_pos.y, 0, &cg.mark_char, cg.mark_font, ink, 1, NULL); } GlyphMetrics(gi, font, chr); } else { Font fnt = Arial(font.GetHeight()); wchar chr = 0x25a1; gi = GetGlyphInfo(fnt, chr); if(!gi.IsNormal()) { chr = ' '; gi = GetGlyphInfo(fnt, chr); } if(angle) DrawTextOp(int(x + cosa * d), int(y - sina * d), angle, &chr, fnt, ink, 1, NULL); else DrawTextOp(x + d, y, 0, &chr, fnt, ink, 1, NULL); } d += dx ? *dx++ : gi.width; } #endif }
void FontFamily_Impl::font_face_load(Canvas &canvas, Sprite &sprite, const std::string &glyph_list, float spacelen, bool monospace, const FontMetrics &metrics) { FontMetrics font_metrics = metrics; const int length = StringHelp::utf8_length(glyph_list); if ((length > sprite.get_frame_count()) || (length == 0)) { throw Exception(string_format("Font error: Letter characters: %1, Available font glyphs: %2", length, sprite.get_frame_count())); } //If monospace font requested, find the width of the widest glyph //Then set the fixed_width var to that width //Also set space to that width, if unset int fixed_width = 0; if (monospace) { for (int i = 0; i < length; ++i) { int glyph_width = sprite.get_frame_size(i).width; if (glyph_width > fixed_width) fixed_width = glyph_width; } if (spacelen) spacelen = fixed_width; } //If not monospace, and space width not specified, then use average width as space width else if (spacelen <= 0) { std::string::size_type space_pos = glyph_list.find(' '); if (space_pos != std::string::npos) { //If there is a character for space, then use it spacelen = sprite.get_frame_size((int)space_pos).width; } else { //Make the space size the average of all character sizes spacelen = 0; for (int pos = 0; pos < length; ++pos) { spacelen += sprite.get_frame_size((int)(pos)).width; } spacelen /= length; } } int height = 0; for (int i = 0; i < length; ++i) { int glyph_height = sprite.get_frame_size(i).height; if (glyph_height > height) height = glyph_height; } if (font_metrics.get_height() == 0) { font_metrics = FontMetrics( height, font_metrics.get_ascent(), font_metrics.get_descent(), font_metrics.get_internal_leading(), font_metrics.get_external_leading(), font_metrics.get_line_height()); } FontDescription desc; desc.set_height(height); std::shared_ptr<FontEngine> engine = std::make_shared<FontEngine_Sprite>(desc, font_metrics); Font_Cache sprite_engine(engine); font_cache.push_back(sprite_engine); GlyphCache *glyph_cache = sprite_engine.glyph_cache.get(); // Setup char to glyph map: UTF8_Reader reader(glyph_list.data(), glyph_list.length()); int sprite_index = 0; while (!reader.is_end()) { unsigned int glyph = reader.get_char(); reader.next(); const Sprite_Impl::SpriteFrame &sprite_frame = sprite.impl->frames[sprite_index]; Point increment; if (fixed_width) { increment.x = fixed_width; } else { increment.x = sprite_frame.position.get_width(); } Pointf offset(sprite_frame.offset); offset.y -= font_metrics.get_ascent(); Sizef size = sprite_frame.position.get_size(); Subtexture sub_texture(sprite_frame.texture, sprite_frame.position); glyph_cache->insert_glyph(canvas, glyph, sub_texture, offset, size, GlyphMetrics(Pointf(offset.x, offset.y), Sizef(increment.x, increment.y), Sizef(increment.x, increment.y))); sprite_index++; } // Did the glyphs not contain a space? std::string::size_type space_pos = glyph_list.find(' '); if (space_pos == std::string::npos) { FontPixelBuffer pb; pb.empty_buffer = true; pb.metrics.advance.width = spacelen; pb.metrics.bbox_size.width = spacelen; pb.glyph = ' '; glyph_cache->insert_glyph(canvas, pb); } float average_character_width = 0.0f; float max_character_width = 0.0f; if (monospace) { average_character_width = fixed_width; max_character_width = fixed_width; } else { for (int i = 0; i < length; ++i) { int glyph_width = sprite.get_frame_size(i).width; average_character_width += glyph_width; if (glyph_width > max_character_width) max_character_width = glyph_width; } if (length) average_character_width /= length; } }