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