diff options
Diffstat (limited to 'src/scroll.c')
-rw-r--r-- | src/scroll.c | 389 |
1 files changed, 145 insertions, 244 deletions
diff --git a/src/scroll.c b/src/scroll.c index df40d33c5e5..9e776f91c55 100644 --- a/src/scroll.c +++ b/src/scroll.c @@ -1,4 +1,4 @@ -/* Calculate what line insertion or deletion to do, and do it, +/* Calculate what ins/del line to do, and do it, for Emacs redisplay. Copyright (C) 1985, 1986, 1990 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -18,34 +18,26 @@ along with GNU Emacs; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include <stdio.h> #include "config.h" #include "termchar.h" -#include "lisp.h" +#include "termhooks.h" #include "dispextern.h" -#include "screen.h" - -extern struct display_line **ophys_lines; #define max(a, b) ((a) > (b) ? (a) : (b)) #define min(a, b) ((a) < (b) ? (a) : (b)) -/* All costs measured in characters. - So no cost can exceed the area of a screen, measured in characters. - Let's hope this is never more than 15000 characters. */ - -#define INFINITY 15000 - struct matrix_elt { /* Cost of outputting through this line if no insert/delete is done just above it. */ - short writecost; + int writecost; /* Cost of outputting through this line if an insert is done just above it. */ - short insertcost; + int insertcost; /* Cost of outputting through this line if a delete is done just above it. */ - short deletecost; + int deletecost; /* Number of inserts so far in this run of inserts, for the cost in insertcost. */ char insertcount; @@ -54,15 +46,32 @@ struct matrix_elt char deletecount; }; -/* See do_line_insertion_deletion_costs for info on these arrays. */ +/* This exceeds the sum of any reasonable number of INFINITY's. */ +#define SUPER_INFINITY (1000 * INFINITY) -#ifndef MULTI_SCREEN -static int *insert_line_cost; -static int *delete_line_cost; -static int *insert_n_lines_cost; -static int *delete_n_lines_cost; -#endif +/* See CalcIDCosts for on the arrays below */ +int *ILcost; +int *DLcost; +int *ILncost; +int *DLncost; + +scrolling_1 (window_size, unchanged_at_top, unchanged_at_bottom, + draw_cost, old_hash, new_hash, free_at_end) + int window_size, unchanged_at_top, unchanged_at_bottom; + int *draw_cost; + int *old_hash; + int *new_hash; + int free_at_end; +{ + struct matrix_elt *matrix; + matrix = ((struct matrix_elt *) + alloca ((window_size + 1) * (window_size + 1) * sizeof *matrix)); + calculate_scrolling (matrix, window_size, unchanged_at_bottom, + draw_cost, old_hash, new_hash, + free_at_end); + do_scrolling (matrix, window_size, unchanged_at_top); +} /* Determine, in matrix[i,j], the cost of updating the first j old lines into the first i new lines. @@ -81,11 +90,9 @@ static int *delete_n_lines_cost; to the place at which the first mismatch between old and new contents appears. */ -static void -calculate_scrolling (screen, matrix, window_size, lines_below, +calculate_scrolling (matrix, window_size, lines_below, draw_cost, old_hash, new_hash, free_at_end) - SCREEN_PTR screen; /* matrix is of size window_size + 1 on each side. */ struct matrix_elt *matrix; int window_size; @@ -95,32 +102,21 @@ calculate_scrolling (screen, matrix, window_size, lines_below, int free_at_end; { register int i, j; - int screen_height = SCREEN_HEIGHT (screen); register struct matrix_elt *p, *p1; register int cost, cost1; int lines_moved = window_size + (scroll_region_ok ? 0 : lines_below); - /* first_insert_cost[I] is the cost of doing the first insert-line - at the I'th line of the lines we are considering, - where I is origin 1 (as it is below). */ - int *first_insert_cost - = &SCREEN_INSERT_COST (screen)[screen_height - 1 - lines_moved]; - int *first_delete_cost - = &SCREEN_DELETE_COST (screen)[screen_height - 1 - lines_moved]; - int *next_insert_cost - = &SCREEN_INSERTN_COST (screen)[screen_height - 1 - lines_moved]; - int *next_delete_cost - = &SCREEN_DELETEN_COST (screen)[screen_height - 1 - lines_moved]; - - /* Discourage long scrolls on fast lines. - Don't scroll nearly a full screen height unless it saves - at least 1/4 second. */ - int extra_cost = baud_rate / (10 * 4 * SCREEN_HEIGHT (screen)); + /* We subtract 1 to compensate for the fact that i and j have values + starting with 1. */ + int *first_insert_cost = &ILcost[screen_height - lines_moved - 1]; + int *first_delete_cost = &DLcost[screen_height - lines_moved - 1]; + int *next_insert_cost = &ILncost[screen_height - lines_moved - 1]; + int *next_delete_cost = &DLncost[screen_height - lines_moved - 1]; /* initialize the top left corner of the matrix */ matrix->writecost = 0; - matrix->insertcost = INFINITY; - matrix->deletecost = INFINITY; + matrix->insertcost = SUPER_INFINITY; + matrix->deletecost = SUPER_INFINITY; matrix->insertcount = 0; matrix->deletecount = 0; @@ -129,10 +125,10 @@ calculate_scrolling (screen, matrix, window_size, lines_below, for (i = 1; i <= window_size; i++) { p = matrix + i * (window_size + 1); - cost += draw_cost[i] + next_insert_cost[i] + extra_cost; + cost += draw_cost[i] + next_insert_cost[i]; p->insertcost = cost; - p->writecost = INFINITY; - p->deletecost = INFINITY; + p->writecost = SUPER_INFINITY; + p->deletecost = SUPER_INFINITY; p->insertcount = i; p->deletecount = 0; } @@ -143,8 +139,8 @@ calculate_scrolling (screen, matrix, window_size, lines_below, { cost += next_delete_cost[j]; matrix[j].deletecost = cost; - matrix[j].writecost = INFINITY; - matrix[j].insertcost = INFINITY; + matrix[j].writecost = SUPER_INFINITY; + matrix[j].insertcost = SUPER_INFINITY; matrix[j].deletecount = j; matrix[j].insertcount = 0; } @@ -195,7 +191,7 @@ calculate_scrolling (screen, matrix, window_size, lines_below, abort (); cost1 = p1->insertcost + next_insert_cost[i - p1->insertcount]; } - p->insertcost = min (cost, cost1) + draw_cost[i] + extra_cost; + p->insertcost = min (cost, cost1) + draw_cost[i]; p->insertcount = (cost < cost1) ? 1 : p1->insertcount + 1; if (p->insertcount > i) abort (); @@ -225,19 +221,15 @@ calculate_scrolling (screen, matrix, window_size, lines_below, /* Perform insert-lines and delete-lines operations according to the costs in the matrix. - Updates the contents of the screen to record what was done. */ + Updates the contents of current_screen to record what was done. */ -static void -do_scrolling (screen, matrix, window_size, unchanged_at_top) - SCREEN_PTR screen; +do_scrolling (matrix, window_size, unchanged_at_top) struct matrix_elt *matrix; int window_size; int unchanged_at_top; { register struct matrix_elt *p; register int i, j; - register struct screen_glyphs *current_screen; - register struct screen_glyphs *temp_screen; struct queue { int count, pos; } *queue; int offset = unchanged_at_top; int qi = 0; @@ -245,39 +237,18 @@ do_scrolling (screen, matrix, window_size, unchanged_at_top) register int tem; int next; - queue = (struct queue *) alloca (SCREEN_HEIGHT (screen) - * sizeof (struct queue)); - - current_screen = SCREEN_CURRENT_GLYPHS (screen); - temp_screen = SCREEN_TEMP_GLYPHS (screen); + queue = (struct queue *) alloca (screen_height * sizeof (struct queue)); - bcopy (current_screen->glyphs, temp_screen->glyphs, - current_screen->height * sizeof (GLYPH *)); + bcopy (current_screen->contents, temp_screen->contents, + current_screen->height * sizeof (char *)); bcopy (current_screen->used, temp_screen->used, current_screen->height * sizeof (int)); bcopy (current_screen->highlight, temp_screen->highlight, - current_screen->height * sizeof (char)); - bzero (temp_screen->enable, temp_screen->height * sizeof (char)); - bcopy (current_screen->bufp, temp_screen->bufp, - current_screen->height * sizeof (int)); + current_screen->height); + bzero (temp_screen->enable, temp_screen->height); -#ifdef HAVE_X_WINDOWS - if (SCREEN_IS_X (screen)) - { - bcopy (current_screen->nruns, temp_screen->nruns, - current_screen->height * sizeof (int)); - bcopy (current_screen->face_list, temp_screen->face_list, - current_screen->height * sizeof (struct run *)); - bcopy (current_screen->top_left_x, temp_screen->top_left_x, - current_screen->height * sizeof (short)); - bcopy (current_screen->top_left_y, temp_screen->top_left_y, - current_screen->height * sizeof (short)); - bcopy (current_screen->pix_width, temp_screen->pix_width, - current_screen->height * sizeof (short)); - bcopy (current_screen->pix_height, temp_screen->pix_height, - current_screen->height * sizeof (short)); - } -#endif +/* First do all deletions of lines; queue up insertions. + Also move lines to correct slots in current_screen. */ i = j = window_size; @@ -308,8 +279,8 @@ do_scrolling (screen, matrix, window_size, unchanged_at_top) { /* Best thing done here is no insert or delete */ /* Old line at vpos j-1 ends up at vpos i-1 */ - current_screen->glyphs[i + offset - 1] - = temp_screen->glyphs[j + offset - 1]; + current_screen->contents[i + offset - 1] + = temp_screen->contents[j + offset - 1]; current_screen->used[i + offset - 1] = temp_screen->used[j + offset - 1]; current_screen->highlight[i + offset - 1] @@ -333,18 +304,16 @@ do_scrolling (screen, matrix, window_size, unchanged_at_top) for (i = qi - 1; i >= 0; i--) { ins_del_lines (queue[i].pos, queue[i].count); - /* Mark the inserted lines as clear, and put into them the line-contents strings that were discarded during the deletions. Those are the ones for which temp_screen->enable was not set. */ tem = queue[i].pos; - for (j = tem + queue[i].count - 1; j > tem; j--) + for (j = tem + queue[i].count - 1; j >= tem; j--) { current_screen->enable[j] = 0; - while (temp_screen->enable[next]) - next++; - current_screen->glyphs[j] = temp_screen->glyphs[next++]; + while (temp_screen->enable[next]) next++; + current_screen->contents[j] = temp_screen->contents[next++]; } } @@ -352,30 +321,10 @@ do_scrolling (screen, matrix, window_size, unchanged_at_top) set_terminal_window (0); } -void -scrolling_1 (screen, window_size, unchanged_at_top, unchanged_at_bottom, - draw_cost, old_hash, new_hash, free_at_end) - SCREEN_PTR screen; - int window_size, unchanged_at_top, unchanged_at_bottom; - int *draw_cost; - int *old_hash; - int *new_hash; - int free_at_end; -{ - struct matrix_elt *matrix; - matrix = ((struct matrix_elt *) - alloca ((window_size + 1) * (window_size + 1) * sizeof *matrix)); - - calculate_scrolling (screen, matrix, window_size, unchanged_at_bottom, - draw_cost, old_hash, new_hash, - free_at_end); - do_scrolling (screen, matrix, window_size, unchanged_at_top); -} - -/* Return number of lines in common between current and desired screen contents - described to us only as vectors of hash codes OLDHASH and NEWHASH. - Consider only vpos range START to END (not including END). - Ignore short lines on the assumption that +/* Return number of lines in common between current screen contents + and the text to be displayed, + considering only vpos range START to END (not including END). + Ignores short lines (length < 20) on the assumption that avoiding redrawing such a line will have little weight. */ int @@ -386,27 +335,13 @@ scrolling_max_lines_saved (start, end, oldhash, newhash, cost) struct { int hash; int count; } lines[01000]; register int i, h; register int matchcount = 0; - int avg_length = 0; - int threshold; - - /* Compute a threshold which is 1/4 of average length of these lines. */ - - for (i = start; i < end; i++) - avg_length += cost[i]; - - avg_length /= end - start; - threshold = avg_length / 4; bzero (lines, sizeof lines); - /* Put new lines' hash codes in hash table. - Ignore lines shorter than the threshold. - Thus, if the lines that are in common - are mainly the ones that are short, - they won't count. */ + /* Put new lines' hash codes in hash table. */ for (i = start; i < end; i++) { - if (cost[i] > threshold) + if (cost[i] > 20) { h = newhash[i] & 0777; lines[h].hash = newhash[i]; @@ -437,20 +372,14 @@ scrolling_max_lines_saved (start, end, oldhash, newhash, cost) These are the same arguments that might be given to scroll_screen_lines to perform this scrolling. */ -scroll_cost (screen, from, to, amount) - SCREEN_PTR screen; +scroll_cost (from, to, amount) int from, to, amount; { /* Compute how many lines, at bottom of screen, will not be involved in actual motion. */ - int limit = to; - int offset; - int height = SCREEN_HEIGHT (screen); - - if (amount > 0) - limit += amount; - if (! scroll_region_ok) - limit = height; + int ok_below = screen_height - to; + if (amount > 0) ok_below -= amount; + if (! scroll_region_ok) ok_below = 0; if (amount == 0) return 0; @@ -463,71 +392,14 @@ scroll_cost (screen, from, to, amount) amount = - amount; } - offset = height - limit; + from += ok_below; + to += ok_below; - return - (SCREEN_INSERT_COST (screen)[offset + from] - + (amount - 1) * SCREEN_INSERTN_COST (screen)[offset + from] - + SCREEN_DELETEN_COST (screen)[offset + to] - + (amount - 1) * SCREEN_DELETE_COST (screen)[offset + to]); + return (ILcost[from] + (amount - 1) * ILncost[from] + + DLcost[to] + (amount - 1) * DLncost[to]); } -/* Calculate the line insertion/deletion - overhead and multiply factor values */ - -static void -line_ins_del (screen, ov1, pf1, ovn, pfn, ov, mf) - SCREEN_PTR screen; - int ov1, ovn; - int pf1, pfn; - register int *ov, *mf; -{ - register int i; - register int screen_height = SCREEN_HEIGHT (screen); - register int insert_overhead = ov1 * 10; - register int next_insert_cost = ovn * 10; - - for (i = 0; i <= screen_height; i++) - { - mf[screen_height - i] = next_insert_cost / 10; - next_insert_cost += pfn; - ov[screen_height - i] = (insert_overhead + next_insert_cost) / 10; - insert_overhead += pf1; - } -} - -static void -ins_del_costs (screen, - one_line_string, multi_string, - setup_string, cleanup_string, - costvec, ncostvec, coefficient) - SCREEN_PTR screen; - char *one_line_string, *multi_string; - char *setup_string, *cleanup_string; - int *costvec, *ncostvec; - int coefficient; -{ - if (multi_string) - line_ins_del (screen, - string_cost (multi_string) * coefficient, - per_line_cost (multi_string) * coefficient, - 0, 0, costvec, ncostvec); - else if (one_line_string) - line_ins_del (screen, - string_cost (setup_string) + string_cost (cleanup_string), 0, - string_cost (one_line_string), - per_line_cost (one_line_string), - costvec, ncostvec); - else - line_ins_del (screen, - 9999, 0, 9999, 0, - costvec, ncostvec); -} - /* Calculate the insert and delete line costs. - Note that this is done even when running with a window system - because we want to know how long scrolling takes (and avoid it). - This must be redone whenever the screen height changes. We keep the ID costs in a precomputed array based on the position at which the I or D is performed. Also, there are two kinds of ID @@ -545,62 +417,91 @@ ins_del_costs (screen, The first bracketed expression above is the overhead; the second is the multiply factor. Both are dependent only on the position at - which the insert is performed. We store the overhead in - SCREEN_INSERT_COST (screen) and the multiply factor in - SCREEN_INSERTN_COST (screen). Note however that any insertion + which the insert is performed. We store the overhead in ILcost and + the multiply factor in ILncost. Note however that any insertion must include at least one multiply factor. Rather than compute this - as SCREEN_INSERT_COST (screen)[line]+SCREEN_INSERTN_COST (screen)[line], - we add SCREEN_INSERTN_COST (screen) into SCREEN_INSERT_COST (screen). - This is reasonable because of the particular algorithm used in calcM. + as ILcost[line]+ILncost[line], we add ILncost into ILcost. This is + reasonable because of the particular algorithm used in calcM. Deletion is essentially the same as insertion. */ -do_line_insertion_deletion_costs (screen, - ins_line_string, multi_ins_string, - del_line_string, multi_del_string, - setup_string, cleanup_string, coefficient) - SCREEN_PTR screen; +CalcIDCosts (ins_line_string, multi_ins_string, + del_line_string, multi_del_string, + setup_string, cleanup_string) char *ins_line_string, *multi_ins_string; char *del_line_string, *multi_del_string; char *setup_string, *cleanup_string; - int coefficient; { - if (SCREEN_INSERT_COST (screen) != 0) + /* Discourage long scrolls slightly on fast lines. + This says that scrolling nearly the full length of the screen + is not worth it if reprinting takes less than 1/4 second. */ + int extra = baud_rate / (10 * 4 * screen_height); + + if (ILcost != 0) { - SCREEN_INSERT_COST (screen) - = (int *) xrealloc (SCREEN_INSERT_COST (screen), - SCREEN_HEIGHT (screen) * sizeof (int)); - SCREEN_DELETEN_COST (screen) - = (int *) xrealloc (SCREEN_DELETEN_COST (screen), - SCREEN_HEIGHT (screen) * sizeof (int)); - SCREEN_INSERTN_COST (screen) - = (int *) xrealloc (SCREEN_INSERTN_COST (screen), - SCREEN_HEIGHT (screen) * sizeof (int)); - SCREEN_DELETE_COST (screen) - = (int *) xrealloc (SCREEN_DELETE_COST (screen), - SCREEN_HEIGHT (screen) * sizeof (int)); + ILcost = (int *) xrealloc (ILcost, screen_height * sizeof (int)); + DLcost = (int *) xrealloc (DLcost, screen_height * sizeof (int)); + ILncost = (int *) xrealloc (ILncost, screen_height * sizeof (int)); + DLncost = (int *) xrealloc (DLncost, screen_height * sizeof (int)); } else { - SCREEN_INSERT_COST (screen) - = (int *) xmalloc (SCREEN_HEIGHT (screen) * sizeof (int)); - SCREEN_DELETEN_COST (screen) - = (int *) xmalloc (SCREEN_HEIGHT (screen) * sizeof (int)); - SCREEN_INSERTN_COST (screen) - = (int *) xmalloc (SCREEN_HEIGHT (screen) * sizeof (int)); - SCREEN_DELETE_COST (screen) - = (int *) xmalloc (SCREEN_HEIGHT (screen) * sizeof (int)); + ILcost = (int *) xmalloc (screen_height * sizeof (int)); + DLcost = (int *) xmalloc (screen_height * sizeof (int)); + ILncost = (int *) xmalloc (screen_height * sizeof (int)); + DLncost = (int *) xmalloc (screen_height * sizeof (int)); } - ins_del_costs (screen, - ins_line_string, multi_ins_string, - setup_string, cleanup_string, - SCREEN_INSERT_COST (screen), SCREEN_INSERTN_COST (screen), - coefficient); - ins_del_costs (screen, - del_line_string, multi_del_string, - setup_string, cleanup_string, - SCREEN_DELETEN_COST (screen), SCREEN_DELETE_COST (screen), - coefficient); + CalcIDCosts1 (ins_line_string, multi_ins_string, + setup_string, cleanup_string, + ILcost, ILncost, extra); + CalcIDCosts1 (del_line_string, multi_del_string, + setup_string, cleanup_string, + DLcost, DLncost, 0); +} + +CalcIDCosts1 (one_line_string, multi_string, + setup_string, cleanup_string, + costvec, ncostvec, extra) + char *one_line_string, *multi_string; + char *setup_string, *cleanup_string; + int *costvec, *ncostvec; + int extra; +{ + if (calculate_costs_hook) + (*calculate_costs_hook) (extra, costvec, ncostvec); + else if (dont_calculate_costs) + CalcLID (0, 0, 0, 0, costvec, ncostvec); + else if (multi_string) + CalcLID (string_cost (multi_string), + per_line_cost (multi_string), + extra, 0, costvec, ncostvec); + else if (one_line_string) + CalcLID (string_cost (setup_string) + string_cost (cleanup_string), 0, + string_cost (one_line_string) + extra, + per_line_cost (one_line_string), + costvec, ncostvec); + else + CalcLID (9999, 0, 9999, 0, + costvec, ncostvec); +} + +/* Calculate the line ID overhead and multiply factor values */ +CalcLID (ov1, pf1, ovn, pfn, ov, mf) + int ov1, ovn; + int pf1, pfn; + register int *ov, *mf; +{ + register int i; + register int insert_overhead = ov1 * 10 + screen_height * pf1; + register int next_insert_cost = ovn * 10 + screen_height * pfn; + + for (i = 0; i < screen_height; i++) + { + *mf++ = next_insert_cost / 10; + next_insert_cost -= pfn; + *ov++ = (insert_overhead + next_insert_cost) / 10; + insert_overhead -= pf1; + } } |