260 lines
5.5 KiB
C
260 lines
5.5 KiB
C
#include "test.h"
|
|
|
|
enum
|
|
{
|
|
Guard = 8,
|
|
Testw = 6 * Fontsz,
|
|
Testh = 3 * Fontsz,
|
|
Testn = Testw * Testh,
|
|
Rgbmask = 0xffffff,
|
|
};
|
|
|
|
static u32int guardcolor = 0x5a5a5a5a;
|
|
|
|
static void
|
|
fillpixels(u32int *p, int n, u32int color)
|
|
{
|
|
int i;
|
|
|
|
for(i = 0; i < n; i++)
|
|
p[i] = color;
|
|
}
|
|
|
|
static int
|
|
hasink(u32int *p, int n, u32int bg)
|
|
{
|
|
int i;
|
|
|
|
bg &= Rgbmask;
|
|
for(i = 0; i < n; i++)
|
|
if((p[i] & Rgbmask) != bg)
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
hascolors(u32int *p, int n, u32int bg)
|
|
{
|
|
u32int c, first;
|
|
int b, found, g, i, r;
|
|
|
|
bg &= Rgbmask;
|
|
first = 0;
|
|
found = 0;
|
|
for(i = 0; i < n; i++){
|
|
c = p[i] & Rgbmask;
|
|
if(c == bg)
|
|
continue;
|
|
r = c >> 16 & 0xff;
|
|
g = c >> 8 & 0xff;
|
|
b = c & 0xff;
|
|
if(r == g && g == b)
|
|
continue;
|
|
if(!found){
|
|
first = c;
|
|
found = 1;
|
|
}else if(c != first)
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
checkguards(struct ct *t, u32int *mem)
|
|
{
|
|
int i;
|
|
|
|
for(i = 0; i < Guard; i++){
|
|
CT_EQ_UINT(t, guardcolor, mem[i]);
|
|
CT_EQ_UINT(t, guardcolor, mem[Guard + Testn + i]);
|
|
}
|
|
}
|
|
|
|
static void
|
|
checkoutside(struct ct *t, u32int *buf, u32int bg, int row)
|
|
{
|
|
int x, y, y0, y1;
|
|
|
|
bg &= Rgbmask;
|
|
y0 = max(row, 0);
|
|
y1 = min(row + Fontsz, Testh);
|
|
for(y = 0; y < Testh; y++){
|
|
if(y >= y0 && y < y1)
|
|
continue;
|
|
for(x = 0; x < Testw; x++)
|
|
CT_EQ_UINT(t, bg, buf[y * Testw + x] & Rgbmask);
|
|
}
|
|
}
|
|
|
|
static int
|
|
inkbounds(u32int *p, u32int bg, int *minx, int *miny, int *maxx, int *maxy)
|
|
{
|
|
int x, y;
|
|
|
|
bg &= Rgbmask;
|
|
*minx = Testw;
|
|
*miny = Testh;
|
|
*maxx = -1;
|
|
*maxy = -1;
|
|
for(y = 0; y < Testh; y++){
|
|
for(x = 0; x < Testw; x++){
|
|
if((p[y * Testw + x] & Rgbmask) == bg)
|
|
continue;
|
|
*minx = min(*minx, x);
|
|
*miny = min(*miny, y);
|
|
*maxx = max(*maxx, x);
|
|
*maxy = max(*maxy, y);
|
|
}
|
|
}
|
|
return *maxx >= 0;
|
|
}
|
|
|
|
static void
|
|
checktext(struct ct *t, u32int *buf, char *utf)
|
|
{
|
|
Str s;
|
|
int maxx, maxy, minx, miny, w;
|
|
|
|
s = mkstr(utf);
|
|
w = textwidth(&s);
|
|
CT_CHECK(t, w > 0);
|
|
CT_CHECK(t, w < Testw - Fontsz);
|
|
fillpixels(buf, Testn, Colbg);
|
|
textdraw(buf, Testw, Testh, Fontsz, Fontsz, &s);
|
|
if(!CT_CHECK(t, inkbounds(buf, Colbg, &minx, &miny, &maxx, &maxy)))
|
|
return;
|
|
CT_CHECK(t, minx >= 0 && miny >= 0);
|
|
CT_CHECK(t, maxx < Testw && maxy < Testh);
|
|
CT_CHECK(t, maxx - minx + 1 <= w);
|
|
}
|
|
|
|
static void
|
|
checkcolor(struct ct *t, u32int *buf, char *utf)
|
|
{
|
|
Str s;
|
|
int w;
|
|
|
|
s = mkstr(utf);
|
|
w = textwidth(&s);
|
|
CT_CHECK(t, w > 0);
|
|
if(s.n > 1)
|
|
CT_CHECK(t, w < s.n * Fontsz);
|
|
fillpixels(buf, Testn, Colbg);
|
|
textdraw(buf, Testw, Testh, Fontsz, Fontsz, &s);
|
|
CT_CHECK(t, hasink(buf, Testn, Colbg));
|
|
CT_CHECK(t, hascolors(buf, Testn, Colbg));
|
|
}
|
|
|
|
static void
|
|
checkshape(struct ct *t, u32int *buf, char *utf)
|
|
{
|
|
Str s;
|
|
int w;
|
|
|
|
s = mkstr(utf);
|
|
w = textwidth(&s);
|
|
CT_CHECK(t, w > 0);
|
|
CT_CHECK(t, w < s.n * Fontsz);
|
|
fillpixels(buf, Testn, Colbg);
|
|
textdraw(buf, Testw, Testh, Fontsz, Fontsz, &s);
|
|
CT_CHECK(t, hasink(buf, Testn, Colbg));
|
|
}
|
|
|
|
static void
|
|
checkclip(struct ct *t, u32int *mem, int x, int y, Str *s)
|
|
{
|
|
u32int *buf;
|
|
|
|
buf = mem + Guard;
|
|
fillpixels(buf, Testn, Colbg);
|
|
textdraw(buf, Testw, Testh, x, y, s);
|
|
CT_CHECK(t, hasink(buf, Testn, Colbg));
|
|
checkoutside(t, buf, Colbg, y);
|
|
checkguards(t, mem);
|
|
}
|
|
|
|
void
|
|
font_render(struct ct *t)
|
|
{
|
|
static char *plain[] = { "A", "가", "あ", "漢", "☆", "𠀋" };
|
|
u32int *buf, *mem;
|
|
Str a, heart, longrow, missing;
|
|
int i, maxx, maxy, minx, miny, natural, w, x, y;
|
|
|
|
mem = emalloc((Testn + 2 * Guard) * sizeof mem[0]);
|
|
fillpixels(mem, Testn + 2 * Guard, guardcolor);
|
|
buf = mem + Guard;
|
|
fillpixels(buf, Testn, Colbg);
|
|
a = mkstr("A");
|
|
if(!CT_CHECK(t, textinit())){
|
|
free(mem);
|
|
return;
|
|
}
|
|
for(i = 0; i < nelem(plain); i++)
|
|
checktext(t, buf, plain[i]);
|
|
|
|
checkcolor(t, buf, "😀");
|
|
checkcolor(t, buf, "❤️");
|
|
checkcolor(t, buf, "☕️");
|
|
checkshape(t, buf, "👩💻");
|
|
checkshape(t, buf, "👍🏽");
|
|
checkshape(t, buf, "🇰🇷");
|
|
checkshape(t, buf, "☕︎");
|
|
|
|
heart = mkstr("❤️");
|
|
fillpixels(buf, Testn, Colsel);
|
|
textdraw(buf, Testw, Testh, Fontsz, Fontsz, &heart);
|
|
CT_CHECK(t, hascolors(buf, Testn, Colsel));
|
|
CT_EQ_UINT(t, Colsel,
|
|
buf[(Fontsz + Fontsz/2) * Testw + Testw - 1] & Rgbmask);
|
|
checkoutside(t, buf, Colsel, Fontsz);
|
|
checkguards(t, mem);
|
|
|
|
w = textwidth(&a);
|
|
checkclip(t, mem, -w / 2, Fontsz, &a);
|
|
checkclip(t, mem, Testw - w / 2, Fontsz, &a);
|
|
checkclip(t, mem, Fontsz, -Fontsz / 2, &a);
|
|
checkclip(t, mem, Fontsz, Testh - Fontsz / 2, &a);
|
|
|
|
longrow = mkstr("abcdefghijklmnopqrstuvwxyz");
|
|
natural = textwidth(&longrow);
|
|
CT_CHECK(t, natural > 2*Fontsz);
|
|
fillpixels(buf, Testn, Colbg);
|
|
textdrawfit(buf, Testw, Testh, 2*Fontsz, Fontsz,
|
|
2*Fontsz, &longrow);
|
|
CT_CHECK(t, hasink(buf, Testn, Colbg));
|
|
for(y = Fontsz; y < 2*Fontsz; y++){
|
|
for(x = 0; x < 2*Fontsz; x++)
|
|
CT_EQ_UINT(t, Colbg, buf[y * Testw + x] & Rgbmask);
|
|
for(x = 4*Fontsz; x < Testw; x++)
|
|
CT_EQ_UINT(t, Colbg, buf[y * Testw + x] & Rgbmask);
|
|
}
|
|
CT_EQ_INT(t, natural, textwidth(&longrow));
|
|
|
|
fillpixels(buf, Testn, Colsel);
|
|
textdrawfitcolor(buf, Testw, Testh, 2*Fontsz, Fontsz,
|
|
2*Fontsz, Colselfg, &longrow);
|
|
CT_CHECK(t, (Colselfg & Rgbmask) != (Colsel & Rgbmask));
|
|
if(CT_CHECK(t, inkbounds(buf, Colsel,
|
|
&minx, &miny, &maxx, &maxy))){
|
|
CT_CHECK(t, minx >= 2*Fontsz);
|
|
CT_CHECK(t, maxx < 4*Fontsz);
|
|
CT_CHECK(t, miny >= Fontsz);
|
|
CT_CHECK(t, maxy < 2*Fontsz);
|
|
}
|
|
checkoutside(t, buf, Colsel, Fontsz);
|
|
checkguards(t, mem);
|
|
CT_EQ_INT(t, natural, textwidth(&longrow));
|
|
|
|
missing = mkstr("\xF4\x8F\xBF\xBF");
|
|
for(i = 0; i < 32; i++){
|
|
textdraw(buf, Testw, Testh, Fontsz, Fontsz, &heart);
|
|
textdraw(buf, Testw, Testh, 0, 0, &missing);
|
|
}
|
|
checkguards(t, mem);
|
|
free(mem);
|
|
textclose();
|
|
textclose();
|
|
CT_EQ_INT(t, 0, textwidth(&a));
|
|
}
|