From 9ca5b1f9ed6d5cc2717b288f2621b8828bb26792 Mon Sep 17 00:00:00 2001 From: cxl Date: Thu, 21 Jul 2011 18:11:08 +0000 Subject: [PATCH] Core, Draw: Applied changes for mac (thanks daveremba) git-svn-id: svn://ultimatepp.org/upp/trunk@3688 f0d560ea-af0d-0410-9eb7-867de7ffcac7 --- uppsrc/Core/config.h | 243 +++++++------ uppsrc/Draw/Font.cpp | 788 +++++++++++++++++++++-------------------- uppsrc/Draw/FontFc.cpp | 483 ++++++++++++------------- 3 files changed, 768 insertions(+), 746 deletions(-) diff --git a/uppsrc/Core/config.h b/uppsrc/Core/config.h index adf829004..1f4869510 100644 --- a/uppsrc/Core/config.h +++ b/uppsrc/Core/config.h @@ -1,115 +1,128 @@ -#if __GNUC__ - - #define COMPILER_GCC 1 - - #define GCC_VERSION (__GNUC__ * 10000 \ - + __GNUC_MINOR__ * 100 \ - + __GNUC_PATCHLEVEL__) - - #if __WIN32 - #define COMPILER_MINGW - #define PLATFORM_WIN32 - #endif - - #if __unix || __unix__ || __APPLE__ - #define PLATFORM_POSIX 1 - - #if __linux - #define PLATFORM_LINUX 1 - #else - #if __FreeBSD__ || __OpenBSD__ || __NetBSD__ || __APPLE__ - #define PLATFORM_BSD 1 - #if __FreeBSD__ - #define PLATFORM_FREEBSD 1 - #endif - #if __OpenBSD__ - #define PLATFORM_OPENBSD 1 - #endif - #if __NetBSD__ - #define PLATFORM_NETBSD 1 - #endif - #elif __sun - #define PLATFORM_SOLARIS 1 - #else - #error Unknown OS - #endif - #endif - #endif - - #if __x86_64 - #define CPU_LE 1 - #define CPU_LITTLE_ENDIAN 1 - #define CPU_UNALIGNED 1 - #define CPU_X86 1 - #define CPU_64 1 - #define CPU_AMD64 1 - #define CPU_SSE2 1 - #define CPU_IA64 1 - #elif __i386 || __i386__ || i386 - #define CPU_LE 1 - #define CPU_LITTLE_ENDIAN 1 - #define CPU_UNALIGNED 1 - #define CPU_X86 1 - #define CPU_32 1 - #define CPU_IA32 1 - #ifdef flagSSE2 - #define CPU_SSE2 1 - #endif - #elif __sparc // ToDo! - #define CPU_32 1 - #define CPU_SPARC 1 - #define CPU_BE 1 - #define CPU_BIG_ENDIAN 1 - #define CPU_ALIGNED 1 - #elif __arm // ToDo! - #define CPU_32 1 - #define CPU_ARM 1 - #define CPU_LE 1 - #define CPU_LITTLE_ENDIAN 1 // is it really? - #define CPU_ALIGNED 1 - #elif __bfin - #define CPU_32 1 - #define CPU_BLACKFIN - #define CPU_LE 1 - #define CPU_LITTLE_ENDIAN 1 - #define CPU_ALIGNED 1 - #define _HAVE_NO_STDWSTRING 1 - //BF toolchain has no support for __thread (TLS), so U++ Heap not possible - #define flagUSEMALLOC - #else - #error Unknown CPU architecture - #endif -#endif - -#ifdef _MSC_VER - #define COMPILER_MSC 1 - #ifndef _CPPRTTI - #error RTTI must be enabled !!! - #endif //_CPPRTTI - #if _MSC_VER <= 1300 - #error MSC 6.0 not supported anymore - #endif - #pragma warning(disable: 4786) - #define _CRT_SECURE_NO_DEPRECATE 1 // we really need strcpy etc. to work with MSC 8.0 - - #define PLATFORM_WIN32 1 - - #define CPU_LE 1 - #define CPU_LITTLE_ENDIAN 1 - #define CPU_UNALIGNED 1 - #define CPU_X86 1 - - #ifdef _WIN64 - #define PLATFORM_WIN64 1 - #define CPU_64 1 - #define CPU_AMD64 1 - #define CPU_SSE2 1 - #define CPU_IA64 1 - #else - #define CPU_32 1 - #define CPU_IA32 1 - #ifdef flagSSE2 - #define CPU_SSE2 1 - #endif - #endif -#endif +#if __GNUC__ + + #define GCC_VERSION (__GNUC__ * 10000 \ + + __GNUC_MINOR__ * 100 \ + + __GNUC_PATCHLEVEL__) + + #define COMPILER_GCC 1 + + #if __WIN32 + #define COMPILER_MINGW + #define PLATFORM_WIN32 + #endif + + #if __unix || __unix__ || __APPLE__ + #define PLATFORM_POSIX 1 + + #ifdef flagGUI + #define PLATFORM_X11 1 + #endif + + #if __linux + #define PLATFORM_LINUX 1 + // zvzv add + // __linux is undef on APPLE MACOSX, MACOSX has BSD stuff + #elif __APPLE__ + // zvzv note + // s/b MACOSX + #define PLATFORM_OSX11 1 + #define PLATFORM_BSD 1 + #else + // zvzv mod + // was: #if __FreeBSD__ || __OpenBSD__ || __NetBSD__ || __APPLE__ + #if __FreeBSD__ || __OpenBSD__ || __NetBSD__ + #define PLATFORM_BSD 1 + #if __FreeBSD__ + #define PLATFORM_FREEBSD 1 + #endif + #if __OpenBSD__ + #define PLATFORM_OPENBSD 1 + #endif + #if __NetBSD__ + #define PLATFORM_NETBSD 1 + #endif + #elif __sun + #define PLATFORM_SOLARIS 1 + #else + #error Unknown OS + #endif + #endif + #endif + + #if __x86_64 + #define CPU_LE 1 + #define CPU_LITTLE_ENDIAN 1 + #define CPU_UNALIGNED 1 + #define CPU_X86 1 + #define CPU_64 1 + #define CPU_AMD64 1 + #define CPU_SSE2 1 + #define CPU_IA64 1 + #elif __i386 || __i386__ || i386 + #define CPU_LE 1 + #define CPU_LITTLE_ENDIAN 1 + #define CPU_UNALIGNED 1 + #define CPU_X86 1 + #define CPU_32 1 + #define CPU_IA32 1 + #ifdef flagSSE2 + #define CPU_SSE2 1 + #endif + #elif __sparc // ToDo! + #define CPU_32 1 + #define CPU_SPARC 1 + #define CPU_BE 1 + #define CPU_BIG_ENDIAN 1 + #define CPU_ALIGNED 1 + #elif __arm // ToDo! + #define CPU_32 1 + #define CPU_ARM 1 + #define CPU_LE 1 + #define CPU_LITTLE_ENDIAN 1 // is it really? + #define CPU_ALIGNED 1 + #elif __bfin + #define CPU_32 1 + #define CPU_BLACKFIN + #define CPU_LE 1 + #define CPU_LITTLE_ENDIAN 1 + #define CPU_ALIGNED 1 + #define _HAVE_NO_STDWSTRING 1 + //BF toolchain has no support for __thread (TLS), so U++ Heap not possible + #define flagUSEMALLOC + #else + #error Unknown CPU architecture + #endif +#endif + +#ifdef _MSC_VER + #define COMPILER_MSC 1 + #ifndef _CPPRTTI + #error RTTI must be enabled !!! + #endif //_CPPRTTI + #if _MSC_VER <= 1300 + #error MSC 6.0 not supported anymore + #endif + #pragma warning(disable: 4786) + #define _CRT_SECURE_NO_DEPRECATE 1 // we really need strcpy etc. to work with MSC 8.0 + + #define PLATFORM_WIN32 1 + + #define CPU_LE 1 + #define CPU_LITTLE_ENDIAN 1 + #define CPU_UNALIGNED 1 + #define CPU_X86 1 + + #ifdef _WIN64 + #define PLATFORM_WIN64 1 + #define CPU_64 1 + #define CPU_AMD64 1 + #define CPU_SSE2 1 + #define CPU_IA64 1 + #else + #define CPU_32 1 + #define CPU_IA32 1 + #ifdef flagSSE2 + #define CPU_SSE2 1 + #endif + #endif +#endif diff --git a/uppsrc/Draw/Font.cpp b/uppsrc/Draw/Font.cpp index 4ec227e59..74fd38a64 100644 --- a/uppsrc/Draw/Font.cpp +++ b/uppsrc/Draw/Font.cpp @@ -1,390 +1,398 @@ -#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); -#ifdef PLATFORM_WIN32 -#ifdef flagWINGL - AStdFont = Font(FindFaceNameIndex("Tahoma"), 12); -#else - int q = FindFaceNameIndex(name); - if(q <= 0) - q = FindFaceNameIndex("Tahoma"); - if(q <= 0) - q = FindFaceNameIndex("Microsoft Sans Serif"); - if(q <= 0) - q = FindFaceNameIndex("MS Sans Serif"); - if(q > 0) - AStdFont = Font(q, max(height, 1)); -#endif - SyncStdFont(); -#endif - } -} - -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 +#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); +#ifdef PLATFORM_WIN32 +#ifdef flagWINGL + AStdFont = Font(FindFaceNameIndex("Tahoma"), 12); +#else + int q = FindFaceNameIndex(name); + if(q <= 0) + q = FindFaceNameIndex("Tahoma"); + if(q <= 0) + q = FindFaceNameIndex("Microsoft Sans Serif"); + if(q <= 0) + q = FindFaceNameIndex("MS Sans Serif"); + if(q > 0) + AStdFont = Font(q, max(height, 1)); +#endif + SyncStdFont(); +#endif + } +} + +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 +{ +#ifdef PLATFORM_OSX11 +// known leak on MacOSX here: getAllCarbonLazyValues2000 calls Core.h op new() +// should not call UPP op new() +// from GetFontInfo() ... XftFontOpenPattern() ... getAllCarbonLazyValues2000() -> new() + MemoryIgnoreLeaksBlock __; +#endif + + 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 diff --git a/uppsrc/Draw/FontFc.cpp b/uppsrc/Draw/FontFc.cpp index 84861b225..b2fad1f46 100644 --- a/uppsrc/Draw/FontFc.cpp +++ b/uppsrc/Draw/FontFc.cpp @@ -1,241 +1,242 @@ -#include "Draw.h" - -#ifdef PLATFORM_POSIX -#include -#include -#endif - -NAMESPACE_UPP - -#ifdef PLATFORM_POSIX - -#define LLOG(x) // LOG(x) -#define LTIMING(x) // TIMING(x) - -void GetStdFontSys(String& name, int& height) -{ - name = "xxxx"; -} - -static FT_Library sFTlib; - -bool sInitFt(void) -{ - if(sFTlib) - return true; - return FT_Init_FreeType(&sFTlib) == 0; -} - -FcPattern *CreateFcPattern(Font font) -{ - LTIMING("CreateXftFont"); - double sina, cosa; - int hg = abs(font.GetHeight()); - if(hg == 0) hg = 10; - String face = font.GetFaceName(); - FcPattern *p = FcPatternCreate(); - FcPatternAddString(p, FC_FAMILY, (FcChar8*)~face); - FcPatternAddInteger(p, FC_SLANT, font.IsItalic() ? 110 : 0); - FcPatternAddInteger(p, FC_PIXEL_SIZE, hg); - FcPatternAddInteger(p, FC_WEIGHT, font.IsBold() ? 200 : 100); - FcPatternAddBool(p, FC_MINSPACE, 1); - FcConfigSubstitute(0, p, FcMatchPattern); - FcDefaultSubstitute(p); - FcResult result; - FcPattern *m = FcFontMatch(0, p, &result); - FcPatternDestroy(p); - return m; -} - -FT_Face CreateFTFace(const FcPattern *pattern, String *rpath) { - FT_Face face = NULL; - - int id; - double dsize; - double aspect; - FcChar8 *filename; - - if(!sInitFt()) - return NULL; - - if(FcPatternGetString(pattern, FC_FILE, 0, &filename) != FcResultMatch) - return NULL; - if(rpath) - *rpath = (const char *)filename; - - if(FcPatternGetDouble(pattern, FC_PIXEL_SIZE, 0, &dsize) != FcResultMatch) - dsize = 16; - - if (FcPatternGetDouble(pattern, FC_ASPECT, 0, &aspect) != FcResultMatch) - aspect = 1.0; - - FT_F26Dot6 ysize = (FT_F26Dot6) (dsize * 64.0); - FT_F26Dot6 xsize = (FT_F26Dot6) (dsize * aspect * 64.0); - - if(FT_New_Face(sFTlib, (const char *)filename, 0, &face)) - return NULL; - - FT_Set_Char_Size(face, xsize, ysize, 0, 0); - return face; -} - -#define FONTCACHE 37 - -struct FtFaceEntry { - Font font; - FT_Face face; - String path; -}; - -static FtFaceEntry ft_cache[FONTCACHE]; - -void ClearFtFaceCache() -{ - for(int i = 0; i < FONTCACHE; i++) - ft_cache[i].font.Height(-30000); -} - -FT_Face (*FTFaceXft)(Font fnt, String *rpath); - -FT_Face FTFace(Font fnt, String *rpath = NULL) -{ - LTIMING("FTFace"); - if(FTFaceXft) - return (*FTFaceXft)(fnt, rpath); - ONCELOCK { - ClearFtFaceCache(); - } - FtFaceEntry be; - be = ft_cache[0]; - for(int i = 0; i < FONTCACHE; i++) { - FtFaceEntry e = ft_cache[i]; - if(i) - ft_cache[i] = be; - if(e.font == fnt) { - if(rpath) - *rpath = e.path; - if(i) - ft_cache[0] = e; - return e.face; - } - be = e; - } - LTIMING("FTFace2"); - if(be.face) { - LLOG("Removing " << be.font << " - " << (void *)be.face); - FT_Done_Face(be.face); - } - be.font = fnt; - FcPattern *p = CreateFcPattern(fnt); - be.face = CreateFTFace(p, &be.path); - FcPatternDestroy(p); - ft_cache[0] = be; - if(rpath) - *rpath = be.path; - return be.face; -} - -CommonFontInfo (*GetFontInfoSysXft)(Font font); - -CommonFontInfo GetFontInfoSys(Font font) -{ - if(GetFontInfoSysXft) - return (*GetFontInfoSysXft)(font); - CommonFontInfo fi; - String path; - FT_Face face = FTFace(font, &path); - if(face) { - fi.ascent = face->size->metrics.ascender >> 6; - fi.descent = -(face->size->metrics.descender >> 6); - fi.height = fi.ascent + fi.descent; - fi.lineheight = face->size->metrics.height >> 6; - fi.external = 0; - fi.internal = 0; - fi.overhang = 0; - fi.maxwidth = face->size->metrics.max_advance >> 6; - fi.avewidth = fi.maxwidth; - fi.default_char = '?'; - fi.fixedpitch = font.GetFaceInfo() & Font::FIXEDPITCH; - if(path.GetCount() < 250) - strcpy(fi.path, ~path); - else - *fi.path = 0; - } - return fi; -} - -#define FLOOR(x) ((x) & -64) -#define CEIL(x) (((x)+63) & -64) -#define TRUNC(x) ((x) >> 6) -#define ROUND(x) (((x)+32) & -64) - -GlyphInfo (*GetGlyphInfoSysXft)(Font font, int chr); - -GlyphInfo GetGlyphInfoSys(Font font, int chr) -{ - LTIMING("GetGlyphInfoSys"); - GlyphInfo gi; - FT_Face face = FTFace(font, NULL); - gi.lspc = gi.rspc = 0; - gi.width = 0x8000; - if(face) { - LTIMING("GetGlyphInfoSys 2"); - int glyph_index = FT_Get_Char_Index(face, chr); - if(glyph_index) { - if(GetGlyphInfoSysXft) - return (*GetGlyphInfoSysXft)(font, chr); - if(FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT|FT_LOAD_NO_BITMAP) == 0 || - FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT) == 0) { - FT_Glyph_Metrics& m = face->glyph->metrics; - int left = FLOOR(m.horiBearingX); - int width = TRUNC(CEIL(m.horiBearingX + m.width) - left); - gi.width = TRUNC(ROUND(face->glyph->advance.x)); - gi.lspc = TRUNC(left); - gi.rspc = gi.width - width - gi.lspc; - } - } - } - return gi; -} - -Vector GetAllFacesSys() -{ - static const char *basic_fonts[] = { - "sans-serif", - "serif", - "sans-serif", - "monospace", - }; - - Vector list; - for(int i = 0; i < __countof(basic_fonts); i++) { - FaceInfo& fi = list.Add(); - fi.name = basic_fonts[i]; - fi.info = (i == 3) ? Font::SCALEABLE|Font::FIXEDPITCH : Font::SCALEABLE; - } - FcPattern *p = FcPatternCreate(); - FcObjectSet *os = FcObjectSetBuild(FC_FAMILY, FC_SPACING, FC_SCALABLE, (void *)0); - FcFontSet *fs = FcFontList(NULL, p, os); - FcPatternDestroy(p); - FcObjectSetDestroy(os); - for(int i = 0; i < fs->nfont; i++) { - FcChar8 *family = NULL; - if(FcPatternGetString(fs->fonts[i], FC_FAMILY, 0, &family) == 0 && family) { - FaceInfo& fi = list.Add(); - fi.name = (const char *)family; - fi.info = 0; - int iv; - if(FcPatternGetInteger(fs->fonts[i], FC_SPACING, 0, &iv) == 0 && iv == FC_MONO) - fi.info |= Font::FIXEDPITCH; - FcBool bv; - if(FcPatternGetBool(fs->fonts[i], FC_SCALABLE, 0, &bv) == 0 && bv) - fi.info |= Font::SCALEABLE; - } - } - FcFontSetDestroy(fs); - return list; -} - -#endif - -END_UPP_NAMESPACE +#include "Draw.h" + +#ifdef PLATFORM_POSIX +#include +#include +#endif + +NAMESPACE_UPP + +#ifdef PLATFORM_POSIX + +#define LLOG(x) // LOG(x) +#define LTIMING(x) // TIMING(x) + +void GetStdFontSys(String& name, int& height) +{ + name = "xxxx"; +} + +static FT_Library sFTlib; + +bool sInitFt(void) +{ + if(sFTlib) + return true; + return FT_Init_FreeType(&sFTlib) == 0; +} + +FcPattern *CreateFcPattern(Font font) +{ + LTIMING("CreateXftFont"); + double sina, cosa; + int hg = abs(font.GetHeight()); + if(hg == 0) hg = 10; + String face = font.GetFaceName(); + FcPattern *p = FcPatternCreate(); + FcPatternAddString(p, FC_FAMILY, (FcChar8*)~face); + FcPatternAddInteger(p, FC_SLANT, font.IsItalic() ? 110 : 0); + FcPatternAddInteger(p, FC_PIXEL_SIZE, hg); + FcPatternAddInteger(p, FC_WEIGHT, font.IsBold() ? 200 : 100); + FcPatternAddBool(p, FC_MINSPACE, 1); + FcConfigSubstitute(0, p, FcMatchPattern); + FcDefaultSubstitute(p); + FcResult result; + FcPattern *m = FcFontMatch(0, p, &result); + FcPatternDestroy(p); + return m; +} + +FT_Face CreateFTFace(const FcPattern *pattern, String *rpath) { + FT_Face face = NULL; + + int id; + double dsize; + double aspect; + FcChar8 *filename; + + if(!sInitFt()) + return NULL; + + if(FcPatternGetString(pattern, FC_FILE, 0, &filename) != FcResultMatch) + return NULL; + if(rpath) + *rpath = (const char *)filename; + + if(FcPatternGetDouble(pattern, FC_PIXEL_SIZE, 0, &dsize) != FcResultMatch) + dsize = 16; + + if (FcPatternGetDouble(pattern, FC_ASPECT, 0, &aspect) != FcResultMatch) + aspect = 1.0; + + FT_F26Dot6 ysize = (FT_F26Dot6) (dsize * 64.0); + FT_F26Dot6 xsize = (FT_F26Dot6) (dsize * aspect * 64.0); + + if(FT_New_Face(sFTlib, (const char *)filename, 0, &face)) + return NULL; + + FT_Set_Char_Size(face, xsize, ysize, 0, 0); + return face; +} + +#define FONTCACHE 37 + +struct FtFaceEntry { + Font font; + FT_Face face; + String path; +}; + +static FtFaceEntry ft_cache[FONTCACHE]; + +void ClearFtFaceCache() +{ + for(int i = 0; i < FONTCACHE; i++) + ft_cache[i].font.Height(-30000); +} + +FT_Face (*FTFaceXft)(Font fnt, String *rpath); + +FT_Face FTFace(Font fnt, String *rpath = NULL) +{ + LTIMING("FTFace"); + if(FTFaceXft) + return (*FTFaceXft)(fnt, rpath); + ONCELOCK { + ClearFtFaceCache(); + } + FtFaceEntry be; + be = ft_cache[0]; + for(int i = 0; i < FONTCACHE; i++) { + FtFaceEntry e = ft_cache[i]; + if(i) + ft_cache[i] = be; + if(e.font == fnt) { + if(rpath) + *rpath = e.path; + if(i) + ft_cache[0] = e; + return e.face; + } + be = e; + } + LTIMING("FTFace2"); + if(be.face) { + LLOG("Removing " << be.font << " - " << (void *)be.face); + FT_Done_Face(be.face); + } + be.font = fnt; + FcPattern *p = CreateFcPattern(fnt); + be.face = CreateFTFace(p, &be.path); + FcPatternDestroy(p); + ft_cache[0] = be; + if(rpath) + *rpath = be.path; + return be.face; +} + +CommonFontInfo (*GetFontInfoSysXft)(Font font); + +CommonFontInfo GetFontInfoSys(Font font) +{ + sInitFt(); + if(GetFontInfoSysXft) + return (*GetFontInfoSysXft)(font); + CommonFontInfo fi; + String path; + FT_Face face = FTFace(font, &path); + if(face) { + fi.ascent = face->size->metrics.ascender >> 6; + fi.descent = -(face->size->metrics.descender >> 6); + fi.height = fi.ascent + fi.descent; + fi.lineheight = face->size->metrics.height >> 6; + fi.external = 0; + fi.internal = 0; + fi.overhang = 0; + fi.maxwidth = face->size->metrics.max_advance >> 6; + fi.avewidth = fi.maxwidth; + fi.default_char = '?'; + fi.fixedpitch = font.GetFaceInfo() & Font::FIXEDPITCH; + if(path.GetCount() < 250) + strcpy(fi.path, ~path); + else + *fi.path = 0; + } + return fi; +} + +#define FLOOR(x) ((x) & -64) +#define CEIL(x) (((x)+63) & -64) +#define TRUNC(x) ((x) >> 6) +#define ROUND(x) (((x)+32) & -64) + +GlyphInfo (*GetGlyphInfoSysXft)(Font font, int chr); + +GlyphInfo GetGlyphInfoSys(Font font, int chr) +{ + LTIMING("GetGlyphInfoSys"); + GlyphInfo gi; + FT_Face face = FTFace(font, NULL); + gi.lspc = gi.rspc = 0; + gi.width = 0x8000; + if(face) { + LTIMING("GetGlyphInfoSys 2"); + int glyph_index = FT_Get_Char_Index(face, chr); + if(glyph_index) { + if(GetGlyphInfoSysXft) + return (*GetGlyphInfoSysXft)(font, chr); + if(FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT|FT_LOAD_NO_BITMAP) == 0 || + FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT) == 0) { + FT_Glyph_Metrics& m = face->glyph->metrics; + int left = FLOOR(m.horiBearingX); + int width = TRUNC(CEIL(m.horiBearingX + m.width) - left); + gi.width = TRUNC(ROUND(face->glyph->advance.x)); + gi.lspc = TRUNC(left); + gi.rspc = gi.width - width - gi.lspc; + } + } + } + return gi; +} + +Vector GetAllFacesSys() +{ + static const char *basic_fonts[] = { + "sans-serif", + "serif", + "sans-serif", + "monospace", + }; + + Vector list; + for(int i = 0; i < __countof(basic_fonts); i++) { + FaceInfo& fi = list.Add(); + fi.name = basic_fonts[i]; + fi.info = (i == 3) ? Font::SCALEABLE|Font::FIXEDPITCH : Font::SCALEABLE; + } + FcPattern *p = FcPatternCreate(); + FcObjectSet *os = FcObjectSetBuild(FC_FAMILY, FC_SPACING, FC_SCALABLE, (void *)0); + FcFontSet *fs = FcFontList(NULL, p, os); + FcPatternDestroy(p); + FcObjectSetDestroy(os); + for(int i = 0; i < fs->nfont; i++) { + FcChar8 *family = NULL; + if(FcPatternGetString(fs->fonts[i], FC_FAMILY, 0, &family) == 0 && family) { + FaceInfo& fi = list.Add(); + fi.name = (const char *)family; + fi.info = 0; + int iv; + if(FcPatternGetInteger(fs->fonts[i], FC_SPACING, 0, &iv) == 0 && iv == FC_MONO) + fi.info |= Font::FIXEDPITCH; + FcBool bv; + if(FcPatternGetBool(fs->fonts[i], FC_SCALABLE, 0, &bv) == 0 && bv) + fi.info |= Font::SCALEABLE; + } + } + FcFontSetDestroy(fs); + return list; +} + +#endif + +END_UPP_NAMESPACE