summaryrefslogtreecommitdiff
path: root/Build
diff options
context:
space:
mode:
authorAkira Kakuto <kakuto@fuk.kindai.ac.jp>2016-02-22 23:48:32 +0000
committerAkira Kakuto <kakuto@fuk.kindai.ac.jp>2016-02-22 23:48:32 +0000
commita2dd35ef222d1e6d713c13dd9c70fcfcff023f9a (patch)
tree9cfc1d0248d316b4b41ca7f99ce4bfc472afed02 /Build
parent57dfe35cc3d712b21fbda8f99ac0eb8995135c52 (diff)
web2c/xetexdir: sync with the upstream (a new primitive \XeTeXinterwordspaceshaping).
git-svn-id: svn://tug.org/texlive/trunk@39824 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build')
-rw-r--r--Build/source/texk/web2c/xetexdir/XeTeX_ext.c54
-rw-r--r--Build/source/texk/web2c/xetexdir/xetex.web180
2 files changed, 206 insertions, 28 deletions
diff --git a/Build/source/texk/web2c/xetexdir/XeTeX_ext.c b/Build/source/texk/web2c/xetexdir/XeTeX_ext.c
index 86ab3438331..a5ba2e40a46 100644
--- a/Build/source/texk/web2c/xetexdir/XeTeX_ext.c
+++ b/Build/source/texk/web2c/xetexdir/XeTeX_ext.c
@@ -1937,11 +1937,55 @@ get_native_glyph(void* pNode, unsigned index)
}
void
-store_justified_native_glyphs(void* node)
+store_justified_native_glyphs(void* pNode)
{
-#ifdef XETEX_MAC /* this is only called for AAT fonts */
- (void)DoAATLayout(node, 1);
+ memoryword* node = (memoryword*)pNode;
+ unsigned f = native_font(node);
+
+#ifdef XETEX_MAC /* separate Mac-only codepath for AAT fonts */
+ if (fontarea[f] == AAT_FONT_FLAG) {
+ (void)DoAATLayout(node, 1);
+ return;
+ }
#endif
+
+ /* save desired width */
+ int savedWidth = node_width(node);
+
+ measure_native_node(node, 0);
+
+ if (node_width(node) != savedWidth) {
+ /* see how much adjustment is needed overall */
+ double justAmount = Fix2D(savedWidth - node_width(node));
+
+ /* apply justification to spaces (or if there are none, distribute it to all glyphs as a last resort) */
+ FixedPoint* locations = (FixedPoint*)native_glyph_info_ptr(node);
+ uint16_t* glyphIDs = (uint16_t*)(locations + native_glyph_count(node));
+ int glyphCount = native_glyph_count(node);
+ int spaceCount = 0, i;
+
+ int spaceGlyph = mapchartoglyph(f, ' ');
+ for (i = 0; i < glyphCount; ++i)
+ if (glyphIDs[i] == spaceGlyph)
+ spaceCount++;
+
+ if (spaceCount > 0) {
+ double adjustment = 0;
+ int spaceIndex = 0;
+ for (i = 0; i < glyphCount; ++i) {
+ locations[i].x = D2Fix(Fix2D(locations[i].x) + adjustment);
+ if (glyphIDs[i] == spaceGlyph) {
+ spaceIndex++;
+ adjustment = justAmount * spaceIndex / spaceCount;
+ }
+ }
+ } else {
+ for (i = 1; i < glyphCount; ++i)
+ locations[i].x = D2Fix(Fix2D(locations[i].x) + justAmount * i / (glyphCount - 1));
+ }
+
+ node_width(node) = savedWidth;
+ }
}
void
@@ -2064,10 +2108,10 @@ measure_native_node(void* pNode, int use_glyph_metrics)
locations[i].x = D2Fix(positions[i].x);
locations[i].y = D2Fix(positions[i].y);
}
- width = D2Fix(positions[totalGlyphCount].x);
+ width = positions[totalGlyphCount].x;
}
- node_width(node) = width;
+ node_width(node) = D2Fix(width);
native_glyph_count(node) = totalGlyphCount;
native_glyph_info_ptr(node) = glyph_info;
diff --git a/Build/source/texk/web2c/xetexdir/xetex.web b/Build/source/texk/web2c/xetexdir/xetex.web
index a3238e4bcad..625e928aa42 100644
--- a/Build/source/texk/web2c/xetexdir/xetex.web
+++ b/Build/source/texk/web2c/xetexdir/xetex.web
@@ -346,7 +346,10 @@ known as `\eTeX'.
@d XeTeX_default_input_encoding_code=7 {|str_number| of encoding name if |mode =| ICU}
@#
@d XeTeX_tracing_fonts_code=8 {non-zero to log native fonts used}
-@d eTeX_states=9 {number of \eTeX\ state variables in |eqtb|}
+@d XeTeX_interword_space_shaping_code=9 { controls shaping of space chars in context when using native fonts;
+ set to 1 for contextual adjustment of space width only,
+ and 2 for full cross-space shaping (e.g. multi-word ligatures) }
+@d eTeX_states=10 {number of \eTeX\ state variables in |eqtb|}
@ Different \PASCAL s have slightly different conventions, and the present
@!@:PASCAL H}{\ph@>
@@ -3549,6 +3552,7 @@ inserted from \.{\\mkern} specifications in math formulas).
@d kern_node=11 {|type| of a kern node}
@d explicit=1 {|subtype| of kern nodes from \.{\\kern} and \.{\\/}}
@d acc_kern=2 {|subtype| of kern nodes from accents}
+@d space_adjustment=3 {|subtype| of kern nodes from \.{\\XeTeXinterwordspaceshaping} adjustment}
@# {memory structure for marginal kerns}
@d margin_kern_node = 40
@@ -4238,8 +4242,9 @@ if subtype(p)<>mu_glue then
begin print_esc("kern");
if subtype(p)<>normal then print_char(" ");
print_scaled(width(p));
- if subtype(p)=acc_kern then print(" (for accent)");
+ if subtype(p)=acc_kern then print(" (for accent)")
@.for accent@>
+ else if subtype(p)=space_adjustment then print(" (space adjustment)");
end
else begin print_esc("mkern"); print_scaled(width(p)); print("mu");
end
@@ -6062,8 +6067,8 @@ A global boolean variable called |no_new_control_sequence| is set to
@ Primitive support needs a few extra variables and definitions
-@d prim_size=481 {maximum number of primitives }
-@d prim_prime=409 {about 85\pct! of |primitive_size|}
+@d prim_size=500 {maximum number of primitives }
+@d prim_prime=431 {about 85\pct! of |primitive_size|}
@d prim_base=1
@d prim_next(#) == prim[#].lh {link for coalesced lists}
@d prim_text(#) == prim[#].rh {string number for control sequence name}
@@ -13917,7 +13922,9 @@ var base_line: scaled; {the baseline coordinate for this box}
begin cur_g:=0; cur_glue:=float_constant(0);
this_box:=temp_ptr; g_order:=glue_order(this_box);
g_sign:=glue_sign(this_box);
-@<Merge sequences of words using AAT fonts and inter-word spaces into single nodes@>;
+if XeTeX_interword_space_shaping_state > 1 then begin
+ @<Merge sequences of words using native fonts and inter-word spaces into single nodes@>;
+end;
p:=list_ptr(this_box);
incr(cur_s);
if cur_s>0 then dvi_out(push);
@@ -13939,13 +13946,22 @@ end;
@d is_native_word_node(#) == (((#)<>null and (not is_char_node(#)) and (type(#) = whatsit_node) and (subtype(#) = native_word_node)))
@d is_glyph_node(#) == (((#)<>null and (not is_char_node(#)) and (type(#) = whatsit_node) and (subtype(#) = glyph_node)))
-@<Merge sequences of words using AAT fonts and inter-word spaces into single nodes@>=
+@d node_is_invisible_to_interword_space(#)==
+ not is_char_node(#) and
+ ((type(#) = penalty_node) or
+ (type(#) = ins_node) or
+ (type(#) = mark_node) or
+ (type(#) = adjust_node) or
+ ((type(#) = whatsit_node) and (subtype(#) <= 4)))
+ { This checks for |subtype|s in the range open/write/close/special/language,
+ but the definitions haven't appeared yet in the .web file so we cheat. }
+
+@<Merge sequences of words using native fonts and inter-word spaces into single nodes@>=
p:=list_ptr(this_box);
prev_p:=this_box+list_offset;
while p<>null do begin
if link(p) <> null then begin {not worth looking ahead at the end}
- if is_native_word_node(p) and (font_area[native_font(p)] = aat_font_flag)
- and (font_letter_space[native_font(p)] = 0) then begin
+ if is_native_word_node(p) and (font_letter_space[native_font(p)] = 0) then begin
{got a word in an AAT font, might be the start of a run}
r:=p; {|r| is start of possible run}
k:=native_length(r);
@@ -13953,15 +13969,30 @@ while p<>null do begin
check_next:
@<Advance |q| past ignorable nodes@>;
if (q <> null) and not is_char_node(q) then begin
- if (type(q) = glue_node) and (subtype(q) = normal) and (glue_ptr(q) = font_glue[native_font(r)]) then begin
- {found a normal space; if the next node is another word in the same font, we'll merge}
- q:=link(q);
- @<Advance |q| past ignorable nodes@>;
- if is_native_word_node(q) and (native_font(q) = native_font(r)) then begin
- p:=q; {record new tail of run in |p|}
- k:=k + 1 + native_length(q);
+ if (type(q) = glue_node) and (subtype(q) = normal) then begin
+ if (glue_ptr(q) = font_glue[native_font(r)]) then begin
+ {found a normal space; if the next node is another word in the same font, we'll merge}
+ q:=link(q);
+ @<Advance |q| past ignorable nodes@>;
+ if is_native_word_node(q) and (native_font(q) = native_font(r)) then begin
+ p:=q; {record new tail of run in |p|}
+ k:=k + 1 + native_length(q);
+ q:=link(q);
+ goto check_next;
+ end
+ end else q:=link(q);
+ {we'll also merge if if space-adjustment was applied at this glue,
+ even if it wasn't the font's standard inter-word space}
+ if (q <> null) and not is_char_node(q) and (type(q) = kern_node) and
+ (subtype(q) = space_adjustment) then begin
q:=link(q);
- goto check_next;
+ @<Advance |q| past ignorable nodes@>;
+ if is_native_word_node(q) and (native_font(q) = native_font(r)) then begin
+ p:=q; {record new tail of run in |p|}
+ k:=k + 1 + native_length(q);
+ q:=link(q);
+ goto check_next;
+ end
end;
goto end_node_run;
end;
@@ -13998,22 +14029,44 @@ end_node_run: {now |r| points to first |native_word_node| of the run, and |p| to
end
end
end
+ end else if type(q) = kern_node then begin
+ k:=k + width(q);
end;
{discretionary and deleted nodes can be discarded here}
if q = p then break
else q:=link(q);
end;
+ { create the new merged node |q| }
q:=new_native_word_node(native_font(r), cur_length);
- link(prev_p):=q;
for j:=0 to cur_length - 1 do
set_native_char(q, j, str_pool[str_start_macro(str_ptr) + j]);
+ { impose the required width on |q|, and shape its text accordingly }
+ width(q):=k;
+ set_justified_native_glyphs(q);
+ { link |q| into the list in place of |r|..|p| }
+ link(prev_p):=q;
link(q):=link(p);
link(p):=null;
+ { Extract any "invisible" nodes from the old list and insert them after the new node,
+ so we don't lose them altogether. Note that the first node cannot be one of these,
+ as we always start merging at a native_word node. }
+ prev_p := r;
+ p := link(r);
+ while p <> null do begin
+ if node_is_invisible_to_interword_space(p) then begin
+ link(prev_p) := link(p);
+ link(p) := link(q);
+ link(q) := p;
+ q := p;
+ end;
+ prev_p := p;
+ p := link(p);
+ end;
+ { discard the remains of the old list }
flush_node_list(r);
- width(q):=k;
- set_justified_native_glyphs(q);
- p:=q;
+ { clean up and prepare for the next round }
pool_ptr:=str_start_macro(str_ptr); {flush the temporary string data}
+ p:=q;
end
end;
prev_p:=p;
@@ -14022,7 +14075,7 @@ end_node_run: {now |r| points to first |native_word_node| of the run, and |p| to
end
@ @<Advance |q| past ignorable nodes@>=
-while (q <> null) and (not is_char_node(q)) and (type(q) = disc_node) do
+while (q <> null) and node_is_invisible_to_interword_space(q) do
q:=link(q)
@ We ought to give special care to the efficiency of one part of |hlist_out|,
@@ -19418,7 +19471,8 @@ width of this glue is subtracted from the background; and we also look
ahead to eliminate all subsequent glue and penalty and kern and math
nodes, subtracting their widths as well.
-Kern nodes do not disappear at a line break unless they are |explicit|.
+Kern nodes do not disappear at a line break unless they are |explicit|
+or |space_adjustment|.
@d set_break_width_to_background(#)==break_width[#]:=background[#]
@@ -20282,7 +20336,7 @@ loop@+ begin q:=link(r);
{now |q| cannot be |null|}
if is_char_node(q) then goto done1;
if non_discardable(q) then goto done1;
- if type(q)=kern_node then if subtype(q)<>explicit then goto done1;
+ if type(q)=kern_node then if (subtype(q)<>explicit) and (subtype(q)<>space_adjustment) then goto done1;
r:=q; {now |type(q)=glue_node|, |kern_node|, |math_node| or |penalty_node|}
if type(q)=math_node then if TeXXeT_en then
@<Adjust \(t)the LR stack for the |post_line_break| routine@>;
@@ -23646,6 +23700,80 @@ collected:
end
end;
+ if XeTeX_interword_space_shaping_state > 0 then begin
+ { |tail| is a word we have just appended. If it is preceded by another word
+ with a normal inter-word space between (all in the same font), then we will
+ measure that space in context and replace it with an adjusted glue value
+ if it differs from the font's normal space. }
+
+ { First we look for the most recent native_word in the list and set |main_pp| to it.
+ This is potentially expensive, in the case of very long paragraphs,
+ but in practice it's negligible compared to the cost of shaping and measurement. }
+ main_p := head;
+ main_pp := null;
+ while main_p <> tail do begin
+ if is_native_word_node(main_p) then main_pp := main_p;
+ main_p := link(main_p);
+ end;
+
+ if (main_pp <> null) then begin
+ { check if the font matches; if so, check the intervening nodes }
+ if (native_font(main_pp) = main_f) then begin
+ main_p := link(main_pp);
+
+ { Skip nodes that should be invisible to inter-word spacing,
+ so that e.g. |\nobreak\ | doesn't prevent contextual measurement.
+ This loop is guaranteed to end safely because it'll eventually hit
+ |tail|, which is a native_word node, if nothing else intervenes. }
+ while node_is_invisible_to_interword_space(main_p) do
+ main_p := link(main_p);
+
+ if not is_char_node(main_p) and (type(main_p) = glue_node) then begin
+ { We found a glue node: we might have an inter-word space to deal with.
+ Again, skip nodes that should be invisible to inter-word spacing.
+ We leave |main_p| pointing to the glue node; |main_pp| is the preceding word. }
+ main_ppp := link(main_p);
+ while node_is_invisible_to_interword_space(main_ppp) do
+ main_ppp := link(main_ppp);
+
+ if main_ppp = tail then begin
+ { We found a candidate inter-word space! Collect the characters of both words,
+ separated by a single space, into a native_word node and measure its overall width. }
+ temp_ptr := new_native_word_node(main_f, native_length(main_pp) + 1 + native_length(tail));
+ main_k := 0;
+ for t := 0 to native_length(main_pp)-1 do begin
+ set_native_char(temp_ptr, main_k, get_native_char(main_pp, t));
+ incr(main_k);
+ end;
+ set_native_char(temp_ptr, main_k, " ");
+ incr(main_k);
+ for t := 0 to native_length(tail)-1 do begin
+ set_native_char(temp_ptr, main_k, get_native_char(tail, t));
+ incr(main_k);
+ end;
+ set_native_metrics(temp_ptr, XeTeX_use_glyph_metrics);
+
+ { The contextual space width is the difference between this width and
+ the sum of the two words measured separately. }
+ t := width(temp_ptr) - width(main_pp) - width(tail);
+ free_node(temp_ptr, native_size(temp_ptr));
+
+ { If the desired width differs from the font's default word space,
+ we will insert a suitable kern after the existing glue.
+ Because kerns are discardable, this will behave OK during line breaking,
+ and it's easier than actually modifying/replacing the glue node. }
+ if t <> width(font_glue[main_f]) then begin
+ temp_ptr := new_kern(t - width(font_glue[main_f]));
+ subtype(temp_ptr) := space_adjustment;
+ link(temp_ptr) := link(main_p);
+ link(main_p) := temp_ptr;
+ end
+ end
+ end
+ end
+ end
+ end;
+
if cur_ptr<>null then goto big_switch
else goto reswitch;
end;
@@ -30898,6 +31026,8 @@ and is never inhibited for words originating from horizontal mode.
@d XeTeX_input_normalization_state == eTeX_state(XeTeX_input_normalization_code)
@d XeTeX_tracing_fonts_state == eTeX_state(XeTeX_tracing_fonts_code)
+@d XeTeX_interword_space_shaping_state==eTeX_state(XeTeX_interword_space_shaping_code)
+
@d XeTeX_default_input_mode == eTeX_state(XeTeX_default_input_mode_code)
@d XeTeX_default_input_encoding == eTeX_state(XeTeX_default_input_encoding_code)
@@ -30910,6 +31040,7 @@ eTeX_state_code+XeTeX_inter_char_tokens_code:print_esc("XeTeXinterchartokenstate
eTeX_state_code+XeTeX_dash_break_code:print_esc("XeTeXdashbreakstate");
eTeX_state_code+XeTeX_input_normalization_code:print_esc("XeTeXinputnormalization");
eTeX_state_code+XeTeX_tracing_fonts_code:print_esc("XeTeXtracingfonts");
+eTeX_state_code+XeTeX_interword_space_shaping_code:print_esc("XeTeXinterwordspaceshaping");
@ @<Generate all \eTeX...@>=
primitive("suppressfontnotfounderror",assign_int,int_base+suppress_fontnotfound_error_code);@/
@@ -30930,6 +31061,9 @@ primitive("XeTeXinputnormalization",assign_int,eTeX_state_base+XeTeX_input_norma
primitive("XeTeXtracingfonts",assign_int,eTeX_state_base+XeTeX_tracing_fonts_code);
+primitive("XeTeXinterwordspaceshaping",assign_int,eTeX_state_base+XeTeX_interword_space_shaping_code);
+@!@:XeTeX_interword_space_shaping_}{\.{\\XeTeXinterwordspaceshaping} primitive@>
+
primitive("XeTeXinputencoding",extension,XeTeX_input_encoding_extension_code);
primitive("XeTeXdefaultencoding",extension,XeTeX_default_encoding_extension_code);
primitive("beginL",valign,begin_L_code);