#include "Draw.h" namespace Upp { #define LLOG(x) // LOG(x) #define LTIMING(x) // TIMING(x) WString TextUnicode(const char *s, int n, byte cs, Font font) { if(n < 0) n = (int)strlen(s); #ifdef PLATFORM_WIN32 if(font.GetFace() == Font::SYMBOL) { WStringBuffer b(n); wchar *t = b; while(n > 0) { *t++ = *s++; n--; } return WString(b); } #endif if(cs == CHARSET_UTF8) return ToUtf32(s, n); return ToUnicode(s, n, cs); } void Draw::DrawText(int x, int y, int angle, const wchar *text, Font font, Color ink, int n, const int *dx) { if(IsNull(ink)) return; ink = ResolveInk(ink); if(n < 0) n = strlen__(text); Std(font); double sina = 0; double cosa = 1; int posx = 0; if(angle) Draw::SinCos(angle, sina, cosa); Font font0 = font; if(GetInfo() & DRAWTEXTLINES) font.Underline(false).Strikeout(false); for(int i = 0; i < n; i++) { wchar chr = text[i]; GlyphInfo gi = GetGlyphInfo(font, chr); if(gi.IsNormal()) if(angle || chr >= 0x10000) DrawTextOp(int(x + cosa * posx), int(y - sina * posx), angle, &chr, font, ink, 1, NULL); else { int c = 1; int dd = 0; while(i + c < n && c < 1000) { GlyphInfo gi2 = GetGlyphInfo(font, text[i + c]); if(!gi2.IsNormal()) break; dd += dx ? dx[c - 1] : gi.width; c++; gi = gi2; } DrawTextOp(x + posx, y, 0, text + i, font, ink, c, dx); posx += dd; i += c - 1; if(dx) dx += c - 1; } else if(gi.IsReplaced()) { Font fnt = font; fnt.Face(gi.lspc); fnt.Height(gi.rspc); if(angle) DrawTextOp(int(x + cosa * posx), int(y - sina * (font.GetAscent() - fnt.GetAscent() + posx)), angle, &chr, fnt, ink, 1, NULL); else DrawTextOp(x + posx, y + font.GetAscent() - fnt.GetAscent(), 0, &chr, fnt, ink, 1, NULL); GlyphMetrics(gi, font, chr); } else if(gi.IsComposed()) { ComposedGlyph cg; Compose(font, chr, cg); if(angle) { DrawTextOp(int(x + cosa * posx), int(y - sina * posx), angle, &cg.basic_char, font, ink, 1, NULL); DrawTextOp(int(x + cosa * (posx + cg.mark_pos.x)), int(y - sina * (cg.mark_pos.y + posx)), angle, &cg.mark_char, cg.mark_font, ink, 1, NULL); } else { DrawTextOp(x + posx, y, 0, &cg.basic_char, font, ink, 1, NULL); DrawTextOp(x + cg.mark_pos.x + posx, y + cg.mark_pos.y, 0, &cg.mark_char, cg.mark_font, ink, 1, NULL); } GlyphMetrics(gi, font, chr); } else { Font fnt = Arial(font.GetHeight()); wchar chr = 0x25a1; gi = GetGlyphInfo(fnt, chr); if(!gi.IsNormal()) { chr = ' '; gi = GetGlyphInfo(fnt, chr); } if(angle) DrawTextOp(int(x + cosa * posx), int(y - sina * posx), angle, &chr, fnt, ink, 1, NULL); else DrawTextOp(x + posx, y, 0, &chr, fnt, ink, 1, NULL); } posx += dx ? *dx++ : gi.width; } if((GetInfo() & DRAWTEXTLINES) && (font0.IsUnderline() || font0.IsStrikeout())) { int hg = abs(font0.GetCy()); if(hg == 0) hg = 10; int thickness = max(font.IsBold() ? hg / 10 : hg / 20, 1); int ascent = font0.GetAscent(); Size offset = Point(0, ascent); if(angle) { offset.cx = fround(ascent * sina); offset.cy = fround(ascent * cosa); } x += offset.cx; y += offset.cy; int p; auto DoLine = [&] { if(angle == 0) DrawRect(x, y + p, posx, thickness, ink); else DrawLine( int(x + p * sina), int(y + p * cosa), int(x + posx * cosa + p * sina), int(y - posx * sina + p * cosa), thickness, ink ); }; if(font0.IsUnderline()) { int descent = font0.GetDescent(); p = min(descent - thickness, max(descent > 0 ? descent / 2 : hg / 15, int(descent > 0))); DoLine(); } if(font0.IsStrikeout()) { p = -ascent / 3; DoLine(); } } } // ---------------------------- void Draw::DrawText(int x, int y, const wchar *text, Font font, Color ink, int n, const int *dx) { DrawText(x, y, 0, text, font, ink, n, dx); } // --------------------------- void Draw::DrawText(int x, int y, int angle, const WString& text, Font font, Color ink, const int *dx) { DrawText(x, y, angle, ~text, font, ink, text.GetLength(), dx); } void Draw::DrawText(int x, int y, const WString& text, Font font, Color ink, const int *dx) { DrawText(x, y, 0, text, font, ink, dx); } // --------------------------- void Draw::DrawText(int x, int y, int angle, const char *text, byte charset, Font font, Color ink, int n, const int *dx) { DrawText(x, y, angle, TextUnicode(text, n, charset, font), font, ink, dx); } void Draw::DrawText(int x, int y, const char *text, byte charset, Font font, Color ink, int n, const int *dx) { DrawText(x, y, 0, text, charset, font, ink, n, dx); } // --------------------------- void Draw::DrawText(int x, int y, int angle, const char *text, Font font, Color ink, int n, const int *dx) { DrawText(x, y, angle, text, CHARSET_DEFAULT, font, ink, n, dx); } void Draw::DrawText(int x, int y, const char *text, Font font, Color ink, int n, const int *dx) { DrawText(x, y, text, CHARSET_DEFAULT, font, ink, n, dx); } // --------------------------- void Draw::DrawText(int x, int y, int angle, const String& text, Font font, Color ink, const int *dx) { DrawText(x, y, angle, text, font, ink, text.GetLength(), dx); } void Draw::DrawText(int x, int y, const String& text, Font font, Color ink, const int *dx) { WString h = TextUnicode(text, text.GetLength(), CHARSET_DEFAULT, font); DrawText(x, y, h, font, ink, h.GetLength(), dx); } // -------------------------- Size GetTextSize(const wchar *text, Font font, int n) { if(n < 0) n = strlen__(text); Size sz; sz.cx = 0; const wchar *wtext = (const wchar *)text; while(n > 0) { if(*wtext >= ' ') sz.cx += font[*wtext]; n--; wtext++; } sz.cy = font.GetCy(); return sz; } Size GetTextSize(const WString& text, Font font) { return GetTextSize(text, font, text.GetLength()); } Size GetTextSize(const char *text, byte charset, Font font, int n) { return GetTextSize(TextUnicode(text, n, charset, font), font); if(ResolveCharset(charset) == CHARSET_UTF8 #ifdef PLATFORM_WIN32 && font.GetFace() != Font::SYMBOL #endif ) { Size sz; sz.cx = 0; const char *lim = text + (n < 0 ? strlen(text) : n); while(text < lim) { int c = FetchUtf8(text, lim); if(c >= ' ') sz.cx += font[c]; n--; } sz.cy = font.GetCy(); return sz; } else return GetTextSize(TextUnicode(text, n, charset, font), font); } Size GetTextSize(const char *text, Font font, int n) { return GetTextSize(text, CHARSET_DEFAULT, font, n); } Size GetTextSize(const String& text, Font font) { return GetTextSize(text, font, text.GetLength()); } }