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.
5 This file is part of GNU Emacs.
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.
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.
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/>. */
26 #include "dispextern.h"
30 #include "termhooks.h"
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. */
36 #define INFINITY 1000000
40 /* Cost of outputting through this line
41 if no insert/delete is done just above it. */
43 /* Cost of outputting through this line
44 if an insert is done just above it. */
46 /* Cost of outputting through this line
47 if a delete is done just above it. */
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
;
60 static void do_direct_scrolling
P_ ((struct frame
*,
61 struct glyph_matrix
*,
64 static void do_scrolling
P_ ((struct frame
*,
65 struct glyph_matrix
*,
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. */
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. */
88 calculate_scrolling (frame
, matrix
, window_size
, lines_below
,
89 draw_cost
, old_hash
, new_hash
,
92 /* matrix is of size window_size + 1 on each side. */
93 struct matrix_elt
*matrix
;
94 int window_size
, lines_below
;
101 int frame_lines
= FRAME_LINES (frame
);
102 register struct matrix_elt
*p
, *p1
;
103 register int cost
, cost1
;
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
];
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
));
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;
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
++)
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
;
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
++)
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;
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
++)
165 /* p contains the address of matrix [i, j] */
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
];
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
)
195 cost
= p1
->writecost
;
196 cost1
= p1
->insertcost
;
200 cost
= p1
->writecost
+ first_insert_cost
[i
];
201 if ((int) p1
->insertcount
> i
)
203 cost1
= p1
->insertcost
+ next_insert_cost
[i
- p1
->insertcount
];
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
)
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
)
220 cost
= p1
->writecost
;
221 cost1
= p1
->deletecost
;
225 cost
= p1
->writecost
+ first_delete_cost
[i
];
226 cost1
= p1
->deletecost
+ next_delete_cost
[i
];
228 p
->deletecost
= min (cost
, cost1
);
229 p
->deletecount
= (cost
< cost1
) ? 1 : p1
->deletecount
+ 1;
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).
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
246 do_scrolling (frame
, current_matrix
, matrix
, window_size
, unchanged_at_top
)
248 struct glyph_matrix
*current_matrix
;
249 struct matrix_elt
*matrix
;
251 int unchanged_at_top
;
253 struct matrix_elt
*p
;
256 /* Set to 1 if we have set a terminal window with
257 set_terminal_window. */
258 int terminal_window_p
= 0;
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
;
266 char *retained_p
= (char *) alloca (window_size
* sizeof (char));
267 int *copy_from
= (int *) alloca (window_size
* sizeof (int));
269 /* Zero means line is empty. */
270 bzero (retained_p
, window_size
* sizeof (char));
271 for (k
= 0; k
< window_size
; ++k
)
274 #define CHECK_BOUNDS \
278 for (k = 0; k < window_size; ++k) \
279 xassert (copy_from[k] == -1 \
280 || (copy_from[k] >= 0 && copy_from[k] < window_size)); \
284 /* When j is advanced, this corresponds to deleted lines.
285 When i is advanced, this corresponds to inserted lines. */
287 while (i
> 0 || j
> 0)
289 p
= matrix
+ i
* (window_size
+ 1) + j
;
291 if (p
->insertcost
< p
->writecost
&& p
->insertcost
< p
->deletecost
)
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
;
299 /* By incrementing I, we leave room in the result rows
300 for the empty rows opened up. */
303 else if (p
->deletecost
< p
->writecost
)
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. */
311 /* Set the terminal window, if not done already. */
312 if (! terminal_window_p
)
314 set_terminal_window (frame
, window_size
+ unchanged_at_top
);
315 terminal_window_p
= 1;
318 /* Delete lines on the terminal. */
319 ins_del_lines (frame
, j
+ unchanged_at_top
, - p
->deletecount
);
323 /* Best thing done here is no insert or delete, i.e. a write. */
325 xassert (i
>= 0 && i
< window_size
);
326 xassert (j
>= 0 && j
< window_size
);
336 /* Now do all insertions queued above. */
337 if (queue
> queue_start
)
341 /* Set the terminal window if not yet done. */
342 if (!terminal_window_p
)
344 set_terminal_window (frame
, window_size
+ unchanged_at_top
);
345 terminal_window_p
= 1;
352 /* Do the deletion on the terminal. */
353 ins_del_lines (frame
, queue
->pos
, queue
->count
);
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
)
362 /* Find the next row not retained. */
363 while (retained_p
[++next
])
366 /* Record that this row is to be used for the empty
368 copy_from
[k
+ j
] = next
;
371 while (queue
> queue_start
);
375 for (k
= 0; k
< window_size
; ++k
)
376 xassert (copy_from
[k
] >= 0 && copy_from
[k
] < window_size
);
378 /* Perform the row swizzling. */
379 mirrored_line_dance (current_matrix
, unchanged_at_top
, window_size
,
380 copy_from
, retained_p
);
382 /* Some sanity checks if GLYPH_DEBUG != 0. */
383 CHECK_MATRIX (current_matrix
);
385 if (terminal_window_p
)
386 set_terminal_window (frame
, 0);
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.
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.
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. */
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 */
431 calculate_direct_scrolling (frame
, matrix
, window_size
, lines_below
,
432 draw_cost
, old_draw_cost
, old_hash
, new_hash
,
435 /* matrix is of size window_size + 1 on each side. */
436 struct matrix_elt
*matrix
;
437 int window_size
, lines_below
;
445 int frame_lines
= FRAME_LINES (frame
);
446 register struct matrix_elt
*p
, *p1
;
447 register int cost
, cost1
, delta
;
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];
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
));
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 */
474 = FRAME_SCROLL_REGION_COST (frame
) + extra_cost
;
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;
484 /* initialize the left edge of the matrix */
486 for (i
= 1; i
<= window_size
; i
++)
488 p
= matrix
+ i
* (window_size
+ 1);
489 cost
+= draw_cost
[i
];
490 p
->insertcost
= cost
;
491 p
->writecost
= INFINITY
;
492 p
->deletecost
= INFINITY
;
498 /* initialize the top edge of the matrix */
499 for (j
= 1; j
<= window_size
; j
++)
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;
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] */
513 for (i
= 1; i
<= window_size
; i
++, p
++)
514 for (j
= 1; j
<= window_size
; j
++, p
++)
516 /* p contains the address of matrix [i, j] */
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.
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
;
538 p
->writecount
= p1
->writecount
+ 1;
542 if (old_hash
[j
] != new_hash
[i
])
544 cost
+= draw_cost
[i
];
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
);
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
]);
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
]);
583 p
->writecount
= p1
->writecount
+ 1;
587 if (old_hash
[j
] != new_hash
[i
])
589 cost
+= draw_cost
[i
] + old_draw_cost
[j
];
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
)
608 cost
= p1
->insertcost
;
609 p
->insertcount
= p1
->insertcount
+ 1;
613 cost
+= draw_cost
[i
];
614 p
->insertcost
= cost
;
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
)
629 cost
= p1
->deletecost
;
630 p
->deletecount
= p1
->deletecount
+ 1;
634 p
->deletecost
= cost
;
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
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
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. */
657 do_direct_scrolling (frame
, current_matrix
, cost_matrix
,
658 window_size
, unchanged_at_top
)
660 struct glyph_matrix
*current_matrix
;
661 struct matrix_elt
*cost_matrix
;
663 int unchanged_at_top
;
665 struct matrix_elt
*p
;
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
;
674 /* Set to 1 if a terminal window has been set with
675 set_terminal_window: */
676 int terminal_window_p
= 0;
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;
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));
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));
694 bzero (retained_p
, window_size
* sizeof (char));
696 /* Perform some sanity checks when GLYPH_DEBUG is on. */
697 CHECK_MATRIX (current_matrix
);
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.
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. */
711 while (i
> 0 || j
> 0)
713 p
= cost_matrix
+ i
* (window_size
+ 1) + j
;
715 if (p
->insertcost
< p
->writecost
716 && p
->insertcost
< p
->deletecost
717 && (write_follows_p
|| i
< j
))
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. */
724 queue
->pos
= i
- p
->insertcount
;
730 else if (p
->deletecost
< p
->writecost
731 && (write_follows_p
|| i
> j
))
733 /* Deleting lines is cheaper. By decrementing J, omit
734 deletecount lines from the original. */
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
;
745 xassert (n_to_write
> 0);
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
);
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
;
763 while (n_to_write
> 0)
765 --i
, --j
, --n_to_write
;
772 /* Do queued operations. */
773 if (queue
> queue_start
)
782 set_terminal_window (frame
, queue
->window
);
783 terminal_window_p
= 1;
784 ins_del_lines (frame
, queue
->pos
, queue
->count
);
788 for (j
= queue
->window
- 1; j
>= queue
->pos
; --j
)
790 while (retained_p
[++next
])
796 while (queue
> queue_start
);
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
803 mirrored_line_dance (current_matrix
, unchanged_at_top
, window_size
,
804 copy_from
, retained_p
);
806 if (terminal_window_p
)
807 set_terminal_window (frame
, 0);
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
)
816 int window_size
, unchanged_at_top
, unchanged_at_bottom
;
823 struct matrix_elt
*matrix
;
824 matrix
= ((struct matrix_elt
*)
825 alloca ((window_size
+ 1) * (window_size
+ 1) * sizeof *matrix
));
827 if (FRAME_SCROLL_REGION_OK (frame
))
829 calculate_direct_scrolling (frame
, matrix
, window_size
,
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
);
838 calculate_scrolling (frame
, matrix
, window_size
, unchanged_at_bottom
,
839 draw_cost
, old_hash
, new_hash
,
842 frame
->current_matrix
, matrix
, window_size
,
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. */
856 scrolling_max_lines_saved (start
, end
, oldhash
, newhash
, cost
)
858 int *oldhash
, *newhash
, *cost
;
860 struct { int hash
; int count
; } lines
[01000];
862 register int matchcount
= 0;
866 /* Compute a threshold which is 1/4 of average length of these lines. */
868 for (i
= start
; i
< end
; i
++)
869 avg_length
+= cost
[i
];
871 avg_length
/= end
- start
;
872 threshold
= avg_length
/ 4;
874 bzero (lines
, sizeof lines
);
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
++)
881 if (cost
[i
] > threshold
)
883 h
= newhash
[i
] & 0777;
884 lines
[h
].hash
= newhash
[i
];
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
++)
893 h
= oldhash
[i
] & 0777;
894 if (oldhash
[i
] == lines
[h
].hash
)
897 if (--lines
[h
].count
== 0)
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. */
911 scroll_cost (frame
, from
, to
, amount
)
913 int from
, to
, amount
;
915 /* Compute how many lines, at bottom of frame,
916 will not be involved in actual motion. */
919 int height
= FRAME_LINES (frame
);
924 if (! FRAME_SCROLL_REGION_OK (frame
))
933 from
= temp
+ amount
;
937 offset
= height
- limit
;
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
]);
946 /* Calculate the line insertion/deletion
947 overhead and multiply factor values */
950 line_ins_del (frame
, ov1
, pf1
, ovn
, pfn
, ov
, mf
)
954 register int *ov
, *mf
;
957 register int frame_lines
= FRAME_LINES (frame
);
958 register int insert_overhead
= ov1
* 10;
959 register int next_insert_cost
= ovn
* 10;
961 for (i
= frame_lines
-1; i
>= 0; i
--)
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
;
971 ins_del_costs (frame
,
972 one_line_string
, multi_string
,
973 setup_string
, cleanup_string
,
974 costvec
, ncostvec
, coefficient
)
976 char *one_line_string
, *multi_string
;
977 char *setup_string
, *cleanup_string
;
978 int *costvec
, *ncostvec
;
983 string_cost (multi_string
) * coefficient
,
984 per_line_cost (multi_string
) * coefficient
,
985 0, 0, costvec
, ncostvec
);
986 else if (one_line_string
)
988 string_cost (setup_string
) + string_cost (cleanup_string
), 0,
989 string_cost (one_line_string
),
990 per_line_cost (one_line_string
),
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.
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.
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]
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.
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.
1027 Deletion is essentially the same as insertion.
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
)
1036 char *ins_line_string
, *multi_ins_string
;
1037 char *del_line_string
, *multi_del_string
;
1038 char *setup_string
, *cleanup_string
;
1041 if (FRAME_INSERT_COST (frame
) != 0)
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));
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));
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
),
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
),
1080 /* arch-tag: cdb7149c-48e7-4793-a948-2786c8e45485
1081 (do not change this comment) */