#include "Draw.h" #define LLOG(x) NAMESPACE_UPP CommonFontInfo GetFontInfoSys(Font font); GlyphInfo GetGlyphInfoSys(Font font, int chr); void GetStdFontSys(String& name, int& height); Vector GetAllFacesSys(); bool Replace(Font fnt, int chr, Font& rfnt); void Std(Font& font) { if(IsNull(font)) font = StdFont(); if(font.GetFace() == 0) font.Face(GetStdFont().GetFace()); if(font.GetHeight() == 0) font.Height(GetStdFont().GetHeight()); } Size Font::StdFontSize; Font Font::AStdFont; INITBLOCK { RichValue::Register(); } const Vector& Font::List() { static Vector *q; ONCELOCK { static Vector x; x = GetAllFacesSys(); q = &x; } return *q; } void sInitFonts() { Font::List(); GetStdFont(); } INITBLOCK { sInitFonts(); } int Font::GetFaceCount() { return List().GetCount(); } String Font::GetFaceName(int index) { if(index == 0) return "STDFONT"; const Vector& l = List(); if(index >= 0 && index < l.GetCount()) return l[index].name; return Null; } dword Font::GetFaceInfo(int index) { const Vector& l = List(); if(index >= 0 && index < l.GetCount()) return l[index].info; return 0; } int FontFilter(int c) { return c >= 'a' && c <= 'z' || c >= '0' && c <= '9' ? c : c >= 'A' && c <= 'Z' ? ToLower(c) : 0; } int Font::FindFaceNameIndex(const String& name) { if(name == "STDFONT") return 0; for(int i = 1; i < GetFaceCount(); i++) if(GetFaceName(i) == name) return i; String n = Filter(name, FontFilter); for(int i = 1; i < GetFaceCount(); i++) if(Filter(GetFaceName(i), FontFilter) == n) return i; return 0; } void Font::SyncStdFont() { DrawLock __; StdFontSize = Size(AStdFont.GetAveWidth(), AStdFont().Bold().GetCy()); } void Font::SetStdFont(Font font) { DrawLock __; InitStdFont(); AStdFont = font; SyncStdFont(); } void Font::InitStdFont() { ONCELOCK { DrawLock __; List(); AStdFont = Arial(12); String name; int height = 0; GetStdFontSys(name, height); int q = FindFaceNameIndex(name); if(q > 0) { AStdFont = Font(q, max(height, 1)); SyncStdFont(); } } } Font Font::GetStdFont() { InitStdFont(); return AStdFont; } Size Font::GetStdFontSize() { InitStdFont(); return StdFontSize; } Font StdFont() { return Font(0, -32000); } int Font::GetHeight() const { return v.height == -32000 ? GetStdFont().GetHeight() : v.height; } String Font::GetFaceName() const { if(IsNull()) return String(); if(GetFace() == 0) return "STDFONT"; return GetFaceName(GetFace()); } dword Font::GetFaceInfo() const { if(IsNull()) return 0; return GetFaceInfo(GetFace()); } Font& Font::FaceName(const String& name) { int n = FindFaceNameIndex(name); Face(n < 0 ? 0xffff : n); return *this; } void Font::Serialize(Stream& s) { int version = 1; s / version; if(version >= 1) { enum { OLD_STDFONT, OLD_SCREEN_SERIF, OLD_SCREEN_SANS, OLD_SCREEN_FIXED, OLD_ROMAN, OLD_ARIAL, OLD_COURIER, }; int f = GetFace(); if(f > COURIER) f = -1; s / f; String name; if(f == OLD_ROMAN) f = ROMAN; if(f == OLD_ARIAL) f = ARIAL; if(f == OLD_COURIER) f = COURIER; if(f < 0) { name = GetFaceName(); s % name; } if(s.IsLoading()) if(f >= 0) Face(f); else FaceName(name); } else { String name = GetFaceName(); s % name; if(s.IsLoading()) { FaceName(name); if(IsNull()) Face(COURIER); } } s % v.flags % v.height % v.width; } template<> String AsString(const Font& f) { if(IsNull(f)) return ""; String s = "<" + f.GetFaceName() + Format(":%d", f.GetHeight()); if(f.IsBold()) s += " Bold"; if(f.IsItalic()) s += " Italic"; if(f.IsUnderline()) s += " Underline"; if(f.IsStrikeout()) s += " Strikeout"; return s + '>'; } struct CharEntry { int64 font; GlyphInfo info; word chr; }; CharEntry fc_cache_global[4093]; bool IsNormal(Font font, int chr) { DrawLock __; CharEntry& e = fc_cache_global[CombineHash(font.GetHashValue(), chr) % 4093]; if(e.font == font.AsInt64() || e.chr == chr) return e.info.IsNormal(); return GetGlyphInfoSys(font, chr).IsNormal(); } CharEntry GetGlyphEntry(Font font, int chr, unsigned hash) { DrawLock __; CharEntry& e = fc_cache_global[hash % 4093]; if(e.font != font.AsInt64() || e.chr != chr) { e.font = font.AsInt64(); e.chr = chr; e.info = GetGlyphInfoSys(font, chr); if(!e.info.IsNormal()) { ComposedGlyph cg; Font rfnt; if(Compose(font, chr, cg)) { e.info.lspc = -1; e.info.rspc = cg.basic_char; } else if(Replace(font, chr, rfnt)) { e.info.lspc = rfnt.GetFace(); e.info.rspc = rfnt.GetHeight(); } else e.info.lspc = -2; } } return e; } thread__ CharEntry fc_cache[512]; GlyphInfo GetGlyphInfo(Font font, int chr) { Std(font); unsigned hash = CombineHash(font.GetHashValue(), chr); CharEntry& e = fc_cache[hash & 511]; if(e.font != font.AsInt64() || e.chr != chr) e = GetGlyphEntry(font, chr, hash); return e.info; } bool Font::IsNormal(int ch) const { return GetGlyphInfo(*this, ch).IsNormal(); } bool Font::IsComposed(int ch) const { return GetGlyphInfo(*this, ch).IsComposed(); } bool Font::IsReplaced(int ch) const { return GetGlyphInfo(*this, ch).IsReplaced(); } bool Font::IsMissing(int ch) const { return GetGlyphInfo(*this, ch).IsMissing(); } int Font::HasChar(int ch) const { return !GetGlyphInfo(*this, ch).IsMissing(); } void GlyphMetrics(GlyphInfo& f, Font font, int chr) { if(f.IsReplaced()) f = GetGlyphInfo(font().Face(f.lspc).Height(f.rspc), chr); if(f.IsComposed()) { f = GetGlyphInfo(font, f.rspc); if(f.IsComposedLM()) f.rspc += f.width / 2; } } GlyphInfo GetGlyphMetrics(Font font, int chr) { GlyphInfo f = GetGlyphInfo(font, chr); if(f.IsMissing()) f = GetGlyphInfo(font, '?'); GlyphMetrics(f, font, chr); return f; } struct FontEntry { CommonFontInfo info; int64 font; }; thread__ FontEntry fi_cache[64]; const CommonFontInfo& GetFontInfo(Font font) { Std(font); unsigned hash = font.GetHashValue() & 63; FontEntry& e = fi_cache[hash]; if(e.font != font.AsInt64()) { DrawLock __; e.font = font.AsInt64(); e.info = GetFontInfoSys(font); } return e.info; } int Font::GetWidth(int c) const { return GetGlyphMetrics(*this, c).width; } int Font::GetLeftSpace(int c) const { return GetGlyphMetrics(*this, c).lspc; } int Font::GetRightSpace(int c) const { return GetGlyphMetrics(*this, c).rspc; } thread__ int64 lastFiFont = INT_MIN; thread__ CommonFontInfo lastFontInfo; thread__ int64 lastStdFont = INT_MIN; const CommonFontInfo& Font::Fi() const { if(lastStdFont != AStdFont.AsInt64()) { lastFiFont = INT_MIN; lastStdFont = AStdFont.AsInt64(); } if(AsInt64() == lastFiFont) return lastFontInfo; lastFontInfo = GetFontInfo(*this); lastFiFont = AsInt64(); return lastFontInfo; } FontInfo Font::Info() const { FontInfo h; h.font = *this; return h; } END_UPP_NAMESPACE