1 #include <stdlib.h>
2 #include "xglk.h"
3 #include "xg_internal.h"
4 
5 static stylehints_t null_hints;
6 static stylehints_t textbuf_hints;
7 static stylehints_t textgrid_hints;
8 
9 static int gli_stylehints_init(stylehints_t *hints);
10 static int gli_stylehints_clone(stylehints_t *dest, stylehints_t *src);
11 static int gli_stylehint_get(stylehints_t *hints, glui32 styl, glui32 hint,
12   glsi32 *val);
13 static void gli_stylehint_set(stylehints_t *hints, glui32 styl, glui32 hint,
14   int set, glsi32 val);
15 
16 static unsigned short MaxRGBDifference(XColor *col1, XColor *col2);
17 
init_gli_styles()18 int init_gli_styles()
19 {
20   int ix, jx;
21 
22   ix = gli_stylehints_init(&null_hints);
23   if (!ix)
24     return FALSE;
25   ix = gli_stylehints_init(&textbuf_hints);
26   if (!ix)
27     return FALSE;
28   ix = gli_stylehints_init(&textgrid_hints);
29   if (!ix)
30     return FALSE;
31 
32   textbuf_hints.type = wintype_TextBuffer;
33   textgrid_hints.type = wintype_TextGrid;
34 
35   return TRUE;
36 }
37 
gli_stylehints_init(stylehints_t * hints)38 static int gli_stylehints_init(stylehints_t *hints)
39 {
40   int ix;
41 
42   hints->type = wintype_AllTypes;
43 
44   for (ix=0; ix<style_NUMSTYLES; ix++) {
45     hints->style[ix].setflags = 0;
46     hints->style[ix].vals = NULL;
47     hints->style[ix].length = 0;
48     hints->style[ix].size = 0;
49   }
50 
51   return TRUE;
52 }
53 
gli_stylehints_clone(stylehints_t * dest,stylehints_t * src)54 static int gli_stylehints_clone(stylehints_t *dest, stylehints_t *src)
55 {
56   int ix, jx, len;
57 
58   dest->type = src->type;
59 
60   for (ix=0; ix<style_NUMSTYLES; ix++) {
61     dest->style[ix].setflags = src->style[ix].setflags;
62     len = src->style[ix].length;
63     dest->style[ix].length = len;
64     dest->style[ix].size = len;
65     if (len) {
66       dest->style[ix].vals = (styleval_t *)malloc(len * sizeof(styleval_t));
67       for (jx=0; jx<len; jx++) {
68 	dest->style[ix].vals[jx] = src->style[ix].vals[jx];
69       }
70     }
71     else {
72       dest->style[ix].vals = NULL;
73     }
74   }
75 
76   return TRUE;
77 }
78 
gli_styles_compute(fontset_t * font,stylehints_t * hints)79 void gli_styles_compute(fontset_t *font, stylehints_t *hints)
80 {
81   int ix;
82   int negindent;
83   glsi32 val;
84   winprefs_t *wprefs;
85 
86   /* Here is the routine: For every (damn) attribute, look at the
87      prefs.fontprefs_t.  That will specify a value, and also a check-hints
88      flag. If the latter is true, and there's a hint, let the hint
89      override. Otherwise, use the value. */
90 
91   if (!hints)
92     hints = &null_hints;
93 
94   if (hints->type == wintype_TextGrid)
95     wprefs = &prefs.textgrid;
96   else
97     wprefs = &prefs.textbuffer;
98 
99   font->forecolor = wprefs->forecolor;
100   font->linkcolor = wprefs->linkcolor;
101   font->backcolor = wprefs->backcolor;
102 
103   for (ix=0; ix<style_NUMSTYLES; ix++) {
104     fontref_t *fref = &(font->gc[ix]);
105     XGCValues gcvalues;
106     int size, weight, oblique, proportional;
107     char buf[256];
108 
109     size = wprefs->style[ix].size;
110     if (wprefs->sizehint
111       && gli_stylehint_get(hints, ix, stylehint_Size, &val))
112       size += val;
113 
114     if (wprefs->attribhint
115       && gli_stylehint_get(hints, ix, stylehint_Weight, &val))
116       weight = val;
117     else
118       weight = wprefs->style[ix].weight;
119 
120     if (wprefs->attribhint
121       && gli_stylehint_get(hints, ix, stylehint_Oblique, &val))
122       oblique = val;
123     else
124       oblique = wprefs->style[ix].oblique;
125 
126     if (wprefs->fixedhint
127       && gli_stylehint_get(hints, ix, stylehint_Proportional, &val))
128       proportional = val;
129     else
130       proportional = wprefs->style[ix].proportional;
131 
132     xglk_build_fontname(wprefs->style[ix].spec, buf,
133       size, weight, oblique, proportional);
134     fref->fontstr = XLoadQueryFont(xiodpy, buf);
135     if (!fref->fontstr) {
136       fprintf(stderr, "### unable to snarf font %s.\n", buf);
137     }
138 
139     fref->specname = (char *)malloc(sizeof(char) * (strlen(buf)+1));
140     /* ### bit of a core leak here, I'm afraid. */
141     strcpy(fref->specname, buf);
142 
143     fref->forecolor = wprefs->style[ix].forecolor;
144     fref->linkcolor = wprefs->style[ix].linkcolor;
145     fref->backcolor = wprefs->style[ix].backcolor;
146     /*### or hint */
147 
148     if (wprefs->justhint
149       && gli_stylehint_get(hints, ix, stylehint_Justification, &val))
150       font->gc[ix].justify = val;
151     else
152       font->gc[ix].justify = wprefs->style[ix].justify;
153 
154     if (wprefs->indenthint
155       && gli_stylehint_get(hints, ix, stylehint_Indentation, &val))
156       font->gc[ix].indent = (font->gc[ix].fontstr->ascent * val) / 2;
157     else
158       font->gc[ix].indent = wprefs->style[ix].baseindent;
159 
160     if (wprefs->indenthint
161       && gli_stylehint_get(hints, ix, stylehint_ParaIndentation, &val))
162       font->gc[ix].parindent = (font->gc[ix].fontstr->ascent * val) / 2;
163     else
164       font->gc[ix].parindent = wprefs->style[ix].parindent;
165   }
166 
167   font->lineheight = 0;
168   font->lineoff = 0;
169   font->baseindent = 0;
170   negindent = 0;
171 
172   for (ix=0; ix<style_NUMSTYLES; ix++) {
173     fontref_t *fref = &(font->gc[ix]);
174     int ascent, descent, dir;
175     int clineheight, clineheightoff, ival;
176     XCharStruct strdat;
177 
178     XTextExtents(fref->fontstr, " ", 1, &dir, &ascent, &descent, &strdat);
179     font->gc[ix].ascent = ascent;
180     font->gc[ix].descent = descent;
181     if (descent < 2)
182       font->gc[ix].underliney = descent-1;
183     else
184       font->gc[ix].underliney = 1;
185 
186     clineheight = ascent + descent + wprefs->leading;
187     clineheightoff = ascent;
188     if (clineheight > font->lineheight)
189       font->lineheight = clineheight;
190     if (clineheightoff > font->lineoff)
191       font->lineoff = clineheightoff;
192     font->gc[ix].spacewidth = strdat.width;
193 
194     ival = font->gc[ix].indent + font->gc[ix].parindent;
195     if (ival < negindent)
196       negindent = ival;
197     if (font->gc[ix].indent < negindent)
198       negindent = font->gc[ix].indent;
199   }
200 
201   font->baseindent = -negindent;
202 }
203 
gli_stylehint_set(stylehints_t * hints,glui32 styl,glui32 hint,int set,glsi32 val)204 static void gli_stylehint_set(stylehints_t *hints, glui32 styl, glui32 hint,
205   int set, glsi32 val)
206 {
207   int ix, len;
208   glui32 hintbit;
209   styleonehint_t *hn;
210 
211   if (styl >= style_NUMSTYLES || hint >= stylehint_NUMHINTS)
212     return;
213 
214   hn = &(hints->style[styl]);
215   hintbit = (1 << hint);
216   len = hn->length;
217 
218   if (set) {
219     if (hn->setflags & hintbit) {
220       for (ix=0; ix<len; ix++) {
221 	if (hn->vals[ix].type == hint) {
222 	  hn->vals[ix].val = val;
223 	  break;
224 	}
225       }
226     }
227     else {
228       if (!hn->size || !hn->vals) {
229 	hn->size = 3;
230 	hn->vals = (styleval_t *)malloc(hn->size * sizeof(styleval_t));
231       }
232       else if (len+1 > hn->size) {
233 	hn->size = len+4;
234 	hn->vals = (styleval_t *)realloc(hn->vals, hn->size * sizeof(styleval_t));
235       }
236       hn->vals[len].type = hint;
237       hn->vals[len].val = val;
238       hn->length++;
239       hn->setflags |= (hintbit);
240     }
241   }
242   else {
243     if (!(hn->setflags & hintbit))
244       return;
245     for (ix=0; ix<len; ix++) {
246       if (hn->vals[ix].type == hint)
247 	break;
248     }
249     for (; ix+1<len; ix++) {
250       hn->vals[ix] = hn->vals[ix+1];
251     }
252     hn->length--;
253     hn->setflags &= (~hintbit);
254   }
255 }
256 
gli_stylehint_get(stylehints_t * hints,glui32 styl,glui32 hint,glsi32 * val)257 static int gli_stylehint_get(stylehints_t *hints, glui32 styl, glui32 hint,
258   glsi32 *val)
259 {
260   int ix, len;
261   styleonehint_t *hn;
262 
263   if (styl >= style_NUMSTYLES || hint >= stylehint_NUMHINTS)
264     return FALSE;
265 
266   hn = &(hints->style[styl]);
267 
268   if (!(hn->setflags & (1 << hint))) {
269     return FALSE;
270   }
271 
272   len = hn->length;
273   for (ix=0; ix<len; ix++) {
274     if (hn->vals[ix].type == hint) {
275       *val = hn->vals[ix].val;
276       return TRUE;
277     }
278   }
279 
280   return FALSE;
281 }
282 
glk_stylehint_set(glui32 wintype,glui32 styl,glui32 hint,glsi32 val)283 void glk_stylehint_set(glui32 wintype, glui32 styl, glui32 hint, glsi32 val)
284 {
285   switch (wintype) {
286   case wintype_TextBuffer:
287     gli_stylehint_set(&textbuf_hints, styl, hint, TRUE, val);
288     break;
289   case wintype_TextGrid:
290     gli_stylehint_set(&textgrid_hints, styl, hint, TRUE, val);
291     break;
292   case wintype_AllTypes:
293     gli_stylehint_set(&textbuf_hints, styl, hint, TRUE, val);
294     gli_stylehint_set(&textgrid_hints, styl, hint, TRUE, val);
295     break;
296   }
297 }
298 
glk_stylehint_clear(glui32 wintype,glui32 styl,glui32 hint)299 void glk_stylehint_clear(glui32 wintype, glui32 styl, glui32 hint)
300 {
301   switch (wintype) {
302   case wintype_TextBuffer:
303     gli_stylehint_set(&textbuf_hints, styl, hint, FALSE, 0);
304     break;
305   case wintype_TextGrid:
306     gli_stylehint_set(&textgrid_hints, styl, hint, FALSE, 0);
307     break;
308   case wintype_AllTypes:
309     gli_stylehint_set(&textbuf_hints, styl, hint, FALSE, 0);
310     gli_stylehint_set(&textgrid_hints, styl, hint, FALSE, 0);
311     break;
312   }
313 }
314 
gli_stylehints_for_window(glui32 wintype,stylehints_t * hints)315 int gli_stylehints_for_window(glui32 wintype, stylehints_t *hints)
316 {
317   switch (wintype) {
318   case wintype_TextBuffer:
319     return gli_stylehints_clone(hints, &textbuf_hints);
320   case wintype_TextGrid:
321     return gli_stylehints_clone(hints, &textgrid_hints);
322   default:
323     return gli_stylehints_init(hints);
324   }
325 }
326 
glk_style_distinguish(window_t * win,glui32 styl1,glui32 styl2)327 glui32 glk_style_distinguish(window_t *win, glui32 styl1, glui32 styl2)
328 {
329   fontset_t *fonts;
330   fontref_t *font1, *font2;
331 
332   if (!win) {
333     gli_strict_warning("window_style_distinguish: invalid id");
334     return FALSE;
335   }
336 
337   fonts = gli_window_get_fontset(win);
338   if (!fonts)
339     return FALSE;
340 
341   if (styl1 >= style_NUMSTYLES || styl2 >= style_NUMSTYLES)
342     return FALSE;
343 
344   if (styl1 == styl2)
345     return FALSE;
346 
347   font1 = &(fonts->gc[styl1]);
348   font2 = &(fonts->gc[styl2]);
349 
350   if (strcmp(font1->specname, font2->specname))
351     return TRUE;
352 
353   if (font1->justify != font2->justify) {
354     if (!((font1->justify == stylehint_just_LeftFlush
355       || font1->justify == stylehint_just_LeftRight)
356       && (font2->justify == stylehint_just_LeftFlush
357 	|| font2->justify == stylehint_just_LeftRight)))
358       return TRUE;
359   }
360 
361   if (font1->indent != font2->indent)
362     return TRUE;
363 
364   if (MaxRGBDifference(&font1->forecolor, &font2->forecolor) >= 6500)
365     return TRUE;
366   if (MaxRGBDifference(&font1->backcolor, &font2->backcolor) >= 6500)
367     return TRUE;
368 
369   return FALSE;
370 }
371 
glk_style_measure(window_t * win,glui32 styl,glui32 hint,glui32 * result)372 glui32 glk_style_measure(window_t *win, glui32 styl, glui32 hint,
373   glui32 *result)
374 {
375   fontset_t *fonts;
376   fontref_t *font;
377   glui32 dummy, val;
378 
379   if (!win) {
380     gli_strict_warning("window_style_measure: invalid id");
381     return FALSE;
382   }
383 
384   if (!result)
385     result = &dummy;
386 
387   fonts = gli_window_get_fontset(win);
388   if (!fonts)
389     return FALSE;
390 
391   if (styl >= style_NUMSTYLES || hint >= stylehint_NUMHINTS)
392     return FALSE;
393 
394   font = &(fonts->gc[styl]);
395 
396   switch (hint) {
397   case stylehint_Weight:
398     /* Can't figure this out in X */
399     return FALSE;
400   case stylehint_Oblique:
401     /* Can't figure this out in X */
402     return FALSE;
403   case stylehint_TextColor:
404     *result = PackRGBColor(&font->forecolor);
405     return TRUE;
406   case stylehint_BackColor:
407     *result = PackRGBColor(&fonts->backcolor);
408     return TRUE;
409   case stylehint_Justification:
410     *result = font->justify;
411     return TRUE;
412   case stylehint_Size:
413     *result = font->fontstr->ascent + font->fontstr->descent;
414     return TRUE;
415   case stylehint_Indentation:
416     *result = font->indent;
417     return TRUE;
418   case stylehint_ParaIndentation:
419     *result = font->parindent;
420     return TRUE;
421   case stylehint_Proportional:
422   default:
423     return FALSE;
424   }
425 }
426 
MaxRGBDifference(XColor * col1,XColor * col2)427 static unsigned short MaxRGBDifference(XColor *col1, XColor *col2)
428 {
429   unsigned short val, result;
430 
431   result = 0;
432 
433   if ((unsigned short)(col1->red) > (unsigned short)(col2->red))
434     val = (unsigned short)(col1->red) - (unsigned short)(col2->red);
435   else
436     val = (unsigned short)(col2->red) - (unsigned short)(col1->red);
437   if (val > result)
438     result = val;
439 
440   if ((unsigned short)(col1->green) > (unsigned short)(col2->green))
441     val = (unsigned short)(col1->green) - (unsigned short)(col2->green);
442   else
443     val = (unsigned short)(col2->green) - (unsigned short)(col1->green);
444   if (val > result)
445     result = val;
446 
447   if ((unsigned short)(col1->blue) > (unsigned short)(col2->blue))
448     val = (unsigned short)(col1->blue) - (unsigned short)(col2->blue);
449   else
450     val = (unsigned short)(col2->blue) - (unsigned short)(col1->blue);
451   if (val > result)
452     result = val;
453 
454   return result;
455 }
456 
457