Mercurial > otakunoraifu
annotate font/font_peer_x11.cc @ 66:d112357a0ec1
Fix a bug with savegames introduced with changeset c7bcc0ec2267.
Warning: savegames created since c7bcc0ec2267 are probably corrupted,
you may have to start the game over.
If you chose not to do so, you should replace all occurrences of 'TextWindow' by 'TextImplWindow',
and 'Text Window' by 'TextImpl Window' in your save files.
author | Thibaut Girka <thib@sitedethib.com> |
---|---|
date | Sat, 11 Dec 2010 18:36:20 +0100 |
parents | 4416cfac86ae |
children |
rev | line source |
---|---|
0 | 1 /* |
27 | 2 * Copyright (c) 2004 Kazunori "jagarl" Ueno |
0 | 3 * Copyright (c) 2000, 2001 Yuki Sawada |
4 * All rights reserved. | |
5 * | |
6 * Redistribution and use in source and binary forms, with or without | |
7 * modification, are permitted provided that the following conditions | |
8 * are met: | |
9 * 1. Redistributions of source code must retain the above copyright | |
10 * notice, this list of conditions and the following disclaimer. | |
11 * 2. Redistributions in binary form must reproduce the above copyright | |
12 * notice, this list of conditions and the following disclaimer in the | |
13 * documentation and/or other materials provided with the distribution. | |
14 * 3. The name of the author may not be used to endorse or promote products | |
15 * derived from this software without specific prior written permission. | |
16 * | |
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
27 */ | |
28 | |
29 #include <stdlib.h> | |
30 | |
31 #include "font.h" | |
32 #include "font_peer.h" | |
33 | |
34 #if USE_X11 | |
35 | |
36 #include <sys/ipc.h> | |
37 #include <sys/shm.h> | |
38 | |
39 #include <X11/Xlib.h> | |
40 #include <X11/Xutil.h> | |
41 #include <X11/extensions/XShm.h> | |
42 #include <stdio.h> | |
52 | 43 #include <iostream> |
0 | 44 |
52 | 45 #include <vector> |
46 #include <map> | |
47 | |
48 #include <sstream> | |
0 | 49 #include <string> |
50 #include <stdexcept> | |
51 | |
52 using namespace std; | |
53 | |
54 namespace XKFont { | |
55 inline int read_little_endian_int(const char* buf) { | |
56 const unsigned char *p = (const unsigned char *) buf; | |
57 return (p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0]; | |
58 } | |
59 | |
60 /*********************************** | |
61 ** | |
62 ** Fontinfo / FontSetInfo | |
63 ** | |
65
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
52
diff
changeset
|
64 ** fontset から特定 pixel size を持つ |
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
52
diff
changeset
|
65 ** 別のfontsetを作成するためのクラス |
0 | 66 */ |
67 struct FontInfo { | |
68 std::map<int, string> fontlist; | |
69 FontInfo(Display* display, const char* fontname_orig); | |
70 string Search(int pixsize); | |
71 }; | |
72 struct FontSetInfo { | |
73 std::vector<FontInfo*> fontlist; | |
74 FontSetInfo(Display* display, const char* fontset_orig); | |
75 string Search(int pixsize); | |
76 ~FontSetInfo(); | |
77 }; | |
78 | |
79 | |
80 /*********************************** | |
81 ** | |
82 ** Methods of Fontinfo / FontSetInfo | |
83 ** | |
84 */ | |
85 FontInfo::FontInfo(Display* display, const char* fontname_orig) { | |
65
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
52
diff
changeset
|
86 /* フォントの大きさ関係の情報を消去 */ |
0 | 87 int i; |
88 char* fontname = new char[strlen(fontname_orig)+50]; | |
52 | 89 int minus_count = 0; |
90 bool is_skip = false; | |
91 int fc = 0; | |
0 | 92 for (i=0; fontname_orig[i]!=0; i++) { |
93 if (fontname_orig[i] == '-') { | |
94 minus_count++; | |
95 if (minus_count >= 7 && minus_count <= 12) { | |
96 fontname[fc++] = '-'; | |
97 fontname[fc++] = '*'; | |
98 is_skip = true; | |
99 } else { | |
100 is_skip = false; | |
101 } | |
102 } | |
103 if (! is_skip) fontname[fc++] = fontname_orig[i]; | |
104 } | |
65
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
52
diff
changeset
|
105 /* フォント情報を得る */ |
0 | 106 fontname[fc] = 0; |
107 int count; | |
108 char** fontnamelist = XListFonts(display, fontname, 100, &count); | |
109 for (i=0; i<count; i++) { | |
110 char* curfont = fontnamelist[i]; | |
65
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
52
diff
changeset
|
111 /* fontname から pixel size 情報を得る */ |
52 | 112 int j; |
113 int minus_count = 0; | |
0 | 114 for (j=0; curfont[j] != 0; j++) { |
115 if (curfont[j] == '-') minus_count++; | |
116 if (minus_count == 7) { | |
117 int pixsize = atoi(curfont+j+1); | |
118 if (fontlist.find(pixsize) == fontlist.end()) { | |
119 fontlist[pixsize] = string(curfont); | |
120 } | |
121 break; | |
122 } | |
123 } | |
124 } | |
65
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
52
diff
changeset
|
125 /* 検索に失敗した場合、とりあえず fontname を入れておく */ |
0 | 126 if (fontlist.find(0) == fontlist.end()) { |
127 fontlist[0] = string(fontname); | |
128 } | |
129 XFreeFontNames(fontnamelist); | |
130 delete[] fontname; | |
131 return; | |
132 } | |
133 string FontInfo::Search(int pixsize) { | |
134 int i; | |
65
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
52
diff
changeset
|
135 /* pixsize に近いフォントが(あれば)帰す */ |
0 | 136 if (fontlist.find(pixsize) != fontlist.end()) return fontlist[pixsize]; |
137 for (i=1; i<4; i++) { | |
138 if (fontlist.find(pixsize-i) != fontlist.end()) return fontlist[pixsize-i]; | |
139 if (fontlist.find(pixsize+i) != fontlist.end()) return fontlist[pixsize+i]; | |
140 } | |
65
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
52
diff
changeset
|
141 /* 見つからない:fontlist[0] を加工して帰す */ |
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
52
diff
changeset
|
142 /* pt/xres/yres などのフィールドに '-0-' というのがあれば '-*-'に変換 |
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
52
diff
changeset
|
143 ** pixsize は与えられた pixsize にする |
0 | 144 */ |
145 string basefont_s = fontlist[0]; | |
146 const char* basefont = basefont_s.c_str(); | |
147 char* retfont = new char[strlen(basefont)+50]; | |
52 | 148 int minus_count = 0; |
149 int rc = 0; | |
150 bool is_skip = false; | |
0 | 151 for (i=0; basefont[i] != 0; i++) { |
152 if (basefont[i] == '-') { | |
153 minus_count++; | |
154 is_skip = false; | |
155 if (minus_count == 7) { | |
156 sprintf(retfont+rc, "-%d", pixsize); | |
157 rc = strlen(retfont); | |
158 is_skip = true; | |
159 } else if (minus_count > 7 && minus_count <= 12) { | |
160 if (basefont[i+1] == '0' && basefont[i+2] == '-') { | |
161 retfont[rc++]='-'; | |
162 retfont[rc++]='*'; | |
163 is_skip = true; | |
164 } | |
165 } | |
166 } | |
167 if (! is_skip) retfont[rc++] = basefont[i]; | |
168 } | |
169 retfont[rc] = 0; | |
170 string retfont_str = string(retfont); | |
171 delete[] retfont; | |
172 return retfont_str; | |
173 } | |
174 | |
175 FontSetInfo::FontSetInfo(Display* display, const char* fontset_orig) { | |
176 char* fontset = new char[strlen(fontset_orig)+1]; | |
177 strcpy(fontset, fontset_orig); | |
178 char* cur = fontset; | |
179 while(strchr(cur, ',')) { | |
180 char* font = cur; | |
181 cur = strchr(cur, ','); | |
182 *cur++ = '\0'; | |
183 fontlist.push_back(new FontInfo(display, font)); | |
184 } | |
185 fontlist.push_back(new FontInfo(display, cur)); | |
186 delete[] fontset; | |
187 return; | |
188 } | |
189 FontSetInfo::~FontSetInfo() { | |
190 std::vector<FontInfo*>::iterator it; | |
191 for (it=fontlist.begin(); it != fontlist.end(); it++) { | |
192 delete (*it); | |
193 } | |
194 return; | |
195 } | |
196 string FontSetInfo::Search(int pixsize) { | |
197 stringstream s; | |
198 std::vector<FontInfo*>::iterator it; | |
199 for (it=fontlist.begin(); it != fontlist.end(); it++) { | |
200 if (it != fontlist.begin()) s << ","; | |
201 s << (*it)->Search(pixsize); | |
202 } | |
52 | 203 s << ends; |
0 | 204 return string(s.str()); |
205 } | |
206 | |
207 /**************************************** | |
208 ** | |
209 ** FontPeerX11 | |
210 */ | |
52 | 211 Display* PeerX11::display = NULL; |
0 | 212 void PeerX11::InitDisplay(Display* _d) { |
213 /* d = ((GdkWindowPrivate*)(top_window.gdkobj()))->xdisplay; */ | |
214 display = _d; | |
215 } | |
216 | |
217 void PeerX11::OpenDisplay(void) { | |
52 | 218 if (display != NULL) return; |
0 | 219 |
47
5f548e5957a8
* get rid of the "deprecated conversion from string constant to ‘char*’" warnings
thib
parents:
27
diff
changeset
|
220 const char* display_name = getenv("DISPLAY"); |
52 | 221 if (display_name == NULL) display_name = ":0"; |
0 | 222 |
223 display = XOpenDisplay(display_name); | |
224 | |
52 | 225 if (display == NULL) { |
0 | 226 string err = string("XKFont::PeerX11:OpenDisplay() : Cannot open X display ") + display_name; |
227 throw std::invalid_argument(err); | |
228 } | |
229 } | |
230 | |
231 inline int MAX(int a, int b) { | |
232 if (a > b) return a; | |
233 else return b; | |
234 } | |
235 | |
236 PeerX11::PeerX11(const char* fontname, int index, int fontsize, int _vsize) : | |
237 fontset(0), gc(0), canvas(0), image(0), colortable(0) { | |
238 OpenDisplay(); | |
239 | |
240 int scr = DefaultScreen(display); | |
241 Window w = RootWindow(display, scr); | |
242 Colormap cmap = DefaultColormap(display, scr); | |
243 visual = DefaultVisual(display, scr); | |
244 | |
245 if (visual->c_class != TrueColor && visual->c_class != DirectColor) { | |
246 string err = "XKFont::PeerX11:PeerX11() : No supported Color mode of X : neither TrueColor nor DirectColor"; | |
247 throw std::runtime_error(err); | |
248 } | |
65
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
52
diff
changeset
|
249 /* 色の初期化 */ |
0 | 250 white = visual->red_mask | visual->green_mask | visual->blue_mask; |
251 black = 0; | |
252 if (visual->green_mask == 0) { | |
253 string err = "XKFont::PeerX11:PeerX11() : Invalid Visual on X"; | |
254 throw std::runtime_error(err); | |
255 } | |
256 shift = 0; | |
257 mask = visual->green_mask; | |
258 while(mask & 0x01) { shift++; mask >>= 1; } | |
259 | |
260 int tablesize = mask+1; | |
261 colortable = new int[tablesize]; | |
52 | 262 int i; |
263 for (i=0; i< tablesize; i++) { | |
0 | 264 colortable[i] = i*255/tablesize; |
265 } | |
52 | 266 |
267 XSupportsLocale(); //FIXME: er... yes? | |
0 | 268 |
65
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
52
diff
changeset
|
269 /* font 読み込み */ |
0 | 270 FontSetInfo fsinfo(display,fontname); |
271 string fontset_name = fsinfo.Search(fontsize); | |
52 | 272 char** missing_cl; |
273 int missing_cc; | |
274 char* def_s; | |
0 | 275 printf("fontset %s\n",fontset_name.c_str()); |
276 fontset = XCreateFontSet(display, fontset_name.c_str(), &missing_cl, &missing_cc, &def_s); | |
277 | |
278 if (fontset == 0) { | |
279 delete[] colortable; | |
280 string err = string("XKFont::PeerX11:PeerX11() : Cannot create fontset "); | |
281 err += fontset_name; err += " (font name "; err += fontname; err += ")"; | |
282 throw std::invalid_argument(err); | |
283 } | |
284 | |
285 if (missing_cc != 0) { | |
286 cerr << "XKFont::PeerX11:PeerX11() : Cannot found some fonts in the fontset"<<endl; | |
287 cerr << " fontset: "<<fontset_name<<endl; | |
288 cerr << " not found fonts:"<<endl; | |
289 int i; for (i=0; i<missing_cc; i++) { | |
290 cerr << " " << missing_cl[i] << endl; | |
291 } | |
292 } | |
293 | |
294 XFontSetExtents* extents = XExtentsOfFontSet(fontset); | |
295 | |
296 width = extents->max_ink_extent.width; | |
297 height = extents->max_ink_extent.height; | |
298 | |
299 /* calculate ascent / descent */ | |
300 XFontStruct** font_structs; char** font_names; | |
301 int num_fonts = XFontsOfFontSet(fontset, &font_structs, &font_names); | |
302 printf("locale %s\n",XLocaleOfOM(XOMOfOC(fontset))); | |
303 | |
304 ascent = 0; | |
305 for (i=0; i<num_fonts; i++) { | |
306 ascent = MAX(ascent, font_structs[i]->ascent); | |
307 } | |
308 | |
65
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
52
diff
changeset
|
309 /* 描画用の pixmap を作成 */ |
52 | 310 XGCValues gc_values; |
311 unsigned int gc_values_mask; | |
0 | 312 gc_values.function = GXcopy; |
313 gc_values.fill_style = FillSolid; | |
314 gc_values.arc_mode = ArcPieSlice; | |
315 gc_values.subwindow_mode = ClipByChildren; | |
316 gc_values.graphics_exposures = False; | |
317 gc_values.foreground = white; | |
318 gc_values.background = black; | |
319 gc_values_mask = GCFunction | GCFillStyle | GCArcMode | GCSubwindowMode | GCGraphicsExposures | GCForeground | GCBackground; | |
320 gc = XCreateGC(display, w, gc_values_mask, &gc_values); | |
321 | |
322 canvas = XCreatePixmap(display, w, width, height, DefaultDepth(display, scr)); | |
323 | |
65
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
52
diff
changeset
|
324 /* イメージ転送用の image の作成 */ |
0 | 325 int ignore; |
326 use_shm = false; | |
327 if (XShmQueryExtension(display) == True) { | |
328 x_shm_info.shmid = -1; | |
329 x_shm_info.shmaddr = (char*)-1; | |
330 image = XShmCreateImage(display, visual, DefaultDepth(display, scr), ZPixmap, NULL, &x_shm_info, width, height); | |
52 | 331 if (image != NULL) { |
0 | 332 x_shm_info.shmid = shmget(IPC_PRIVATE, image->bytes_per_line*image->height, IPC_CREAT | 0600); |
333 if (x_shm_info.shmid == -1) { | |
334 XDestroyImage(image); | |
52 | 335 image = NULL; |
0 | 336 goto no_shm; |
337 } | |
338 x_shm_info.readOnly = False; | |
339 x_shm_info.shmaddr = (char*) shmat(x_shm_info.shmid, 0, 0); | |
340 image->data = x_shm_info.shmaddr; | |
341 if (x_shm_info.shmaddr == (char*) -1) { | |
342 XDestroyImage(image); | |
343 shmctl(x_shm_info.shmid, IPC_RMID, 0); | |
344 image = 0; | |
345 goto no_shm; | |
346 } | |
347 XShmAttach(display, &x_shm_info); | |
348 XSync(display, False); | |
349 shmctl(x_shm_info.shmid, IPC_RMID, 0); | |
350 use_shm = true; | |
351 } | |
352 } | |
52 | 353 no_shm: //TODO: Understand why he did it, and supress it if needed |
0 | 354 if (image == 0) { |
355 use_shm = false; | |
356 image = XCreateImage(display, visual, DefaultDepth(display, scr), ZPixmap, 0, 0, width, height, 32, 0); | |
357 image->data = (char*)malloc(image->bytes_per_line * image->height); | |
52 | 358 if (image->data == NULL) { |
0 | 359 XDestroyImage(image); |
52 | 360 image = NULL; |
0 | 361 throw bad_alloc(); |
362 } | |
363 } | |
52 | 364 |
365 Glyph g; | |
366 GlyphCreate(0xa1a2, &g); //FIXME: Two calls? Huh? | |
367 GlyphCreate(0xa4a3, &g); | |
0 | 368 } |
369 | |
370 PeerX11::~PeerX11() { | |
371 if (display) { | |
372 if (fontset) XFreeFontSet(display, fontset); | |
373 if (gc) XFlushGC(display, gc); | |
374 if (canvas) XFreePixmap(display, canvas); | |
375 if (image) { | |
376 if (use_shm) XShmDetach(display, &x_shm_info); | |
377 XDestroyImage(image); | |
378 if (use_shm) shmdt(x_shm_info.shmaddr); | |
379 } | |
380 if (colortable) delete[] colortable; | |
381 } | |
382 } | |
383 | |
384 bool PeerX11::GlyphCreate(unsigned int code, Glyph* glyph) { | |
385 XRectangle ink, logic; | |
386 | |
387 char str[3]={0,0,0}; | |
388 | |
389 if ( (code>>8)&0xff){ | |
390 str[0]=code>>8; | |
391 str[1]=code & 0xff; | |
392 } else { | |
393 str[0]=code; | |
394 } | |
395 | |
396 XmbTextExtents(fontset, str, strlen(str),&ink,&logic); | |
397 int cwidth = logic.width; | |
398 XmbDrawImageString(display, canvas, fontset, gc, 0, -logic.y, str, strlen(str)); | |
399 if (use_shm) { | |
400 XShmGetImage(display, canvas, image, 0, 0, AllPlanes); | |
401 } else { | |
402 XGetSubImage(display, canvas, 0, 0, width, height, AllPlanes, ZPixmap, image, 0, 0); | |
403 } | |
404 XSync(display, False); | |
405 glyph->bitmap.buffer = new unsigned char[logic.width*logic.height]; | |
406 int i; | |
407 unsigned char* mem = (unsigned char*) image->data; | |
408 unsigned char* dest = glyph->bitmap.buffer; | |
409 int bpp = image->bytes_per_line/width; | |
410 int bpl = image->bytes_per_line; | |
52 | 411 for (i=0; i < logic.height; i++) { |
0 | 412 unsigned char* m = mem; |
413 int j; for (j=0; j<cwidth; j++) { | |
414 *dest = colortable[((read_little_endian_int((char*)m))>>shift) & mask]; | |
415 dest++; | |
416 m += bpp; | |
417 } | |
418 mem += bpl; | |
419 } | |
420 glyph->bitmap_left = logic.x; | |
421 glyph->bitmap_top = -logic.y; | |
422 glyph->bitmap.width = logic.width; | |
423 glyph->bitmap.rows = logic.height; | |
424 glyph->advance.x = logic.width + 1; | |
425 glyph->advance.y = logic.height+ 1; | |
426 | |
427 return true; | |
428 } | |
429 }; | |
430 | |
431 #endif /* USE_X11 */ |