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