linedata.c revision 190d7dce
1/* $XTermId: linedata.c,v 1.107 2024/12/01 20:27:00 tom Exp $ */
2
3/*
4 * Copyright 2009-2023,2024 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
36#include <assert.h>
37
38/*
39 * Given a row-number, find the corresponding data for the line in the VT100
40 * widget.  Row numbers can be positive or negative.
41 *
42 * If the data comes from the scrollback, defer that to getScrollback().
43 */
44LineData *
45getLineData(TScreen *screen, int row)
46{
47    LineData *result = NULL;
48    ScrnBuf buffer;
49    int max_row = LastRowNumber(screen);
50
51    if (row >= 0) {
52	buffer = screen->visbuf;
53    } else {
54	buffer = NULL;
55	result = getScrollback(screen, row);
56    }
57    if (row >= 0 && row <= max_row) {
58	result = (LineData *) scrnHeadAddr(screen, buffer, (unsigned) row);
59    }
60
61    return result;
62}
63
64/*
65 * Copy line's data, e.g., from one screen buffer to another, given the preset
66 * pointers for the destination.
67 *
68 * TODO: optionally prune unused combining character data from the result.
69 */
70void
71copyLineData(LineData *dst, CLineData *src)
72{
73    if (dst == NULL || src == NULL || dst == src)
74	return;
75
76    dst->bufHead = src->bufHead;
77
78#if OPT_WIDE_CHARS
79    dst->combSize = src->combSize;
80#endif
81
82    /*
83     * Usually we're copying the same-sized line; a memcpy is faster than
84     * several loops.
85     */
86    if (dst->lineSize == src->lineSize) {
87	size_t size = (sizeof(dst->attribs[0])
88#if OPT_ISO_COLORS
89		       + sizeof(dst->color[0])
90#endif
91		       + sizeof(dst->charData[0])
92#if OPT_WIDE_CHARS
93		       + sizeof(dst->combData[0][0]) * dst->combSize
94#endif
95#if OPT_DEC_RECTOPS
96		       + sizeof(dst->charSeen[0])
97		       + sizeof(dst->charSets[0])
98#endif
99	);
100
101	memcpy(dst->attribs, src->attribs, size * dst->lineSize);
102    } else {
103	Dimension col;
104	Dimension limit = ((dst->lineSize < src->lineSize)
105			   ? dst->lineSize
106			   : src->lineSize);
107#if OPT_WIDE_CHARS
108	Char comb;
109#endif
110
111	for (col = 0; col < limit; ++col) {
112	    dst->attribs[col] = src->attribs[col];
113#if OPT_ISO_COLORS
114	    dst->color[col] = src->color[col];
115#endif
116	    dst->charData[col] = src->charData[col];
117#if OPT_DEC_RECTOPS
118	    dst->charSeen[col] = src->charSeen[col];
119	    dst->charSets[col] = src->charSets[col];
120#endif
121#if OPT_WIDE_CHARS
122	    for (comb = 0; comb < dst->combSize; ++comb) {
123		dst->combData[comb][col] = src->combData[comb][col];
124	    }
125#endif
126	}
127	for (col = limit; col < dst->lineSize; ++col) {
128	    dst->attribs[col] = 0;
129#if OPT_ISO_COLORS
130	    dst->color[col] = initCColor;
131#endif
132	    dst->charData[col] = 0;
133#if OPT_DEC_RECTOPS
134	    dst->charSeen[col] = 0;
135	    dst->charSets[col] = 0;
136#endif
137#if OPT_WIDE_CHARS
138	    for (comb = 0; comb < dst->combSize; ++comb) {
139		dst->combData[comb][col] = 0;
140	    }
141#endif
142	}
143    }
144}
145
146#if OPT_WIDE_CHARS
147#define initLineExtra(screen) \
148    screen->lineExtra = ((size_t) (screen->max_combining) * sizeof(IChar *)); \
149    screen->cellExtra = ((size_t) (screen->max_combining) * sizeof(IChar))
150#else
151#define initLineExtra(screen) \
152    screen->lineExtra = 0; \
153    screen->cellExtra = 0
154#endif
155
156/*
157 * CellData size depends on the "combiningChars" resource.
158 */
159#define CellDataSize(screen) (SizeOfCellData + screen->cellExtra)
160
161#define CellDataAddr(screen, data, cell) \
162	( (CellData *)(void *) ((char *)data + (cell * CellDataSize(screen))) )
163#define ConstCellDataAddr(screen, data, cell) \
164	( (const CellData *)(const void *) ( \
165	      (const char *)data + (cell * CellDataSize(screen))) )
166
167void
168initLineData(XtermWidget xw)
169{
170    TScreen *screen = TScreenOf(xw);
171
172    initLineExtra(screen);
173
174#if OPT_WIDE_CHARS
175    TRACE(("initLineData %lu (%d combining chars)\n",
176	   (unsigned long) screen->lineExtra, screen->max_combining));
177#else
178    TRACE(("initLineData\n"));
179#endif
180
181    /*
182     * Per-line size/offsets.
183     */
184    TRACE(("** sizeof(LineData)  %lu\n", (unsigned long) sizeof(LineData)));
185    TRACE(("   offset(lineSize)  %lu\n", (unsigned long) offsetof(LineData, lineSize)));
186    TRACE(("   offset(bufHead)   %lu\n", (unsigned long) offsetof(LineData, bufHead)));
187#if OPT_WIDE_CHARS
188    TRACE(("   offset(combSize)  %lu\n", (unsigned long) offsetof(LineData, combSize)));
189#endif
190#if OPT_DEC_RECTOPS
191    TRACE(("   offset(*charSeen) %lu\n", (unsigned long) offsetof(LineData, charSeen)));
192    TRACE(("   offset(*charSets) %lu\n", (unsigned long) offsetof(LineData, charSets)));
193#endif
194    TRACE(("   offset(*attribs)  %lu\n", (unsigned long) offsetof(LineData, attribs)));
195#if OPT_ISO_COLORS
196    TRACE(("   offset(*color)    %lu\n", (unsigned long) offsetof(LineData, color)));
197#endif
198    TRACE(("   offset(*charData) %lu\n", (unsigned long) offsetof(LineData, charData)));
199    TRACE(("   offset(*combData) %lu\n", (unsigned long) offsetof(LineData, combData)));
200
201    /*
202     * Per-cell size/offsets.
203     */
204    TRACE(("** sizeof(CellData)  %lu\n", (unsigned long) CellDataSize(screen)));
205    TRACE(("   offset(attribs)   %lu\n", (unsigned long) offsetof(CellData, attribs)));
206#if OPT_WIDE_CHARS
207    TRACE(("   offset(combSize)  %lu\n", (unsigned long) offsetof(CellData, combSize)));
208#endif
209#if OPT_DEC_RECTOPS
210    TRACE(("   offset(charSeen)  %lu\n", (unsigned long) offsetof(CellData, charSeen)));
211    TRACE(("   offset(charSets)  %lu\n", (unsigned long) offsetof(CellData, charSets)));
212#endif
213#if OPT_ISO_COLORS
214    TRACE(("   offset(color)     %lu\n", (unsigned long) offsetof(CellData, color)));
215#endif
216    TRACE(("   offset(charData)  %lu\n", (unsigned long) offsetof(CellData, charData)));
217    TRACE(("   offset(combData)  %lu\n", (unsigned long) offsetof(CellData, combData)));
218
219    /*
220     * Data-type sizes.
221     */
222#if OPT_ISO_COLORS
223    TRACE(("** sizeof(CellColor) %lu\n", (unsigned long) sizeof(CellColor)));
224#endif
225    TRACE(("** sizeof(IAttr)     %lu\n", (unsigned long) sizeof(IAttr)));
226    TRACE(("** sizeof(IChar)     %lu\n", (unsigned long) sizeof(IChar)));
227    TRACE(("** sizeof(RowData)   %lu\n", (unsigned long) sizeof(RowData)));
228}
229
230CellData *
231newCellData(XtermWidget xw, Cardinal count)
232{
233    CellData *result;
234    TScreen *screen = TScreenOf(xw);
235
236    initLineExtra(screen);
237    result = (CellData *) calloc((size_t) count, (size_t) CellDataSize(screen));
238    return result;
239}
240
241void
242saveCellData(TScreen *screen,
243	     CellData *data,
244	     Cardinal cell,
245	     CLineData *ld,
246	     XTermRect *limits,
247	     int column)
248{
249    CellData *item = CellDataAddr(screen, data, cell);
250
251    (void) limits;
252    if (column < MaxCols(screen)) {
253	item->attribs = ld->attribs[column];
254	if_OPT_ISO_COLORS(screen, {
255	    item->color = ld->color[column];
256	});
257	if_OPT_DEC_RECTOPS({
258	    item->charSeen = ld->charSeen[column];
259	    item->charData = ld->charData[column];
260	});
261	if_OPT_WIDE_CHARS(screen, {
262	    size_t off;
263	    Bool blank = (((item->charData == HIDDEN_CHAR)
264			   && (limits == NULL
265			       || (column + 1) == limits->left))
266			  || (item->charData != HIDDEN_CHAR
267			      && WideCells(item->charData) > 1
268			      && (limits == NULL
269				  || (column + 1) >= limits->right)));
270	    if (blank) {
271		if_OPT_DEC_RECTOPS(item->charSeen = ' ');
272		item->charData = (CharData) ' ';
273	    }
274	    item->combSize = blank ? 0 : ld->combSize;
275	    if_OPT_DEC_RECTOPS(item->charSets = (blank
276						 ? 0
277						 : ld->charSets[column]));
278	    for_each_combData(off, item) {
279		item->combData[off] = ld->combData[off][column];
280	    }
281	});
282	TRACE2(("SAVED::%s\n", visibleIChars(&(item->charData), 1)));
283    }
284}
285
286void
287restoreCellData(TScreen *screen,
288		const CellData *data,
289		Cardinal cell,
290		LineData *ld,
291		XTermRect *limits,
292		int column)
293{
294    const CellData *item = ConstCellDataAddr(screen, data, cell);
295
296    (void) limits;
297    if (column < MaxCols(screen)) {
298	ld->attribs[column] = item->attribs;
299	TRACE2(("BEFORE:%2d:%s\n", column + 1, visibleIChars(ld->charData, ld->lineSize)));
300	if_OPT_ISO_COLORS(screen, {
301	    ld->color[column] = item->color;
302	});
303	if_OPT_DEC_RECTOPS({
304	    ld->charSeen[column] = item->charSeen;
305	    ld->charSets[column] = item->charSets;
306	});
307	ld->charData[column] = item->charData;
308	if_OPT_WIDE_CHARS(screen, {
309	    size_t off;
310	    ld->combSize = item->combSize;
311	    if_OPT_DEC_RECTOPS(ld->charSets[column] = item->charSets);
312	    for_each_combData(off, ld) {
313		ld->combData[off][column] = item->combData[off];
314	    }
315	});
316	TRACE2(("AFTER::%2d:%s\n", column + 1, visibleIChars(ld->charData, ld->lineSize)));
317    }
318}
319