0
|
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 */
|