mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-07-11 22:03:01 -06:00
Core, Draw: Applied changes for mac (thanks daveremba)
git-svn-id: svn://ultimatepp.org/upp/trunk@3688 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
parent
af75851094
commit
9ca5b1f9ed
3 changed files with 768 additions and 746 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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<FaceInfo> 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<Font>::Register();
|
||||
}
|
||||
|
||||
const Vector<FaceInfo>& Font::List()
|
||||
{
|
||||
static Vector<FaceInfo> *q;
|
||||
ONCELOCK {
|
||||
static Vector<FaceInfo> 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<FaceInfo>& l = List();
|
||||
if(index >= 0 && index < l.GetCount())
|
||||
return l[index].name;
|
||||
return Null;
|
||||
}
|
||||
|
||||
dword Font::GetFaceInfo(int index)
|
||||
{
|
||||
const Vector<FaceInfo>& 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 "<null>";
|
||||
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<FaceInfo> 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<Font>::Register();
|
||||
}
|
||||
|
||||
const Vector<FaceInfo>& Font::List()
|
||||
{
|
||||
static Vector<FaceInfo> *q;
|
||||
ONCELOCK {
|
||||
static Vector<FaceInfo> 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<FaceInfo>& l = List();
|
||||
if(index >= 0 && index < l.GetCount())
|
||||
return l[index].name;
|
||||
return Null;
|
||||
}
|
||||
|
||||
dword Font::GetFaceInfo(int index)
|
||||
{
|
||||
const Vector<FaceInfo>& 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 "<null>";
|
||||
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
|
||||
|
|
|
|||
|
|
@ -1,241 +1,242 @@
|
|||
#include "Draw.h"
|
||||
|
||||
#ifdef PLATFORM_POSIX
|
||||
#include <fontconfig/fontconfig.h>
|
||||
#include <fontconfig/fcfreetype.h>
|
||||
#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<FaceInfo> GetAllFacesSys()
|
||||
{
|
||||
static const char *basic_fonts[] = {
|
||||
"sans-serif",
|
||||
"serif",
|
||||
"sans-serif",
|
||||
"monospace",
|
||||
};
|
||||
|
||||
Vector<FaceInfo> 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 <fontconfig/fontconfig.h>
|
||||
#include <fontconfig/fcfreetype.h>
|
||||
#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<FaceInfo> GetAllFacesSys()
|
||||
{
|
||||
static const char *basic_fonts[] = {
|
||||
"sans-serif",
|
||||
"serif",
|
||||
"sans-serif",
|
||||
"monospace",
|
||||
};
|
||||
|
||||
Vector<FaceInfo> 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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue