#include "Draw.h" NAMESPACE_UPP enum { CG_NONE, CG_CAPITAL, CG_SMALL }; enum { CG_GRAVE = 0x60, CG_ACUTE = 0xb4, CG_CEDILLA = 0xb8, CG_MACRON = 175, CG_CIRCUMFLEX = 0x2c6, CG_TILDE = 0x2dc, CG_DOT_ABOVE = 0x2d9, CG_OGONEK = 0x2db, CG_STROKE = '-', CG_BREVE = 0x2d8, CG_CARON = 0x2c7, CG_MIDDLE_DOT = 0xb7, CG_DOUBLE_ACUTE = 0x2dd, CG_DIAERESIS = 0xa8, CG_RING_ABOVE = 0x2da, CG_COMMA_T = ',', CG_COMMA_UR = 1, CG_COMMA_URI, }; struct CGInfo { byte type; char ascii; wchar mark; } gc_info[128] = { { CG_CAPITAL, 'A', CG_MACRON }, { CG_SMALL, 'a', CG_MACRON }, { CG_CAPITAL, 'A', CG_BREVE }, { CG_SMALL, 'a', CG_BREVE }, { CG_CAPITAL, 'A', CG_OGONEK }, { CG_SMALL, 'a', CG_OGONEK }, { CG_CAPITAL, 'C', CG_ACUTE }, { CG_SMALL, 'c', CG_ACUTE }, { CG_CAPITAL, 'C', CG_CIRCUMFLEX }, { CG_SMALL, 'c', CG_CIRCUMFLEX }, { CG_CAPITAL, 'C', CG_DOT_ABOVE }, { CG_SMALL, 'c', CG_DOT_ABOVE }, { CG_CAPITAL, 'C', CG_CARON }, { CG_SMALL, 'c', CG_CARON }, { CG_CAPITAL, 'D', CG_CARON }, { CG_SMALL, 'd', CG_COMMA_UR }, { CG_CAPITAL, 'D', CG_STROKE }, { CG_SMALL, 'd', CG_STROKE }, { CG_CAPITAL, 'E', CG_MACRON }, { CG_SMALL, 'e', CG_MACRON }, { CG_CAPITAL, 'E', CG_BREVE }, { CG_SMALL, 'e', CG_BREVE }, { CG_CAPITAL, 'E', CG_DOT_ABOVE }, { CG_SMALL, 'e', CG_DOT_ABOVE }, { CG_CAPITAL, 'E', CG_OGONEK }, { CG_SMALL, 'e', CG_OGONEK }, { CG_CAPITAL, 'E', CG_CARON }, { CG_SMALL, 'e', CG_CARON }, { CG_CAPITAL, 'G', CG_CIRCUMFLEX }, { CG_SMALL, 'g', CG_CIRCUMFLEX }, { CG_CAPITAL, 'G', CG_BREVE }, { CG_SMALL, 'g', CG_BREVE }, { CG_CAPITAL, 'G', CG_DOT_ABOVE }, { CG_SMALL, 'g', CG_DOT_ABOVE }, { CG_CAPITAL, 'G', CG_CEDILLA }, { CG_SMALL, 'g', CG_CEDILLA }, { CG_CAPITAL, 'H', CG_CIRCUMFLEX }, { CG_SMALL, 'h', CG_CIRCUMFLEX }, { CG_CAPITAL, 'H', CG_STROKE }, { CG_SMALL, 'h', CG_STROKE }, { CG_CAPITAL, 'I', CG_TILDE }, { CG_SMALL, 'i', CG_TILDE }, { CG_CAPITAL, 'I', CG_MACRON }, { CG_SMALL, 'i', CG_MACRON }, { CG_CAPITAL, 'I', CG_BREVE }, { CG_SMALL, 'i', CG_BREVE }, { CG_CAPITAL, 'I', CG_OGONEK }, { CG_SMALL, 'i', CG_OGONEK }, { CG_CAPITAL, 'I', CG_DOT_ABOVE }, { CG_NONE, 0, 0 }, // , CG_SMALL, 'DOTLESS I { CG_NONE, 0, 0 }, // LATIN CAPITAL LIGATURE IJ { CG_NONE, 0, 0 }, // LATIN SMALL LIGATURE IJ { CG_CAPITAL, 'J', CG_CIRCUMFLEX }, { CG_SMALL, 'j', CG_CIRCUMFLEX }, { CG_CAPITAL, 'K', CG_CEDILLA }, { CG_SMALL, 'k', CG_CEDILLA }, { CG_NONE, 0, 0 }, // CG_SMALL, 'KRA { CG_CAPITAL, 'L', CG_ACUTE }, { CG_SMALL, 'l', CG_ACUTE }, { CG_CAPITAL, 'L', CG_CEDILLA }, { CG_SMALL, 'l', CG_CEDILLA }, { CG_CAPITAL, 'L', CG_COMMA_URI }, { CG_SMALL, 'l', CG_COMMA_UR }, { CG_CAPITAL, 'L', CG_MIDDLE_DOT }, { CG_SMALL, 'l', CG_MIDDLE_DOT }, { CG_CAPITAL, 'L', CG_STROKE }, { CG_SMALL, 'l', CG_STROKE }, { CG_CAPITAL, 'N', CG_ACUTE }, { CG_SMALL, 'n', CG_ACUTE }, { CG_CAPITAL, 'N', CG_CEDILLA }, { CG_SMALL, 'n', CG_CEDILLA }, { CG_CAPITAL, 'N', CG_CARON }, { CG_SMALL, 'n', CG_CARON }, { CG_NONE, 0, 0 }, // CG_SMALL, 'N PRECEDED BY APOSTROPHE { CG_NONE, 0, 0 }, //CG_CAPITAL, 'ENG { CG_NONE, 0, 0 }, //CG_SMALL, 'ENG { CG_CAPITAL, 'O', CG_MACRON }, { CG_SMALL, 'o', CG_MACRON }, { CG_CAPITAL, 'O', CG_BREVE }, { CG_SMALL, 'o', CG_BREVE }, { CG_CAPITAL, 'O', CG_DOUBLE_ACUTE }, { CG_SMALL, 'o', CG_DOUBLE_ACUTE }, { CG_NONE, 0, 0 }, // LATIN CAPITAL LIGATURE OE { CG_NONE, 0, 0 }, // LATIN SMALL LIGATURE OE { CG_CAPITAL, 'R', CG_ACUTE }, { CG_SMALL, 'r', CG_ACUTE }, { CG_CAPITAL, 'R', CG_CEDILLA }, { CG_SMALL, 'r', CG_CEDILLA }, { CG_CAPITAL, 'R', CG_CARON }, { CG_SMALL, 'r', CG_CARON }, { CG_CAPITAL, 'S', CG_ACUTE }, { CG_SMALL, 's', CG_ACUTE }, { CG_CAPITAL, 'S', CG_CIRCUMFLEX }, { CG_SMALL, 's', CG_CIRCUMFLEX }, { CG_CAPITAL, 'S', CG_CEDILLA }, { CG_SMALL, 's', CG_CEDILLA }, { CG_CAPITAL, 'S', CG_CARON }, { CG_SMALL, 's', CG_CARON }, { CG_CAPITAL, 'T', CG_CEDILLA }, { CG_SMALL, 't', CG_CEDILLA }, { CG_CAPITAL, 'T', CG_CARON }, { CG_SMALL, 't', CG_COMMA_T }, { CG_CAPITAL, 'T', CG_STROKE }, { CG_SMALL, 't', CG_STROKE }, { CG_CAPITAL, 'U', CG_TILDE }, { CG_SMALL, 'u', CG_TILDE }, { CG_CAPITAL, 'U', CG_MACRON }, { CG_SMALL, 'u', CG_MACRON }, { CG_CAPITAL, 'U', CG_BREVE }, { CG_SMALL, 'u', CG_BREVE }, { CG_CAPITAL, 'U', CG_RING_ABOVE }, { CG_SMALL, 'u', CG_RING_ABOVE }, { CG_CAPITAL, 'U', CG_DOUBLE_ACUTE }, { CG_SMALL, 'u', CG_DOUBLE_ACUTE }, { CG_CAPITAL, 'U', CG_OGONEK }, { CG_SMALL, 'u', CG_OGONEK }, { CG_CAPITAL, 'W', CG_CIRCUMFLEX }, { CG_SMALL, 'w', CG_CIRCUMFLEX }, { CG_CAPITAL, 'Y', CG_CIRCUMFLEX }, { CG_SMALL, 'y', CG_CIRCUMFLEX }, { CG_CAPITAL, 'Y', CG_DIAERESIS }, { CG_CAPITAL, 'Z', CG_ACUTE }, { CG_SMALL, 'z', CG_ACUTE }, { CG_CAPITAL, 'Z', CG_DOT_ABOVE }, { CG_SMALL, 'z', CG_DOT_ABOVE }, { CG_CAPITAL, 'Z', CG_CARON }, { CG_SMALL, 'z', CG_CARON }, { CG_NONE, 0, 0 } // CG_SMALL, 'LONG S }; bool Compose(Font font, int chr, ComposedGlyph& cg) { if(chr < 256 || chr > 256 + 128) return false; CGInfo f = gc_info[chr - 256]; if(f.type == CG_NONE) return false; GlyphInfo gi = GetGlyphInfo(font, f.ascii); if(!gi.IsNormal()) return false; int cw = gi.width; CommonFontInfo fi = GetFontInfo(font); gi = GetGlyphInfo(font, f.mark); if(!gi.IsNormal()) return false; int mw = gi.width; cg.mark_font = font; cg.mark_pos.x = cg.mark_pos.y = 0; cg.basic_char = f.ascii; cg.mark_char = f.mark; if(cg.mark_char == CG_COMMA_UR && fi.fixedpitch) cg.mark_char = CG_CARON; if(cg.mark_char == CG_COMMA_T) { cg.mark_pos.y -= 3 * font.GetHeight() / 4; cg.mark_pos.x += 4 * cw / 10; if(font.IsItalic()) cg.mark_pos.x += mw / 2; } else if(cg.mark_char == CG_COMMA_UR) { cg.mark_pos.y -= 2 * font.GetHeight() / 3; cg.mark_pos.x += cw - mw / 4; cg.mark_char = ','; if(font.IsItalic()) cg.mark_pos.x += mw / 3; } else if(cg.mark_char == CG_COMMA_URI) { cg.mark_pos.y -= 2 * font.GetHeight() / 3; cg.mark_pos.x += cw - mw / 2; cg.mark_char = ','; if(font.IsItalic()) cg.mark_pos.x += mw / 3; } else if(cg.mark_char != CG_STROKE) { if(cg.mark_char != CG_OGONEK && cg.mark_char != CG_CEDILLA && f.type == CG_CAPITAL) { cg.mark_font = font(9 * font.GetHeight() / 10); mw = GetGlyphInfo(cg.mark_font, f.mark).width; cg.mark_pos.y -= cg.mark_char == CG_RING_ABOVE ? font.GetHeight() / 19 : font.GetHeight() / 10; } cg.mark_pos.x += (cw - mw) / 2; if(font.IsItalic()) cg.mark_pos.x += mw / 5; } return true; } static const char *sFontReplacements[] = { "sans-serif", "Arial", "Arial Unicode MS", "Symbol", "???????", "?????", "MS UI Gothic", "MS Mincho", "Arial", "AlArabiya" "FreeSerif", "Kochi Mincho", "Kochi Gothic", "Sazanami Mincho", "Sazanami Gothic", "Gulim", "SimSun", "PMingLiU", }; struct sFontMetricsReplacement { Font src; Font dst; Font mdst; }; bool Replace(Font fnt, int chr, Font& rfnt) { static Vector rface; ONCELOCK { for(int i = 0; i < __countof(sFontReplacements) && rface.GetCount() < 20; i++) { int q = Font::FindFaceNameIndex(sFontReplacements[i]); if(q > 0) rface.Add(q); } } Font f = fnt; for(int i = 0; i < rface.GetCount(); i++) if(IsNormal(f.Face(rface[i]), chr)) { int a = fnt.GetAscent(); int d = fnt.GetDescent(); if(f.GetAscent() > a || f.GetDescent() > d) { static sFontMetricsReplacement cache[256]; int q = CombineHash(fnt, f) & 255; if(cache[q].src != fnt || cache[q].dst != f) { cache[q].src = fnt; cache[q].dst = f; while((f.GetAscent() > a || f.GetDescent() > d) && f.GetHeight() > 1) { f.Height(max(1, min(f.GetHeight() - 1, f.GetHeight() * 9 / 10))); } cache[q].mdst = f; } else f = cache[q].mdst; } rfnt = f; return true; } return false; } END_UPP_NAMESPACE