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