1 /* $XTermId: linedata.c,v 1.100 2021/08/22 20:02:23 tom Exp $ */
2 
3 /*
4  * Copyright 2009-2019,2021 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  */
44 LineData *
getLineData(TScreen * screen,int row)45 getLineData(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 	buffer = 0;
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  */
70 void
copyLineData(LineData * dst,CLineData * src)71 copyLineData(LineData *dst, CLineData *src)
72 {
73     if (dst == NULL || src == NULL)
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 	);
96 
97 	memcpy(dst->attribs, src->attribs, size * dst->lineSize);
98     } else {
99 	Dimension col;
100 	Dimension limit = ((dst->lineSize < src->lineSize)
101 			   ? dst->lineSize
102 			   : src->lineSize);
103 #if OPT_WIDE_CHARS
104 	Char comb;
105 #endif
106 
107 	for (col = 0; col < limit; ++col) {
108 	    dst->attribs[col] = src->attribs[col];
109 #if OPT_ISO_COLORS
110 	    dst->color[col] = src->color[col];
111 #endif
112 	    dst->charData[col] = src->charData[col];
113 #if OPT_WIDE_CHARS
114 	    for (comb = 0; comb < dst->combSize; ++comb) {
115 		dst->combData[comb][col] = src->combData[comb][col];
116 	    }
117 #endif
118 	}
119 	for (col = limit; col < dst->lineSize; ++col) {
120 	    dst->attribs[col] = 0;
121 #if OPT_ISO_COLORS
122 	    dst->color[col] = initCColor;
123 #endif
124 	    dst->charData[col] = 0;
125 #if OPT_WIDE_CHARS
126 	    for (comb = 0; comb < dst->combSize; ++comb) {
127 		dst->combData[comb][col] = 0;
128 	    }
129 #endif
130 	}
131     }
132 }
133 
134 #if OPT_WIDE_CHARS
135 #define initLineExtra(screen) \
136     screen->lineExtra = ((size_t) (screen->max_combining) * sizeof(IChar *)); \
137     screen->cellExtra = ((size_t) (screen->max_combining) * sizeof(IChar))
138 #else
139 #define initLineExtra(screen) \
140     screen->lineExtra = 0; \
141     screen->cellExtra = 0
142 #endif
143 
144 /*
145  * CellData size depends on the "combiningChars" resource.
146  */
147 #define CellDataSize(screen) (SizeOfCellData + screen->cellExtra)
148 
149 #define CellDataAddr(screen, data, cell) \
150 	( (CellData *)(void *) ((char *)data + (cell * CellDataSize(screen))) )
151 #define ConstCellDataAddr(screen, data, cell) \
152 	( (const CellData *)(const void *) ( \
153 	      (const char *)data + (cell * CellDataSize(screen))) )
154 
155 void
initLineData(XtermWidget xw)156 initLineData(XtermWidget xw)
157 {
158     TScreen *screen = TScreenOf(xw);
159 
160     initLineExtra(screen);
161 
162 #if OPT_WIDE_CHARS
163     TRACE(("initLineData %lu (%d combining chars)\n",
164 	   (unsigned long) screen->lineExtra, screen->max_combining));
165 #else
166     TRACE(("initLineData\n"));
167 #endif
168 
169     /*
170      * Per-line size/offsets.
171      */
172     TRACE(("** sizeof(LineData)  %lu\n", (unsigned long) sizeof(LineData)));
173     TRACE(("   offset(lineSize)  %lu\n", (unsigned long) offsetof(LineData, lineSize)));
174     TRACE(("   offset(bufHead)   %lu\n", (unsigned long) offsetof(LineData, bufHead)));
175 #if OPT_WIDE_CHARS
176     TRACE(("   offset(combSize)  %lu\n", (unsigned long) offsetof(LineData, combSize)));
177 #endif
178     TRACE(("   offset(*attribs)  %lu\n", (unsigned long) offsetof(LineData, attribs)));
179 #if OPT_ISO_COLORS
180     TRACE(("   offset(*color)    %lu\n", (unsigned long) offsetof(LineData, color)));
181 #endif
182     TRACE(("   offset(*charData) %lu\n", (unsigned long) offsetof(LineData, charData)));
183     TRACE(("   offset(*combData) %lu\n", (unsigned long) offsetof(LineData, combData)));
184 
185     /*
186      * Per-cell size/offsets.
187      */
188     TRACE(("** sizeof(CellData)  %lu\n", (unsigned long) CellDataSize(screen)));
189     TRACE(("   offset(attribs)   %lu\n", (unsigned long) offsetof(CellData, attribs)));
190 #if OPT_WIDE_CHARS
191     TRACE(("   offset(combSize)  %lu\n", (unsigned long) offsetof(CellData, combSize)));
192 #endif
193 #if OPT_ISO_COLORS
194     TRACE(("   offset(color)     %lu\n", (unsigned long) offsetof(CellData, color)));
195 #endif
196     TRACE(("   offset(charData)  %lu\n", (unsigned long) offsetof(CellData, charData)));
197     TRACE(("   offset(combData)  %lu\n", (unsigned long) offsetof(CellData, combData)));
198 
199     /*
200      * Data-type sizes.
201      */
202 #if OPT_ISO_COLORS
203     TRACE(("** sizeof(CellColor) %lu\n", (unsigned long) sizeof(CellColor)));
204 #endif
205     TRACE(("** sizeof(IAttr)     %lu\n", (unsigned long) sizeof(IAttr)));
206     TRACE(("** sizeof(IChar)     %lu\n", (unsigned long) sizeof(IChar)));
207     TRACE(("** sizeof(RowData)   %lu\n", (unsigned long) sizeof(RowData)));
208 }
209 
210 CellData *
newCellData(XtermWidget xw,Cardinal count)211 newCellData(XtermWidget xw, Cardinal count)
212 {
213     CellData *result;
214     TScreen *screen = TScreenOf(xw);
215 
216     initLineExtra(screen);
217     result = (CellData *) calloc((size_t) count, (size_t) CellDataSize(screen));
218     return result;
219 }
220 
221 void
saveCellData(TScreen * screen,CellData * data,Cardinal cell,CLineData * ld,XTermRect * limits,int column)222 saveCellData(TScreen *screen,
223 	     CellData *data,
224 	     Cardinal cell,
225 	     CLineData *ld,
226 	     XTermRect *limits,
227 	     int column)
228 {
229     CellData *item = CellDataAddr(screen, data, cell);
230 
231     (void) limits;
232     if (column < MaxCols(screen)) {
233 	item->attribs = ld->attribs[column];
234 	if_OPT_ISO_COLORS(screen, {
235 	    item->color = ld->color[column];
236 	});
237 	item->charData = ld->charData[column];
238 	if_OPT_WIDE_CHARS(screen, {
239 	    size_t off;
240 	    Bool blank = (((item->charData == HIDDEN_CHAR)
241 			   && (limits == NULL
242 			       || (column + 1) == limits->left))
243 			  || (item->charData != HIDDEN_CHAR
244 			      && WideCells(item->charData) > 1
245 			      && (limits == NULL
246 				  || (column + 1) >= limits->right)));
247 	    if (blank) {
248 		item->charData = (CharData) ' ';
249 	    }
250 	    item->combSize = blank ? 0 : ld->combSize;
251 	    for_each_combData(off, item) {
252 		item->combData[off] = ld->combData[off][column];
253 	    }
254 	});
255 	TRACE2(("SAVED::%s\n", visibleIChars(&(item->charData), 1)));
256     }
257 }
258 
259 void
restoreCellData(TScreen * screen,const CellData * data,Cardinal cell,LineData * ld,XTermRect * limits,int column)260 restoreCellData(TScreen *screen,
261 		const CellData *data,
262 		Cardinal cell,
263 		LineData *ld,
264 		XTermRect *limits,
265 		int column)
266 {
267     const CellData *item = ConstCellDataAddr(screen, data, cell);
268 
269     (void) limits;
270     if (column < MaxCols(screen)) {
271 	ld->attribs[column] = item->attribs;
272 	TRACE2(("BEFORE:%2d:%s\n", column + 1, visibleIChars(ld->charData, ld->lineSize)));
273 	if_OPT_ISO_COLORS(screen, {
274 	    ld->color[column] = item->color;
275 	});
276 	ld->charData[column] = item->charData;
277 	if_OPT_WIDE_CHARS(screen, {
278 	    size_t off;
279 	    ld->combSize = item->combSize;
280 	    for_each_combData(off, ld) {
281 		ld->combData[off][column] = item->combData[off];
282 	    }
283 	});
284 	TRACE2(("AFTER::%2d:%s\n", column + 1, visibleIChars(ld->charData, ld->lineSize)));
285     }
286 }
287