New version of mod_xinerama
[notion/jeffpc.git] / de / font.c
blobcff767caa4a88f708afc8b2add6dcbbea123dc6b
1 /*
2 * ion/de/font.c
4 * Copyright (c) Tuomo Valkonen 1999-2009.
6 * See the included file LICENSE for details.
7 */
9 #include <string.h>
11 #include <libtu/objp.h>
12 #include <ioncore/common.h>
13 #include "font.h"
14 #include "fontset.h"
15 #include "brush.h"
16 #include "precompose.h"
19 /*{{{ UTF-8 processing */
22 #define UTF_DATA 0x3F
23 #define UTF_2_DATA 0x1F
24 #define UTF_3_DATA 0x0F
25 #define UTF_1 0x80
26 #define UTF_2 0xC0
27 #define UTF_3 0xE0
28 #define UTF_4 0xF0
29 #define UTF_5 0xF8
30 #define UTF_6 0xFC
32 static void toucs(const char *str_, int len, XChar2b **str16, int *len16)
34 int i=0;
35 const uchar *str=(const uchar*)str_;
36 wchar_t prev=0;
38 *str16=ALLOC_N(XChar2b, len);
39 *len16=0;
41 while(i<len){
42 wchar_t ch=0;
44 if((str[i] & UTF_3) == UTF_3){
45 if(i+2>=len)
46 break;
47 ch=((str[i] & UTF_3_DATA) << 12)
48 | ((str[i+1] & UTF_DATA) << 6)
49 | (str[i+2] & UTF_DATA);
50 i+=3;
51 }else if((str[i] & UTF_2) == UTF_2){
52 if(i+1>=len)
53 break;
54 ch = ((str[i] & UTF_2_DATA) << 6) | (str[i+1] & UTF_DATA);
55 i+=2;
56 }else if(str[i] < UTF_1){
57 ch = str[i];
58 i++;
59 }else{
60 ch='?';
61 i++;
64 if(*len16>0){
65 wchar_t precomp=do_precomposition(prev, ch);
66 if(precomp!=-1){
67 (*len16)--;
68 ch=precomp;
72 (*str16)[*len16].byte2=ch&0xff;
73 (*str16)[*len16].byte1=(ch>>8)&0xff;
74 (*len16)++;
75 prev=ch;
80 /*}}}*/
83 /*{{{ Load/free */
86 static DEFont *fonts=NULL;
89 static bool iso10646_font(const char *fontname)
91 const char *iso;
93 if(strchr(fontname, ',')!=NULL)
94 return FALSE; /* fontset */
96 iso=strstr(fontname, "iso10646-1");
97 return (iso!=NULL && iso[10]=='\0');
101 DEFont *de_load_font(const char *fontname)
103 DEFont *fnt;
104 XFontSet fontset=NULL;
105 XFontStruct *fontstruct=NULL;
107 assert(fontname!=NULL);
109 /* There shouldn't be that many fonts... */
110 for(fnt=fonts; fnt!=NULL; fnt=fnt->next){
111 if(strcmp(fnt->pattern, fontname)==0){
112 fnt->refcount++;
113 return fnt;
117 if(ioncore_g.use_mb && !(ioncore_g.enc_utf8 && iso10646_font(fontname))){
118 fontset=de_create_font_set(fontname);
119 if(fontset!=NULL){
120 if(XContextDependentDrawing(fontset)){
121 warn(TR("Fontset for font pattern '%s' implements context "
122 "dependent drawing, which is unsupported. Expect "
123 "clutter."), fontname);
126 }else{
127 fontstruct=XLoadQueryFont(ioncore_g.dpy, fontname);
130 if(fontstruct==NULL && fontset==NULL){
131 if(strcmp(fontname, CF_FALLBACK_FONT_NAME)!=0){
132 DEFont *fnt;
133 warn(TR("Could not load font \"%s\", trying \"%s\""),
134 fontname, CF_FALLBACK_FONT_NAME);
135 fnt=de_load_font(CF_FALLBACK_FONT_NAME);
136 if(fnt==NULL)
137 warn(TR("Failed to load fallback font."));
138 return fnt;
140 return NULL;
143 fnt=ALLOC(DEFont);
145 if(fnt==NULL)
146 return NULL;
148 fnt->fontset=fontset;
149 fnt->fontstruct=fontstruct;
150 fnt->pattern=scopy(fontname);
151 fnt->next=NULL;
152 fnt->prev=NULL;
153 fnt->refcount=1;
155 LINK_ITEM(fonts, fnt, next, prev);
157 return fnt;
161 bool de_set_font_for_style(DEStyle *style, DEFont *font)
163 if(style->font!=NULL)
164 de_free_font(style->font);
166 style->font=font;
167 font->refcount++;
169 if(style->font->fontstruct!=NULL){
170 XSetFont(ioncore_g.dpy, style->normal_gc,
171 style->font->fontstruct->fid);
174 return TRUE;
178 bool de_load_font_for_style(DEStyle *style, const char *fontname)
180 if(style->font!=NULL)
181 de_free_font(style->font);
183 style->font=de_load_font(fontname);
185 if(style->font==NULL)
186 return FALSE;
188 if(style->font->fontstruct!=NULL){
189 XSetFont(ioncore_g.dpy, style->normal_gc,
190 style->font->fontstruct->fid);
193 return TRUE;
197 void de_free_font(DEFont *font)
199 if(--font->refcount!=0)
200 return;
202 if(font->fontset!=NULL)
203 XFreeFontSet(ioncore_g.dpy, font->fontset);
204 if(font->fontstruct!=NULL)
205 XFreeFont(ioncore_g.dpy, font->fontstruct);
206 if(font->pattern!=NULL)
207 free(font->pattern);
209 UNLINK_ITEM(fonts, font, next, prev);
210 free(font);
214 /*}}}*/
217 /*{{{ Lengths */
220 void debrush_get_font_extents(DEBrush *brush, GrFontExtents *fnte)
222 if(brush->d->font==NULL){
223 DE_RESET_FONT_EXTENTS(fnte);
224 return;
227 defont_get_font_extents(brush->d->font, fnte);
231 void defont_get_font_extents(DEFont *font, GrFontExtents *fnte)
233 if(font->fontset!=NULL){
234 XFontSetExtents *ext=XExtentsOfFontSet(font->fontset);
235 if(ext==NULL)
236 goto fail;
237 fnte->max_height=ext->max_logical_extent.height;
238 fnte->max_width=ext->max_logical_extent.width;
239 fnte->baseline=-ext->max_logical_extent.y;
240 return;
241 }else if(font->fontstruct!=NULL){
242 XFontStruct *fnt=font->fontstruct;
243 fnte->max_height=fnt->ascent+fnt->descent;
244 fnte->max_width=fnt->max_bounds.width;
245 fnte->baseline=fnt->ascent;
246 return;
249 fail:
250 DE_RESET_FONT_EXTENTS(fnte);
254 uint debrush_get_text_width(DEBrush *brush, const char *text, uint len)
256 if(brush->d->font==NULL || text==NULL || len==0)
257 return 0;
259 return defont_get_text_width(brush->d->font, text, len);
263 uint defont_get_text_width(DEFont *font, const char *text, uint len)
265 if(font->fontset!=NULL){
266 XRectangle lext;
267 #ifdef CF_DE_USE_XUTF8
268 if(ioncore_g.enc_utf8)
269 Xutf8TextExtents(font->fontset, text, len, NULL, &lext);
270 else
271 #endif
272 XmbTextExtents(font->fontset, text, len, NULL, &lext);
273 return lext.width;
274 }else if(font->fontstruct!=NULL){
275 if(ioncore_g.enc_utf8){
276 XChar2b *str16; int len16=0;
277 uint res;
279 toucs(text, len, &str16, &len16);
281 res=XTextWidth16(font->fontstruct, str16, len16);
283 free(str16);
285 return res;
286 }else{
287 return XTextWidth(font->fontstruct, text, len);
289 }else{
290 return 0;
295 /*}}}*/
298 /*{{{ String drawing */
301 void debrush_do_draw_string_default(DEBrush *brush, int x, int y,
302 const char *str, int len, bool needfill,
303 DEColourGroup *colours)
305 GC gc=brush->d->normal_gc;
307 if(brush->d->font==NULL)
308 return;
310 XSetForeground(ioncore_g.dpy, gc, colours->fg);
312 if(!needfill){
313 if(brush->d->font->fontset!=NULL){
314 #ifdef CF_DE_USE_XUTF8
315 if(ioncore_g.enc_utf8)
316 Xutf8DrawString(ioncore_g.dpy, brush->win,
317 brush->d->font->fontset,
318 gc, x, y, str, len);
319 else
320 #endif
321 XmbDrawString(ioncore_g.dpy, brush->win,
322 brush->d->font->fontset,
323 gc, x, y, str, len);
324 }else if(brush->d->font->fontstruct!=NULL){
325 if(ioncore_g.enc_utf8){
326 XChar2b *str16; int len16=0;
327 toucs(str, len, &str16, &len16);
328 XDrawString16(ioncore_g.dpy, brush->win, gc, x, y, str16, len16);
329 free(str16);
330 }else{
331 XDrawString(ioncore_g.dpy, brush->win, gc, x, y, str, len);
334 }else{
335 XSetBackground(ioncore_g.dpy, gc, colours->bg);
336 if(brush->d->font->fontset!=NULL){
337 #ifdef CF_DE_USE_XUTF8
338 if(ioncore_g.enc_utf8)
339 Xutf8DrawImageString(ioncore_g.dpy, brush->win,
340 brush->d->font->fontset,
341 gc, x, y, str, len);
342 else
343 #endif
344 XmbDrawImageString(ioncore_g.dpy, brush->win,
345 brush->d->font->fontset,
346 gc, x, y, str, len);
347 }else if(brush->d->font->fontstruct!=NULL){
348 if(ioncore_g.enc_utf8){
349 XChar2b *str16; int len16=0;
350 toucs(str, len, &str16, &len16);
351 XDrawImageString16(ioncore_g.dpy, brush->win, gc, x, y, str16, len16);
352 free(str16);
353 }else{
354 XDrawImageString(ioncore_g.dpy, brush->win, gc, x, y, str, len);
361 void debrush_do_draw_string(DEBrush *brush, int x, int y,
362 const char *str, int len, bool needfill,
363 DEColourGroup *colours)
365 CALL_DYN(debrush_do_draw_string, brush, (brush, x, y, str, len,
366 needfill, colours));
370 void debrush_draw_string(DEBrush *brush, int x, int y,
371 const char *str, int len, bool needfill)
373 DEColourGroup *cg=debrush_get_current_colour_group(brush);
374 if(cg!=NULL)
375 debrush_do_draw_string(brush, x, y, str, len, needfill, cg);
379 /*}}}*/