Skip to content

Instantly share code, notes, and snippets.

@t-mat
Created January 18, 2012 01:35
Show Gist options
  • Select an option

  • Save t-mat/1630234 to your computer and use it in GitHub Desktop.

Select an option

Save t-mat/1630234 to your computer and use it in GitHub Desktop.
xyzzy自前アンチエイリアスパッチ(のやりかけ)

何をするもの?

xyzzy0.2.2.235のsrc/disp.ccに不完全なアンチエイリアス描画機能をつける。

手元の用途では、等幅のメイリオで十分だと分かったので、 やりかけのまま。

コンパイル

disp.cc を適宜書き換え、src/Makefileのコンパイル指定(CXX)に -DUSE_XYZZY_TEXT_ANTI_ALIAS を追加してから、コンパイルを行う。

TODO

  • 文字色、背景色の指定
    • 現状は ROP2 でごまかしている
    • CPUでがんばるか、Direct2Dを使うか?
  • 遅い
  • ガンマ値指定
#if defined(USE_XYZZY_TEXT_ANTI_ALIAS)
#include <vector>
#include <map>
namespace XyzzyTextAtiAlias {
struct FontChar {
HDC srcHdc;
int x;
int y;
int w;
int h;
void clear() {
srcHdc = 0;
x = 0;
y = 0;
w = 0;
h = 0;
}
};
static void debugOut(const char* fmt, ...) {
va_list args;
va_start(args, fmt);
char buf[1024];
// wvsprintf(buf, fmt, args);
vsprintf(buf, fmt, args);
OutputDebugString(buf);
va_end(args);
}
static void renderAntiAliasChar(HDC dstDc, unsigned char* dstMap, int pitch, const FontObject& f, const RECT* rc, const char* str, int len) {
int dstWidth = rc->right - rc->left;
int dstHeight = rc->bottom - rc->top;
int bpp = 8;
int ncolor = 1 << bpp;
int sr = 16;
static HFONT hfont = 0;
static HFONT srcHfont = 0;
static HDC hdc = 0;
{
if(hdc == 0 || hfont == 0 || srcHfont != static_cast<HFONT>(f)) {
if(hdc) {
DeleteDC(hdc);
hdc = 0;
}
if(hfont) {
DeleteObject(hfont);
hfont = 0;
}
LOGFONT logFont = f.logfont();
logFont.lfWidth *= sr;
logFont.lfHeight *= sr;
hfont = CreateFontIndirect(&logFont);
srcHfont = f;
hdc = CreateCompatibleDC(dstDc);
}
}
HGDIOBJ oldFont = SelectObject(hdc, hfont);
SIZE bsize;
GetTextExtentPoint32(hdc, str, len, &bsize);
BITMAPINFOHEADER bih = { 0 };
bih.biSize = sizeof(bih);
bih.biWidth = bsize.cx;
bih.biHeight = -bsize.cy;
bih.biPlanes = 1;
bih.biCompression = BI_RGB;
bih.biBitCount = 32;
int bitmapsize = bsize.cx * bsize.cy * 4;
std::vector<unsigned char> bitmapbuf(bitmapsize);
unsigned char *bitmap = &bitmapbuf[0];
HBITMAP dibsection = CreateDIBSection(hdc, (BITMAPINFO *) &bih, DIB_RGB_COLORS, (void **) &bitmap, NULL, 0);
memset(bitmap, 0, bitmapbuf.size());
HGDIOBJ obm = SelectObject(hdc, dibsection);
SetTextColor(hdc, RGB(255,255,255));
SetBkColor(hdc, RGB(0,0,0));
SetBkMode(hdc, OPAQUE);
TextOut(hdc, 0, 0, str, len);
for(int y = 0; y < bsize.cy; y += sr) {
for(int x = 0; x < bsize.cx; x += sr) {
int cnt = 0;
for(int vy = 0; vy < sr; vy++) {
if(y+vy >= bsize.cy || y+vy < 0) {
continue;
}
for(int vx = 0; vx < sr; vx++) {
if(x+vx >= bsize.cx || x+vx < 0) {
continue;
}
if(bitmap[((bsize.cy-1-(y+vy))*bsize.cx + x+vx)*4] != 0) {
cnt++;
}
}
}
{
float dmax = (float) (sr*sr);
float ddiv = (float) (ncolor-1);
// float ddiv = 4.0f - 1.0f;
// float ddiv = 16.0f - 1.0f;
// float ddiv = 256.0f - 1.0f;
float d = (float) cnt;
// d の値を正規化
d /= dmax;
if(d < 0.0f) d = 0.0f;
if(d >= 1.0f) d = 1.0f;
// d の [0, 1/(ddiv-1)] の範囲が新しく [0,1] の範囲になるようにマッピングする
d *= ddiv / (ddiv - 1.0f);
if(d >= 1.0f) {
d = 1.0f;
}
d *= dmax;
// d を分割する
d /= dmax / ddiv;
d = floorf(d);
d *= dmax / ddiv;
// printf("%5.1f ", d);
cnt = (int) d;
}
{
float c = sr * sqrtf((float)cnt);
#if 999
c = c * (sr*sr*sr-1) / (sr*sr*sr);
#else
c = c * (sr*sr-1) / (sr*sr);
#endif
int ic = (int) c;
int xx = x/sr;
int yy = y/sr;
int width = rc->right - rc->left;
int height = rc->bottom - rc->top;
if(xx < width && yy < height) {
// int addr = yy*pitch +xx;
unsigned char* p = &dstMap[(height - 1 - yy) * pitch + (xx * 4)];
p[0] =
p[1] =
p[2] =
p[3] = (unsigned char) ic;
}
}
}
}
SelectObject(hdc, oldFont);
SelectObject(hdc, obm);
DeleteObject(dibsection);
}
static void renderAntiAliasChar(HDC dstDc, unsigned char* dstMap, int pitch, const FontObject& f, const RECT* rc, int code) {
char str[3];
int len = 1;
if(code < 0x100) {
str[0] = code & 0xff;
str[1] = 0;
len = 1;
} else {
str[0] = (code >> 8) & 0xff;
str[1] = code & 0xff;
str[2] = 0;
len = 2;
}
return renderAntiAliasChar(dstDc, dstMap, pitch, f, rc, str, len);
}
class FontRender {
public:
typedef enum FONT_SET {
FONT_SET_ASCII = FONT_ASCII , //0
FONT_SET_JP = FONT_JP , //1
FONT_SET_LATIN = FONT_LATIN , //2
FONT_SET_CYRILLIC = FONT_CYRILLIC , //3
FONT_SET_GREEK = FONT_GREEK , //4
FONT_SET_CN_SIMPLIFIED = FONT_CN_SIMPLIFIED , //5
FONT_SET_CN_TRADITIONAL = FONT_CN_TRADITIONAL , //6
FONT_SET_HANGUL = FONT_HANGUL , //7
FONT_SET_GEORGIAN = FONT_GEORGIAN , //8
FONT_SET_MAX = FONT_MAX , //9
} FONT_SET;
FontRender();
virtual ~FontRender();
void paintChars(FONT_SET fontSet, HDC hdc, int x, int y,
int flags, const RECT &r, const char *string,
int len, const INT *padding);
void clear();
void dump();
protected:
const FontChar* getFontChar(FONT_SET fontSet, HDC hdc, int charCode, int charCode1 = 0);
struct Ascii {
bool initialized;
HFONT cachedFontHandle;
std::vector<FontChar> fontChar;
int maxW;
int maxH;
int maxY;
unsigned char* bitmapImage;
HDC cdc;
HBITMAP hbm;
HGDIOBJ obm;
void clear();
} ascii;
struct Jp {
bool initialized;
HFONT cachedFontHandle;
std::vector<FontChar> fontChar;
int maxW;
int maxH;
int maxY;
std::vector<unsigned short> codeToIndex;
int nCharCode;
unsigned char* bitmapImage;
HDC cdc;
HBITMAP hbm;
HGDIOBJ obm;
void clear();
} jp;
};
FontRender::FontRender() {
ascii.cachedFontHandle = 0;
ascii.cdc = 0;
ascii.hbm = 0;
jp.cachedFontHandle = 0;
jp.cdc = 0;
jp.hbm = 0;
ascii.clear();
jp.clear();
}
FontRender::~FontRender() {
}
void FontRender::dump() {
}
void FontRender::clear() {
ascii.clear();
jp.clear();
}
void FontRender::Ascii::clear() {
initialized = false;
cachedFontHandle = 0;
fontChar.clear();
maxW = 0;
maxH = 0;
maxY = 0;
bitmapImage = 0;
if(cdc) {
if(! DeleteDC(cdc)) {
debugOut(__FUNCTION__ " : ascii.DeleteDC(%p) failed\n", cdc);
}
cdc = 0;
}
if(hbm) {
if(! DeleteObject(hbm)) {
debugOut(__FUNCTION__ " : ascii.DeleteObject(%p) failed\n", hbm);
}
hbm = 0;
}
}
void FontRender::Jp::clear() {
initialized = false;
cachedFontHandle = 0;
fontChar.clear();
maxW = 0;
maxH = 0;
maxY = 0;
codeToIndex.clear();
nCharCode = 0;
bitmapImage = 0;
if(cdc) {
if(! DeleteDC(cdc)) {
debugOut(__FUNCTION__ " : jp.DeleteDC(%p) failed\n", cdc);
}
cdc = 0;
}
if(hbm) {
if(! DeleteObject(hbm)) {
debugOut(__FUNCTION__ " : jp.DeleteObject(%p) failed\n", hbm);
}
hbm = 0;
}
obm = 0;
}
const FontChar* FontRender::getFontChar(FONT_SET fontSet, HDC hdc, int charCode, int charCode1) {
const FontChar* fc = 0;
switch(fontSet) {
case FONT_SET_ASCII:
{
int firstCharCode = 0;
int lastCharCode = 256;
int nCharCode = lastCharCode - firstCharCode;
if(charCode >= firstCharCode && charCode < lastCharCode) {
// キャッシュ確認
const FontObject &f = app.text_font.font (FONT_ASCII);
if(ascii.cachedFontHandle != static_cast<HFONT>(f)) {
ascii.clear();
}
if(! ascii.initialized) {
ascii.initialized = true;
ascii.cachedFontHandle = static_cast<HFONT>(f);
ascii.fontChar.resize(nCharCode);
for(size_t i = 0; i < ascii.fontChar.size(); ++i) {
ascii.fontChar[i].clear();
}
//
ascii.maxW = 0;
ascii.maxH = 0;
ascii.maxY = 0;
{
int y = 0;
HGDIOBJ of = SelectObject (hdc, f);
for(int i = firstCharCode; i < lastCharCode; ++i) {
FontChar& o = ascii.fontChar[i-firstCharCode];
char str[2];
str[0] = i;
str[1] = 0;
int len = 1;
SIZE s = { 0 };
GetTextExtentPoint32(hdc, str, len, &s);
if(s.cx > ascii.maxW) {
ascii.maxW = s.cx;
}
if(s.cy > ascii.maxH) {
ascii.maxH = s.cy;
}
o.srcHdc = 0;
o.x = 0;
o.y = y;
o.w = s.cx;
o.h = s.cy;
y += s.cy;
}
SelectObject(hdc, of);
ascii.maxY = y;
}
//
{
HDC cdc = CreateCompatibleDC(hdc);
ascii.cdc = cdc;
BITMAPINFOHEADER bih = { 0 };
bih.biSize = sizeof(bih);
bih.biWidth = ascii.maxW;
bih.biHeight = -ascii.maxY;
bih.biPlanes = 1;
bih.biCompression = BI_RGB;
bih.biBitCount = 32;
HBITMAP hbm = CreateDIBSection(cdc, (BITMAPINFO*)&bih, DIB_RGB_COLORS, (void**) &ascii.bitmapImage, 0, 0);
HGDIOBJ obm = SelectObject(cdc, hbm);
for(int i = firstCharCode; i < lastCharCode; ++i) {
FontChar& o = ascii.fontChar[i-firstCharCode];
o.srcHdc = cdc;
RECT r = { o.x, o.y, o.x+o.w, o.y+o.h };
renderAntiAliasChar(cdc, ascii.bitmapImage+o.y*ascii.maxW*4, ascii.maxW*4, f, &r, i);
}
}
}
fc = &ascii.fontChar[charCode-firstCharCode];
}
}
break;
case FONT_SET_JP:
{
{
// キャッシュ確認
const FontObject &f = app.text_font.font(FONT_JP);
if(jp.cachedFontHandle != static_cast<HFONT>(f)) {
jp.clear();
}
if(! jp.initialized) {
jp.initialized = true;
jp.cachedFontHandle = static_cast<HFONT>(f);
jp.codeToIndex.resize(65536);
for(size_t i = 0; i < jp.codeToIndex.size(); ++i) {
jp.codeToIndex[i] = 0;
}
jp.nCharCode = 0;
jp.fontChar.clear();
jp.maxW = 0;
jp.maxH = 0;
jp.maxY = 0;
jp.cdc = 0;
typedef std::map<int, int> CodeToIndexMap;
CodeToIndexMap codeToIndexMap; // コード番号で引くと、インデクス値が返るマップ
if(jp.nCharCode == 0) {
int index = 0;
// 英数字
for(int c = 0x20; c <= 0x7e; ++c) {
codeToIndexMap[c] = index;
jp.codeToIndex[c] = index;
index += 1;
}
// 半角カナ
for(int c = 0xa1; c <= 0xdf; ++c) {
codeToIndexMap[c] = index;
jp.codeToIndex[c] = index;
index += 1;
}
// 区点
for(int ku = 1; ku <= 120; ku++) {
bool isKuPrintable = true;
if((ku >= 9 && ku <= 15)
|| (ku >= 89 && ku < 92)
|| (ku >= 115 && ku <= 119)
) {
isKuPrintable = false;
}
if(isKuPrintable) {
for(int ten = 1; ten <= 94; ten++) {
static int inval_kuten[][3] = {
// 区 点最小値 点最大値
2, 15, 25, // 記号(2区)
2, 34, 41, // 記号(2区)
2, 49, 59, // 記号(2区)
2, 75, 81, // 記号(2区)
2, 90, 93, // 記号(2区)
2, 94, 94, // 記号(2区) - 数字合成用丸印
3, 1, 15, // アルファベット(3区)
3, 26, 32, // アルファベット(3区)
3, 59, 64, // アルファベット(3区)
3, 91, 94, // アルファベット(3区)
4, 84, 94, // ひらがな(4区)
5, 87, 94, // カタカナ(5区)
6, 25, 32, // ギリシア文字(6区)
6, 57, 94, // ギリシア文字(6区)
7, 34, 48, // キリル文字(7区)
7, 82, 94, // キリル文字(7区)
8, 33, 94, // 罫線のうしろの空き領域(8区)
9, 1, 94,
10, 1, 94,
11, 1, 94,
12, 1, 94,
13, 31, 31, // NEC拡張文字空き領域(13区)
13, 55, 62, // NEC拡張文字空き領域(13区)
13, 93, 94, // NEC拡張文字空き領域(13区)
14, 1, 94, // 非漢字空き領域(14区)
15, 1, 94, // 非漢字空き領域(15区)
// 第一水準末端
47, 52, 94,
// 第二水準末端
84, 7, 94,
//
92, 79, 80, // NEC拡張文字
119, 13, 94,
};
bool isTenPrintable = true;
for(int i = 0; i < sizeof(inval_kuten)/sizeof(inval_kuten[0]); i++) {
int k = inval_kuten[i][0];
if(k == ku) {
int tmin = inval_kuten[i][1];
int tmax = inval_kuten[i][2];
if(ten >= tmin && ten <= tmax) {
isTenPrintable = false;
break;
}
}
}
if(isTenPrintable) {
int s0, s1;
int sk = ku - 1;
int skf = sk >> 1;
if(skf <= 0x1e) {
s0 = skf + 0x81;
} else {
s0 = (skf - 0x1f) + 0xe0;
}
int st = ten - 1;
if((sk & 1) == 0) {
st += 0x40;
if(st >= 0x7f) {
st++;
}
s1 = st;
} else {
s1 = st + 0x9f;
}
int c = (s0 << 8) | s1;
codeToIndexMap[c] = index;
jp.codeToIndex[c] = index;
index += 1;
}
}
}
}
jp.nCharCode = index;
}
if(jp.fontChar.empty()) {
jp.fontChar.resize(jp.nCharCode);
for(size_t i = 0; i < jp.fontChar.size(); ++i) {
jp.fontChar[i].clear();
}
}
// 横幅が最大になるキャラクタを見つけて、jp.maxW, jp.maxH に格納する
if(jp.maxW == 0 || jp.maxH == 0) {
int y = 0;
HGDIOBJ of = SelectObject (hdc, f);
for(CodeToIndexMap::iterator it = codeToIndexMap.begin(); it != codeToIndexMap.end(); ++it) {
int code = it->first;
int index = it->second;
FontChar& o = jp.fontChar[index];
char str[3];
int len = 1;
if(code < 0x100) {
str[0] = code & 0xff;
str[1] = 0;
len = 1;
} else {
str[0] = (code >> 8) & 0xff;
str[1] = code & 0xff;
str[2] = 0;
len = 2;
}
SIZE s = { 0 };
GetTextExtentPoint32(hdc, str, len, &s);
if(s.cx > jp.maxW) {
jp.maxW = s.cx;
}
if(s.cy > jp.maxH) {
jp.maxH = s.cy;
}
o.srcHdc = 0;
o.x = 0;
o.y = y;
o.w = s.cx;
o.h = s.cy;
y += s.cy;
}
SelectObject(hdc, of);
jp.maxY = y;
}
//
if(jp.cdc == 0) {
HDC cdc = CreateCompatibleDC(hdc);
jp.cdc = cdc;
BITMAPINFOHEADER bih = { 0 };
bih.biSize = sizeof(bih);
bih.biWidth = jp.maxW;
bih.biHeight = -jp.maxY;
bih.biPlanes = 1;
bih.biCompression = BI_RGB;
bih.biBitCount = 32;
jp.bitmapImage = 0;
jp.hbm = CreateDIBSection(cdc, (BITMAPINFO*)&bih, DIB_RGB_COLORS, (void**)&jp.bitmapImage, 0, 0);
jp.obm = SelectObject(cdc, jp.hbm);
}
}
if(charCode1) {
charCode = (charCode << 8) | charCode1;
}
unsigned short index = jp.codeToIndex[charCode];
if(index && index < jp.nCharCode) {
fc = &jp.fontChar[index];
if(fc->srcHdc == 0) {
int code = charCode;
FontChar& o = jp.fontChar[index];
const FontObject &f = app.text_font.font(FONT_JP);
o.srcHdc = jp.cdc;
RECT r = { o.x, o.y, o.x+o.w, o.y+o.h };
renderAntiAliasChar(jp.cdc, &jp.bitmapImage[o.y*jp.maxW*4], jp.maxW*4, f, &r, code);
}
}
}
}
break;
default:
break;
}
return fc;
}
void FontRender::paintChars(
FONT_SET fontSet, HDC hdc, int x, int y,
int flags, const RECT &r, const char *string,
int len, const INT *padding
) {
// flags
// xyzzy で使われる flags (fuOptions) は以下の2つ
//
// ETO_CLIPPED : The text will be clipped to the rectangle.
// ETO_OPAQUE : The current background color should be used to fill the rectangle.
//
#if 1
static HGDIOBJ cachedBkBrush = 0;
static COLORREF cachedBkBrushColor = 0;
COLORREF bkColor = GetBkColor(hdc);
if(flags & ETO_OPAQUE) {
if(cachedBkBrush == 0 || cachedBkBrushColor != bkColor) {
if(cachedBkBrush) {
// SelectObject(hdc, GetStockObject(NULL_BRUSH));
DeleteObject(cachedBkBrush);
cachedBkBrush = 0;
}
if(cachedBkBrush == 0) {
cachedBkBrushColor = bkColor;
cachedBkBrush = CreateSolidBrush(cachedBkBrushColor);
}
}
{
// RECT rc = { dstX, dstY, dstX+size.cx, dstY+size.cy };
// HGDIOBJ ob = SelectObject(hdc, cachedBkBrush);
FillRect(hdc, &r, (HBRUSH) cachedBkBrush);
// SelectObject(hdc, ob);
}
}
#endif
switch(fontSet) {
case FONT_SET_ASCII:
{
#if 1
// GDI
const FontObject &f = app.text_font.font (FONT_ASCII);
HFONT hFont = f;
int needPad = f.need_pad_p();
POINT offset = f.offset();
SIZE size = f.size();
int ascent = f.ascent();
LOGFONT logFont = f.logfont();
int dstX = x;
int dstY = y;
for(int i = 0; i < len; ++i) {
int c = int (string[i]) & 0xff;
const FontChar* fc = getFontChar(fontSet, hdc, c);
if(fc) {
// BitBlt(hdc, dstX, dstY, fc->w, fc->h, fc->srcHdc, fc->x, fc->y, SRCCOPY); // bold, 背景色, 文字色出ない
// BitBlt(hdc, dstX, dstY, fc->w, fc->h, fc->srcHdc, fc->x, fc->y, SRCPAINT); // DSo 文字色出ない
// (S & P) | D -> DPSao -> 00EA02E9
COLORREF textColor = GetTextColor(hdc);
HBRUSH hb = CreateSolidBrush(textColor);
HGDIOBJ ob = SelectObject(hdc, hb);
BitBlt(hdc, dstX, dstY, fc->w, fc->h, fc->srcHdc, fc->x, fc->y, 0x00ea02e9); // DPSao 一応出るが、階調が減るのでガビガビ
SelectObject(hdc, ob);
DeleteObject(hb);
if(needPad && padding) {
dstX += padding[i];
} else {
dstX += fc->w;
}
} else {
if(needPad && padding) {
dstX += padding[i];
} else {
dstX += size.cx;
}
}
}
#else
const FontObject &f = app.text_font.font (FONT_ASCII);
ExtTextOut (hdc, x + f.offset ().x, y + f.offset ().y, flags,
&r, string, len, f.need_pad_p () ? padding : 0);
#endif
}
break;
case FONT_SET_JP:
{
#if 1
const FontObject &f = app.text_font.font (FONT_JP);
HFONT hFont = f;
int needPad = f.need_pad_p();
POINT offset = f.offset();
SIZE size = f.size();
int ascent = f.ascent();
LOGFONT logFont = f.logfont();
int dstX = x;// + offset.x;
int dstY = y;// + offset.y;
for(int i = 0; i < len; ++i) {
int c0 = int (string[i]) & 0xff;
int c1 = 0;
if(_ismbblead(c0)) {
if(i+1 < len) {
c1 = int (string[i+1]) & 0xff;
i += 1;
}
}
const FontChar* fc = getFontChar(fontSet, hdc, c0, c1);
if(fc) {
// BitBlt(hdc, dstX, dstY, fc->w, fc->h, fc->srcHdc, fc->x, fc->y, SRCCOPY);
// BitBlt(hdc, dstX, dstY, fc->w, fc->h, fc->srcHdc, fc->x, fc->y, SRCPAINT);
// (S & P) | D -> DPSao -> 00EA02E9
COLORREF textColor = GetTextColor(hdc);
HBRUSH hb = CreateSolidBrush(textColor);
HGDIOBJ ob = SelectObject(hdc, hb);
BitBlt(hdc, dstX, dstY, fc->w, fc->h, fc->srcHdc, fc->x, fc->y, 0x00ea02e9); // DPSao 一応出るが、階調が減るのでガビガビ
SelectObject(hdc, ob);
DeleteObject(hb);
if(needPad && padding) {
dstX += padding[i];
if(c1) {
dstX += padding[i-1];
}
} else {
dstX += fc->w;
if(c1) {
dstX += padding[i-1];
}
}
} else {
if(needPad && padding) {
dstX += padding[i];
} else {
dstX += size.cx;
}
}
}
#else
const FontObject &f = app.text_font.font (FONT_JP);
HGDIOBJ of = SelectObject (hdc, f);
ExtTextOutA (hdc, x + f.offset ().x, y + f.offset ().y, flags,
&r, string, len, f.need_pad_p () ? padding : 0);
SelectObject (hdc, of);
#endif
}
break;
default:
{
}
break;
}
}
static FontRender fontRender;
inline void
paint_ascii_chars (HDC hdc, int x, int y, int flags, const RECT &r,
const char *string, int len, const INT *padding)
{
fontRender.paintChars(FontRender::FONT_SET_ASCII,
hdc, x, y, flags, r, string, len, padding);
}
inline void
paint_jp_chars (HDC hdc, int x, int y, int flags, const RECT &r,
const char *string, int len, const INT *padding)
{
fontRender.paintChars(FontRender::FONT_SET_JP,
hdc, x, y, flags, r, string, len, padding);
}
} // namespace XyzzyTextAtiAlias
#endif // USE_XYZZY_TEXT_ANTI_ALIAS
static inline void
paint_ascii_chars (HDC hdc, int x, int y, int flags, const RECT &r,
const char *string, int len, const INT *padding)
{
#if defined(USE_XYZZY_TEXT_ANTI_ALIAS)
return XyzzyTextAtiAlias::paint_ascii_chars(hdc, x, y, flags, r, string, len, padding);
#else // USE_XYZZY_TEXT_ANTI_ALIAS
const FontObject &f = app.text_font.font (FONT_ASCII);
ExtTextOut (hdc, x + f.offset ().x, y + f.offset ().y, flags,
&r, string, len, f.need_pad_p () ? padding : 0);
#endif // USE_XYZZY_TEXT_ANTI_ALIAS
}
static inline void
paint_jp_chars (HDC hdc, int x, int y, int flags, const RECT &r,
const char *string, int len, const INT *padding)
{
#if defined(USE_XYZZY_TEXT_ANTI_ALIAS)
return XyzzyTextAtiAlias::paint_jp_chars(hdc, x, y, flags, r, string, len, padding);
#else // USE_XYZZY_TEXT_ANTI_ALIAS
const FontObject &f = app.text_font.font (FONT_JP);
HGDIOBJ of = SelectObject (hdc, f);
ExtTextOut (hdc, x + f.offset ().x, y + f.offset ().y, flags,
&r, string, len, f.need_pad_p () ? padding : 0);
SelectObject (hdc, of);
#endif
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment