More cleanups of dead code
[notion.git] / de / font.c
blob3518aa384b79e37876768c2f1346dc5f59988a88
1 /*
2 * notion/de/font.c
4 * Copyright (c) the Notion team 2013.
5 * Copyright (c) Tuomo Valkonen 1999-2009.
7 * See the included file LICENSE for details.
8 */
10 #include <string.h>
12 #include <libtu/objp.h>
13 #include <ioncore/common.h>
14 #include <ioncore/log.h>
15 #include "font.h"
16 #include "fontset.h"
17 #include "brush.h"
18 #include "precompose.h"
21 /*{{{ UTF-8 processing */
24 #define UTF_DATA 0x3F
25 #define UTF_2_DATA 0x1F
26 #define UTF_3_DATA 0x0F
27 #define UTF_1 0x80
28 #define UTF_2 0xC0
29 #define UTF_3 0xE0
31 static void toucs(const char *str_, int len, XChar2b **str16, int *len16)
33 int i=0;
34 const uchar *str=(const uchar*)str_;
35 wchar_t prev=0;
37 *str16=ALLOC_N(XChar2b, len);
38 *len16=0;
40 while(i<len){
41 wchar_t ch=0;
43 if((str[i] & UTF_3) == UTF_3){
44 if(i+2>=len)
45 break;
46 ch=((str[i] & UTF_3_DATA) << 12)
47 | ((str[i+1] & UTF_DATA) << 6)
48 | (str[i+2] & UTF_DATA);
49 i+=3;
50 }else if((str[i] & UTF_2) == UTF_2){
51 if(i+1>=len)
52 break;
53 ch = ((str[i] & UTF_2_DATA) << 6) | (str[i+1] & UTF_DATA);
54 i+=2;
55 }else if(str[i] < UTF_1){
56 ch = str[i];
57 i++;
58 }else{
59 ch='?';
60 i++;
63 if(*len16>0){
64 wchar_t precomp=do_precomposition(prev, ch);
65 if(precomp!=-1){
66 (*len16)--;
67 ch=precomp;
71 (*str16)[*len16].byte2=ch&0xff;
72 (*str16)[*len16].byte1=(ch>>8)&0xff;
73 (*len16)++;
74 prev=ch;
79 /*}}}*/
82 /*{{{ Load/free */
85 static DEFont *fonts=NULL;
88 static bool iso10646_font(const char *fontname)
90 const char *iso;
92 if(strchr(fontname, ',')!=NULL)
93 return FALSE; /* fontset */
95 iso=strstr(fontname, "iso10646-1");
96 return (iso!=NULL && iso[10]=='\0');
99 const char *de_default_fontname()
101 if(ioncore_g.use_mb)
102 return "-*-helvetica-medium-r-normal-*-12-*-*-*-*-*-*-*";
103 else
104 return "fixed";
107 DEFont *de_load_font(const char *fontname)
109 DEFont *fnt;
110 XFontSet fontset=NULL;
111 XFontStruct *fontstruct=NULL;
112 const char *default_fontname=de_default_fontname();
114 assert(fontname!=NULL);
116 /* There shouldn't be that many fonts... */
117 for(fnt=fonts; fnt!=NULL; fnt=fnt->next){
118 if(strcmp(fnt->pattern, fontname)==0){
119 fnt->refcount++;
120 return fnt;
124 if(ioncore_g.use_mb && !(ioncore_g.enc_utf8 && iso10646_font(fontname))){
125 LOG(DEBUG, FONT, "Loading fontset %s", fontname);
126 fontset=de_create_font_set(fontname);
127 if(fontset!=NULL){
128 if(XContextDependentDrawing(fontset)){
129 warn(TR("Fontset for font pattern '%s' implements context "
130 "dependent drawing, which is unsupported. Expect "
131 "clutter."), fontname);
134 }else{
135 LOG(DEBUG, FONT, "Loading fontstruct %s", fontname);
136 fontstruct=XLoadQueryFont(ioncore_g.dpy, fontname);
139 if(fontstruct==NULL && fontset==NULL){
140 if(strcmp(fontname, default_fontname)!=0){
141 DEFont *fnt;
142 LOG(WARN, FONT, TR("Could not load font \"%s\", trying \"%s\""),
143 fontname, default_fontname);
144 fnt=de_load_font(default_fontname);
145 if(fnt==NULL)
146 LOG(WARN, FONT, TR("Failed to load fallback font."));
147 return fnt;
149 return NULL;
152 fnt=ALLOC(DEFont);
154 if(fnt==NULL)
155 return NULL;
157 fnt->fontset=fontset;
158 fnt->fontstruct=fontstruct;
159 fnt->pattern=scopy(fontname);
160 fnt->next=NULL;
161 fnt->prev=NULL;
162 fnt->refcount=1;
164 LINK_ITEM(fonts, fnt, next, prev);
166 return fnt;
170 bool de_set_font_for_style(DEStyle *style, DEFont *font)
172 if(style->font!=NULL)
173 de_free_font(style->font);
175 style->font=font;
176 font->refcount++;
178 if(style->font->fontstruct!=NULL){
179 XSetFont(ioncore_g.dpy, style->normal_gc,
180 style->font->fontstruct->fid);
183 return TRUE;
187 bool de_load_font_for_style(DEStyle *style, const char *fontname)
189 if(style->font!=NULL)
190 de_free_font(style->font);
192 style->font=de_load_font(fontname);
194 if(style->font==NULL)
195 return FALSE;
197 if(style->font->fontstruct!=NULL){
198 XSetFont(ioncore_g.dpy, style->normal_gc,
199 style->font->fontstruct->fid);
202 return TRUE;
206 void de_free_font(DEFont *font)
208 if(--font->refcount!=0)
209 return;
211 if(font->fontset!=NULL)
212 XFreeFontSet(ioncore_g.dpy, font->fontset);
213 if(font->fontstruct!=NULL)
214 XFreeFont(ioncore_g.dpy, font->fontstruct);
215 if(font->pattern!=NULL)
216 free(font->pattern);
218 UNLINK_ITEM(fonts, font, next, prev);
219 free(font);
223 /*}}}*/
226 /*{{{ Lengths */
229 void debrush_get_font_extents(DEBrush *brush, GrFontExtents *fnte)
231 if(brush->d->font==NULL){
232 DE_RESET_FONT_EXTENTS(fnte);
233 return;
236 defont_get_font_extents(brush->d->font, fnte);
240 void defont_get_font_extents(DEFont *font, GrFontExtents *fnte)
242 if(font->fontset!=NULL){
243 XFontSetExtents *ext=XExtentsOfFontSet(font->fontset);
244 if(ext==NULL)
245 goto fail;
246 fnte->max_height=ext->max_logical_extent.height;
247 fnte->max_width=ext->max_logical_extent.width;
248 fnte->baseline=-ext->max_logical_extent.y;
249 return;
250 }else if(font->fontstruct!=NULL){
251 XFontStruct *fnt=font->fontstruct;
252 fnte->max_height=fnt->ascent+fnt->descent;
253 fnte->max_width=fnt->max_bounds.width;
254 fnte->baseline=fnt->ascent;
255 return;
258 fail:
259 DE_RESET_FONT_EXTENTS(fnte);
263 uint debrush_get_text_width(DEBrush *brush, const char *text, uint len)
265 if(brush->d->font==NULL || text==NULL || len==0)
266 return 0;
268 return defont_get_text_width(brush->d->font, text, len);
272 uint defont_get_text_width(DEFont *font, const char *text, uint len)
274 if(font->fontset!=NULL){
275 XRectangle lext;
276 #ifdef CF_DE_USE_XUTF8
277 if(ioncore_g.enc_utf8)
278 Xutf8TextExtents(font->fontset, text, len, NULL, &lext);
279 else
280 #endif
281 XmbTextExtents(font->fontset, text, len, NULL, &lext);
282 return lext.width;
283 }else if(font->fontstruct!=NULL){
284 if(ioncore_g.enc_utf8){
285 XChar2b *str16; int len16=0;
286 uint res;
288 toucs(text, len, &str16, &len16);
290 res=XTextWidth16(font->fontstruct, str16, len16);
292 free(str16);
294 return res;
295 }else{
296 return XTextWidth(font->fontstruct, text, len);
298 }else{
299 return 0;
304 /*}}}*/
307 /*{{{ String drawing */
310 void debrush_do_draw_string_default(DEBrush *brush, int x, int y,
311 const char *str, int len, bool needfill,
312 DEColourGroup *colours)
314 GC gc=brush->d->normal_gc;
316 if(brush->d->font==NULL)
317 return;
319 XSetForeground(ioncore_g.dpy, gc, colours->fg);
321 if(!needfill){
322 if(brush->d->font->fontset!=NULL){
323 #ifdef CF_DE_USE_XUTF8
324 if(ioncore_g.enc_utf8)
325 Xutf8DrawString(ioncore_g.dpy, brush->win,
326 brush->d->font->fontset,
327 gc, x, y, str, len);
328 else
329 #endif
330 XmbDrawString(ioncore_g.dpy, brush->win,
331 brush->d->font->fontset,
332 gc, x, y, str, len);
333 }else if(brush->d->font->fontstruct!=NULL){
334 if(ioncore_g.enc_utf8){
335 XChar2b *str16; int len16=0;
336 toucs(str, len, &str16, &len16);
337 XDrawString16(ioncore_g.dpy, brush->win, gc, x, y, str16, len16);
338 free(str16);
339 }else{
340 XDrawString(ioncore_g.dpy, brush->win, gc, x, y, str, len);
343 }else{
344 XSetBackground(ioncore_g.dpy, gc, colours->bg);
345 if(brush->d->font->fontset!=NULL){
346 #ifdef CF_DE_USE_XUTF8
347 if(ioncore_g.enc_utf8)
348 Xutf8DrawImageString(ioncore_g.dpy, brush->win,
349 brush->d->font->fontset,
350 gc, x, y, str, len);
351 else
352 #endif
353 XmbDrawImageString(ioncore_g.dpy, brush->win,
354 brush->d->font->fontset,
355 gc, x, y, str, len);
356 }else if(brush->d->font->fontstruct!=NULL){
357 if(ioncore_g.enc_utf8){
358 XChar2b *str16; int len16=0;
359 toucs(str, len, &str16, &len16);
360 XDrawImageString16(ioncore_g.dpy, brush->win, gc, x, y, str16, len16);
361 free(str16);
362 }else{
363 XDrawImageString(ioncore_g.dpy, brush->win, gc, x, y, str, len);
370 void debrush_do_draw_string(DEBrush *brush, int x, int y,
371 const char *str, int len, bool needfill,
372 DEColourGroup *colours)
374 CALL_DYN(debrush_do_draw_string, brush, (brush, x, y, str, len,
375 needfill, colours));
379 void debrush_draw_string(DEBrush *brush, int x, int y,
380 const char *str, int len, bool needfill)
382 DEColourGroup *cg=debrush_get_current_colour_group(brush);
383 if(cg!=NULL)
384 debrush_do_draw_string(brush, x, y, str, len, needfill, cg);
388 /*}}}*/