Fix Cursive positioning

Test case: "مرا" rendered using IranNastaliq.
This commit is contained in:
Behdad Esfahbod 2010-10-27 11:09:48 -04:00
parent aefdb64689
commit ea22c749c7
1 changed files with 3 additions and 121 deletions

View File

@ -826,123 +826,6 @@ struct CursivePosFormat1
inline bool apply (hb_apply_context_t *c) const inline bool apply (hb_apply_context_t *c) const
{ {
TRACE_APPLY (); TRACE_APPLY ();
/* Now comes the messiest part of the whole OpenType
specification. At first glance, cursive connections seem easy
to understand, but there are pitfalls! The reason is that
the specs don't mention how to compute the advance values
resp. glyph offsets. I was told it would be an omission, to
be fixed in the next OpenType version... Again many thanks to
Andrei Burago <andreib@microsoft.com> for clarifications.
Consider the following example:
| xadv1 |
+---------+
| |
+-----+--+ 1 |
| | .| |
| 0+--+------+
| 2 |
| |
0+--------+
| xadv2 |
glyph1: advance width = 12
anchor point = (3,1)
glyph2: advance width = 11
anchor point = (9,4)
LSB is 1 for both glyphs (so the boxes drawn above are glyph
bboxes). Writing direction is R2L; `0' denotes the glyph's
coordinate origin.
Now the surprising part: The advance width of the *left* glyph
(resp. of the *bottom* glyph) will be modified, no matter
whether the writing direction is L2R or R2L (resp. T2B or
B2T)! This assymetry is caused by the fact that the glyph's
coordinate origin is always the lower left corner for all
writing directions.
Continuing the above example, we can compute the new
(horizontal) advance width of glyph2 as
9 - 3 = 6 ,
and the new vertical offset of glyph2 as
1 - 4 = -3 .
Vertical writing direction is far more complicated:
a) Assuming that we recompute the advance height of the lower glyph:
--
+---------+
-- | |
+-----+--+ 1 | yadv1
| | .| |
yadv2 | 0+--+------+ -- BSB1 --
| 2 | -- -- y_offset
| |
BSB2 -- 0+--------+ --
-- --
glyph1: advance height = 6
anchor point = (3,1)
glyph2: advance height = 7
anchor point = (9,4)
TSB is 1 for both glyphs; writing direction is T2B.
BSB1 = yadv1 - (TSB1 + ymax1)
BSB2 = yadv2 - (TSB2 + ymax2)
y_offset = y2 - y1
vertical advance width of glyph2
= y_offset + BSB2 - BSB1
= (y2 - y1) + (yadv2 - (TSB2 + ymax2)) - (yadv1 - (TSB1 + ymax1))
= y2 - y1 + yadv2 - TSB2 - ymax2 - (yadv1 - TSB1 - ymax1)
= y2 - y1 + yadv2 - TSB2 - ymax2 - yadv1 + TSB1 + ymax1
b) Assuming that we recompute the advance height of the upper glyph:
-- --
+---------+ -- TSB1
-- -- | |
TSB2 -- +-----+--+ 1 | yadv1 ymax1
| | .| |
yadv2 | 0+--+------+ -- --
ymax2 | 2 | -- y_offset
| |
-- 0+--------+ --
--
glyph1: advance height = 6
anchor point = (3,1)
glyph2: advance height = 7
anchor point = (9,4)
TSB is 1 for both glyphs; writing direction is T2B.
y_offset = y2 - y1
vertical advance width of glyph2
= TSB1 + ymax1 + y_offset - (TSB2 + ymax2)
= TSB1 + ymax1 + y2 - y1 - TSB2 - ymax2
Comparing a) with b) shows that b) is easier to compute. I'll wait
for a reply from Andrei to see what should really be implemented...
Since horizontal advance widths or vertical advance heights
can be used alone but not together, no ambiguity occurs. */
struct hb_ot_layout_context_t::info_t::gpos_t *gpi = &c->layout->info.gpos; struct hb_ot_layout_context_t::info_t::gpos_t *gpi = &c->layout->info.gpos;
hb_codepoint_t last_pos = gpi->last; hb_codepoint_t last_pos = gpi->last;
gpi->last = HB_OT_LAYOUT_GPOS_NO_LAST; gpi->last = HB_OT_LAYOUT_GPOS_NO_LAST;
@ -965,15 +848,14 @@ struct CursivePosFormat1
/* TODO vertical */ /* TODO vertical */
/* Align the exit anchor of the left glyph with the entry anchor of the right glyph. */
if (c->buffer->props.direction == HB_DIRECTION_RTL) if (c->buffer->props.direction == HB_DIRECTION_RTL)
{ {
/* advance is absolute, not relative */ c->buffer->pos[c->buffer->i].x_advance = c->buffer->pos[c->buffer->i].x_offset + entry_x - gpi->anchor_x;
c->buffer->pos[c->buffer->i].x_advance = entry_x - gpi->anchor_x;
} }
else else
{ {
/* advance is absolute, not relative */ c->buffer->pos[last_pos].x_advance = c->buffer->pos[last_pos].x_advance + gpi->anchor_x - entry_x;
c->buffer->pos[last_pos].x_advance = gpi->anchor_x - entry_x;
} }
if (c->lookup_flag & LookupFlag::RightToLeft) if (c->lookup_flag & LookupFlag::RightToLeft)