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