|
|
1.1 ! root 1: // ! 2: // nono ! 3: // Copyright (C) 2019 [email protected] ! 4: // ! 5: ! 6: #include "wxheader.h" ! 7: #include "wxcolor.h" ! 8: #include "wxtextpanel.h" ! 9: #include "cgrom.h" ! 10: #include "bitrev.h" ! 11: ! 12: // wxOSX(-3.0.2) の wxLIGHT_GREY は値が(色も透明度も)正しくない。 ! 13: // wxGTK の wxLIGHT_GREY は 0xffd3d3d3 だけどこれを Mac で見ると ! 14: // (Mac の統一感としては) 暗く見えるので色コード自体を変える。 ! 15: #if defined(__WXOSX__) ! 16: #define LIGHT_GREY wxColour(0xffe0e0e0) ! 17: #else ! 18: #define LIGHT_GREY *wxLIGHT_GREY ! 19: #endif ! 20: ! 21: // ! 22: // テキストフォントを管理するクラス ! 23: // ! 24: ! 25: struct fontinfo { ! 26: int width; ! 27: int height; ! 28: } fontinfo[] = { ! 29: // 順序はヘッダの FONT_* 識別子の順と揃えること ! 30: { 6, 12 }, ! 31: { 8, 16 }, ! 32: { 12, 24 }, ! 33: }; ! 34: static_assert(countof(fontinfo) == FONT_MAX, ""); ! 35: ! 36: // コンストラクタ ! 37: WXTextPanel::WXTextPanel(wxWindow *parent) ! 38: : inherited(parent, wxID_ANY) ! 39: { ! 40: UpdateFont(global_fontsize); ! 41: ! 42: // デフォルト色 ! 43: SetTextColor(*wxBLACK, LIGHT_GREY, wxColour(0x50, 0x50, 0x50)); ! 44: } ! 45: ! 46: // デストラクタ ! 47: WXTextPanel::~WXTextPanel() ! 48: { ! 49: FreeFont(fontsize); ! 50: } ! 51: ! 52: // フォント関連の内部情報をよしなに更新する ! 53: void ! 54: WXTextPanel::UpdateFont(fontsize_t new_fontsize) ! 55: { ! 56: assert(fontsize != new_fontsize); ! 57: ! 58: // フォントデータを更新 ! 59: FreeFont(fontsize); ! 60: AllocFont(new_fontsize); ! 61: ! 62: // 内部変数を更新 ! 63: fontsize = new_fontsize; ! 64: font_width = fontinfo[fontsize].width; ! 65: font_height = fontinfo[fontsize].height; ! 66: ascii_glyph = ascii_glyph_table[fontsize]; ! 67: bold_glyph = bold_glyph_table[fontsize]; ! 68: } ! 69: ! 70: // 必要ならフォントを用意する ! 71: /*static*/ void ! 72: WXTextPanel::AllocFont(fontsize_t fontsize) ! 73: { ! 74: const uint8 *base; ! 75: ! 76: std::unique_lock<std::mutex> lock(global_font_mutex); ! 77: if (font_refcnt[fontsize]++ != 0) { ! 78: return; ! 79: } ! 80: ! 81: // 6x12, 8x16, 12x24 半角は X68030 CGROM にあるのでそれを使う ! 82: switch (fontsize) { ! 83: case FONT_6x12: ! 84: base = builtin_cgrom + 0xbf400; ! 85: break; ! 86: case FONT_8x16: ! 87: base = builtin_cgrom + 0x3a800; ! 88: break; ! 89: case FONT_12x24: ! 90: base = builtin_cgrom + 0x3d000; ! 91: break; ! 92: default: ! 93: fprintf(stderr, "%s:%d fontsize=%d\n", ! 94: __FILE__, __LINE__, fontsize); ! 95: assert(false); ! 96: __unreachable(); ! 97: } ! 98: ! 99: // フォントの行ストライド[byte] ! 100: int font_width = fontinfo[fontsize].width; ! 101: int font_height = fontinfo[fontsize].height; ! 102: int font_stride = (font_width + 7) / 8; ! 103: int bytes = font_stride * font_height; ! 104: char buf[bytes]; ! 105: ! 106: wxBitmap **ascii_glyph = ascii_glyph_table[fontsize]; ! 107: wxBitmap **bold_glyph = bold_glyph_table[fontsize]; ! 108: // ASCII というか半角というかは通常 0x7f までだが ! 109: // X680x0 の CGROM の 0x80, 0x81, 0x82 には '\\', '~', '|' が ! 110: // 収納されているのでここまで含めてデータを作っておく。 ! 111: for (int ch = 0; ch < countof(ascii_glyph_table[0]); ch++) { ! 112: const uint8 *ptr = base + ch * bytes; ! 113: ! 114: // wxBitmap は XBM 形式で 1bpp ビットマップを受け取る。 ! 115: // XBM は MSB が右なので、ビット左右を反転する ! 116: for (int i = 0; i < bytes; i++) { ! 117: uint8 src = ptr[i]; ! 118: buf[i] = bitrev(src); ! 119: } ! 120: // その XBM データから1文字分のビットマップオブジェクトを作成 ! 121: ascii_glyph[ch] = new wxBitmap(buf, font_width, font_height, 1); ! 122: ! 123: // 続いてボールドに加工 ! 124: for (int i = 0; i < bytes; i++) { ! 125: // XBM 形式は MSB が右なので左シフトすると一般的なボールド。 ! 126: buf[i] |= ((uint8)buf[i] << 1); ! 127: } ! 128: bold_glyph[ch] = new wxBitmap(buf, font_width, font_height, 1); ! 129: } ! 130: } ! 131: ! 132: // 最後の一人ならフォントを解放する ! 133: /*static*/ void ! 134: WXTextPanel::FreeFont(fontsize_t fontsize) ! 135: { ! 136: std::unique_lock<std::mutex> lock(global_font_mutex); ! 137: ! 138: if (fontsize < 0 || fontsize >= FONT_MAX) { ! 139: return; ! 140: } ! 141: if (--font_refcnt[fontsize] != 0) { ! 142: return; ! 143: } ! 144: ! 145: wxBitmap **ascii_glyph = ascii_glyph_table[fontsize]; ! 146: wxBitmap **bold_glyph = bold_glyph_table[fontsize]; ! 147: for (int i = 0; i < countof(ascii_glyph_table[0]); i++) { ! 148: if (ascii_glyph[i]) { ! 149: delete ascii_glyph[i]; ! 150: ascii_glyph[i] = NULL; ! 151: } ! 152: if (bold_glyph[i]) { ! 153: delete bold_glyph[i]; ! 154: bold_glyph[i] = NULL; ! 155: } ! 156: } ! 157: } ! 158: ! 159: // テキスト色を指定する ! 160: void ! 161: WXTextPanel::SetTextColor(const wxColour& fg, const wxColour& bg, ! 162: const wxColour& dc) ! 163: { ! 164: text_fgcolor = fg; ! 165: text_bgcolor = bg; ! 166: text_disable_color = dc; ! 167: } ! 168: ! 169: // (px, py) を左上とする座標から Shift_JIS 文字列を属性 attr で描画する。 ! 170: // 文字列中で属性を変えることはできない。 ! 171: // キャンバスをはみ出すかどうかについてはこちらでは関知しない。 ! 172: // フォントサイズは現行のフォント。 ! 173: void ! 174: WXTextPanel::DrawStringSJIS(wxDC& dc, int px, int py, const char *sjis, ! 175: uint attr) ! 176: { ! 177: const uint8 *s; ! 178: ! 179: for (s = (const uint8 *)sjis; *s; ) { ! 180: if (__predict_true(*s < 128)) { ! 181: // 半角 ! 182: DrawChar1(dc, px, py, *s++, attr); ! 183: px += font_width; ! 184: } else { ! 185: // 全角 ! 186: int code; ! 187: code = (*s++ << 8); ! 188: code |= *s++; ! 189: DrawChar2(dc, px, py, code, attr); ! 190: px += font_width * 2; ! 191: } ! 192: } ! 193: } ! 194: ! 195: // (px, py) を左上とする座標からASCII文字 code を属性 attr で描画する。 ! 196: // code は 0x80 未満。 ! 197: // フォントサイズは現行のフォント。 ! 198: void ! 199: WXTextPanel::DrawChar1(wxDC& dc, int px, int py, uint code, uint attr) ! 200: { ! 201: wxBitmap **glyph; ! 202: ! 203: assert(code < 0x80); ! 204: ! 205: // ボールドかどうかでテーブルが別 ! 206: if ((attr & TA::Em)) { ! 207: glyph = bold_glyph; ! 208: } else { ! 209: glyph = ascii_glyph; ! 210: } ! 211: ! 212: // 変更可能なグリフ ! 213: if (__predict_false(code == 0x5c)) { ! 214: if (glyph_5c) { ! 215: code = 0x80; ! 216: } ! 217: } else if (__predict_false(code == 0x7e)) { ! 218: if (glyph_7e) { ! 219: code = 0x81; ! 220: } ! 221: } else if (__predict_false(code == 0x7c)) { ! 222: if (glyph_7c) { ! 223: code = 0x82; ! 224: } ! 225: } ! 226: DrawBitmap(dc, px, py, *glyph[code], attr); ! 227: } ! 228: ! 229: // (px, py) を左上とする座標から漢字1文字を出力する。 ! 230: // sjiscode は Shift_JIS。 ! 231: // フォントサイズは現行のフォント。 ! 232: void ! 233: WXTextPanel::DrawChar2(wxDC& dc, int px, int py, uint sjiscode, uint attr) ! 234: { ! 235: wxBitmap *kanji = KanjiBitmap(sjiscode, attr); ! 236: DrawBitmap(dc, px, py, *kanji, attr); ! 237: delete kanji; ! 238: } ! 239: ! 240: // (px, py) を左上とする座標に bitmap を描画する。 ! 241: // この DrawBitmap() は dc のペン色を設定して dc.DrawBitmap() を呼ぶ。 ! 242: // ちょっと紛らわしいので注意。 ! 243: void ! 244: WXTextPanel::DrawBitmap(wxDC& dc, int px, int py, const wxBitmap& bitmap, ! 245: uint attr) ! 246: { ! 247: // 文字の背景は透過ではなく背景色で塗りつぶす ! 248: // XXX もっと初期化時に近いところへ移してよさそうだが ! 249: dc.SetBackgroundMode(wxSOLID); ! 250: ! 251: // 属性を設定 ! 252: switch (attr) { ! 253: case TA::On: ! 254: dc.SetTextForeground(text_bgcolor); ! 255: dc.SetTextBackground(text_fgcolor); ! 256: break; ! 257: case TA::Disable: ! 258: dc.SetTextForeground(text_disable_color); ! 259: dc.SetTextBackground(text_bgcolor); ! 260: break; ! 261: default: ! 262: dc.SetTextForeground(text_fgcolor); ! 263: dc.SetTextBackground(text_bgcolor); ! 264: break; ! 265: } ! 266: ! 267: // 1文字出力 ! 268: dc.DrawBitmap(bitmap, px, py); ! 269: ! 270: // 1文字ずつ属性を元に戻す ! 271: dc.SetTextForeground(text_fgcolor); ! 272: dc.SetTextBackground(text_bgcolor); ! 273: } ! 274: ! 275: // Shift_JIS の漢字1文字のビットマップを作成する。 ! 276: wxBitmap * ! 277: WXTextPanel::KanjiBitmap(uint16 sjiscode, uint attr) ! 278: { ! 279: // Shift_JIS を JIS というかコードポイントに変換 ! 280: uint sh = (sjiscode >> 8); ! 281: uint sl = sjiscode & 0xff; ! 282: uint jh; ! 283: uint jl; ! 284: if (sh < 0xa0) { ! 285: jh = sh - 0x71; ! 286: } else { ! 287: jh = sh - 0xb1; ! 288: } ! 289: jh = jh * 2 + 1; ! 290: jl = sl; ! 291: if (sl > 0x7f) { ! 292: jl--; ! 293: } ! 294: if (jl < 0x9e) { ! 295: jl -= 0x1f; ! 296: } else { ! 297: jl -= 0x7d; ! 298: jh++; ! 299: } ! 300: // ここで JIS。これを CGROM 格納コードポイントに変換。 ! 301: jh -= 0x21; ! 302: jl -= 0x21; ! 303: if (jh >= 15) { ! 304: jh -= 7; ! 305: } ! 306: int code = jh * 94 + jl; ! 307: ! 308: // XXX 見付からなかったらゲタ文字にしたい ! 309: if (code <0) code=0x6b; ! 310: ! 311: // フォント領域 ! 312: const uint8 *base; ! 313: switch (fontsize) { ! 314: case FONT_6x12: ! 315: // 12x12 は内蔵フォントデータ ! 316: base = builtin_kanji12; ! 317: break; ! 318: case FONT_8x16: ! 319: // 16x16 は X680x0 CGROM のを使う。 ! 320: base = builtin_cgrom + 0; ! 321: break; ! 322: case FONT_12x24: ! 323: // 24x24 は X680x0 CGROM のを使う。 ! 324: base = builtin_cgrom + 0x40000; ! 325: break; ! 326: default: ! 327: // ここより先に必ず半角のほうでエラーが出るはず ! 328: __unreachable(); ! 329: } ! 330: ! 331: int bytes = (((font_width * 2) + 7) / 8) * font_height; ! 332: char buf[bytes]; ! 333: ! 334: const uint8 *ptr; ! 335: ptr = base + code * bytes; ! 336: ! 337: for (int i = 0; i < bytes; i++) { ! 338: buf[i] = bitrev(ptr[i]); ! 339: } ! 340: if (attr == TA::Em) { ! 341: for (int i = 0; i < bytes; i++) { ! 342: buf[i] |= buf[i] >> 1; ! 343: } ! 344: } ! 345: ! 346: // その XBM データから1文字分のビットマップオブジェクトを作成 ! 347: return new wxBitmap(buf, font_width * 2, font_height, 1); ! 348: } ! 349: ! 350: // スタティック変数 ! 351: fontsize_t WXTextPanel::global_fontsize; ! 352: std::mutex WXTextPanel::global_font_mutex; ! 353: u_int WXTextPanel::font_refcnt[FONT_MAX]; ! 354: wxBitmap *WXTextPanel::ascii_glyph_table[FONT_MAX][0x83]; ! 355: wxBitmap *WXTextPanel::bold_glyph_table[FONT_MAX][0x83];
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.