1 /* $XTermId: doublechr.c,v 1.104 2020/12/10 19:43:26 tom Exp $ */
2
3 /*
4 * Copyright 1997-2019,2020 by Thomas E. Dickey
5 *
6 * All Rights Reserved
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the
10 * "Software"), to deal in the Software without restriction, including
11 * without limitation the rights to use, copy, modify, merge, publish,
12 * distribute, sublicense, and/or sell copies of the Software, and to
13 * permit persons to whom the Software is furnished to do so, subject to
14 * the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22 * IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY
23 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 *
27 * Except as contained in this notice, the name(s) of the above copyright
28 * holders shall not be used in advertising or otherwise to promote the
29 * sale, use or other dealings in this Software without prior written
30 * authorization.
31 */
32
33 #include <xterm.h>
34 #include <data.h>
35 #include <fontutils.h>
36
37 #include <assert.h>
38
39 #define WhichCgsId(flag) (((flag) & BOLD) ? gcCBold : gcCNorm)
40
41 /*
42 * The first column is all that matters for double-size characters (since the
43 * controls apply to a whole line). However, it's easier to maintain the
44 * information for special fonts by writing to all cells.
45 */
46 #if OPT_DEC_CHRSET
47
48 static void
repaint_line(XtermWidget xw,unsigned newChrSet)49 repaint_line(XtermWidget xw, unsigned newChrSet)
50 {
51 TScreen *screen = TScreenOf(xw);
52 LineData *ld;
53 int curcol = screen->cur_col;
54 int currow = screen->cur_row;
55 int width = MaxCols(screen);
56 unsigned len = (unsigned) width;
57
58 assert(width > 0);
59
60 /*
61 * Ignore repetition.
62 */
63 if (!IsLeftRightMode(xw)
64 && (ld = getLineData(screen, currow)) != 0) {
65 unsigned oldChrSet = GetLineDblCS(ld);
66
67 if (oldChrSet != newChrSet) {
68 TRACE(("repaint_line(%2d,%2d) (%s -> %s)\n", currow, screen->cur_col,
69 visibleDblChrset(oldChrSet),
70 visibleDblChrset(newChrSet)));
71 HideCursor(xw);
72
73 /* If switching from single-width, keep the cursor in the visible part
74 * of the line.
75 */
76 if (CSET_DOUBLE(newChrSet)) {
77 width /= 2;
78 if (curcol > width)
79 curcol = width;
80 }
81
82 /*
83 * ScrnRefresh won't paint blanks for us if we're switching between a
84 * single-size and double-size font. So we paint our own.
85 */
86 ClearCurBackground(xw,
87 currow,
88 0,
89 1,
90 len,
91 (unsigned) LineFontWidth(screen, ld));
92
93 SetLineDblCS(ld, newChrSet);
94
95 set_cur_col(screen, 0);
96 ScrnUpdate(xw, currow, 0, 1, (int) len, True);
97 set_cur_col(screen, curcol);
98 }
99 }
100 }
101 #endif
102
103 /*
104 * Set the line to double-height characters. The 'top' flag denotes whether
105 * we'll be using it for the top (true) or bottom (false) of the line.
106 */
107 void
xterm_DECDHL(XtermWidget xw,Bool top)108 xterm_DECDHL(XtermWidget xw, Bool top)
109 {
110 #if OPT_DEC_CHRSET
111 repaint_line(xw, (unsigned) (top ? CSET_DHL_TOP : CSET_DHL_BOT));
112 #else
113 (void) xw;
114 (void) top;
115 #endif
116 }
117
118 /*
119 * Set the line to single-width characters (the normal state).
120 */
121 void
xterm_DECSWL(XtermWidget xw)122 xterm_DECSWL(XtermWidget xw)
123 {
124 #if OPT_DEC_CHRSET
125 repaint_line(xw, CSET_SWL);
126 #else
127 (void) xw;
128 #endif
129 }
130
131 /*
132 * Set the line to double-width characters
133 */
134 void
xterm_DECDWL(XtermWidget xw)135 xterm_DECDWL(XtermWidget xw)
136 {
137 #if OPT_DEC_CHRSET
138 repaint_line(xw, CSET_DWL);
139 #else
140 (void) xw;
141 #endif
142 }
143
144 /*
145 * Reset all lines on the screen to single-width/single-height.
146 */
147 void
xterm_ResetDouble(XtermWidget xw)148 xterm_ResetDouble(XtermWidget xw)
149 {
150 #if OPT_DEC_CHRSET
151 TScreen *screen = TScreenOf(xw);
152 Boolean changed = False;
153 unsigned code;
154 int row;
155
156 for (row = 0; row < screen->max_row; ++row) {
157 LineData *ld;
158
159 if ((ld = getLineData(screen, ROW2INX(screen, row))) != 0) {
160 code = GetLineDblCS(ld);
161 if (code != CSET_SWL) {
162 SetLineDblCS(ld, CSET_SWL);
163 changed = True;
164 }
165 }
166 }
167 if (changed) {
168 xtermRepaint(xw);
169 }
170 #else
171 (void) xw;
172 #endif
173 }
174
175 #if OPT_DEC_CHRSET
176 static void
discard_font(XtermWidget xw,int n)177 discard_font(XtermWidget xw, int n)
178 {
179 TScreen *screen = TScreenOf(xw);
180 XTermFonts *data = getDoubleFont(screen, n);
181
182 TRACE(("discard_font chrset=%d %s\n", data->chrset,
183 (data->fn != 0) ? data->fn : "<no-name>"));
184
185 data->chrset = 0;
186 data->flags = 0;
187 FreeAndNull(data->fn);
188 xtermCloseFont(xw, data);
189
190 screen->fonts_used -= 1;
191 while (n < screen->fonts_used) {
192 screen->double_fonts[n] = screen->double_fonts[n + 1];
193 ++n;
194 }
195 }
196
197 /* push back existing fonts and create a new entry */
198 static XTermFonts *
pushback_font(XtermWidget xw,XTermFonts * source)199 pushback_font(XtermWidget xw, XTermFonts * source)
200 {
201 TScreen *screen = TScreenOf(xw);
202 XTermFonts *data = getDoubleFont(screen, 0);
203 int n;
204
205 if (screen->fonts_used >= screen->cache_doublesize) {
206 TRACE(("pushback_font: discard oldest\n"));
207 discard_font(xw, screen->fonts_used - 1);
208 } else {
209 screen->fonts_used += 1;
210 }
211
212 for (n = screen->fonts_used; n > 0; n--)
213 data[n] = data[n - 1];
214 data[0] = *source;
215
216 TRACE(("pushback_font -> (NEW:%d)\n", screen->fonts_used));
217
218 return data;
219 }
220
221 static int
xterm_Double_index(XTermDraw * params)222 xterm_Double_index(XTermDraw * params)
223 {
224 XTermDraw local = *params;
225 int n;
226 int result = -1;
227 TScreen *screen = TScreenOf(local.xw);
228 XTermFonts *data = getDoubleFont(screen, 0);
229
230 local.attr_flags &= BOLD;
231 TRACE(("xterm_Double_index chrset=%#x, flags=%#x\n", local.this_chrset, local.attr_flags));
232
233 for (n = 0; n < screen->fonts_used; n++) {
234 if (data[n].chrset == (unsigned) local.this_chrset
235 && data[n].flags == local.attr_flags) {
236 if (n != 0) {
237 XTermFonts save;
238 TRACE(("...xterm_Double_index -> %d (OLD:%d)\n", n, screen->fonts_used));
239 save = data[n];
240 while (n > 0) {
241 data[n] = data[n - 1];
242 n--;
243 }
244 data[n] = save;
245 }
246 result = n;
247 break;
248 }
249 }
250
251 return result;
252 }
253
254 /*
255 * Lookup/cache a GC for the double-size character display. We save up to
256 * NUM_CHRSET values.
257 */
258 GC
xterm_DoubleGC(XTermDraw * params,GC old_gc,int * inxp)259 xterm_DoubleGC(XTermDraw * params, GC old_gc, int *inxp)
260 {
261 TScreen *screen = TScreenOf(params->xw);
262 VTwin *cgsWin = WhichVWin(screen);
263 char *name;
264 GC result = 0;
265
266 if ((name = xtermSpecialFont(params))
267 != 0) {
268 CgsEnum cgsId = WhichCgsId(params->attr_flags);
269 Boolean found = False;
270 XTermFonts *data = 0;
271 int n;
272
273 if ((n = xterm_Double_index(params)) >= 0) {
274 data = getDoubleFont(screen, n);
275 if (data->fn != 0) {
276 if (!strcmp(data->fn, name)
277 && data->fs != 0) {
278 found = True;
279 FreeAndNull(name);
280 } else {
281 discard_font(params->xw, n);
282 }
283 }
284 }
285
286 if (!found && name != NULL) {
287 XTermFonts temp;
288
289 TRACE(("xterm_DoubleGC %s %d: %s\n",
290 (params->attr_flags & BOLD) ? "BOLD" : "NORM", n, name));
291
292 memset(&temp, 0, sizeof(temp));
293 temp.fn = name;
294 temp.chrset = params->this_chrset;
295 temp.flags = (params->attr_flags & BOLD);
296 temp.warn = fwResource;
297
298 if (!xtermOpenFont(params->xw, name, &temp, False)) {
299 XTermDraw local = *params;
300 char *nname;
301
302 /* Retry with * in resolutions */
303 local.draw_flags |= NORESOLUTION;
304 nname = xtermSpecialFont(&local);
305 if (nname != 0) {
306 found = (Boolean) xtermOpenFont(params->xw, nname, &temp,
307 False);
308 free(nname);
309 }
310 } else {
311 found = True;
312 }
313 free(name);
314
315 if (found) {
316 n = 0;
317 data = pushback_font(params->xw, &temp);
318 }
319
320 TRACE(("-> %s\n", found ? "OK" : "FAIL"));
321 }
322
323 if (found) {
324 setCgsCSet(params->xw, cgsWin, cgsId, params->this_chrset);
325 setCgsFont(params->xw, cgsWin, cgsId, data);
326 setCgsFore(params->xw, cgsWin, cgsId, getCgsFore(params->xw,
327 cgsWin, old_gc));
328 setCgsBack(params->xw, cgsWin, cgsId, getCgsBack(params->xw,
329 cgsWin, old_gc));
330 result = getCgsGC(params->xw, cgsWin, cgsId);
331 *inxp = n;
332 } else if (params->attr_flags & BOLD) {
333 UIntClr(params->attr_flags, BOLD);
334 result = xterm_DoubleGC(params, old_gc, inxp);
335 }
336 }
337
338 return result;
339 }
340
341 #if OPT_RENDERFONT
342 /*
343 * Like xterm_DoubleGC(), but returning an Xft font.
344 */
345 XftFont *
xterm_DoubleFT(XTermDraw * params,unsigned chrset,unsigned attr_flags)346 xterm_DoubleFT(XTermDraw * params, unsigned chrset, unsigned attr_flags)
347 {
348 XftFont *result;
349 TScreen *screen = TScreenOf(params->xw);
350 unsigned num = (chrset & CSET_DWL);
351
352 if ((attr_flags &= BOLD) != 0)
353 num |= 4;
354
355 if ((result = screen->double_xft_fonts[num]) == 0) {
356 result = getDoubleXftFont(params, chrset, attr_flags);
357 screen->double_xft_fonts[num] = result;
358 }
359 return result;
360 }
361
362 void
freeall_DoubleFT(XtermWidget xw)363 freeall_DoubleFT(XtermWidget xw)
364 {
365 TScreen *screen = TScreenOf(xw);
366 unsigned num;
367
368 for (num = 0; num < XtNumber(screen->double_xft_fonts); ++num) {
369 closeCachedXft(screen, screen->double_xft_fonts[num]);
370 screen->double_xft_fonts[num] = 0;
371 }
372 }
373 #endif /* OPT_RENDERFONT */
374
375 #endif /* OPT_DEC_CHRSET */
376