* fileio.c (read_non_regular, read_non_regular_quit): Rename arg.
[bpt/emacs.git] / src / scroll.c
CommitLineData
632a8dd6 1/* Calculate what line insertion or deletion to do, and do it,
429ab54e 2 Copyright (C) 1985, 1986, 1990, 1993, 1994, 2001, 2002, 2003, 2004,
114f9c96 3 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
632a8dd6
JB
4
5This file is part of GNU Emacs.
6
9ec0b715 7GNU Emacs is free software: you can redistribute it and/or modify
632a8dd6 8it under the terms of the GNU General Public License as published by
9ec0b715
GM
9the Free Software Foundation, either version 3 of the License, or
10(at your option) any later version.
632a8dd6
JB
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
9ec0b715 18along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
632a8dd6
JB
19
20
18160b98 21#include <config.h>
89700111
GM
22#include <stdio.h>
23#include <string.h>
d7306fe6 24#include <setjmp.h>
9628b887 25#include "lisp.h"
632a8dd6 26#include "termchar.h"
632a8dd6 27#include "dispextern.h"
2538fae4 28#include "keyboard.h"
0137dbf7 29#include "frame.h"
89700111 30#include "window.h"
daf01701 31#include "termhooks.h"
632a8dd6 32
632a8dd6 33/* All costs measured in characters.
0137dbf7 34 So no cost can exceed the area of a frame, measured in characters.
61df1a5e 35 Let's hope this is never more than 1000000 characters. */
632a8dd6 36
61df1a5e 37#define INFINITY 1000000
632a8dd6
JB
38
39struct matrix_elt
40 {
41 /* Cost of outputting through this line
42 if no insert/delete is done just above it. */
61df1a5e 43 int writecost;
632a8dd6
JB
44 /* Cost of outputting through this line
45 if an insert is done just above it. */
61df1a5e 46 int insertcost;
632a8dd6
JB
47 /* Cost of outputting through this line
48 if a delete is done just above it. */
61df1a5e 49 int deletecost;
632a8dd6
JB
50 /* Number of inserts so far in this run of inserts,
51 for the cost in insertcost. */
61df1a5e 52 unsigned char insertcount;
632a8dd6
JB
53 /* Number of deletes so far in this run of deletes,
54 for the cost in deletecost. */
61df1a5e 55 unsigned char deletecount;
1af1b1e8
RS
56 /* Number of writes so far since the last insert
57 or delete for the cost in writecost. */
58 unsigned char writecount;
632a8dd6
JB
59 };
60
f57e2426
J
61static void do_direct_scrolling (struct frame *,
62 struct glyph_matrix *,
63 struct matrix_elt *,
64 int, int);
65static void do_scrolling (struct frame *,
66 struct glyph_matrix *,
67 struct matrix_elt *,
68 int, int);
89700111 69
632a8dd6 70\f
1af1b1e8
RS
71/* Determine, in matrix[i,j], the cost of updating the first j old
72 lines into the first i new lines using the general scrolling method.
632a8dd6
JB
73 This involves using insert or delete somewhere if i != j.
74 For each matrix elements, three kinds of costs are recorded:
75 the smallest cost that ends with an insert, the smallest
76 cost that ends with a delete, and the smallest cost that
77 ends with neither one. These are kept separate because
78 on some terminals the cost of doing an insert varies
79 depending on whether one was just done, etc. */
80
81/* draw_cost[VPOS] is the cost of outputting new line at VPOS.
82 old_hash[VPOS] is the hash code of the old line at VPOS.
83 new_hash[VPOS] is the hash code of the new line at VPOS.
0137dbf7 84 Note that these are not true frame vpos's, but relative
632a8dd6
JB
85 to the place at which the first mismatch between old and
86 new contents appears. */
87
88static void
0137dbf7 89calculate_scrolling (frame, matrix, window_size, lines_below,
632a8dd6
JB
90 draw_cost, old_hash, new_hash,
91 free_at_end)
0137dbf7 92 FRAME_PTR frame;
632a8dd6
JB
93 /* matrix is of size window_size + 1 on each side. */
94 struct matrix_elt *matrix;
250368af 95 int window_size, lines_below;
632a8dd6
JB
96 int *draw_cost;
97 int *old_hash;
98 int *new_hash;
99 int free_at_end;
100{
101 register int i, j;
9882535b 102 int frame_lines = FRAME_LINES (frame);
632a8dd6
JB
103 register struct matrix_elt *p, *p1;
104 register int cost, cost1;
105
8a56675d 106 int lines_moved = window_size
daf01701 107 + (FRAME_SCROLL_REGION_OK (frame) ? 0 : lines_below);
632a8dd6 108 /* first_insert_cost[I] is the cost of doing the first insert-line
89700111 109 at the i'th line of the lines we are considering,
632a8dd6
JB
110 where I is origin 1 (as it is below). */
111 int *first_insert_cost
9882535b 112 = &FRAME_INSERT_COST (frame)[frame_lines - 1 - lines_moved];
632a8dd6 113 int *first_delete_cost
9882535b 114 = &FRAME_DELETE_COST (frame)[frame_lines - 1 - lines_moved];
632a8dd6 115 int *next_insert_cost
9882535b 116 = &FRAME_INSERTN_COST (frame)[frame_lines - 1 - lines_moved];
632a8dd6 117 int *next_delete_cost
9882535b 118 = &FRAME_DELETEN_COST (frame)[frame_lines - 1 - lines_moved];
632a8dd6
JB
119
120 /* Discourage long scrolls on fast lines.
0137dbf7 121 Don't scroll nearly a full frame height unless it saves
632a8dd6 122 at least 1/4 second. */
9882535b 123 int extra_cost = baud_rate / (10 * 4 * FRAME_LINES (frame));
632a8dd6 124
7fb08f69
RS
125 if (baud_rate <= 0)
126 extra_cost = 1;
127
632a8dd6
JB
128 /* initialize the top left corner of the matrix */
129 matrix->writecost = 0;
130 matrix->insertcost = INFINITY;
131 matrix->deletecost = INFINITY;
132 matrix->insertcount = 0;
133 matrix->deletecount = 0;
134
135 /* initialize the left edge of the matrix */
136 cost = first_insert_cost[1] - next_insert_cost[1];
137 for (i = 1; i <= window_size; i++)
138 {
139 p = matrix + i * (window_size + 1);
140 cost += draw_cost[i] + next_insert_cost[i] + extra_cost;
141 p->insertcost = cost;
142 p->writecost = INFINITY;
143 p->deletecost = INFINITY;
144 p->insertcount = i;
145 p->deletecount = 0;
146 }
147
148 /* initialize the top edge of the matrix */
149 cost = first_delete_cost[1] - next_delete_cost[1];
150 for (j = 1; j <= window_size; j++)
151 {
152 cost += next_delete_cost[j];
153 matrix[j].deletecost = cost;
154 matrix[j].writecost = INFINITY;
155 matrix[j].insertcost = INFINITY;
156 matrix[j].deletecount = j;
157 matrix[j].insertcount = 0;
158 }
159
0137dbf7
JB
160 /* `i' represents the vpos among new frame contents.
161 `j' represents the vpos among the old frame contents. */
632a8dd6
JB
162 p = matrix + window_size + 2; /* matrix [1, 1] */
163 for (i = 1; i <= window_size; i++, p++)
164 for (j = 1; j <= window_size; j++, p++)
165 {
166 /* p contains the address of matrix [i, j] */
167
168 /* First calculate the cost assuming we do
169 not insert or delete above this line.
170 That is, if we update through line i-1
171 based on old lines through j-1,
172 and then just change old line j to new line i. */
173 p1 = p - window_size - 2; /* matrix [i-1, j-1] */
174 cost = p1->writecost;
175 if (cost > p1->insertcost)
176 cost = p1->insertcost;
177 if (cost > p1->deletecost)
178 cost = p1->deletecost;
179 if (old_hash[j] != new_hash[i])
180 cost += draw_cost[i];
181 p->writecost = cost;
182
183 /* Calculate the cost if we do an insert-line
184 before outputting this line.
185 That is, we update through line i-1
186 based on old lines through j,
187 do an insert-line on line i,
188 and then output line i from scratch,
189 leaving old lines starting from j for reuse below. */
190 p1 = p - window_size - 1; /* matrix [i-1, j] */
191 /* No need to think about doing a delete followed
192 immediately by an insert. It cannot be as good
193 as not doing either of them. */
194 if (free_at_end == i)
195 {
196 cost = p1->writecost;
197 cost1 = p1->insertcost;
198 }
199 else
200 {
201 cost = p1->writecost + first_insert_cost[i];
0fe4741d 202 if ((int) p1->insertcount > i)
632a8dd6
JB
203 abort ();
204 cost1 = p1->insertcost + next_insert_cost[i - p1->insertcount];
205 }
206 p->insertcost = min (cost, cost1) + draw_cost[i] + extra_cost;
207 p->insertcount = (cost < cost1) ? 1 : p1->insertcount + 1;
0fe4741d 208 if ((int) p->insertcount > i)
632a8dd6
JB
209 abort ();
210
211 /* Calculate the cost if we do a delete line after
212 outputting this line.
213 That is, we update through line i
214 based on old lines through j-1,
215 and throw away old line j. */
216 p1 = p - 1; /* matrix [i, j-1] */
217 /* No need to think about doing an insert followed
218 immediately by a delete. */
219 if (free_at_end == i)
220 {
221 cost = p1->writecost;
222 cost1 = p1->deletecost;
223 }
224 else
225 {
226 cost = p1->writecost + first_delete_cost[i];
227 cost1 = p1->deletecost + next_delete_cost[i];
228 }
229 p->deletecost = min (cost, cost1);
230 p->deletecount = (cost < cost1) ? 1 : p1->deletecount + 1;
231 }
232}
89700111
GM
233
234
632a8dd6 235\f
89700111
GM
236/* Perform insert-lines and delete-lines operations on CURRENT_MATRIX
237 according to the costs in MATRIX, using the general scrolling
238 method that is used if the terminal does not support the setting of
177c0ea7 239 scroll windows (scroll_region_ok == 0).
2d810f84
RS
240
241 WINDOW_SIZE is the number of lines being considered for scrolling
89700111
GM
242 and UNCHANGED_AT_TOP is the vpos of the first line being
243 considered. These two arguments can specify any contiguous range
244 of lines. */
177c0ea7 245
632a8dd6 246static void
971de7fb 247do_scrolling (struct frame *frame, struct glyph_matrix *current_matrix, struct matrix_elt *matrix, int window_size, int unchanged_at_top)
632a8dd6 248{
89700111
GM
249 struct matrix_elt *p;
250 int i, j, k;
251
252 /* Set to 1 if we have set a terminal window with
253 set_terminal_window. */
254 int terminal_window_p = 0;
255
256 /* A queue for line insertions to be done. */
257 struct queue { int count, pos; };
258 struct queue *queue_start
259 = (struct queue *) alloca (current_matrix->nrows * sizeof (struct queue));
260 struct queue *queue = queue_start;
177c0ea7 261
89700111
GM
262 char *retained_p = (char *) alloca (window_size * sizeof (char));
263 int *copy_from = (int *) alloca (window_size * sizeof (int));
264
265 /* Zero means line is empty. */
266 bzero (retained_p, window_size * sizeof (char));
267 for (k = 0; k < window_size; ++k)
268 copy_from[k] = -1;
269
b96f9fb7 270#define CHECK_BOUNDS \
89700111
GM
271 do \
272 { \
273 int k; \
274 for (k = 0; k < window_size; ++k) \
275 xassert (copy_from[k] == -1 \
276 || (copy_from[k] >= 0 && copy_from[k] < window_size)); \
277 } \
278 while (0);
279
280 /* When j is advanced, this corresponds to deleted lines.
281 When i is advanced, this corresponds to inserted lines. */
632a8dd6 282 i = j = window_size;
632a8dd6
JB
283 while (i > 0 || j > 0)
284 {
285 p = matrix + i * (window_size + 1) + j;
177c0ea7 286
89700111 287 if (p->insertcost < p->writecost && p->insertcost < p->deletecost)
632a8dd6 288 {
89700111
GM
289 /* Insert should be done at vpos i-1, plus maybe some before.
290 Queue the screen operation to be performed. */
291 queue->count = p->insertcount;
292 queue->pos = i + unchanged_at_top - p->insertcount;
293 ++queue;
294
295 /* By incrementing I, we leave room in the result rows
296 for the empty rows opened up. */
632a8dd6 297 i -= p->insertcount;
632a8dd6
JB
298 }
299 else if (p->deletecost < p->writecost)
300 {
89700111
GM
301 /* Old line at vpos j-1, and maybe some before it, should be
302 deleted. By decrementing J, we skip some lines in the
303 temp_rows which is equivalent to omitting these lines in
304 the result rows, thus deleting them. */
632a8dd6 305 j -= p->deletecount;
89700111
GM
306
307 /* Set the terminal window, if not done already. */
308 if (! terminal_window_p)
632a8dd6 309 {
385ed61f 310 set_terminal_window (frame, window_size + unchanged_at_top);
89700111 311 terminal_window_p = 1;
632a8dd6 312 }
89700111
GM
313
314 /* Delete lines on the terminal. */
385ed61f 315 ins_del_lines (frame, j + unchanged_at_top, - p->deletecount);
632a8dd6
JB
316 }
317 else
318 {
89700111
GM
319 /* Best thing done here is no insert or delete, i.e. a write. */
320 --i, --j;
321 xassert (i >= 0 && i < window_size);
322 xassert (j >= 0 && j < window_size);
323 copy_from[i] = j;
324 retained_p[j] = 1;
325
326#if GLYPH_DEBUG
b96f9fb7 327 CHECK_BOUNDS;
89700111 328#endif
632a8dd6
JB
329 }
330 }
331
89700111
GM
332 /* Now do all insertions queued above. */
333 if (queue > queue_start)
632a8dd6 334 {
89700111 335 int next = -1;
632a8dd6 336
89700111
GM
337 /* Set the terminal window if not yet done. */
338 if (!terminal_window_p)
339 {
385ed61f 340 set_terminal_window (frame, window_size + unchanged_at_top);
89700111
GM
341 terminal_window_p = 1;
342 }
632a8dd6 343
89700111 344 do
632a8dd6 345 {
89700111
GM
346 --queue;
347
348 /* Do the deletion on the terminal. */
385ed61f 349 ins_del_lines (frame, queue->pos, queue->count);
89700111
GM
350
351 /* All lines in the range deleted become empty in the glyph
352 matrix. Assign to them glyph rows that are not retained.
353 K is the starting position of the deleted range relative
354 to the window we are working in. */
355 k = queue->pos - unchanged_at_top;
356 for (j = 0; j < queue->count; ++j)
357 {
358 /* Find the next row not retained. */
359 while (retained_p[++next])
360 ;
361
362 /* Record that this row is to be used for the empty
363 glyph row j. */
364 copy_from[k + j] = next;
365 }
632a8dd6 366 }
89700111 367 while (queue > queue_start);
177c0ea7 368
632a8dd6
JB
369 }
370
89700111
GM
371 for (k = 0; k < window_size; ++k)
372 xassert (copy_from[k] >= 0 && copy_from[k] < window_size);
373
374 /* Perform the row swizzling. */
375 mirrored_line_dance (current_matrix, unchanged_at_top, window_size,
376 copy_from, retained_p);
377
378 /* Some sanity checks if GLYPH_DEBUG != 0. */
379 CHECK_MATRIX (current_matrix);
177c0ea7 380
89700111 381 if (terminal_window_p)
385ed61f 382 set_terminal_window (frame, 0);
632a8dd6 383}
89700111 384
632a8dd6 385\f
1af1b1e8
RS
386/* Determine, in matrix[i,j], the cost of updating the first j
387 old lines into the first i new lines using the direct
388 scrolling method. When the old line and the new line have
389 different hash codes, the calculated cost of updating old
390 line j into new line i includes the cost of outputting new
391 line i, and if i != j, the cost of outputting the old line j
392 is also included, as a penalty for moving the line and then
393 erasing it. In addition, the cost of updating a sequence of
394 lines with constant i - j includes the cost of scrolling the
395 old lines into their new positions, unless i == j. Scrolling
396 is achieved by setting the screen window to avoid affecting
397 other lines below, and inserting or deleting lines at the top
398 of the scrolled region. The cost of scrolling a sequence of
399 lines includes the fixed cost of specifying a scroll region,
400 plus a variable cost which can depend upon the number of lines
401 involved and the distance by which they are scrolled, and an
402 extra cost to discourage long scrolls.
403
404 As reflected in the matrix, an insert or delete does not
405 correspond directly to the insertion or deletion which is
406 used in scrolling lines. An insert means that the value of i
407 has increased without a corresponding increase in the value
408 of j. A delete means that the value of j has increased
409 without a corresponding increase in the value of i. A write
410 means that i and j are both increased by the same amount, and
411 that the old lines will be moved to their new positions.
412
413 An insert following a delete is allowed only if i > j.
414 A delete following an insert is allowed only if i < j.
415 These restrictions ensure that the new lines in an insert
416 will always be blank as an effect of the neighboring writes.
417 Thus the calculated cost of an insert is simply the cost of
418 outputting the new line contents. The direct cost of a
419 delete is zero. Inserts and deletes indirectly affect the
420 total cost through their influence on subsequent writes. */
421
422/* The vectors draw_cost, old_hash, and new_hash have the same
423 meanings here as in calculate_scrolling, and old_draw_cost
424 is the equivalent of draw_cost for the old line contents */
425
426static void
427calculate_direct_scrolling (frame, matrix, window_size, lines_below,
428 draw_cost, old_draw_cost, old_hash, new_hash,
429 free_at_end)
430 FRAME_PTR frame;
431 /* matrix is of size window_size + 1 on each side. */
432 struct matrix_elt *matrix;
250368af 433 int window_size, lines_below;
1af1b1e8
RS
434 int *draw_cost;
435 int *old_draw_cost;
436 int *old_hash;
437 int *new_hash;
438 int free_at_end;
439{
440 register int i, j;
9882535b 441 int frame_lines = FRAME_LINES (frame);
1af1b1e8
RS
442 register struct matrix_elt *p, *p1;
443 register int cost, cost1, delta;
444
445 /* first_insert_cost[-I] is the cost of doing the first insert-line
446 at a position I lines above the bottom line in the scroll window. */
447 int *first_insert_cost
9882535b 448 = &FRAME_INSERT_COST (frame)[frame_lines - 1];
1af1b1e8 449 int *first_delete_cost
9882535b 450 = &FRAME_DELETE_COST (frame)[frame_lines - 1];
1af1b1e8 451 int *next_insert_cost
9882535b 452 = &FRAME_INSERTN_COST (frame)[frame_lines - 1];
1af1b1e8 453 int *next_delete_cost
9882535b 454 = &FRAME_DELETEN_COST (frame)[frame_lines - 1];
1af1b1e8
RS
455
456 int scroll_overhead;
457
458 /* Discourage long scrolls on fast lines.
459 Don't scroll nearly a full frame height unless it saves
460 at least 1/4 second. */
9882535b 461 int extra_cost = baud_rate / (10 * 4 * FRAME_LINES (frame));
1af1b1e8
RS
462
463 if (baud_rate <= 0)
464 extra_cost = 1;
465
466 /* Overhead of setting the scroll window, plus the extra cost
467 cost of scrolling by a distance of one. The extra cost is
468 added once for consistency with the cost vectors */
8a56675d 469 scroll_overhead
daf01701 470 = FRAME_SCROLL_REGION_COST (frame) + extra_cost;
1af1b1e8
RS
471
472 /* initialize the top left corner of the matrix */
473 matrix->writecost = 0;
474 matrix->insertcost = INFINITY;
475 matrix->deletecost = INFINITY;
476 matrix->writecount = 0;
477 matrix->insertcount = 0;
478 matrix->deletecount = 0;
479
480 /* initialize the left edge of the matrix */
481 cost = 0;
482 for (i = 1; i <= window_size; i++)
483 {
484 p = matrix + i * (window_size + 1);
485 cost += draw_cost[i];
486 p->insertcost = cost;
487 p->writecost = INFINITY;
488 p->deletecost = INFINITY;
489 p->insertcount = i;
490 p->writecount = 0;
491 p->deletecount = 0;
492 }
493
494 /* initialize the top edge of the matrix */
495 for (j = 1; j <= window_size; j++)
496 {
497 matrix[j].deletecost = 0;
498 matrix[j].writecost = INFINITY;
499 matrix[j].insertcost = INFINITY;
500 matrix[j].deletecount = j;
501 matrix[j].writecount = 0;
502 matrix[j].insertcount = 0;
503 }
504
505 /* `i' represents the vpos among new frame contents.
506 `j' represents the vpos among the old frame contents. */
507 p = matrix + window_size + 2; /* matrix [1, 1] */
508
509 for (i = 1; i <= window_size; i++, p++)
510 for (j = 1; j <= window_size; j++, p++)
511 {
512 /* p contains the address of matrix [i, j] */
513
514 /* First calculate the cost assuming we do
515 not insert or delete above this line.
516 That is, if we update through line i-1
517 based on old lines through j-1,
518 and then just change old line j to new line i.
519
520 Depending on which choice gives the lower cost,
521 this usually involves either scrolling a single line
522 or extending a sequence of scrolled lines, but
523 when i == j, no scrolling is required. */
524 p1 = p - window_size - 2; /* matrix [i-1, j-1] */
525 cost = p1->insertcost;
526 if (cost > p1->deletecost)
527 cost = p1->deletecost;
528 cost1 = p1->writecost;
529 if (i == j)
530 {
531 if (cost > cost1)
532 {
533 cost = cost1;
534 p->writecount = p1->writecount + 1;
535 }
536 else
537 p->writecount = 1;
538 if (old_hash[j] != new_hash[i])
539 {
540 cost += draw_cost[i];
541 }
542 }
543 else
544 {
545 if (i > j)
546 {
547 delta = i - j;
548
549 /* The cost added here for scrolling the first line by
550 a distance N includes the overhead of setting the
551 scroll window, the cost of inserting N lines at a
552 position N lines above the bottom line of the window,
553 and an extra cost which is proportional to N. */
554 cost += scroll_overhead + first_insert_cost[-delta] +
555 (delta-1) * (next_insert_cost[-delta] + extra_cost);
556
557 /* In the most general case, the insertion overhead and
558 the multiply factor can grow linearly as the distance
559 from the bottom of the window increases. The incremental
560 cost of scrolling an additional line depends upon the
561 rate of change of these two parameters. Each of these
562 growth rates can be determined by a simple difference.
563 To reduce the cumulative effects of rounding error, we
564 vary the position at which the difference is computed. */
565 cost1 += first_insert_cost[-j] - first_insert_cost[1-j] +
177c0ea7 566 (delta-1) * (next_insert_cost[-j] - next_insert_cost[1-j]);
1af1b1e8
RS
567 }
568 else
569 {
570 delta = j - i;
571 cost += scroll_overhead + first_delete_cost[-delta] +
572 (delta-1) * (next_delete_cost[-delta] + extra_cost);
573 cost1 += first_delete_cost[-i] - first_delete_cost[1-i] +
177c0ea7 574 (delta-1) * ( next_delete_cost[-i] - next_delete_cost[1-i]);
1af1b1e8
RS
575 }
576 if (cost1 < cost)
577 {
578 cost = cost1;
579 p->writecount = p1->writecount + 1;
580 }
581 else
582 p->writecount = 1;
583 if (old_hash[j] != new_hash[i])
584 {
585 cost += draw_cost[i] + old_draw_cost[j];
586 }
587 }
588 p->writecost = cost;
589
590 /* Calculate the cost if we do an insert-line
591 before outputting this line.
592 That is, we update through line i-1
593 based on old lines through j,
594 do an insert-line on line i,
595 and then output line i from scratch,
596 leaving old lines starting from j for reuse below. */
597 p1 = p - window_size - 1; /* matrix [i-1, j] */
598 cost = p1->writecost;
599 /* If i > j, an insert is allowed after a delete. */
600 if (i > j && p1->deletecost < cost)
601 cost = p1->deletecost;
602 if (p1->insertcost <= cost)
603 {
604 cost = p1->insertcost;
605 p->insertcount = p1->insertcount + 1;
606 }
607 else
608 p->insertcount = 1;
609 cost += draw_cost[i];
610 p->insertcost = cost;
611
612 /* Calculate the cost if we do a delete line after
613 outputting this line.
614 That is, we update through line i
615 based on old lines through j-1,
616 and throw away old line j. */
617 p1 = p - 1; /* matrix [i, j-1] */
618 cost = p1->writecost;
619 /* If i < j, a delete is allowed after an insert. */
620 if (i < j && p1->insertcost < cost)
621 cost = p1->insertcost;
622 cost1 = p1->deletecost;
623 if (p1->deletecost <= cost)
624 {
625 cost = p1->deletecost;
626 p->deletecount = p1->deletecount + 1;
627 }
628 else
629 p->deletecount = 1;
630 p->deletecost = cost;
631 }
632}
89700111
GM
633
634
1af1b1e8 635\f
89700111
GM
636/* Perform insert-lines and delete-lines operations on CURRENT_MATRIX
637 according to the costs in MATRIX, using the direct scrolling method
638 which is used when the terminal supports setting a scroll window
639 (scroll_region_ok).
1af1b1e8
RS
640
641 WINDOW_SIZE is the number of lines being considered for scrolling
89700111
GM
642 and UNCHANGED_AT_TOP is the vpos of the first line being
643 considered. These two arguments can specify any contiguous range
644 of lines.
177c0ea7 645
1af1b1e8
RS
646 In the direct scrolling method, a new scroll window is selected
647 before each insertion or deletion, so that groups of lines can be
648 scrolled directly to their final vertical positions. This method
89700111
GM
649 is described in more detail in calculate_direct_scrolling, where
650 the cost matrix for this approach is constructed. */
1af1b1e8
RS
651
652static void
385ed61f
KL
653do_direct_scrolling (frame, current_matrix, cost_matrix,
654 window_size, unchanged_at_top)
655 struct frame *frame;
89700111
GM
656 struct glyph_matrix *current_matrix;
657 struct matrix_elt *cost_matrix;
1af1b1e8
RS
658 int window_size;
659 int unchanged_at_top;
660{
89700111
GM
661 struct matrix_elt *p;
662 int i, j;
1af1b1e8 663
89700111
GM
664 /* A queue of deletions and insertions to be performed. */
665 struct alt_queue { int count, pos, window; };
666 struct alt_queue *queue_start = (struct alt_queue *)
667 alloca (window_size * sizeof *queue_start);
668 struct alt_queue *queue = queue_start;
1af1b1e8 669
89700111
GM
670 /* Set to 1 if a terminal window has been set with
671 set_terminal_window: */
672 int terminal_window_p = 0;
1af1b1e8 673
89700111
GM
674 /* A nonzero value of write_follows indicates that a write has been
675 selected, allowing either an insert or a delete to be selected
676 next. When write_follows is zero, a delete cannot be selected
677 unless j < i, and an insert cannot be selected unless i < j.
678 This corresponds to a similar restriction (with the ordering
679 reversed) in calculate_direct_scrolling, which is intended to
680 ensure that lines marked as inserted will be blank. */
681 int write_follows_p = 1;
682
683 /* For each row in the new matrix what row of the old matrix it is. */
684 int *copy_from = (int *) alloca (window_size * sizeof (int));
685
686 /* Non-zero for each row in the new matrix that is retained from the
687 old matrix. Lines not retained are empty. */
688 char *retained_p = (char *) alloca (window_size * sizeof (char));
689
690 bzero (retained_p, window_size * sizeof (char));
691
692 /* Perform some sanity checks when GLYPH_DEBUG is on. */
693 CHECK_MATRIX (current_matrix);
694
695 /* We are working on the line range UNCHANGED_AT_TOP ...
696 UNCHANGED_AT_TOP + WINDOW_SIZE (not including) in CURRENT_MATRIX.
697 We step through lines in this range from the end to the start. I
698 is an index into new lines, j an index into old lines. The cost
699 matrix determines what to do for ranges of indices.
700
701 If i is decremented without also decrementing j, this corresponds
702 to inserting empty lines in the result. If j is decremented
703 without also decrementing i, this corresponds to omitting these
704 lines in the new rows, i.e. rows are deleted. */
705 i = j = window_size;
177c0ea7 706
1af1b1e8
RS
707 while (i > 0 || j > 0)
708 {
89700111 709 p = cost_matrix + i * (window_size + 1) + j;
177c0ea7 710
89700111
GM
711 if (p->insertcost < p->writecost
712 && p->insertcost < p->deletecost
713 && (write_follows_p || i < j))
1af1b1e8 714 {
89700111
GM
715 /* Insert is cheaper than deleting or writing lines. Leave
716 a hole in the result display that will be filled with
717 empty lines when the queue is emptied. */
718 queue->count = 0;
719 queue->window = i;
720 queue->pos = i - p->insertcount;
721 ++queue;
177c0ea7 722
1af1b1e8 723 i -= p->insertcount;
89700111 724 write_follows_p = 0;
1af1b1e8 725 }
89700111
GM
726 else if (p->deletecost < p->writecost
727 && (write_follows_p || i > j))
1af1b1e8 728 {
89700111
GM
729 /* Deleting lines is cheaper. By decrementing J, omit
730 deletecount lines from the original. */
731 write_follows_p = 0;
1af1b1e8
RS
732 j -= p->deletecount;
733 }
734 else
735 {
89700111
GM
736 /* One or more lines should be written. In the direct
737 scrolling method we do this by scrolling the lines to the
738 place they belong. */
739 int n_to_write = p->writecount;
740 write_follows_p = 1;
177c0ea7 741 xassert (n_to_write > 0);
89700111 742
1af1b1e8
RS
743 if (i > j)
744 {
89700111 745 /* Immediately insert lines */
385ed61f 746 set_terminal_window (frame, i + unchanged_at_top);
89700111 747 terminal_window_p = 1;
385ed61f 748 ins_del_lines (frame, j - n_to_write + unchanged_at_top, i - j);
1af1b1e8
RS
749 }
750 else if (i < j)
751 {
89700111
GM
752 /* Queue the deletion of a group of lines */
753 queue->pos = i - n_to_write + unchanged_at_top;
754 queue->window = j + unchanged_at_top;
755 queue->count = i - j;
756 ++queue;
1af1b1e8
RS
757 }
758
89700111 759 while (n_to_write > 0)
1af1b1e8 760 {
89700111
GM
761 --i, --j, --n_to_write;
762 copy_from[i] = j;
763 retained_p[j] = 1;
1af1b1e8
RS
764 }
765 }
766 }
767
89700111
GM
768 /* Do queued operations. */
769 if (queue > queue_start)
1af1b1e8 770 {
89700111
GM
771 int next = -1;
772
773 do
1af1b1e8 774 {
89700111
GM
775 --queue;
776 if (queue->count)
777 {
385ed61f 778 set_terminal_window (frame, queue->window);
89700111 779 terminal_window_p = 1;
385ed61f 780 ins_del_lines (frame, queue->pos, queue->count);
89700111
GM
781 }
782 else
1af1b1e8 783 {
89700111
GM
784 for (j = queue->window - 1; j >= queue->pos; --j)
785 {
786 while (retained_p[++next])
787 ;
788 copy_from[j] = next;
789 }
1af1b1e8
RS
790 }
791 }
89700111 792 while (queue > queue_start);
1af1b1e8
RS
793 }
794
89700111
GM
795 /* Now, for each row I in the range of rows we are working on,
796 copy_from[i] gives the original line to copy to I, and
797 retained_p[copy_from[i]] is zero if line I in the new display is
798 empty. */
799 mirrored_line_dance (current_matrix, unchanged_at_top, window_size,
800 copy_from, retained_p);
801
802 if (terminal_window_p)
385ed61f 803 set_terminal_window (frame, 0);
1af1b1e8 804}
89700111
GM
805
806
1af1b1e8 807\f
632a8dd6 808void
0137dbf7 809scrolling_1 (frame, window_size, unchanged_at_top, unchanged_at_bottom,
1af1b1e8 810 draw_cost, old_draw_cost, old_hash, new_hash, free_at_end)
0137dbf7 811 FRAME_PTR frame;
632a8dd6
JB
812 int window_size, unchanged_at_top, unchanged_at_bottom;
813 int *draw_cost;
1af1b1e8 814 int *old_draw_cost;
632a8dd6
JB
815 int *old_hash;
816 int *new_hash;
817 int free_at_end;
818{
819 struct matrix_elt *matrix;
820 matrix = ((struct matrix_elt *)
821 alloca ((window_size + 1) * (window_size + 1) * sizeof *matrix));
822
daf01701 823 if (FRAME_SCROLL_REGION_OK (frame))
1af1b1e8
RS
824 {
825 calculate_direct_scrolling (frame, matrix, window_size,
826 unchanged_at_bottom,
177c0ea7 827 draw_cost, old_draw_cost,
1af1b1e8 828 old_hash, new_hash, free_at_end);
385ed61f 829 do_direct_scrolling (frame, frame->current_matrix,
89700111 830 matrix, window_size, unchanged_at_top);
1af1b1e8
RS
831 }
832 else
833 {
834 calculate_scrolling (frame, matrix, window_size, unchanged_at_bottom,
835 draw_cost, old_hash, new_hash,
836 free_at_end);
385ed61f
KL
837 do_scrolling (frame,
838 frame->current_matrix, matrix, window_size,
89700111 839 unchanged_at_top);
1af1b1e8 840 }
632a8dd6 841}
89700111
GM
842
843
632a8dd6 844\f
89700111
GM
845/* Return number of lines in common between current and desired frame
846 contents described to us only as vectors of hash codes OLDHASH and
847 NEWHASH. Consider only vpos range START to END (not including
848 END). Ignore short lines on the assumption that avoiding redrawing
849 such a line will have little weight. */
632a8dd6
JB
850
851int
971de7fb 852scrolling_max_lines_saved (int start, int end, int *oldhash, int *newhash, int *cost)
632a8dd6
JB
853{
854 struct { int hash; int count; } lines[01000];
855 register int i, h;
856 register int matchcount = 0;
857 int avg_length = 0;
858 int threshold;
859
860 /* Compute a threshold which is 1/4 of average length of these lines. */
861
862 for (i = start; i < end; i++)
863 avg_length += cost[i];
864
865 avg_length /= end - start;
866 threshold = avg_length / 4;
867
868 bzero (lines, sizeof lines);
869
89700111
GM
870 /* Put new lines' hash codes in hash table. Ignore lines shorter
871 than the threshold. Thus, if the lines that are in common are
872 mainly the ones that are short, they won't count. */
632a8dd6
JB
873 for (i = start; i < end; i++)
874 {
875 if (cost[i] > threshold)
876 {
877 h = newhash[i] & 0777;
878 lines[h].hash = newhash[i];
879 lines[h].count++;
880 }
881 }
882
89700111
GM
883 /* Look up old line hash codes in the hash table. Count number of
884 matches between old lines and new. */
632a8dd6
JB
885 for (i = start; i < end; i++)
886 {
887 h = oldhash[i] & 0777;
888 if (oldhash[i] == lines[h].hash)
889 {
890 matchcount++;
891 if (--lines[h].count == 0)
892 lines[h].hash = 0;
893 }
894 }
895
896 return matchcount;
897}
898\f
89700111
GM
899/* Return a measure of the cost of moving the lines starting with vpos
900 FROM, up to but not including vpos TO, down by AMOUNT lines (AMOUNT
901 may be negative). These are the same arguments that might be given
902 to scroll_frame_lines to perform this scrolling. */
632a8dd6 903
dfcf069d 904int
971de7fb 905scroll_cost (FRAME_PTR frame, int from, int to, int amount)
632a8dd6 906{
0137dbf7 907 /* Compute how many lines, at bottom of frame,
632a8dd6
JB
908 will not be involved in actual motion. */
909 int limit = to;
910 int offset;
9882535b 911 int height = FRAME_LINES (frame);
632a8dd6 912
632a8dd6
JB
913 if (amount == 0)
914 return 0;
915
daf01701 916 if (! FRAME_SCROLL_REGION_OK (frame))
3e2bea7c
JB
917 limit = height;
918 else if (amount > 0)
919 limit += amount;
920
632a8dd6
JB
921 if (amount < 0)
922 {
923 int temp = to;
924 to = from + amount;
925 from = temp + amount;
926 amount = - amount;
927 }
928
929 offset = height - limit;
930
931 return
0137dbf7
JB
932 (FRAME_INSERT_COST (frame)[offset + from]
933 + (amount - 1) * FRAME_INSERTN_COST (frame)[offset + from]
00eb4c4a
RS
934 + FRAME_DELETE_COST (frame)[offset + to]
935 + (amount - 1) * FRAME_DELETEN_COST (frame)[offset + to]);
632a8dd6
JB
936}
937\f
938/* Calculate the line insertion/deletion
939 overhead and multiply factor values */
940
941static void
971de7fb 942line_ins_del (FRAME_PTR frame, int ov1, int pf1, int ovn, int pfn, register int *ov, register int *mf)
632a8dd6
JB
943{
944 register int i;
9882535b 945 register int frame_lines = FRAME_LINES (frame);
632a8dd6
JB
946 register int insert_overhead = ov1 * 10;
947 register int next_insert_cost = ovn * 10;
948
9882535b 949 for (i = frame_lines-1; i >= 0; i--)
632a8dd6 950 {
326e0cf8 951 mf[i] = next_insert_cost / 10;
632a8dd6 952 next_insert_cost += pfn;
326e0cf8 953 ov[i] = (insert_overhead + next_insert_cost) / 10;
632a8dd6
JB
954 insert_overhead += pf1;
955 }
956}
957
958static void
0137dbf7 959ins_del_costs (frame,
632a8dd6
JB
960 one_line_string, multi_string,
961 setup_string, cleanup_string,
962 costvec, ncostvec, coefficient)
0137dbf7 963 FRAME_PTR frame;
632a8dd6
JB
964 char *one_line_string, *multi_string;
965 char *setup_string, *cleanup_string;
966 int *costvec, *ncostvec;
967 int coefficient;
968{
969 if (multi_string)
0137dbf7 970 line_ins_del (frame,
632a8dd6
JB
971 string_cost (multi_string) * coefficient,
972 per_line_cost (multi_string) * coefficient,
973 0, 0, costvec, ncostvec);
974 else if (one_line_string)
0137dbf7 975 line_ins_del (frame,
632a8dd6
JB
976 string_cost (setup_string) + string_cost (cleanup_string), 0,
977 string_cost (one_line_string),
978 per_line_cost (one_line_string),
979 costvec, ncostvec);
980 else
0137dbf7 981 line_ins_del (frame,
632a8dd6
JB
982 9999, 0, 9999, 0,
983 costvec, ncostvec);
984}
985
986/* Calculate the insert and delete line costs.
987 Note that this is done even when running with a window system
988 because we want to know how long scrolling takes (and avoid it).
0137dbf7 989 This must be redone whenever the frame height changes.
632a8dd6
JB
990
991 We keep the ID costs in a precomputed array based on the position
992 at which the I or D is performed. Also, there are two kinds of ID
993 costs: the "once-only" and the "repeated". This is to handle both
994 those terminals that are able to insert N lines at a time (once-
995 only) and those that must repeatedly insert one line.
996
997 The cost to insert N lines at line L is
9882535b
KS
998 [tt.t_ILov + (frame_lines + 1 - L) * tt.t_ILpf] +
999 N * [tt.t_ILnov + (frame_lines + 1 - L) * tt.t_ILnpf]
632a8dd6
JB
1000
1001 ILov represents the basic insert line overhead. ILpf is the padding
1002 required to allow the terminal time to move a line: insertion at line
9882535b 1003 L changes (frame_lines + 1 - L) lines.
632a8dd6
JB
1004
1005 The first bracketed expression above is the overhead; the second is
1006 the multiply factor. Both are dependent only on the position at
1007 which the insert is performed. We store the overhead in
0137dbf7
JB
1008 FRAME_INSERT_COST (frame) and the multiply factor in
1009 FRAME_INSERTN_COST (frame). Note however that any insertion
632a8dd6 1010 must include at least one multiply factor. Rather than compute this
0137dbf7
JB
1011 as FRAME_INSERT_COST (frame)[line]+FRAME_INSERTN_COST (frame)[line],
1012 we add FRAME_INSERTN_COST (frame) into FRAME_INSERT_COST (frame).
632a8dd6
JB
1013 This is reasonable because of the particular algorithm used in calcM.
1014
1015 Deletion is essentially the same as insertion.
1016 */
1017
dfcf069d 1018void
0137dbf7 1019do_line_insertion_deletion_costs (frame,
632a8dd6
JB
1020 ins_line_string, multi_ins_string,
1021 del_line_string, multi_del_string,
1022 setup_string, cleanup_string, coefficient)
0137dbf7 1023 FRAME_PTR frame;
632a8dd6
JB
1024 char *ins_line_string, *multi_ins_string;
1025 char *del_line_string, *multi_del_string;
1026 char *setup_string, *cleanup_string;
1027 int coefficient;
1028{
0137dbf7 1029 if (FRAME_INSERT_COST (frame) != 0)
632a8dd6 1030 {
0137dbf7
JB
1031 FRAME_INSERT_COST (frame) =
1032 (int *) xrealloc (FRAME_INSERT_COST (frame),
9882535b 1033 FRAME_LINES (frame) * sizeof (int));
0137dbf7
JB
1034 FRAME_DELETEN_COST (frame) =
1035 (int *) xrealloc (FRAME_DELETEN_COST (frame),
9882535b 1036 FRAME_LINES (frame) * sizeof (int));
0137dbf7
JB
1037 FRAME_INSERTN_COST (frame) =
1038 (int *) xrealloc (FRAME_INSERTN_COST (frame),
9882535b 1039 FRAME_LINES (frame) * sizeof (int));
0137dbf7
JB
1040 FRAME_DELETE_COST (frame) =
1041 (int *) xrealloc (FRAME_DELETE_COST (frame),
9882535b 1042 FRAME_LINES (frame) * sizeof (int));
632a8dd6
JB
1043 }
1044 else
1045 {
0137dbf7 1046 FRAME_INSERT_COST (frame) =
9882535b 1047 (int *) xmalloc (FRAME_LINES (frame) * sizeof (int));
0137dbf7 1048 FRAME_DELETEN_COST (frame) =
9882535b 1049 (int *) xmalloc (FRAME_LINES (frame) * sizeof (int));
0137dbf7 1050 FRAME_INSERTN_COST (frame) =
9882535b 1051 (int *) xmalloc (FRAME_LINES (frame) * sizeof (int));
177c0ea7 1052 FRAME_DELETE_COST (frame) =
9882535b 1053 (int *) xmalloc (FRAME_LINES (frame) * sizeof (int));
632a8dd6
JB
1054 }
1055
0137dbf7 1056 ins_del_costs (frame,
632a8dd6
JB
1057 ins_line_string, multi_ins_string,
1058 setup_string, cleanup_string,
0137dbf7 1059 FRAME_INSERT_COST (frame), FRAME_INSERTN_COST (frame),
632a8dd6 1060 coefficient);
0137dbf7 1061 ins_del_costs (frame,
632a8dd6
JB
1062 del_line_string, multi_del_string,
1063 setup_string, cleanup_string,
fd374ddc 1064 FRAME_DELETE_COST (frame), FRAME_DELETEN_COST (frame),
632a8dd6
JB
1065 coefficient);
1066}
ab5796a9
MB
1067
1068/* arch-tag: cdb7149c-48e7-4793-a948-2786c8e45485
1069 (do not change this comment) */