|
|
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.