This source file includes following definitions.
- calculate_scrolling
- do_scrolling
- calculate_direct_scrolling
- do_direct_scrolling
- scrolling_1
- scrolling_max_lines_saved
- line_ins_del
- ins_del_costs
- do_line_insertion_deletion_costs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 #include <config.h>
23
24 #include "lisp.h"
25 #include "termchar.h"
26 #include "dispextern.h"
27 #include "frame.h"
28 #include "termhooks.h"
29
30 struct matrix_elt
31 {
32
33
34 int writecost;
35
36
37 int insertcost;
38
39
40 int deletecost;
41
42
43 int insertcount;
44
45
46 int deletecount;
47
48
49 int writecount;
50 };
51
52 static void do_direct_scrolling (struct frame *,
53 struct glyph_matrix *,
54 struct matrix_elt *,
55 int, int);
56 static void do_scrolling (struct frame *,
57 struct glyph_matrix *,
58 struct matrix_elt *,
59 int, int);
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79 static void
80 calculate_scrolling (struct frame *frame,
81
82 struct matrix_elt *matrix,
83 int window_size, int lines_below,
84 int *draw_cost, unsigned *old_hash, unsigned *new_hash,
85 int free_at_end)
86 {
87 int i, j;
88 int frame_total_lines = FRAME_TOTAL_LINES (frame);
89 struct matrix_elt *p, *p1;
90 int cost, cost1;
91
92 int lines_moved = window_size
93 + (FRAME_SCROLL_REGION_OK (frame) ? 0 : lines_below);
94
95
96
97 int *first_insert_cost
98 = &FRAME_INSERT_COST (frame)[frame_total_lines - 1 - lines_moved];
99 int *first_delete_cost
100 = &FRAME_DELETE_COST (frame)[frame_total_lines - 1 - lines_moved];
101 int *next_insert_cost
102 = &FRAME_INSERTN_COST (frame)[frame_total_lines - 1 - lines_moved];
103 int *next_delete_cost
104 = &FRAME_DELETEN_COST (frame)[frame_total_lines - 1 - lines_moved];
105
106
107
108
109 int extra_cost
110 = clip_to_bounds (1, baud_rate / (10 * 4) / frame_total_lines, INT_MAX / 2);
111
112
113 matrix->writecost = 0;
114 matrix->insertcost = SCROLL_INFINITY;
115 matrix->deletecost = SCROLL_INFINITY;
116 matrix->insertcount = 0;
117 matrix->deletecount = 0;
118
119
120 cost = first_insert_cost[1] - next_insert_cost[1];
121 for (i = 1; i <= window_size; i++)
122 {
123 p = matrix + i * (window_size + 1);
124 cost += draw_cost[i] + next_insert_cost[i] + extra_cost;
125 p->insertcost = cost;
126 p->writecost = SCROLL_INFINITY;
127 p->deletecost = SCROLL_INFINITY;
128 p->insertcount = i;
129 p->deletecount = 0;
130 }
131
132
133 cost = first_delete_cost[1] - next_delete_cost[1];
134 for (j = 1; j <= window_size; j++)
135 {
136 cost += next_delete_cost[j];
137 matrix[j].deletecost = cost;
138 matrix[j].writecost = SCROLL_INFINITY;
139 matrix[j].insertcost = SCROLL_INFINITY;
140 matrix[j].deletecount = j;
141 matrix[j].insertcount = 0;
142 }
143
144
145
146 p = matrix + window_size + 2;
147 for (i = 1; i <= window_size; i++, p++)
148 for (j = 1; j <= window_size; j++, p++)
149 {
150
151
152
153
154
155
156
157 p1 = p - window_size - 2;
158 cost = p1->writecost;
159 if (cost > p1->insertcost)
160 cost = p1->insertcost;
161 if (cost > p1->deletecost)
162 cost = p1->deletecost;
163 if (old_hash[j] != new_hash[i])
164 cost += draw_cost[i];
165 p->writecost = cost;
166
167
168
169
170
171
172
173
174 p1 = p - window_size - 1;
175
176
177
178 if (free_at_end == i)
179 {
180 cost = p1->writecost;
181 cost1 = p1->insertcost;
182 }
183 else
184 {
185 cost = p1->writecost + first_insert_cost[i];
186 if (p1->insertcount > i)
187 emacs_abort ();
188 cost1 = p1->insertcost + next_insert_cost[i - p1->insertcount];
189 }
190 p->insertcost = min (cost, cost1) + draw_cost[i] + extra_cost;
191 p->insertcount = (cost < cost1) ? 1 : p1->insertcount + 1;
192 if (p->insertcount > i)
193 emacs_abort ();
194
195
196
197
198
199
200 p1 = p - 1;
201
202
203 if (free_at_end == i)
204 {
205 cost = p1->writecost;
206 cost1 = p1->deletecost;
207 }
208 else
209 {
210 cost = p1->writecost + first_delete_cost[i];
211 cost1 = p1->deletecost + next_delete_cost[i];
212 }
213 p->deletecost = min (cost, cost1);
214 p->deletecount = (cost < cost1) ? 1 : p1->deletecount + 1;
215 }
216 }
217
218
219
220
221
222
223
224
225
226
227
228
229
230 static void
231 do_scrolling (struct frame *frame, struct glyph_matrix *current_matrix,
232 struct matrix_elt *matrix, int window_size,
233 int unchanged_at_top)
234 {
235 struct matrix_elt *p;
236 int i, j, k;
237 USE_SAFE_ALLOCA;
238
239
240 bool terminal_window_p = 0;
241
242
243 struct queue { int count, pos; };
244 struct queue *queue_start;
245 SAFE_NALLOCA (queue_start, 1, current_matrix->nrows);
246 struct queue *queue = queue_start;
247
248 char *retained_p = SAFE_ALLOCA (window_size);
249 int *copy_from;
250 SAFE_NALLOCA (copy_from, 1, window_size);
251
252
253 memset (retained_p, 0, window_size * sizeof (char));
254 for (k = 0; k < window_size; ++k)
255 copy_from[k] = -1;
256
257 #ifdef GLYPH_DEBUG
258 # define CHECK_BOUNDS \
259 do \
260 { \
261 int ck; \
262 for (ck = 0; ck < window_size; ++ck) \
263 eassert (copy_from[ck] == -1 \
264 || (copy_from[ck] >= 0 && copy_from[ck] < window_size)); \
265 } \
266 while (0);
267 #endif
268
269
270
271 i = j = window_size;
272 while (i > 0 || j > 0)
273 {
274 p = matrix + i * (window_size + 1) + j;
275
276 if (p->insertcost < p->writecost && p->insertcost < p->deletecost)
277 {
278
279
280 queue->count = p->insertcount;
281 queue->pos = i + unchanged_at_top - p->insertcount;
282 ++queue;
283
284
285
286 i -= p->insertcount;
287 }
288 else if (p->deletecost < p->writecost)
289 {
290
291
292
293
294 j -= p->deletecount;
295
296
297 if (! terminal_window_p)
298 {
299 set_terminal_window (frame, window_size + unchanged_at_top);
300 terminal_window_p = 1;
301 }
302
303
304 ins_del_lines (frame, j + unchanged_at_top, - p->deletecount);
305 }
306 else
307 {
308
309 --i, --j;
310 eassert (i >= 0 && i < window_size);
311 eassert (j >= 0 && j < window_size);
312 copy_from[i] = j;
313 retained_p[j] = 1;
314
315 #ifdef GLYPH_DEBUG
316 CHECK_BOUNDS;
317 #endif
318 }
319 }
320
321
322 if (queue > queue_start)
323 {
324 int next = -1;
325
326
327 if (!terminal_window_p)
328 {
329 set_terminal_window (frame, window_size + unchanged_at_top);
330 terminal_window_p = 1;
331 }
332
333 do
334 {
335 --queue;
336
337
338 ins_del_lines (frame, queue->pos, queue->count);
339
340
341
342
343
344 k = queue->pos - unchanged_at_top;
345 for (j = 0; j < queue->count; ++j)
346 {
347
348 while (retained_p[++next])
349 ;
350
351
352
353 copy_from[k + j] = next;
354 }
355 }
356 while (queue > queue_start);
357
358 }
359
360 for (k = 0; k < window_size; ++k)
361 eassert (copy_from[k] >= 0 && copy_from[k] < window_size);
362
363
364 mirrored_line_dance (current_matrix, unchanged_at_top, window_size,
365 copy_from, retained_p);
366
367
368 CHECK_MATRIX (current_matrix);
369
370 if (terminal_window_p)
371 set_terminal_window (frame, 0);
372 SAFE_FREE ();
373 }
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416 static void
417 calculate_direct_scrolling (struct frame *frame,
418
419 struct matrix_elt *matrix,
420 int window_size, int lines_below,
421 int *draw_cost, int *old_draw_cost,
422 unsigned *old_hash, unsigned *new_hash,
423 int free_at_end)
424 {
425 int i, j;
426 int frame_total_lines = FRAME_TOTAL_LINES (frame);
427 struct matrix_elt *p, *p1;
428 int cost, cost1, delta;
429
430
431
432 int *first_insert_cost
433 = &FRAME_INSERT_COST (frame)[frame_total_lines - 1];
434 int *first_delete_cost
435 = &FRAME_DELETE_COST (frame)[frame_total_lines - 1];
436 int *next_insert_cost
437 = &FRAME_INSERTN_COST (frame)[frame_total_lines - 1];
438 int *next_delete_cost
439 = &FRAME_DELETEN_COST (frame)[frame_total_lines - 1];
440
441 int scroll_overhead;
442
443
444
445
446 int extra_cost
447 = clip_to_bounds (1, baud_rate / (10 * 4) / frame_total_lines, INT_MAX / 2);
448
449
450
451
452 scroll_overhead
453 = FRAME_SCROLL_REGION_COST (frame) + extra_cost;
454
455
456 matrix->writecost = 0;
457 matrix->insertcost = SCROLL_INFINITY;
458 matrix->deletecost = SCROLL_INFINITY;
459 matrix->writecount = 0;
460 matrix->insertcount = 0;
461 matrix->deletecount = 0;
462
463
464 cost = 0;
465 for (i = 1; i <= window_size; i++)
466 {
467 p = matrix + i * (window_size + 1);
468 cost += draw_cost[i];
469 p->insertcost = cost;
470 p->writecost = SCROLL_INFINITY;
471 p->deletecost = SCROLL_INFINITY;
472 p->insertcount = i;
473 p->writecount = 0;
474 p->deletecount = 0;
475 }
476
477
478 for (j = 1; j <= window_size; j++)
479 {
480 matrix[j].deletecost = 0;
481 matrix[j].writecost = SCROLL_INFINITY;
482 matrix[j].insertcost = SCROLL_INFINITY;
483 matrix[j].deletecount = j;
484 matrix[j].writecount = 0;
485 matrix[j].insertcount = 0;
486 }
487
488
489
490 p = matrix + window_size + 2;
491
492 for (i = 1; i <= window_size; i++, p++)
493 for (j = 1; j <= window_size; j++, p++)
494 {
495
496
497
498
499
500
501
502
503
504
505
506
507 p1 = p - window_size - 2;
508 cost = p1->insertcost;
509 if (cost > p1->deletecost)
510 cost = p1->deletecost;
511 cost1 = p1->writecost;
512 if (i == j)
513 {
514 if (cost > cost1)
515 {
516 cost = cost1;
517 p->writecount = p1->writecount + 1;
518 }
519 else
520 p->writecount = 1;
521 if (old_hash[j] != new_hash[i])
522 {
523 cost += draw_cost[i];
524 }
525 }
526 else
527 {
528 if (i > j)
529 {
530 delta = i - j;
531
532
533
534
535
536
537 cost += scroll_overhead + first_insert_cost[-delta] +
538 (delta-1) * (next_insert_cost[-delta] + extra_cost);
539
540
541
542
543
544
545
546
547
548 cost1 += first_insert_cost[-j] - first_insert_cost[1-j] +
549 (delta-1) * (next_insert_cost[-j] - next_insert_cost[1-j]);
550 }
551 else
552 {
553 delta = j - i;
554 cost += scroll_overhead + first_delete_cost[-delta] +
555 (delta-1) * (next_delete_cost[-delta] + extra_cost);
556 cost1 += first_delete_cost[-i] - first_delete_cost[1-i] +
557 (delta-1) * ( next_delete_cost[-i] - next_delete_cost[1-i]);
558 }
559 if (cost1 < cost)
560 {
561 cost = cost1;
562 p->writecount = p1->writecount + 1;
563 }
564 else
565 p->writecount = 1;
566 if (old_hash[j] != new_hash[i])
567 {
568 cost += draw_cost[i] + old_draw_cost[j];
569 }
570 }
571 p->writecost = cost;
572
573
574
575
576
577
578
579
580 p1 = p - window_size - 1;
581 cost = p1->writecost;
582
583 if (i > j && p1->deletecost < cost)
584 cost = p1->deletecost;
585 if (p1->insertcost <= cost)
586 {
587 cost = p1->insertcost;
588 p->insertcount = p1->insertcount + 1;
589 }
590 else
591 p->insertcount = 1;
592 cost += draw_cost[i];
593 p->insertcost = cost;
594
595
596
597
598
599
600 p1 = p - 1;
601 cost = p1->writecost;
602
603 if (i < j && p1->insertcost < cost)
604 cost = p1->insertcost;
605 cost1 = p1->deletecost;
606 if (p1->deletecost <= cost)
607 {
608 cost = p1->deletecost;
609 p->deletecount = p1->deletecount + 1;
610 }
611 else
612 p->deletecount = 1;
613 p->deletecost = cost;
614 }
615 }
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635 static void
636 do_direct_scrolling (struct frame *frame, struct glyph_matrix *current_matrix,
637 struct matrix_elt *cost_matrix, int window_size,
638 int unchanged_at_top)
639 {
640 struct matrix_elt *p;
641 int i, j;
642 USE_SAFE_ALLOCA;
643
644
645 struct alt_queue { int count, pos, window; };
646 struct alt_queue *queue_start;
647 SAFE_NALLOCA (queue_start, 1, window_size);
648 struct alt_queue *queue = queue_start;
649
650
651 bool terminal_window_p = 0;
652
653
654
655
656
657
658
659 bool write_follows_p = 1;
660
661
662 int *copy_from;
663 SAFE_NALLOCA (copy_from, 1, window_size);
664
665
666
667 char *retained_p = SAFE_ALLOCA (window_size);
668
669 memset (retained_p, 0, window_size * sizeof (char));
670
671
672 CHECK_MATRIX (current_matrix);
673
674
675
676
677
678
679
680
681
682
683
684 i = j = window_size;
685
686 while (i > 0 || j > 0)
687 {
688 p = cost_matrix + i * (window_size + 1) + j;
689
690 if (p->insertcost < p->writecost
691 && p->insertcost < p->deletecost
692 && (write_follows_p || i < j))
693 {
694
695
696
697 queue->count = 0;
698 queue->window = i;
699 queue->pos = i - p->insertcount;
700 ++queue;
701
702 i -= p->insertcount;
703 write_follows_p = 0;
704 }
705 else if (p->deletecost < p->writecost
706 && (write_follows_p || i > j))
707 {
708
709
710 write_follows_p = 0;
711 j -= p->deletecount;
712 }
713 else
714 {
715
716
717
718 int n_to_write = p->writecount;
719 write_follows_p = 1;
720 eassert (n_to_write > 0);
721
722 if (i > j)
723 {
724
725 set_terminal_window (frame, i + unchanged_at_top);
726 terminal_window_p = 1;
727 ins_del_lines (frame, j - n_to_write + unchanged_at_top, i - j);
728 }
729 else if (i < j)
730 {
731
732 queue->pos = i - n_to_write + unchanged_at_top;
733 queue->window = j + unchanged_at_top;
734 queue->count = i - j;
735 ++queue;
736 }
737
738 while (n_to_write > 0)
739 {
740 --i, --j, --n_to_write;
741 copy_from[i] = j;
742 retained_p[j] = 1;
743 }
744 }
745 }
746
747
748 if (queue > queue_start)
749 {
750 int next = -1;
751
752 do
753 {
754 --queue;
755 if (queue->count)
756 {
757 set_terminal_window (frame, queue->window);
758 terminal_window_p = 1;
759 ins_del_lines (frame, queue->pos, queue->count);
760 }
761 else
762 {
763 for (j = queue->window - 1; j >= queue->pos; --j)
764 {
765 while (retained_p[++next])
766 ;
767 copy_from[j] = next;
768 }
769 }
770 }
771 while (queue > queue_start);
772 }
773
774
775
776
777
778 mirrored_line_dance (current_matrix, unchanged_at_top, window_size,
779 copy_from, retained_p);
780
781 if (terminal_window_p)
782 set_terminal_window (frame, 0);
783 SAFE_FREE ();
784 }
785
786
787
788 void
789 scrolling_1 (struct frame *frame, int window_size, int unchanged_at_top,
790 int unchanged_at_bottom, int *draw_cost, int *old_draw_cost,
791 unsigned *old_hash, unsigned *new_hash, int free_at_end)
792 {
793 USE_SAFE_ALLOCA;
794 struct matrix_elt *matrix;
795 SAFE_NALLOCA (matrix, window_size + 1, window_size + 1);
796
797 if (FRAME_SCROLL_REGION_OK (frame))
798 {
799 calculate_direct_scrolling (frame, matrix, window_size,
800 unchanged_at_bottom,
801 draw_cost, old_draw_cost,
802 old_hash, new_hash, free_at_end);
803 do_direct_scrolling (frame, frame->current_matrix,
804 matrix, window_size, unchanged_at_top);
805 }
806 else
807 {
808 calculate_scrolling (frame, matrix, window_size, unchanged_at_bottom,
809 draw_cost, old_hash, new_hash,
810 free_at_end);
811 do_scrolling (frame,
812 frame->current_matrix, matrix, window_size,
813 unchanged_at_top);
814 }
815
816 SAFE_FREE ();
817 }
818
819
820
821
822
823
824
825
826
827 int
828 scrolling_max_lines_saved (int start, int end,
829 unsigned *oldhash, unsigned *newhash,
830 int *cost)
831 {
832 enum { LOG2_NLINES = 9 };
833 enum { NLINES = 1 << LOG2_NLINES };
834 struct { unsigned hash; int count; } lines[NLINES];
835 int i, h;
836 int matchcount = 0;
837 int avg_length = 0;
838 int threshold;
839
840
841
842 for (i = start; i < end; i++)
843 avg_length += cost[i];
844
845 avg_length /= end - start;
846 threshold = avg_length / 4;
847
848 memset (lines, 0, sizeof lines);
849
850
851
852
853 for (i = start; i < end; i++)
854 {
855 if (cost[i] > threshold)
856 {
857 h = newhash[i] & (NLINES - 1);
858 lines[h].hash = newhash[i];
859 lines[h].count++;
860 }
861 }
862
863
864
865 for (i = start; i < end; i++)
866 {
867 h = oldhash[i] & (NLINES - 1);
868 if (oldhash[i] == lines[h].hash)
869 {
870 matchcount++;
871 if (--lines[h].count == 0)
872 lines[h].hash = 0;
873 }
874 }
875
876 return matchcount;
877 }
878
879
880
881
882 static void
883 line_ins_del (struct frame *frame, int ov1, int pf1, int ovn, int pfn,
884 int *ov, int *mf)
885 {
886 int i;
887 int frame_total_lines = FRAME_TOTAL_LINES (frame);
888 int insert_overhead = ov1 * 10;
889 int next_insert_cost = ovn * 10;
890
891 for (i = frame_total_lines - 1; i >= 0; i--)
892 {
893 mf[i] = next_insert_cost / 10;
894 next_insert_cost += pfn;
895 ov[i] = (insert_overhead + next_insert_cost) / 10;
896 insert_overhead += pf1;
897 }
898 }
899
900 static void
901 ins_del_costs (struct frame *frame,
902 const char *one_line_string, const char *multi_string,
903 const char *setup_string, const char *cleanup_string,
904 int *costvec, int *ncostvec,
905 int coefficient)
906 {
907 if (multi_string)
908 line_ins_del (frame,
909 string_cost (multi_string) * coefficient,
910 per_line_cost (multi_string) * coefficient,
911 0, 0, costvec, ncostvec);
912 else if (one_line_string)
913 line_ins_del (frame,
914 string_cost (setup_string) + string_cost (cleanup_string), 0,
915 string_cost (one_line_string),
916 per_line_cost (one_line_string),
917 costvec, ncostvec);
918 else
919 line_ins_del (frame,
920 9999, 0, 9999, 0,
921 costvec, ncostvec);
922 }
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956 void
957 do_line_insertion_deletion_costs (struct frame *frame,
958 const char *ins_line_string,
959 const char *multi_ins_string,
960 const char *del_line_string,
961 const char *multi_del_string,
962 const char *setup_string,
963 const char *cleanup_string,
964 int coefficient)
965 {
966 int frame_total_lines = FRAME_TOTAL_LINES (frame);
967 FRAME_INSERT_COST (frame) =
968 xnrealloc (FRAME_INSERT_COST (frame), frame_total_lines, sizeof (int));
969 FRAME_DELETEN_COST (frame) =
970 xnrealloc (FRAME_DELETEN_COST (frame), frame_total_lines, sizeof (int));
971 FRAME_INSERTN_COST (frame) =
972 xnrealloc (FRAME_INSERTN_COST (frame), frame_total_lines, sizeof (int));
973 FRAME_DELETE_COST (frame) =
974 xnrealloc (FRAME_DELETE_COST (frame), frame_total_lines, sizeof (int));
975
976 ins_del_costs (frame,
977 ins_line_string, multi_ins_string,
978 setup_string, cleanup_string,
979 FRAME_INSERT_COST (frame), FRAME_INSERTN_COST (frame),
980 coefficient);
981 ins_del_costs (frame,
982 del_line_string, multi_del_string,
983 setup_string, cleanup_string,
984 FRAME_DELETE_COST (frame), FRAME_DELETEN_COST (frame),
985 coefficient);
986 }