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