winamp/Src/Wasabi/api/font/bitmapfont.cpp

395 lines
16 KiB
C++
Raw Permalink Normal View History

2024-09-24 12:54:57 +00:00
#include "precomp.h"
// ============================================================================================================================================================
// Font abstract class + statics to install TT fonts and Bitmap fonts
// ============================================================================================================================================================
#include "bitmapfont.h"
#include <api/wnd/fontdef.h>
#include <api/config/items/cfgitem.h>
#ifdef WASABI_COMPILE_SKIN
#include <api/skin/skin.h>
#endif
#ifdef WA3COMPATIBILITY
#endif
#include <tataki/canvas/ifc_canvas.h>
#include <tataki/region/api_region.h>
#include <api/skin/skinparse.h>
// ============================================================================================================================================================
// BitmapFont implementation.
// ============================================================================================================================================================
// -------------------------------------------------------------------------------------------------------------------------------------------------------------
BitmapFont::BitmapFont() : scriptid(0), char_width(0), char_height(0), hor_spacing(0), vert_spacing(0) {
}
// -------------------------------------------------------------------------------------------------------------------------------------------------------------
BitmapFont::~BitmapFont() {
}
// -------------------------------------------------------------------------------------------------------------------------------------------------------------
int BitmapFont::isBitmap() {
return 1;
}
// -------------------------------------------------------------------------------------------------------------------------------------------------------------
const wchar_t *BitmapFont::getFaceName() {
return getFontId();
}
// -------------------------------------------------------------------------------------------------------------------------------------------------------------
void BitmapFont::textOut(ifc_canvas *c, int x, int y, const wchar_t *txt, int size, int bold, int opaque, int underline, int italic, ARGB32 color, ARGB32 bkcolor, int xoffset, int yoffset, int antialiased) {
do_textOut(this, c, x+xoffset, y+yoffset, -1, -1, txt, size, bold, opaque, underline, italic, STDFONT_LEFT, color, WA_FONT_TEXTOUT_NORMAL);
}
// -------------------------------------------------------------------------------------------------------------------------------------------------------------
void BitmapFont::textOut2(ifc_canvas *c, int x, int y, int w, int h, const wchar_t *txt, int size, int bold, int opaque, int underline, int italic, int align, ARGB32 color, ARGB32 bkcolor, int xoffset, int yoffset, int antialiased) {
do_textOut(this, c, x+xoffset, y+yoffset, x+xoffset+w, y+yoffset+h, txt, size, bold, opaque, underline, italic, align, color, WA_FONT_TEXTOUT_RECT);
}
// -------------------------------------------------------------------------------------------------------------------------------------------------------------
void BitmapFont::textOutEllipsed(ifc_canvas *c, int x, int y, int w, int h, const wchar_t *txt, int size, int bold, int opaque, int underline, int italic, int align, ARGB32 color, ARGB32 bkcolor, int xoffset, int yoffset, int antialiased) {
do_textOut(this, c, x+xoffset, y+yoffset, x+xoffset+w, y+yoffset+h, txt, size, bold, opaque, underline, italic, align, color, WA_FONT_TEXTOUT_ELLIPSED);
}
// -------------------------------------------------------------------------------------------------------------------------------------------------------------
void BitmapFont::textOutWrapped(ifc_canvas *c, int x, int y, int w, int h, const wchar_t *txt, int size, int bold, int opaque, int underline, int italic, int align, ARGB32 color, ARGB32 bkcolor, int xoffset, int yoffset, int antialiased) {
do_textOut(this, c, x+xoffset, y+yoffset, x+xoffset+w, y+yoffset+h, txt, size, bold, opaque, underline, italic, align, color, WA_FONT_TEXTOUT_WRAPPED);
}
// -------------------------------------------------------------------------------------------------------------------------------------------------------------
void BitmapFont::textOutWrappedPathed(ifc_canvas *c, int x, int y, int w, const wchar_t *txt, int size, int bold, int opaque, int underline, int italic, int align, ARGB32 color, ARGB32 bkcolor, int xoffset, int yoffset, int antialiased) {
do_textOut(this, c, x+xoffset, y+yoffset, x+xoffset+w, -1, txt, size, bold, opaque, underline, italic, align, color, WA_FONT_TEXTOUT_WRAPPEDPATHED);
}
// -------------------------------------------------------------------------------------------------------------------------------------------------------------
void BitmapFont::textOutCentered(ifc_canvas *c, RECT *r, const wchar_t *txt, int size, int bold, int opaque, int underline, int italic, int align, ARGB32 color, ARGB32 bkcolor, int xoffset, int yoffset, int antialiased) {
do_textOut(this, c, r->left, r->top, r->right-r->left, r->bottom-r->top, txt, size, bold, opaque, underline, italic, align, color, WA_FONT_TEXTOUT_CENTERED);
}
// -------------------------------------------------------------------------------------------------------------------------------------------------------------
int BitmapFont::getTextWidth(ifc_canvas *c, const wchar_t *text, int size, int bold, int underline, int italic, int antialiased)
{
return wcslen(text) * char_width + wcslen(text)*hor_spacing;
}
// -------------------------------------------------------------------------------------------------------------------------------------------------------------
int BitmapFont::getTextHeight(ifc_canvas *c, const wchar_t *text, int size, int bold, int underline, int italic, int antialiased)
{
return char_height;
}
// -------------------------------------------------------------------------------------------------------------------------------------------------------------
int BitmapFont::getTextHeight2(ifc_canvas *c, int size, int bold, int underline, int italic, int antialiased)
{
return char_height;
}
// -------------------------------------------------------------------------------------------------------------------------------------------------------------
void BitmapFont::getTextExtent(ifc_canvas *c, const wchar_t *text, int *w, int *h, int size, int bold, int underline, int italic, int antialiased)
{
if (w) *w = getTextWidth(c, text, size, bold, underline, italic, antialiased);
if (h) *h = char_height;
}
// -------------------------------------------------------------------------------------------------------------------------------------------------------------
void BitmapFont::setFontBitmap(const wchar_t *name_or_element, const wchar_t *path)
{
StringW pathfile;
if (!wcschr(name_or_element, L':'))
{
pathfile = path;
pathfile.AddBackslash();
}
pathfile.cat(name_or_element);
if (!WACCESS(pathfile, 0))
table = pathfile;
else
table = name_or_element;
}
// -------------------------------------------------------------------------------------------------------------------------------------------------------------
void BitmapFont::setFontMetrics(int _char_width, int _char_height, int _hor_spacing, int _vert_spacing) {
char_width = _char_width;
char_height = _char_height;
hor_spacing = _hor_spacing;
vert_spacing = _vert_spacing;
}
// -------------------------------------------------------------------------------------------------------------------------------------------------------------
int BitmapFont::getHorizontalSpacing() {
return hor_spacing;
}
// -------------------------------------------------------------------------------------------------------------------------------------------------------------
int BitmapFont::getVerticalSpacing() {
return vert_spacing;
}
// -------------------------------------------------------------------------------------------------------------------------------------------------------------
int BitmapFont::getCharWidth() {
return char_width;
}
// -------------------------------------------------------------------------------------------------------------------------------------------------------------
int BitmapFont::getCharHeight() {
return char_height;
}
AutoSkinBitmap *BitmapFont::getCharTable() {
return &table;
}
// -------------------------------------------------------------------------------------------------------------------------------------------------------------
void BitmapFont::getXYfromChar(wchar_t ic, int *x, int *y)
{
int c,c2=0;
switch (ic)
{
case L'\u00B0': /*<2A>*/ ic = L'0'; break;
case L'\u00C6':/*<2A>*/ ic = L'A'; break;
// case '\u00C1':/*<2A>*/ ic = L'A'; break;
// case '\u00C2': ic = L'A'; break;
case L'\u00C7': /*<2A>*/ ic = L'C'; break;
case L'\u00C9':/*<2A>*/ ic = L'E'; break;
case L'\u00E0': /*<2A>*/ case L'\u00E1': /*<2A>*/ case L'\u00E2': /*<2A>*/ ic = L'a'; break;
case L'\u00E6':/*<2A>*/ ic = L'a'; break;
case L'\u00E7': /*<2A>*/ ic = L'c'; break;
case L'\u00E8': /*<2A>*/ case L'\u00E9': /*<2A>*/ case L'\u00EB': /*<2A>*/case L'\u00EA':/*<2A>*/ ic = L'e'; break;
case L'\u00EC':/*<2A>*/ case L'\u00ED':/*<2A>*/ case L'\u00EE':/*<2A>*/ case L'\u00EF':/*<2A>*/ ic = L'i'; break;
#ifdef _WIN32
case L'<EFBFBD>':/*<2A>*/ case L'<EFBFBD>':/*<2A>*/ case L'<EFBFBD>':/*<2A>*/ ic = L'o'; break;
case L'<EFBFBD>':/*<2A>*/ case L'<EFBFBD>':/*<2A>*/ case L'<EFBFBD>':/*<2A>*/ ic = L'u'; break;
case L'<EFBFBD>':/*<2A>*/ ic = L'y'; break;
case L'<EFBFBD>':/*<2A>*/ ic = L'U'; break;
#else
#warning change these to \u
#endif
case L'\u00D1':/*<2A>*/ ic = L'N'; break;
case L'\u00F1':/*<2A>*/ ic = L'n'; break;
case L'\u00FC': /*<2A>*/ ic = L'u'; break;
case L'\u0192':/*<2A>*/ ic = L'f'; break;
default: break;
} // quick relocations
if (ic <= L'Z' && ic >= L'A') c = (ic-'A');
else if (ic <= L'z' && ic >= L'a') c = (ic-'a');
else if (ic == L' ') c = 30;
else {
c2 += char_height;
if (ic == L'\1') c=10;
else if (ic == L'.') c = 11;
else if (ic <= L'9' && ic >= L'0') c = ic - L'0';
else if (ic == L':') c = 12;
else if (ic == L'(') c = 13;
else if (ic == L')') c = 14;
else if (ic == L'-') c = 15;
else if (ic == L'\'' || ic=='`') c = 16;
else if (ic == L'!') c = 17;
else if (ic == L'_') c = 18;
else if (ic == L'+') c = 19;
else if (ic == L'\\') c = 20;
else if (ic == L'/') c = 21;
else if (ic == L'[' || ic == L'{' || ic == L'<') c = 22;
else if (ic == L']' || ic == L'}' || ic == L'>') c = 23;
else if (ic == L'~' || ic == L'^') c = 24;
else if (ic == L'&') c = 25;
else if (ic == L'%') c = 26;
else if (ic == L',') c = 27;
else if (ic == L'=') c = 28;
else if (ic == L'$') c = 29;
else if (ic == L'#') c = 30;
else
{
c2 += char_height;
#ifdef _WIN32
if (ic == L'<EFBFBD>' || ic == L'<EFBFBD>') c = 0;
else if (ic == L'<EFBFBD>' || ic == L'<EFBFBD>') c = 1;
else if (ic == L'<EFBFBD>' || ic == L'<EFBFBD>') c = 2;
else
#else
#warning change these to \u
#endif
if (ic == L'?') c = 3;
else if (ic == L'*') c = 4;
else {
c2 = 0;
if (ic == L'"') c = 26;
else if (ic == L'@') c = 27;
else c = 30;
}
}
}
c*=char_width;
*x=c;
*y=c2;
}
// -------------------------------------------------------------------------------------------------------------------------------------------------------------
int BitmapFont::getWordLength(const wchar_t *p) {
int n=0;
while (p && *p && *p != L' ') {
p++;
n++;
}
return n;
}
// -------------------------------------------------------------------------------------------------------------------------------------------------------------
wchar_t *BitmapFont::makeLine(const wchar_t *t, BitmapFont *font, int line, int width, int style) {
static wchar_t str[4096];
wchar_t *p = (wchar_t *)t;
size_t len = wcslen(t);
switch (style) {
case WA_FONT_TEXTOUT_NORMAL:
case WA_FONT_TEXTOUT_RECT:
case WA_FONT_TEXTOUT_ELLIPSED:
case WA_FONT_TEXTOUT_CENTERED:
return line == 0 ? (wchar_t *)t : NULL;
case WA_FONT_TEXTOUT_WRAPPEDPATHED:
case WA_FONT_TEXTOUT_WRAPPED: {
size_t maxchar = width / (font->getCharWidth() + font->getVerticalSpacing());
for (int i = 0; i < line; i++) {
wchar_t *oldp = p;
p += maxchar;
if ((size_t)(p-t) >= len) return NULL;
while (p >= t) {
if (p == t || *(p-1) == L' ')
break;
p--;
}
if (p == oldp) {
p += maxchar;
while (p && *p && *p != L' ')
p++;
}
}
WCSCPYN(str, p, maxchar);
wchar_t *d = &str[maxchar-1];
int wr=0;
if (wcslen(p) > maxchar && *(p+maxchar) != L' ' && wcschr(str, L' '))
while (d >= str) {
if (*d == L' ') {
*d = 0;
wr=1;
}
else {
if (wr) break;
d--;
}
}
return str;
}
}
return NULL;
}
// -------------------------------------------------------------------------------------------------------------------------------------------------------------
void BitmapFont::do_textOut(BitmapFont *font, ifc_canvas *c, int x, int y, int x2, int y2, const wchar_t *text, int size, int bold, int opaque, int underline, int italic, int align, ARGB32 color, int style)
{
static wchar_t *dotdotdot=L"...";
if (!text) return;
BaseCloneCanvas canvas;
int ret = canvas.clone(c);
if (!ret) return;
RECT bounds;
RECT defbounds={x,y,x2,y2};
int __w, __h;
c->getDim(&__w, &__h, NULL);
if (x2 == -1) defbounds.right = defbounds.left + __w;
if (y2 == -1) defbounds.bottom = defbounds.top + __h;
#ifdef _WIN32
RegionI oldclip(&canvas, &defbounds); // get clipping region in oldclip
RegionI *andclip=NULL;
oldclip.getBox(&bounds); // get boundaries
#else
bounds = defbounds;
#warning port me
#endif
/* if (x2 != -1 && y2 != -1) {
andclip = new RegionI(x, y, x2, y2); // create region for rect
andclip->andRegion(oldclip); // and them
canvas.selectClipRgn(andclip); // select new clipping rect
andclip->getBox(&bounds); // update boundaries
}*/
int lc=-1;
wchar_t *p = dotdotdot+3; // just a zero to triger next line
int _x = x+(font->getHorizontalSpacing()/2);
int _y = y;
if (style == WA_FONT_TEXTOUT_CENTERED) {
_y += (y2 - y - font->getCharHeight()) / 2;
}
_y -= font->getCharHeight() + font->getVerticalSpacing();
int xp, yp;
while (p) {
if (!*p) {
lc++;
p = makeLine(text, font, lc, x2-x, style);
if (!p || !*p) break;
_x = x+(font->getHorizontalSpacing()/2);
_y += font->getCharHeight() + font->getVerticalSpacing();
if ((align == STDFONT_RIGHT || align == STDFONT_CENTER) && x2 != -1) {
int l = wcslen(p);
_x -= l * (font->getCharWidth() + font->getHorizontalSpacing()) - (x2-x);
}
if (align == STDFONT_CENTER)
_x = x + (_x - x) / 2;
}
if ((style == WA_FONT_TEXTOUT_ELLIPSED || style == WA_FONT_TEXTOUT_WRAPPEDPATHED) && x2 != -1) {
if (_x > x2 - 4 * (font->getCharWidth() + font->getHorizontalSpacing()) && wcslen(p) > 3) {
p = dotdotdot;
}
}
font->getXYfromChar(*p, &xp, &yp);
RECT r;
r.left = xp;
r.top = yp;
r.right = xp + font->getCharWidth();
r.bottom = yp + font->getCharHeight();
RECT dst;
dst.left = _x;
dst.top = _y;
dst.right = _x + font->getCharWidth();
dst.bottom = _y + font->getCharHeight();
if (Wasabi::Std::rectIntersect(dst, bounds))
// if (IntersectRect(&dummy, &dst, &bounds)) // port me / checks clipping, not passed x,y,x2,y2
font->getCharTable()->stretchToRectAlpha(&canvas, &r, &dst, 255);
p++;
_x += font->getCharWidth();
_x += font->getHorizontalSpacing();
}
#ifdef _WIN32
if (andclip) {
canvas.selectClipRgn(&oldclip); // restore previously saved clipping region
delete andclip;
}
#else
#warning port me
#endif
}