552
551
#define act_width active_width[1] /*length from first active node to current node*/
554
#define kern_break() { \
555
if ((!is_char_node(vlink(cur_p))) && auto_breaking) \
556
if (type(vlink(cur_p))==glue_node) \
557
ext_try_break(0,unhyphenated_node, pdf_adjust_spacing, \
558
par_shape_ptr, adj_demerits, \
559
tracing_paragraphs, pdf_protrude_chars, \
560
line_penalty, last_line_fit, \
561
double_hyphen_demerits, final_hyphen_demerits,first_p,cur_p); \
562
if (type(cur_p)!=math_node) act_width+=width(cur_p); \
563
else act_width+=surround(cur_p); \
553
#define kern_break() { \
554
if ((!is_char_node(vlink(cur_p))) && auto_breaking) \
555
if (type(vlink(cur_p))==glue_node) \
556
ext_try_break(0,unhyphenated_node, pdf_adjust_spacing, \
557
par_shape_ptr, adj_demerits, \
558
tracing_paragraphs, pdf_protrude_chars, \
559
line_penalty, last_line_fit, \
560
double_hyphen_demerits, final_hyphen_demerits,first_p,cur_p); \
561
if (type(cur_p)!=math_node) act_width+=width(cur_p); \
562
else act_width+=surround(cur_p); \
566
#define clean_up_the_memory() { \
568
while (q!=active) { \
570
if (type(q)==delta_node) free_node(q,delta_node_size); \
571
else free_node(q,active_node_size); \
577
free_node(q,passive_node_size); \
565
#define clean_up_the_memory() { \
567
while (q!=active) { \
569
if (type(q)==delta_node) flush_node(q); \
570
else flush_node(q); \
582
581
#define inf_bad 10000 /* infinitely bad value */
656
compute_break_width (int break_type, int pdf_adjust_spacing, halfword p) {
657
halfword s; /*runs through nodes ahead of |cur_p|*/
658
halfword v; /*points to a glue specification or a node ahead of |cur_p|*/
637
compute_break_width (int break_type, int pdf_adjust_spacing, halfword p
639
halfword s; /* glue and other 'whitespace' to be skipped after a break
640
* used if unhyphenated, or post_break==empty */
660
if (break_type>unhyphenated_node) {
662
/*@<Compute the discretionary |break_width| values@>;*/
663
/* When |p| is a discretionary break, the length of a line
664
``from |p| to |p|'' has to be defined properly so
665
that the other calculations work out. Suppose that the
666
pre-break text at |p| has length $l_0$, the post-break
667
text has length $l_1$, and the replacement text has length
668
|l|. Suppose also that |q| is the node following the
669
replacement text. Then length of a line from |p| to |q|
670
will be computed as $\gamma+\beta(q)-\alpha(|p|)$, where
671
$\beta(q)=\beta(|p|)-l_0+l$. The actual length will be
672
the background plus $l_1$, so the length from |p| to
673
|p| should be $\gamma+l_0+l_1-l$. If the post-break text
674
of the discretionary is empty, a break may also discard~|q|;
675
in that unusual case we subtract the length of~|q| and any
676
other nodes that will be discarded after the discretionary
679
TH: I don't quite understand the above remarks.
681
The value of $l_0$ need not be computed, since |line_break|
682
will put it into the global variable |disc_width| before
686
v=vlink(no_break(p));
688
/* @<Subtract the width of node |v| from |break_width|@>; */
689
/* Replacement texts and discretionary texts are supposed to contain
690
only character nodes, kern nodes, and box or rule nodes.*/
691
if (is_char_node(v)) {
692
if (is_rotated(line_break_dir)) {
693
break_width[1] -= (glyph_height(v)+glyph_depth(v));
695
break_width[1] -= glyph_width(v);
697
if ((pdf_adjust_spacing > 1) && check_expand_pars(font(v))) {
699
sub_char_stretch(break_width[8],v);
700
sub_char_shrink(break_width[9],v);
642
if (break_type>unhyphenated_node && p!=null) {
643
/*@<Compute the discretionary |break_width| values@>;*/
644
/* When |p| is a discretionary break, the length of a line
645
``from |p| to |p|'' has to be defined properly so
646
that the other calculations work out. Suppose that the
647
pre-break text at |p| has length $l_0$, the post-break
648
text has length $l_1$, and the replacement text has length
649
|l|. Suppose also that |q| is the node following the
650
replacement text. Then length of a line from |p| to |q|
651
will be computed as $\gamma+\beta(q)-\alpha(|p|)$, where
652
$\beta(q)=\beta(|p|)-l_0+l$. The actual length will be
653
the background plus $l_1$, so the length from |p| to
654
|p| should be $\gamma+l_0+l_1-l$. If the post-break text
655
of the discretionary is empty, a break may also discard~|q|;
656
in that unusual case we subtract the length of~|q| and any
657
other nodes that will be discarded after the discretionary
660
TH: I don't quite understand the above remarks.
662
The value of $l_0$ need not be computed, since |line_break|
663
will put it into the global variable |disc_width| before
666
/* In case of nested discretionaries, we always follow the no_break
667
path, as we are talking about the breaking on _this_ position.
671
for (v=vlink_no_break(p); v!=null; v=vlink(v)) {
672
/* @<Subtract the width of node |v| from |break_width|@>; */
673
/* Replacement texts and discretionary texts are supposed to contain
674
only character nodes, kern nodes, and box or rule nodes.*/
675
if (is_char_node(v)) {
676
if (is_rotated(line_break_dir)) {
677
break_width[1] -= (glyph_height(v)+glyph_depth(v));
706
if (!(dir_orthogonal(dir_primary[box_dir(v)],
707
dir_primary[line_break_dir])))
708
break_width[1] -= width(v);
710
break_width[1] -= (depth(v)+height(v));
713
if ((pdf_adjust_spacing > 1) && (subtype(v) == normal)) {
714
sub_kern_stretch(break_width[8],v);
715
sub_kern_shrink(break_width[9],v);
679
break_width[1] -= glyph_width(v);
681
if ((pdf_adjust_spacing > 1) && check_expand_pars(font(v))) {
683
sub_char_stretch(break_width[8],v);
684
sub_char_shrink(break_width[9],v);
690
if (!(dir_orthogonal(dir_primary[box_dir(v)],
691
dir_primary[line_break_dir])))
719
692
break_width[1] -= width(v);
725
confusion(maketexstring("disc1"));
731
s=vlink(post_break(p));
733
/* @<Add the width of node |s| to |break_width|@>; */
734
if (is_char_node(s)) {
735
if (is_rotated(line_break_dir))
736
break_width[1] += (glyph_height(s)+glyph_depth(s));
738
break_width[1] += glyph_width(s);
739
if ((pdf_adjust_spacing > 1) && check_expand_pars(font(s))) {
741
add_char_stretch(break_width[8],s);
742
add_char_shrink(break_width[9],s);
748
if (!(dir_orthogonal(dir_primary[box_dir(s)],
749
dir_primary[line_break_dir])))
750
break_width[1] += width(s);
752
break_width[1] += (depth(s)+height(s));
755
if ((pdf_adjust_spacing > 1) && (subtype(s) == normal)) {
756
add_kern_stretch(break_width[8],s);
757
add_kern_shrink(break_width[9],s);
761
break_width[1] += width(s);
765
assert(vlink(s)==null);
766
/* NB: temporary solution: not good, but not bad either */
770
confusion(maketexstring("disc2"));
775
do_one_seven_eight(add_disc_width_to_break_width);
776
if (vlink(post_break(p))==null) {
777
/* nodes may be discardable after the break */
694
break_width[1] -= (depth(v)+height(v));
697
if ((pdf_adjust_spacing > 1) && (subtype(v) == normal)) {
698
sub_kern_stretch(break_width[8],v);
699
sub_kern_shrink(break_width[9],v);
703
break_width[1] -= width(v);
706
assert(vlink(v)==null); /* discs are _always_ last */
716
for (v=vlink_post_break(p); v!=null; v=vlink(v)) {
717
/* @<Add the width of node |v| to |break_width|@>; */
718
if (is_char_node(v)) {
719
if (is_rotated(line_break_dir))
720
break_width[1] += (glyph_height(v)+glyph_depth(v));
722
break_width[1] += glyph_width(v);
723
if ((pdf_adjust_spacing > 1) && check_expand_pars(font(v))) {
725
add_char_stretch(break_width[8],v);
726
add_char_shrink(break_width[9],v);
732
if (!(dir_orthogonal(dir_primary[box_dir(v)],
733
dir_primary[line_break_dir])))
734
break_width[1] += width(v);
736
break_width[1] += (depth(v)+height(v));
739
if ((pdf_adjust_spacing > 1) && (subtype(v) == normal)) {
740
add_kern_stretch(break_width[8],v);
741
add_kern_shrink(break_width[9],v);
745
break_width[1] += width(v);
748
assert(vlink(v)==null);
757
do_one_seven_eight(add_disc_width_to_break_width);
758
if (vlink_post_break(p)==null) {
759
s=vlink(p); /* no post_break: 'skip' any 'whitespace' following */
764
s = p; /* unhyphenated: we need to 'skip' any 'whitespace' following */
783
766
while (s!=null) {
784
767
switch (type(s)) {
786
769
/*@<Subtract glue from |break_width|@>;*/
770
{halfword v=glue_ptr(s);
788
771
break_width[1] -= width(v);
789
772
break_width[2+stretch_order(v)] -= stretch(v);
790
773
break_width[7] -= shrink(v);
792
775
case penalty_node:
795
print_break_node(halfword q, fitness_value fit_class,
796
quarterword break_type, halfword cur_p) {
797
/* @<Print a symbolic description of the new break node@> */
799
print_int(serial(passive));
801
print_int(line_number(q)-1);
803
print_int(fit_class);
804
if (break_type==hyphenated_node)
807
print_int(total_demerits(q));
808
if (do_last_line_fit) {
809
/*@<Print additional data in the new active node@>; */
811
print_scaled(active_short(q));
816
print_scaled(active_glue(q));
819
if (prev_break(passive)==null)
822
print_int(serial(prev_break(passive)));
827
print_feasible_break(halfword cur_p, pointer r, halfword b, integer pi,
828
integer d, boolean artificial_demerits) {
829
/* @<Print a symbolic description of this feasible break@>;*/
830
if (printed_node!=cur_p) {
831
/* @<Print the list between |printed_node| and |cur_p|, then
832
set |printed_node:=cur_p|@>;*/
835
short_display(vlink(printed_node));
837
halfword save_link=vlink(cur_p);
840
short_display(vlink(printed_node));
841
vlink(cur_p)=save_link;
848
} else if (type(cur_p)!=glue_node) {
849
if (type(cur_p)==penalty_node) tprint_esc("penalty");
850
else if (type(cur_p)==disc_node) tprint_esc("discretionary");
851
else if (type(cur_p)==kern_node) tprint_esc("kern");
852
else tprint_esc("math");
855
if (break_node(r)==null)
858
print_int(serial(break_node(r)));
867
if (artificial_demerits)
873
#define add_disc_width_to_active_width(a) active_width[a] += disc_width[a]
874
#define update_width(a) cur_active_width[a] += varmem[(r+(a))].cint
876
#define set_break_width_to_background(a) break_width[a]=background[(a)]
878
#define convert_to_break_width(a) \
879
varmem[(prev_r+(a))].cint -= (cur_active_width[(a)]+break_width[(a)])
881
#define store_break_width(a) active_width[(a)]=break_width[(a)]
883
#define new_delta_to_break_width(a) \
884
varmem[(q+(a))].cint=break_width[(a)]-cur_active_width[(a)]
886
#define new_delta_from_break_width(a) \
887
varmem[(q+(a))].cint=cur_active_width[(a)]-break_width[(a)]
889
#define copy_to_cur_active(a) cur_active_width[(a)]=active_width[(a)]
810
891
#define combine_two_deltas(a) varmem[(prev_r+(a))].cint += varmem[(r+(a))].cint
811
892
#define downdate_width(a) cur_active_width[(a)] -= varmem[(prev_r+(a))].cint
812
893
#define update_active(a) active_width[(a)]+=varmem[(r+(a))].cint
1062
1110
then |goto continue| if a line from |r| to |cur_p| is infeasible,
1063
1111
otherwise record a new feasible break@>; */
1064
1112
artificial_demerits=false;
1065
shortfall = line_width-cur_active_width[1]; /*we're this much too short*/
1066
if (break_node(r)==null)
1067
shortfall -= init_internal_left_box_width;
1069
shortfall -= passive_last_left_box_width(break_node(r));
1070
shortfall -= internal_right_box_width;
1113
shortfall = line_width
1114
- cur_active_width[1]
1115
-(( break_node(r)==null)
1116
? init_internal_left_box_width
1117
: passive_last_left_box_width(break_node(r)))
1118
- internal_right_box_width;
1071
1119
if (pdf_protrude_chars > 1) {
1073
1121
l = (break_node(r) == null) ? first_p : cur_break(break_node(r));
1074
assert(vlink(alink(cur_p))==cur_p);
1124
} else { /* TODO if (is_character_node(alink(cur_p))) */
1126
assert(vlink(o)==cur_p);
1076
1128
/* let's look at the right margin first */
1077
if ((cur_p != null) && (type(cur_p) == disc_node) && (vlink(pre_break(cur_p)) != null)) {
1129
if ((cur_p != null) && (type(cur_p) == disc_node) && (vlink_pre_break(cur_p) != null)) {
1078
1130
/* a |disc_node| with non-empty |pre_break|, protrude the last char of |pre_break| */
1079
o = tlink(pre_break(cur_p));
1131
o = tlink_pre_break(cur_p);
1081
1133
o = find_protchar_right(l, o);
1083
1135
/* now the left margin */
1084
if ((l != null) && (type(l) == disc_node) && (vlink(post_break(l)) != null)) {
1136
if ((l != null) && (type(l) == disc_node) && (vlink_post_break(l) != null)) {
1085
1137
/* FIXME: first 'char' could be a disc! */
1086
l = vlink(post_break(l)); /* protrude the first char */
1138
l = vlink_post_break(l); /* protrude the first char */
1088
1140
l = find_protchar_left(l, true);
1301
1354
if (abs(fit_class-fitness(r))>1) d=d+adj_demerits;
1303
if (tracing_paragraphs>0) {
1304
/* @<Print a symbolic description of this feasible break@>;*/
1305
if (printed_node!=cur_p) {
1306
/* @<Print the list between |printed_node| and |cur_p|, then
1307
set |printed_node:=cur_p|@>;*/
1308
print_nl(maketexstring(""));
1310
short_display(vlink(printed_node));
1312
save_link=vlink(cur_p);
1314
print_nl(maketexstring(""));
1315
short_display(vlink(printed_node));
1316
vlink(cur_p)=save_link;
1320
print_nl(maketexstring("@"));
1322
print_esc(maketexstring("par"));
1323
} else if (type(cur_p)!=glue_node) {
1324
if (type(cur_p)==penalty_node) print_esc(maketexstring("penalty"));
1325
else if (type(cur_p)==disc_node) print_esc(maketexstring("discretionary"));
1326
else if (type(cur_p)==kern_node) print_esc(maketexstring("kern"));
1327
else print_esc(maketexstring("math"));
1329
print(maketexstring(" via @@"));
1330
if (break_node(r)==null)
1333
print_int(serial(break_node(r)));
1334
print(maketexstring(" b="));
1339
print(maketexstring(" p="));
1341
print(maketexstring(" d="));
1342
if (artificial_demerits)
1356
if (tracing_paragraphs>0)
1357
print_feasible_break(cur_p, r, b, pi, d, artificial_demerits);
1347
1358
d += total_demerits(r); /*this is the minimum total demerits
1348
1359
from the beginning to |cur_p| via |r| */
1349
1360
if (d<=minimal_demerits[fit_class]) {
1363
1374
/* /Record a new feasible break */
1364
1375
if (node_r_stays_active)
1365
goto CONTINUE; /*|prev_r| has been set to |r| */
1376
continue; /*|prev_r| has been set to |r| */
1367
1378
/* @<Deactivate node |r|@>; */
1368
/* When an active node disappears, we must delete an adjacent delta node if the
1369
active node was at the beginning or the end of the active list, or if it
1370
was surrounded by delta nodes. We also must preserve the property that
1371
|cur_active_width| represents the length of material from |vlink(prev_r)|
1379
/* When an active node disappears, we must delete an adjacent delta node if
1380
the active node was at the beginning or the end of the active list, or
1381
if it was surrounded by delta nodes. We also must preserve the property
1382
that |cur_active_width| represents the length of material from
1383
|vlink(prev_r)| to~|cur_p|.*/
1374
1385
vlink(prev_r)=vlink(r);
1375
free_node(r,active_node_size);
1376
1387
if (prev_r==active) {
1377
/*@<Update the active widths, since the first active node has been deleted@>*/
1378
/* The following code uses the fact that |type(active)<>delta_node|. If the
1379
active list has just become empty, we do not need to update the
1388
/*@<Update the active widths, since the first active node has been
1390
/* The following code uses the fact that |type(active)<>delta_node|.
1391
If the active list has just become empty, we do not need to update the
1380
1392
|active_width| array, since it will be initialized when an active
1381
1393
node is next inserted.
1383
1395
r=vlink(active);
1384
1396
if (type(r)==delta_node) {
1385
do_all_eight(update_active);
1397
do_all_eight(update_active); /* IMPLICIT r */
1386
1398
do_all_eight(copy_to_cur_active);
1387
1399
vlink(active)=vlink(r);
1388
free_node(r,delta_node_size);
1390
1402
} else if (type(prev_r)==delta_node){
1391
1403
r=vlink(prev_r);
1392
1404
if (r==active) {
1393
do_all_eight(downdate_width);
1405
do_all_eight(downdate_width); /* IMPLICIT prev_r */
1394
1406
vlink(prev_prev_r)=active;
1395
free_node(prev_r,delta_node_size);
1396
1408
prev_r=prev_prev_r;
1397
1409
} else if (type(r)==delta_node) {
1398
do_all_eight(update_width);
1399
do_all_eight(combine_two_deltas);
1410
do_all_eight(update_width); /* IMPLICIT ,r */
1411
do_all_eight(combine_two_deltas); /* IMPLICIT r prev_r */
1400
1412
vlink(prev_r)=vlink(r);
1401
free_node(r,delta_node_size);