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