Log startup
[notion/jeffpc.git] / de / font.c
blob4812f46bc04ca0da64c498bdab14d212fea7a4c3
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 <ioncore/log.h>
14 #include "font.h"
15 #include "fontset.h"
16 #include "brush.h"
17 #include "precompose.h"
20 /*{{{ UTF-8 processing */
23 #define UTF_DATA 0x3F
24 #define UTF_2_DATA 0x1F
25 #define UTF_3_DATA 0x0F
26 #define UTF_1 0x80
27 #define UTF_2 0xC0
28 #define UTF_3 0xE0
29 #define UTF_4 0xF0
30 #define UTF_5 0xF8
31 #define UTF_6 0xFC
33 static void toucs(const char *str_, int len, XChar2b **str16, int *len16)
35 int i=0;
36 const uchar *str=(const uchar*)str_;
37 wchar_t prev=0;
39 *str16=ALLOC_N(XChar2b, len);
40 *len16=0;
42 while(i<len){
43 wchar_t ch=0;
45 if((str[i] & UTF_3) == UTF_3){
46 if(i+2>=len)
47 break;
48 ch=((str[i] & UTF_3_DATA) << 12)
49 | ((str[i+1] & UTF_DATA) << 6)
50 | (str[i+2] & UTF_DATA);
51 i+=3;
52 }else if((str[i] & UTF_2) == UTF_2){
53 if(i+1>=len)
54 break;
55 ch = ((str[i] & UTF_2_DATA) << 6) | (str[i+1] & UTF_DATA);
56 i+=2;
57 }else if(str[i] < UTF_1){
58 ch = str[i];
59 i++;
60 }else{
61 ch='?';
62 i++;
65 if(*len16>0){
66 wchar_t precomp=do_precomposition(prev, ch);
67 if(precomp!=-1){
68 (*len16)--;
69 ch=precomp;
73 (*str16)[*len16].byte2=ch&0xff;
74 (*str16)[*len16].byte1=(ch>>8)&0xff;
75 (*len16)++;
76 prev=ch;
81 /*}}}*/
84 /*{{{ Load/free */
87 static DEFont *fonts=NULL;
90 static bool iso10646_font(const char *fontname)
92 const char *iso;
94 if(strchr(fontname, ',')!=NULL)
95 return FALSE; /* fontset */
97 iso=strstr(fontname, "iso10646-1");
98 return (iso!=NULL && iso[10]=='\0');
102 DEFont *de_load_font(const char *fontname)
104 DEFont *fnt;
105 XFontSet fontset=NULL;
106 XFontStruct *fontstruct=NULL;
108 assert(fontname!=NULL);
110 /* There shouldn't be that many fonts... */
111 for(fnt=fonts; fnt!=NULL; fnt=fnt->next){
112 if(strcmp(fnt->pattern, fontname)==0){
113 fnt->refcount++;
114 return fnt;
118 if(ioncore_g.use_mb && !(ioncore_g.enc_utf8 && iso10646_font(fontname))){
119 LOG(DEBUG, FONT, "Loading fontset %s", fontname);
120 fontset=de_create_font_set(fontname);
121 if(fontset!=NULL){
122 if(XContextDependentDrawing(fontset)){
123 warn(TR("Fontset for font pattern '%s' implements context "
124 "dependent drawing, which is unsupported. Expect "
125 "clutter."), fontname);
128 }else{
129 LOG(DEBUG, FONT, "Loading fontstruct %s", fontname);
130 fontstruct=XLoadQueryFont(ioncore_g.dpy, fontname);
133 if(fontstruct==NULL && fontset==NULL){
134 if(strcmp(fontname, CF_FALLBACK_FONT_NAME)!=0){
135 DEFont *fnt;
136 LOG(WARN, FONT, TR("Could not load font \"%s\", trying \"%s\""),
137 fontname, CF_FALLBACK_FONT_NAME);
138 fnt=de_load_font(CF_FALLBACK_FONT_NAME);
139 if(fnt==NULL)
140 LOG(WARN, FONT, TR("Failed to load fallback font."));
141 return fnt;
143 return NULL;
146 fnt=ALLOC(DEFont);
148 if(fnt==NULL)
149 return NULL;
151 fnt->fontset=fontset;
152 fnt->fontstruct=fontstruct;
153 fnt->pattern=scopy(fontname);
154 fnt->next=NULL;
155 fnt->prev=NULL;
156 fnt->refcount=1;
158 LINK_ITEM(fonts, fnt, next, prev);
160 return fnt;
164 bool de_set_font_for_style(DEStyle *style, DEFont *font)
166 if(style->font!=NULL)
167 de_free_font(style->font);
169 style->font=font;
170 font->refcount++;
172 if(style->font->fontstruct!=NULL){
173 XSetFont(ioncore_g.dpy, style->normal_gc,
174 style->font->fontstruct->fid);
177 return TRUE;
181 bool de_load_font_for_style(DEStyle *style, const char *fontname)
183 if(style->font!=NULL)
184 de_free_font(style->font);
186 style->font=de_load_font(fontname);
188 if(style->font==NULL)
189 return FALSE;
191 if(style->font->fontstruct!=NULL){
192 XSetFont(ioncore_g.dpy, style->normal_gc,
193 style->font->fontstruct->fid);
196 return TRUE;
200 void de_free_font(DEFont *font)
202 if(--font->refcount!=0)
203 return;
205 if(font->fontset!=NULL)
206 XFreeFontSet(ioncore_g.dpy, font->fontset);
207 if(font->fontstruct!=NULL)
208 XFreeFont(ioncore_g.dpy, font->fontstruct);
209 if(font->pattern!=NULL)
210 free(font->pattern);
212 UNLINK_ITEM(fonts, font, next, prev);
213 free(font);
217 /*}}}*/
220 /*{{{ Lengths */
223 void debrush_get_font_extents(DEBrush *brush, GrFontExtents *fnte)
225 if(brush->d->font==NULL){
226 DE_RESET_FONT_EXTENTS(fnte);
227 return;
230 defont_get_font_extents(brush->d->font, fnte);
234 void defont_get_font_extents(DEFont *font, GrFontExtents *fnte)
236 if(font->fontset!=NULL){
237 XFontSetExtents *ext=XExtentsOfFontSet(font->fontset);
238 if(ext==NULL)
239 goto fail;
240 fnte->max_height=ext->max_logical_extent.height;
241 fnte->max_width=ext->max_logical_extent.width;
242 fnte->baseline=-ext->max_logical_extent.y;
243 return;
244 }else if(font->fontstruct!=NULL){
245 XFontStruct *fnt=font->fontstruct;
246 fnte->max_height=fnt->ascent+fnt->descent;
247 fnte->max_width=fnt->max_bounds.width;
248 fnte->baseline=fnt->ascent;
249 return;
252 fail:
253 DE_RESET_FONT_EXTENTS(fnte);
257 uint debrush_get_text_width(DEBrush *brush, const char *text, uint len)
259 if(brush->d->font==NULL || text==NULL || len==0)
260 return 0;
262 return defont_get_text_width(brush->d->font, text, len);
266 uint defont_get_text_width(DEFont *font, const char *text, uint len)
268 if(font->fontset!=NULL){
269 XRectangle lext;
270 #ifdef CF_DE_USE_XUTF8
271 if(ioncore_g.enc_utf8)
272 Xutf8TextExtents(font->fontset, text, len, NULL, &lext);
273 else
274 #endif
275 XmbTextExtents(font->fontset, text, len, NULL, &lext);
276 return lext.width;
277 }else if(font->fontstruct!=NULL){
278 if(ioncore_g.enc_utf8){
279 XChar2b *str16; int len16=0;
280 uint res;
282 toucs(text, len, &str16, &len16);
284 res=XTextWidth16(font->fontstruct, str16, len16);
286 free(str16);
288 return res;
289 }else{
290 return XTextWidth(font->fontstruct, text, len);
292 }else{
293 return 0;
298 /*}}}*/
301 /*{{{ String drawing */
304 void debrush_do_draw_string_default(DEBrush *brush, int x, int y,
305 const char *str, int len, bool needfill,
306 DEColourGroup *colours)
308 GC gc=brush->d->normal_gc;
310 if(brush->d->font==NULL)
311 return;
313 XSetForeground(ioncore_g.dpy, gc, colours->fg);
315 if(!needfill){
316 if(brush->d->font->fontset!=NULL){
317 #ifdef CF_DE_USE_XUTF8
318 if(ioncore_g.enc_utf8)
319 Xutf8DrawString(ioncore_g.dpy, brush->win,
320 brush->d->font->fontset,
321 gc, x, y, str, len);
322 else
323 #endif
324 XmbDrawString(ioncore_g.dpy, brush->win,
325 brush->d->font->fontset,
326 gc, x, y, str, len);
327 }else if(brush->d->font->fontstruct!=NULL){
328 if(ioncore_g.enc_utf8){
329 XChar2b *str16; int len16=0;
330 toucs(str, len, &str16, &len16);
331 XDrawString16(ioncore_g.dpy, brush->win, gc, x, y, str16, len16);
332 free(str16);
333 }else{
334 XDrawString(ioncore_g.dpy, brush->win, gc, x, y, str, len);
337 }else{
338 XSetBackground(ioncore_g.dpy, gc, colours->bg);
339 if(brush->d->font->fontset!=NULL){
340 #ifdef CF_DE_USE_XUTF8
341 if(ioncore_g.enc_utf8)
342 Xutf8DrawImageString(ioncore_g.dpy, brush->win,
343 brush->d->font->fontset,
344 gc, x, y, str, len);
345 else
346 #endif
347 XmbDrawImageString(ioncore_g.dpy, brush->win,
348 brush->d->font->fontset,
349 gc, x, y, str, len);
350 }else if(brush->d->font->fontstruct!=NULL){
351 if(ioncore_g.enc_utf8){
352 XChar2b *str16; int len16=0;
353 toucs(str, len, &str16, &len16);
354 XDrawImageString16(ioncore_g.dpy, brush->win, gc, x, y, str16, len16);
355 free(str16);
356 }else{
357 XDrawImageString(ioncore_g.dpy, brush->win, gc, x, y, str, len);
364 void debrush_do_draw_string(DEBrush *brush, int x, int y,
365 const char *str, int len, bool needfill,
366 DEColourGroup *colours)
368 CALL_DYN(debrush_do_draw_string, brush, (brush, x, y, str, len,
369 needfill, colours));
373 void debrush_draw_string(DEBrush *brush, int x, int y,
374 const char *str, int len, bool needfill)
376 DEColourGroup *cg=debrush_get_current_colour_group(brush);
377 if(cg!=NULL)
378 debrush_do_draw_string(brush, x, y, str, len, needfill, cg);
382 /*}}}*/