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