Merge 'remotes/dkogan/merged_submodules'
[notion.git] / de / font.c
blob1444a59e62cf0916ffeacfa0da525bd89ab4e809
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
30 #define UTF_4 0xF0
31 #define UTF_5 0xF8
32 #define UTF_6 0xFC
34 static void toucs(const char *str_, int len, XChar2b **str16, int *len16)
36 int i=0;
37 const uchar *str=(const uchar*)str_;
38 wchar_t prev=0;
40 *str16=ALLOC_N(XChar2b, len);
41 *len16=0;
43 while(i<len){
44 wchar_t ch=0;
46 if((str[i] & UTF_3) == UTF_3){
47 if(i+2>=len)
48 break;
49 ch=((str[i] & UTF_3_DATA) << 12)
50 | ((str[i+1] & UTF_DATA) << 6)
51 | (str[i+2] & UTF_DATA);
52 i+=3;
53 }else if((str[i] & UTF_2) == UTF_2){
54 if(i+1>=len)
55 break;
56 ch = ((str[i] & UTF_2_DATA) << 6) | (str[i+1] & UTF_DATA);
57 i+=2;
58 }else if(str[i] < UTF_1){
59 ch = str[i];
60 i++;
61 }else{
62 ch='?';
63 i++;
66 if(*len16>0){
67 wchar_t precomp=do_precomposition(prev, ch);
68 if(precomp!=-1){
69 (*len16)--;
70 ch=precomp;
74 (*str16)[*len16].byte2=ch&0xff;
75 (*str16)[*len16].byte1=(ch>>8)&0xff;
76 (*len16)++;
77 prev=ch;
82 /*}}}*/
85 /*{{{ Load/free */
88 static DEFont *fonts=NULL;
91 static bool iso10646_font(const char *fontname)
93 const char *iso;
95 if(strchr(fontname, ',')!=NULL)
96 return FALSE; /* fontset */
98 iso=strstr(fontname, "iso10646-1");
99 return (iso!=NULL && iso[10]=='\0');
102 const char *de_default_fontname()
104 if(ioncore_g.use_mb)
105 return "-*-helvetica-medium-r-normal-*-12-*-*-*-*-*-*-*";
106 else
107 return "fixed";
110 DEFont *de_load_font(const char *fontname)
112 DEFont *fnt;
113 XFontSet fontset=NULL;
114 XFontStruct *fontstruct=NULL;
115 const char *default_fontname=de_default_fontname();
117 assert(fontname!=NULL);
119 /* There shouldn't be that many fonts... */
120 for(fnt=fonts; fnt!=NULL; fnt=fnt->next){
121 if(strcmp(fnt->pattern, fontname)==0){
122 fnt->refcount++;
123 return fnt;
127 if(ioncore_g.use_mb && !(ioncore_g.enc_utf8 && iso10646_font(fontname))){
128 LOG(DEBUG, FONT, "Loading fontset %s", fontname);
129 fontset=de_create_font_set(fontname);
130 if(fontset!=NULL){
131 if(XContextDependentDrawing(fontset)){
132 warn(TR("Fontset for font pattern '%s' implements context "
133 "dependent drawing, which is unsupported. Expect "
134 "clutter."), fontname);
137 }else{
138 LOG(DEBUG, FONT, "Loading fontstruct %s", fontname);
139 fontstruct=XLoadQueryFont(ioncore_g.dpy, fontname);
142 if(fontstruct==NULL && fontset==NULL){
143 if(strcmp(fontname, default_fontname)!=0){
144 DEFont *fnt;
145 LOG(WARN, FONT, TR("Could not load font \"%s\", trying \"%s\""),
146 fontname, default_fontname);
147 fnt=de_load_font(default_fontname);
148 if(fnt==NULL)
149 LOG(WARN, FONT, TR("Failed to load fallback font."));
150 return fnt;
152 return NULL;
155 fnt=ALLOC(DEFont);
157 if(fnt==NULL)
158 return NULL;
160 fnt->fontset=fontset;
161 fnt->fontstruct=fontstruct;
162 fnt->pattern=scopy(fontname);
163 fnt->next=NULL;
164 fnt->prev=NULL;
165 fnt->refcount=1;
167 LINK_ITEM(fonts, fnt, next, prev);
169 return fnt;
173 bool de_set_font_for_style(DEStyle *style, DEFont *font)
175 if(style->font!=NULL)
176 de_free_font(style->font);
178 style->font=font;
179 font->refcount++;
181 if(style->font->fontstruct!=NULL){
182 XSetFont(ioncore_g.dpy, style->normal_gc,
183 style->font->fontstruct->fid);
186 return TRUE;
190 bool de_load_font_for_style(DEStyle *style, const char *fontname)
192 if(style->font!=NULL)
193 de_free_font(style->font);
195 style->font=de_load_font(fontname);
197 if(style->font==NULL)
198 return FALSE;
200 if(style->font->fontstruct!=NULL){
201 XSetFont(ioncore_g.dpy, style->normal_gc,
202 style->font->fontstruct->fid);
205 return TRUE;
209 void de_free_font(DEFont *font)
211 if(--font->refcount!=0)
212 return;
214 if(font->fontset!=NULL)
215 XFreeFontSet(ioncore_g.dpy, font->fontset);
216 if(font->fontstruct!=NULL)
217 XFreeFont(ioncore_g.dpy, font->fontstruct);
218 if(font->pattern!=NULL)
219 free(font->pattern);
221 UNLINK_ITEM(fonts, font, next, prev);
222 free(font);
226 /*}}}*/
229 /*{{{ Lengths */
232 void debrush_get_font_extents(DEBrush *brush, GrFontExtents *fnte)
234 if(brush->d->font==NULL){
235 DE_RESET_FONT_EXTENTS(fnte);
236 return;
239 defont_get_font_extents(brush->d->font, fnte);
243 void defont_get_font_extents(DEFont *font, GrFontExtents *fnte)
245 if(font->fontset!=NULL){
246 XFontSetExtents *ext=XExtentsOfFontSet(font->fontset);
247 if(ext==NULL)
248 goto fail;
249 fnte->max_height=ext->max_logical_extent.height;
250 fnte->max_width=ext->max_logical_extent.width;
251 fnte->baseline=-ext->max_logical_extent.y;
252 return;
253 }else if(font->fontstruct!=NULL){
254 XFontStruct *fnt=font->fontstruct;
255 fnte->max_height=fnt->ascent+fnt->descent;
256 fnte->max_width=fnt->max_bounds.width;
257 fnte->baseline=fnt->ascent;
258 return;
261 fail:
262 DE_RESET_FONT_EXTENTS(fnte);
266 uint debrush_get_text_width(DEBrush *brush, const char *text, uint len)
268 if(brush->d->font==NULL || text==NULL || len==0)
269 return 0;
271 return defont_get_text_width(brush->d->font, text, len);
275 uint defont_get_text_width(DEFont *font, const char *text, uint len)
277 if(font->fontset!=NULL){
278 XRectangle lext;
279 #ifdef CF_DE_USE_XUTF8
280 if(ioncore_g.enc_utf8)
281 Xutf8TextExtents(font->fontset, text, len, NULL, &lext);
282 else
283 #endif
284 XmbTextExtents(font->fontset, text, len, NULL, &lext);
285 return lext.width;
286 }else if(font->fontstruct!=NULL){
287 if(ioncore_g.enc_utf8){
288 XChar2b *str16; int len16=0;
289 uint res;
291 toucs(text, len, &str16, &len16);
293 res=XTextWidth16(font->fontstruct, str16, len16);
295 free(str16);
297 return res;
298 }else{
299 return XTextWidth(font->fontstruct, text, len);
301 }else{
302 return 0;
307 /*}}}*/
310 /*{{{ String drawing */
313 void debrush_do_draw_string_default(DEBrush *brush, int x, int y,
314 const char *str, int len, bool needfill,
315 DEColourGroup *colours)
317 GC gc=brush->d->normal_gc;
319 if(brush->d->font==NULL)
320 return;
322 XSetForeground(ioncore_g.dpy, gc, colours->fg);
324 if(!needfill){
325 if(brush->d->font->fontset!=NULL){
326 #ifdef CF_DE_USE_XUTF8
327 if(ioncore_g.enc_utf8)
328 Xutf8DrawString(ioncore_g.dpy, brush->win,
329 brush->d->font->fontset,
330 gc, x, y, str, len);
331 else
332 #endif
333 XmbDrawString(ioncore_g.dpy, brush->win,
334 brush->d->font->fontset,
335 gc, x, y, str, len);
336 }else if(brush->d->font->fontstruct!=NULL){
337 if(ioncore_g.enc_utf8){
338 XChar2b *str16; int len16=0;
339 toucs(str, len, &str16, &len16);
340 XDrawString16(ioncore_g.dpy, brush->win, gc, x, y, str16, len16);
341 free(str16);
342 }else{
343 XDrawString(ioncore_g.dpy, brush->win, gc, x, y, str, len);
346 }else{
347 XSetBackground(ioncore_g.dpy, gc, colours->bg);
348 if(brush->d->font->fontset!=NULL){
349 #ifdef CF_DE_USE_XUTF8
350 if(ioncore_g.enc_utf8)
351 Xutf8DrawImageString(ioncore_g.dpy, brush->win,
352 brush->d->font->fontset,
353 gc, x, y, str, len);
354 else
355 #endif
356 XmbDrawImageString(ioncore_g.dpy, brush->win,
357 brush->d->font->fontset,
358 gc, x, y, str, len);
359 }else if(brush->d->font->fontstruct!=NULL){
360 if(ioncore_g.enc_utf8){
361 XChar2b *str16; int len16=0;
362 toucs(str, len, &str16, &len16);
363 XDrawImageString16(ioncore_g.dpy, brush->win, gc, x, y, str16, len16);
364 free(str16);
365 }else{
366 XDrawImageString(ioncore_g.dpy, brush->win, gc, x, y, str, len);
373 void debrush_do_draw_string(DEBrush *brush, int x, int y,
374 const char *str, int len, bool needfill,
375 DEColourGroup *colours)
377 CALL_DYN(debrush_do_draw_string, brush, (brush, x, y, str, len,
378 needfill, colours));
382 void debrush_draw_string(DEBrush *brush, int x, int y,
383 const char *str, int len, bool needfill)
385 DEColourGroup *cg=debrush_get_current_colour_group(brush);
386 if(cg!=NULL)
387 debrush_do_draw_string(brush, x, y, str, len, needfill, cg);
391 /*}}}*/