+ for (k = 0; k < window_size; ++k)
+ xassert (copy_from[k] >= 0 && copy_from[k] < window_size);
+
+ /* Perform the row swizzling. */
+ mirrored_line_dance (current_matrix, unchanged_at_top, window_size,
+ copy_from, retained_p);
+
+ /* Some sanity checks if GLYPH_DEBUG != 0. */
+ CHECK_MATRIX (current_matrix);
+
+ if (terminal_window_p)
+ set_terminal_window (0);
+}
+
+\f
+/* Determine, in matrix[i,j], the cost of updating the first j
+ old lines into the first i new lines using the direct
+ scrolling method. When the old line and the new line have
+ different hash codes, the calculated cost of updating old
+ line j into new line i includes the cost of outputting new
+ line i, and if i != j, the cost of outputting the old line j
+ is also included, as a penalty for moving the line and then
+ erasing it. In addition, the cost of updating a sequence of
+ lines with constant i - j includes the cost of scrolling the
+ old lines into their new positions, unless i == j. Scrolling
+ is achieved by setting the screen window to avoid affecting
+ other lines below, and inserting or deleting lines at the top
+ of the scrolled region. The cost of scrolling a sequence of
+ lines includes the fixed cost of specifying a scroll region,
+ plus a variable cost which can depend upon the number of lines
+ involved and the distance by which they are scrolled, and an
+ extra cost to discourage long scrolls.
+
+ As reflected in the matrix, an insert or delete does not
+ correspond directly to the insertion or deletion which is
+ used in scrolling lines. An insert means that the value of i
+ has increased without a corresponding increase in the value
+ of j. A delete means that the value of j has increased
+ without a corresponding increase in the value of i. A write
+ means that i and j are both increased by the same amount, and
+ that the old lines will be moved to their new positions.
+
+ An insert following a delete is allowed only if i > j.
+ A delete following an insert is allowed only if i < j.
+ These restrictions ensure that the new lines in an insert
+ will always be blank as an effect of the neighboring writes.
+ Thus the calculated cost of an insert is simply the cost of
+ outputting the new line contents. The direct cost of a
+ delete is zero. Inserts and deletes indirectly affect the
+ total cost through their influence on subsequent writes. */
+
+/* The vectors draw_cost, old_hash, and new_hash have the same
+ meanings here as in calculate_scrolling, and old_draw_cost
+ is the equivalent of draw_cost for the old line contents */
+
+static void
+calculate_direct_scrolling (frame, matrix, window_size, lines_below,
+ draw_cost, old_draw_cost, old_hash, new_hash,
+ free_at_end)
+ FRAME_PTR frame;
+ /* matrix is of size window_size + 1 on each side. */
+ struct matrix_elt *matrix;
+ int window_size;
+ int *draw_cost;
+ int *old_draw_cost;
+ int *old_hash;
+ int *new_hash;
+ int free_at_end;
+{
+ register int i, j;
+ int frame_height = FRAME_HEIGHT (frame);
+ register struct matrix_elt *p, *p1;
+ register int cost, cost1, delta;
+
+ /* first_insert_cost[-I] is the cost of doing the first insert-line
+ at a position I lines above the bottom line in the scroll window. */
+ int *first_insert_cost
+ = &FRAME_INSERT_COST (frame)[frame_height - 1];
+ int *first_delete_cost
+ = &FRAME_DELETE_COST (frame)[frame_height - 1];
+ int *next_insert_cost
+ = &FRAME_INSERTN_COST (frame)[frame_height - 1];
+ int *next_delete_cost
+ = &FRAME_DELETEN_COST (frame)[frame_height - 1];
+
+ int scroll_overhead;
+
+ /* Discourage long scrolls on fast lines.
+ Don't scroll nearly a full frame height unless it saves
+ at least 1/4 second. */
+ int extra_cost = baud_rate / (10 * 4 * FRAME_HEIGHT (frame));
+
+ if (baud_rate <= 0)
+ extra_cost = 1;
+
+ /* Overhead of setting the scroll window, plus the extra cost
+ cost of scrolling by a distance of one. The extra cost is
+ added once for consistency with the cost vectors */
+ scroll_overhead = scroll_region_cost + extra_cost;
+
+ /* initialize the top left corner of the matrix */
+ matrix->writecost = 0;
+ matrix->insertcost = INFINITY;
+ matrix->deletecost = INFINITY;
+ matrix->writecount = 0;
+ matrix->insertcount = 0;
+ matrix->deletecount = 0;
+
+ /* initialize the left edge of the matrix */
+ cost = 0;
+ for (i = 1; i <= window_size; i++)
+ {
+ p = matrix + i * (window_size + 1);
+ cost += draw_cost[i];
+ p->insertcost = cost;
+ p->writecost = INFINITY;
+ p->deletecost = INFINITY;
+ p->insertcount = i;
+ p->writecount = 0;
+ p->deletecount = 0;
+ }
+
+ /* initialize the top edge of the matrix */
+ for (j = 1; j <= window_size; j++)
+ {
+ matrix[j].deletecost = 0;
+ matrix[j].writecost = INFINITY;
+ matrix[j].insertcost = INFINITY;
+ matrix[j].deletecount = j;
+ matrix[j].writecount = 0;
+ matrix[j].insertcount = 0;
+ }
+
+ /* `i' represents the vpos among new frame contents.
+ `j' represents the vpos among the old frame contents. */
+ p = matrix + window_size + 2; /* matrix [1, 1] */
+
+ for (i = 1; i <= window_size; i++, p++)
+ for (j = 1; j <= window_size; j++, p++)
+ {
+ /* p contains the address of matrix [i, j] */
+
+ /* First calculate the cost assuming we do
+ not insert or delete above this line.
+ That is, if we update through line i-1
+ based on old lines through j-1,
+ and then just change old line j to new line i.
+
+ Depending on which choice gives the lower cost,
+ this usually involves either scrolling a single line
+ or extending a sequence of scrolled lines, but
+ when i == j, no scrolling is required. */
+ p1 = p - window_size - 2; /* matrix [i-1, j-1] */
+ cost = p1->insertcost;
+ if (cost > p1->deletecost)
+ cost = p1->deletecost;
+ cost1 = p1->writecost;
+ if (i == j)
+ {
+ if (cost > cost1)
+ {
+ cost = cost1;
+ p->writecount = p1->writecount + 1;
+ }
+ else
+ p->writecount = 1;
+ if (old_hash[j] != new_hash[i])
+ {
+ cost += draw_cost[i];
+ }
+ }
+ else
+ {
+ if (i > j)
+ {
+ delta = i - j;
+
+ /* The cost added here for scrolling the first line by
+ a distance N includes the overhead of setting the
+ scroll window, the cost of inserting N lines at a
+ position N lines above the bottom line of the window,
+ and an extra cost which is proportional to N. */
+ cost += scroll_overhead + first_insert_cost[-delta] +
+ (delta-1) * (next_insert_cost[-delta] + extra_cost);
+
+ /* In the most general case, the insertion overhead and
+ the multiply factor can grow linearly as the distance
+ from the bottom of the window increases. The incremental
+ cost of scrolling an additional line depends upon the
+ rate of change of these two parameters. Each of these
+ growth rates can be determined by a simple difference.
+ To reduce the cumulative effects of rounding error, we
+ vary the position at which the difference is computed. */
+ cost1 += first_insert_cost[-j] - first_insert_cost[1-j] +
+ (delta-1) * (next_insert_cost[-j] - next_insert_cost[1-j]);
+ }
+ else
+ {
+ delta = j - i;
+ cost += scroll_overhead + first_delete_cost[-delta] +
+ (delta-1) * (next_delete_cost[-delta] + extra_cost);
+ cost1 += first_delete_cost[-i] - first_delete_cost[1-i] +
+ (delta-1) * ( next_delete_cost[-i] - next_delete_cost[1-i]);
+ }
+ if (cost1 < cost)
+ {
+ cost = cost1;
+ p->writecount = p1->writecount + 1;
+ }
+ else
+ p->writecount = 1;
+ if (old_hash[j] != new_hash[i])
+ {
+ cost += draw_cost[i] + old_draw_cost[j];
+ }
+ }
+ p->writecost = cost;
+
+ /* Calculate the cost if we do an insert-line
+ before outputting this line.
+ That is, we update through line i-1
+ based on old lines through j,
+ do an insert-line on line i,
+ and then output line i from scratch,
+ leaving old lines starting from j for reuse below. */
+ p1 = p - window_size - 1; /* matrix [i-1, j] */
+ cost = p1->writecost;
+ /* If i > j, an insert is allowed after a delete. */
+ if (i > j && p1->deletecost < cost)
+ cost = p1->deletecost;
+ if (p1->insertcost <= cost)
+ {
+ cost = p1->insertcost;
+ p->insertcount = p1->insertcount + 1;
+ }
+ else
+ p->insertcount = 1;
+ cost += draw_cost[i];
+ p->insertcost = cost;
+
+ /* Calculate the cost if we do a delete line after
+ outputting this line.
+ That is, we update through line i
+ based on old lines through j-1,
+ and throw away old line j. */
+ p1 = p - 1; /* matrix [i, j-1] */
+ cost = p1->writecost;
+ /* If i < j, a delete is allowed after an insert. */
+ if (i < j && p1->insertcost < cost)
+ cost = p1->insertcost;
+ cost1 = p1->deletecost;
+ if (p1->deletecost <= cost)
+ {
+ cost = p1->deletecost;
+ p->deletecount = p1->deletecount + 1;
+ }
+ else
+ p->deletecount = 1;
+ p->deletecost = cost;
+ }
+}
+