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