comparison font/font_peer_x11.cc @ 0:223b71206888

Initial import
author thib
date Fri, 01 Aug 2008 16:32:45 +0000
parents
children 3a6aaeab7b4e
comparison
equal deleted inserted replaced
-1:000000000000 0:223b71206888
1 /*
2 * Copyright (c) 2004 Kazunor "jagarl" Ueno
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>
43 #include<iostream>
44
45 #include<vector>
46 #include<map>
47 //#include<iostream>
48 #include<sstream>
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 **
64 ** fontset から特定 pixel size を持つ
65 ** 別のfontsetを作成するためのクラス
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) {
86 /* フォントの大きさ関係の情報を消去 */
87 int i;
88 char* fontname = new char[strlen(fontname_orig)+50];
89 int minus_count = 0; bool is_skip = false; int fc = 0;
90 for (i=0; fontname_orig[i]!=0; i++) {
91 if (fontname_orig[i] == '-') {
92 minus_count++;
93 if (minus_count >= 7 && minus_count <= 12) {
94 fontname[fc++] = '-';
95 fontname[fc++] = '*';
96 is_skip = true;
97 } else {
98 is_skip = false;
99 }
100 }
101 if (! is_skip) fontname[fc++] = fontname_orig[i];
102 }
103 /* フォント情報を得る */
104 fontname[fc] = 0;
105 int count;
106 char** fontnamelist = XListFonts(display, fontname, 100, &count);
107 for (i=0; i<count; i++) {
108 char* curfont = fontnamelist[i];
109 /* fontname から pixel size 情報を得る */
110 int j; int minus_count = 0;
111 for (j=0; curfont[j] != 0; j++) {
112 if (curfont[j] == '-') minus_count++;
113 if (minus_count == 7) {
114 int pixsize = atoi(curfont+j+1);
115 if (fontlist.find(pixsize) == fontlist.end()) {
116 fontlist[pixsize] = string(curfont);
117 }
118 break;
119 }
120 }
121 }
122 /* 検索に失敗した場合、とりあえず fontname を入れておく */
123 if (fontlist.find(0) == fontlist.end()) {
124 fontlist[0] = string(fontname);
125 }
126 XFreeFontNames(fontnamelist);
127 delete[] fontname;
128 return;
129 }
130 string FontInfo::Search(int pixsize) {
131 int i;
132 /* pixsize に近いフォントが(あれば)帰す */
133 if (fontlist.find(pixsize) != fontlist.end()) return fontlist[pixsize];
134 for (i=1; i<4; i++) {
135 if (fontlist.find(pixsize-i) != fontlist.end()) return fontlist[pixsize-i];
136 if (fontlist.find(pixsize+i) != fontlist.end()) return fontlist[pixsize+i];
137 }
138 /* 見つからない:fontlist[0] を加工して帰す */
139 /* pt/xres/yres などのフィールドに '-0-' というのがあれば '-*-'に変換
140 ** pixsize は与えられた pixsize にする
141 */
142 string basefont_s = fontlist[0];
143 const char* basefont = basefont_s.c_str();
144 char* retfont = new char[strlen(basefont)+50];
145 int minus_count = 0; int rc = 0; bool is_skip = false;
146 for (i=0; basefont[i] != 0; i++) {
147 if (basefont[i] == '-') {
148 minus_count++;
149 is_skip = false;
150 if (minus_count == 7) {
151 sprintf(retfont+rc, "-%d", pixsize);
152 rc = strlen(retfont);
153 is_skip = true;
154 } else if (minus_count > 7 && minus_count <= 12) {
155 if (basefont[i+1] == '0' && basefont[i+2] == '-') {
156 retfont[rc++]='-';
157 retfont[rc++]='*';
158 is_skip = true;
159 }
160 }
161 }
162 if (! is_skip) retfont[rc++] = basefont[i];
163 }
164 retfont[rc] = 0;
165 string retfont_str = string(retfont);
166 delete[] retfont;
167 return retfont_str;
168 }
169
170 FontSetInfo::FontSetInfo(Display* display, const char* fontset_orig) {
171 char* fontset = new char[strlen(fontset_orig)+1];
172 strcpy(fontset, fontset_orig);
173 char* cur = fontset;
174 while(strchr(cur, ',')) {
175 char* font = cur;
176 cur = strchr(cur, ',');
177 *cur++ = '\0';
178 fontlist.push_back(new FontInfo(display, font));
179 }
180 fontlist.push_back(new FontInfo(display, cur));
181 delete[] fontset;
182 return;
183 }
184 FontSetInfo::~FontSetInfo() {
185 std::vector<FontInfo*>::iterator it;
186 for (it=fontlist.begin(); it != fontlist.end(); it++) {
187 delete (*it);
188 }
189 return;
190 }
191 string FontSetInfo::Search(int pixsize) {
192 stringstream s;
193 std::vector<FontInfo*>::iterator it;
194 for (it=fontlist.begin(); it != fontlist.end(); it++) {
195 if (it != fontlist.begin()) s << ",";
196 s << (*it)->Search(pixsize);
197 }
198 s<<ends;
199 return string(s.str());
200 }
201
202 /****************************************
203 **
204 ** FontPeerX11
205 */
206 Display* PeerX11::display = 0;
207 void PeerX11::InitDisplay(Display* _d) {
208 /* d = ((GdkWindowPrivate*)(top_window.gdkobj()))->xdisplay; */
209 display = _d;
210 }
211
212 void PeerX11::OpenDisplay(void) {
213 if (display) return;
214
215 char* display_name = getenv("DISPLAY");
216 if (display_name == 0) display_name = ":0";
217
218 display = XOpenDisplay(display_name);
219
220 if (display == 0) {
221 string err = string("XKFont::PeerX11:OpenDisplay() : Cannot open X display ") + display_name;
222 throw std::invalid_argument(err);
223 }
224 }
225
226 inline int MAX(int a, int b) {
227 if (a > b) return a;
228 else return b;
229 }
230
231 PeerX11::PeerX11(const char* fontname, int index, int fontsize, int _vsize) :
232 fontset(0), gc(0), canvas(0), image(0), colortable(0) {
233 OpenDisplay();
234
235 int scr = DefaultScreen(display);
236 Window w = RootWindow(display, scr);
237 Colormap cmap = DefaultColormap(display, scr);
238 visual = DefaultVisual(display, scr);
239
240 if (visual->c_class != TrueColor && visual->c_class != DirectColor) {
241 string err = "XKFont::PeerX11:PeerX11() : No supported Color mode of X : neither TrueColor nor DirectColor";
242 throw std::runtime_error(err);
243 }
244 /* 色の初期化 */
245 white = visual->red_mask | visual->green_mask | visual->blue_mask;
246 black = 0;
247 if (visual->green_mask == 0) {
248 string err = "XKFont::PeerX11:PeerX11() : Invalid Visual on X";
249 throw std::runtime_error(err);
250 }
251 shift = 0;
252 mask = visual->green_mask;
253 while(mask & 0x01) { shift++; mask >>= 1; }
254
255 int tablesize = mask+1;
256 colortable = new int[tablesize];
257 int i; for (i=0; i< tablesize; i++) {
258 colortable[i] = i*255/tablesize;
259 }
260 XSupportsLocale();
261
262 /* font 読み込み */
263 FontSetInfo fsinfo(display,fontname);
264 string fontset_name = fsinfo.Search(fontsize);
265 char** missing_cl; int missing_cc; char* def_s;
266 printf("fontset %s\n",fontset_name.c_str());
267 fontset = XCreateFontSet(display, fontset_name.c_str(), &missing_cl, &missing_cc, &def_s);
268
269 if (fontset == 0) {
270 delete[] colortable;
271 string err = string("XKFont::PeerX11:PeerX11() : Cannot create fontset ");
272 err += fontset_name; err += " (font name "; err += fontname; err += ")";
273 throw std::invalid_argument(err);
274 }
275
276 if (missing_cc != 0) {
277 cerr << "XKFont::PeerX11:PeerX11() : Cannot found some fonts in the fontset"<<endl;
278 cerr << " fontset: "<<fontset_name<<endl;
279 cerr << " not found fonts:"<<endl;
280 int i; for (i=0; i<missing_cc; i++) {
281 cerr << " " << missing_cl[i] << endl;
282 }
283 }
284
285 XFontSetExtents* extents = XExtentsOfFontSet(fontset);
286
287 width = extents->max_ink_extent.width;
288 height = extents->max_ink_extent.height;
289
290 /* calculate ascent / descent */
291 XFontStruct** font_structs; char** font_names;
292 int num_fonts = XFontsOfFontSet(fontset, &font_structs, &font_names);
293 printf("locale %s\n",XLocaleOfOM(XOMOfOC(fontset)));
294
295 ascent = 0;
296 for (i=0; i<num_fonts; i++) {
297 ascent = MAX(ascent, font_structs[i]->ascent);
298 }
299
300 /* 描画用の pixmap を作成 */
301 XGCValues gc_values; unsigned int gc_values_mask;
302 gc_values.function = GXcopy;
303 gc_values.fill_style = FillSolid;
304 gc_values.arc_mode = ArcPieSlice;
305 gc_values.subwindow_mode = ClipByChildren;
306 gc_values.graphics_exposures = False;
307 gc_values.foreground = white;
308 gc_values.background = black;
309 gc_values_mask = GCFunction | GCFillStyle | GCArcMode | GCSubwindowMode | GCGraphicsExposures | GCForeground | GCBackground;
310 gc = XCreateGC(display, w, gc_values_mask, &gc_values);
311
312 canvas = XCreatePixmap(display, w, width, height, DefaultDepth(display, scr));
313
314 /* イメージ転送用の image の作成 */
315 int ignore;
316 use_shm = false;
317 if (XShmQueryExtension(display) == True) {
318 x_shm_info.shmid = -1;
319 x_shm_info.shmaddr = (char*)-1;
320 image = XShmCreateImage(display, visual, DefaultDepth(display, scr), ZPixmap, NULL, &x_shm_info, width, height);
321 if (image) {
322 x_shm_info.shmid = shmget(IPC_PRIVATE, image->bytes_per_line*image->height, IPC_CREAT | 0600);
323 if (x_shm_info.shmid == -1) {
324 XDestroyImage(image);
325 image = 0;
326 goto no_shm;
327 }
328 x_shm_info.readOnly = False;
329 x_shm_info.shmaddr = (char*) shmat(x_shm_info.shmid, 0, 0);
330 image->data = x_shm_info.shmaddr;
331 if (x_shm_info.shmaddr == (char*) -1) {
332 XDestroyImage(image);
333 shmctl(x_shm_info.shmid, IPC_RMID, 0);
334 image = 0;
335 goto no_shm;
336 }
337 XShmAttach(display, &x_shm_info);
338 XSync(display, False);
339 shmctl(x_shm_info.shmid, IPC_RMID, 0);
340 use_shm = true;
341 }
342 }
343 no_shm:
344 if (image == 0) {
345 use_shm = false;
346 image = XCreateImage(display, visual, DefaultDepth(display, scr), ZPixmap, 0, 0, width, height, 32, 0);
347 image->data = (char*)malloc(image->bytes_per_line * image->height);
348 if (image->data == 0) {
349 XDestroyImage(image);
350 image = 0;
351 throw bad_alloc();
352 }
353 }
354 Glyph g;
355 GlyphCreate(0xa1a2,&g);
356 GlyphCreate(0xa4a3,&g);
357 }
358
359 PeerX11::~PeerX11() {
360 if (display) {
361 if (fontset) XFreeFontSet(display, fontset);
362 if (gc) XFlushGC(display, gc);
363 if (canvas) XFreePixmap(display, canvas);
364 if (image) {
365 if (use_shm) XShmDetach(display, &x_shm_info);
366 XDestroyImage(image);
367 if (use_shm) shmdt(x_shm_info.shmaddr);
368 }
369 if (colortable) delete[] colortable;
370 }
371 }
372
373 bool PeerX11::GlyphCreate(unsigned int code, Glyph* glyph) {
374 XRectangle ink, logic;
375
376 char str[3]={0,0,0};
377
378 if ( (code>>8)&0xff){
379 str[0]=code>>8;
380 str[1]=code & 0xff;
381 } else {
382 str[0]=code;
383 }
384
385 XmbTextExtents(fontset, str, strlen(str),&ink,&logic);
386 int cwidth = logic.width;
387 XmbDrawImageString(display, canvas, fontset, gc, 0, -logic.y, str, strlen(str));
388 if (use_shm) {
389 XShmGetImage(display, canvas, image, 0, 0, AllPlanes);
390 } else {
391 XGetSubImage(display, canvas, 0, 0, width, height, AllPlanes, ZPixmap, image, 0, 0);
392 }
393 XSync(display, False);
394 glyph->bitmap.buffer = new unsigned char[logic.width*logic.height];
395 int i;
396 unsigned char* mem = (unsigned char*) image->data;
397 unsigned char* dest = glyph->bitmap.buffer;
398 int bpp = image->bytes_per_line/width;
399 int bpl = image->bytes_per_line;
400 for (i=0; i<logic.height; i++) {
401 unsigned char* m = mem;
402 int j; for (j=0; j<cwidth; j++) {
403 *dest = colortable[((read_little_endian_int((char*)m))>>shift) & mask];
404 dest++;
405 m += bpp;
406 }
407 mem += bpl;
408 }
409 glyph->bitmap_left = logic.x;
410 glyph->bitmap_top = -logic.y;
411 glyph->bitmap.width = logic.width;
412 glyph->bitmap.rows = logic.height;
413 glyph->advance.x = logic.width + 1;
414 glyph->advance.y = logic.height+ 1;
415
416 return true;
417 }
418 };
419
420 #endif /* USE_X11 */