ultimatepp/uppsrc/Draw/Font.cpp
cxl 3ecde91bb5 CtrlCore,Draw, POSIX: Fixed font metrics issue, fixed editfield frame issue, fixed PdfDraw
git-svn-id: svn://ultimatepp.org/upp/trunk@1480 f0d560ea-af0d-0410-9eb7-867de7ffcac7
2009-08-08 21:52:08 +00:00

379 lines
6.8 KiB
C++

#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);
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, 0);
}
int Font::GetHeight() const
{
return v.height || v.face ? v.height : GetStdFont().GetHeight();
}
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