xyzzy0.2.2.235のsrc/disp.ccに不完全なアンチエイリアス描画機能をつける。
手元の用途では、等幅のメイリオで十分だと分かったので、 やりかけのまま。
disp.cc を適宜書き換え、src/Makefileのコンパイル指定(CXX)に -DUSE_XYZZY_TEXT_ANTI_ALIAS を追加してから、コンパイルを行う。
- 文字色、背景色の指定
- 現状は ROP2 でごまかしている
- CPUでがんばるか、Direct2Dを使うか?
- 遅い
- ガンマ値指定
xyzzy0.2.2.235のsrc/disp.ccに不完全なアンチエイリアス描画機能をつける。
手元の用途では、等幅のメイリオで十分だと分かったので、 やりかけのまま。
disp.cc を適宜書き換え、src/Makefileのコンパイル指定(CXX)に -DUSE_XYZZY_TEXT_ANTI_ALIAS を追加してから、コンパイルを行う。
| #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 | |
| } | |