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