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