From d18fd8e3f7185f531fa4c4988d3f5d5c5282b8eb Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Tue, 19 May 2009 23:25:41 -0400 Subject: [PATCH] [GPOS] CursivePosFormat1 --- src/hb-ot-layout-gpos-private.h | 174 ++++++++++++++++++++++++++++++++++++++-- src/hb-ot-layout-private.h | 2 +- 2 files changed, 169 insertions(+), 7 deletions(-) diff --git a/src/hb-ot-layout-gpos-private.h b/src/hb-ot-layout-gpos-private.h index 65a1a49..b4b6b3b 100644 --- a/src/hb-ot-layout-gpos-private.h +++ b/src/hb-ot-layout-gpos-private.h @@ -532,9 +532,6 @@ ASSERT_SIZE (PairPos, 2); struct EntryExitRecord { - /* TODO */ - - private: OffsetTo entryAnchor; /* Offset to EntryAnchor table--from * beginning of CursivePos @@ -551,9 +548,174 @@ struct CursivePosFormat1 { friend struct CursivePos; private: - inline bool apply (APPLY_ARG_DEF) const { - /* TODO */ - return false; + inline bool apply (APPLY_ARG_DEF) const + { + struct hb_ot_layout_t::gpos_info_t *gpi = &layout->gpos_info; + hb_codepoint_t last_pos = gpi->last; + gpi->last = 0xFFFF; + + /* We don't handle mark glyphs here. */ + if (property == HB_OT_LAYOUT_GLYPH_CLASS_MARK) + return false; + + unsigned int index = (this+coverage) (IN_CURGLYPH ()); + if (HB_LIKELY (index == NOT_COVERED)) + return false; + + /* 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 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. */ + + const EntryExitRecord &record = entryExitRecord[index]; + + hb_position_t entry_x, entry_y, exit_x, exit_y; + + if (last_pos == 0xFFFF || !record.entryAnchor) + goto end; + + (this+record.entryAnchor).get_anchor (layout, IN_CURGLYPH (), &entry_x, &entry_y); + + if (gpi->r2l) + { + POSITION (buffer->in_pos)->x_advance = entry_x - gpi->anchor_x; + POSITION (buffer->in_pos)->new_advance = TRUE; + } + else + { + POSITION (gpi->last)->x_advance = gpi->anchor_x - entry_x; + POSITION (gpi->last)->new_advance = TRUE; + } + + if (lookup_flag & LookupFlag::RightToLeft) + { + POSITION (gpi->last)->cursive_chain = gpi->last - buffer->in_pos; + POSITION (gpi->last)->y_pos = entry_y - gpi->anchor_y; + } + else + { + POSITION (buffer->in_pos)->cursive_chain = buffer->in_pos - gpi->last; + POSITION (buffer->in_pos)->y_pos = gpi->anchor_y - entry_y; + } + + end: + if (record.exitAnchor) + (this+record.exitAnchor).get_anchor (layout, IN_CURGLYPH (), &gpi->anchor_x, &gpi->anchor_y); + + buffer->in_pos++; + return true; } private: diff --git a/src/hb-ot-layout-private.h b/src/hb-ot-layout-private.h index 540145b..43ea247 100644 --- a/src/hb-ot-layout-private.h +++ b/src/hb-ot-layout-private.h @@ -47,7 +47,7 @@ struct _hb_ot_layout_t { } new_gdef; /* TODO full-matrix transformation? */ - struct { + struct gpos_info_t { unsigned int x_ppem, y_ppem; hb_16dot16_t x_scale, y_scale; -- 2.7.4