root/font/font_peer_x11.cc

Revision 65:4416cfac86ae, 12.4 KB (checked in by Thibaut Girka <thib@…>, 18 months ago)
Convert EUC-JP files to UTF8
Line 
1/*
2 * Copyright (c) 2004  Kazunori "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
48#include <sstream>
49#include <string>
50#include <stdexcept>
51
52using namespace std;
53
54namespace XKFont {
55inline 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*/
67struct FontInfo {
68        std::map<int, string> fontlist;
69        FontInfo(Display* display, const char* fontname_orig);
70        string Search(int pixsize);
71};
72struct 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*/
85FontInfo::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;
90        bool is_skip = false;
91        int fc = 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        }
105        /* フォント情報を埗る */
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];
111                /* fontname から pixel size 情報を埗る */
112                int j;
113                int minus_count = 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        }
125        /* 怜玢に倱敗した堎合、ずりあえず fontname を入れおおく */
126        if (fontlist.find(0) == fontlist.end()) {
127                fontlist[0] = string(fontname);
128        }
129        XFreeFontNames(fontnamelist);
130        delete[] fontname;
131        return;
132}
133string FontInfo::Search(int pixsize) {
134        int i;
135        /* pixsize に近いフォントが(あれば)垰す */
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        }
141        /* 芋぀からないfontlist[0] を加工しお垰す */
142        /* pt/xres/yres などのフィヌルドに '-0-' ずいうのがあれば '-*-'に倉換
143        ** pixsize は䞎えられた pixsize にする
144        */
145        string basefont_s = fontlist[0];
146        const char* basefont = basefont_s.c_str();
147        char* retfont = new char[strlen(basefont)+50];
148        int minus_count = 0;
149        int rc = 0;
150        bool is_skip = false;
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
175FontSetInfo::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}
189FontSetInfo::~FontSetInfo() {
190        std::vector<FontInfo*>::iterator it;
191        for (it=fontlist.begin(); it != fontlist.end(); it++) {
192                delete (*it);
193        }
194        return;
195}
196string 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        }
203        s << ends;
204        return string(s.str());
205}
206
207/****************************************
208**
209** FontPeerX11
210*/
211Display* PeerX11::display = NULL;
212void PeerX11::InitDisplay(Display* _d) {
213        /* d = ((GdkWindowPrivate*)(top_window.gdkobj()))->xdisplay; */
214        display = _d;
215}
216
217void PeerX11::OpenDisplay(void) {
218        if (display != NULL) return;
219
220        const char* display_name = getenv("DISPLAY");
221        if (display_name == NULL) display_name = ":0";
222
223        display = XOpenDisplay(display_name);
224
225        if (display == NULL) {
226                string err = string("XKFont::PeerX11:OpenDisplay() : Cannot open X display ") + display_name;
227                throw std::invalid_argument(err);
228        }
229}
230
231inline int MAX(int a, int b) {
232        if (a > b) return a;
233        else return b;
234}
235
236PeerX11::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        }
249        /* 色の初期化 */
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];
262        int i;
263        for (i=0; i< tablesize; i++) {
264                colortable[i] = i*255/tablesize;
265        }
266
267        XSupportsLocale(); //FIXME: er... yes?
268
269        /* font 読み蟌み */
270        FontSetInfo fsinfo(display,fontname);
271        string fontset_name = fsinfo.Search(fontsize);
272        char** missing_cl;
273        int missing_cc;
274        char* def_s;
275printf("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);
302printf("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       
309        /* 描画甚の pixmap を䜜成 */
310        XGCValues gc_values;
311        unsigned int gc_values_mask;
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
324        /* むメヌゞ転送甚の image の䜜成 */
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);
331                if (image != NULL) {
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);
335                                image = NULL;
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        }
353no_shm: //TODO: Understand why he did it, and supress it if needed
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);
358                if (image->data == NULL) {
359                        XDestroyImage(image);
360                        image = NULL;
361                        throw bad_alloc();
362                }
363        }
364
365        Glyph g;
366        GlyphCreate(0xa1a2, &g); //FIXME: Two calls? Huh?
367        GlyphCreate(0xa4a3, &g);
368}
369
370PeerX11::~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
384bool 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;
411        for (i=0; i < logic.height; i++) {
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 */
Note: See TracBrowser for help on using the browser.