@@ -80,9 +80,8 @@ propagate_attachment_offsets (hb_glyph_position_t *pos,
8080{
8181 /* Adjusts offsets of attached glyphs (both cursive and mark) to accumulate
8282 * offset of glyph they are attached to. */
83- int chain = pos[i].attach_chain (), type = pos[i].attach_type ();
84- if (likely (!chain))
85- return ;
83+ int chain = pos[i].attach_chain ();
84+ int type = pos[i].attach_type ();
8685
8786 pos[i].attach_chain () = 0 ;
8887
@@ -94,7 +93,8 @@ propagate_attachment_offsets (hb_glyph_position_t *pos,
9493 if (unlikely (!nesting_level))
9594 return ;
9695
97- propagate_attachment_offsets (pos, len, j, direction, nesting_level - 1 );
96+ if (pos[j].attach_chain ())
97+ propagate_attachment_offsets (pos, len, j, direction, nesting_level - 1 );
9898
9999 assert (!!(type & GPOS_impl::ATTACH_TYPE_MARK) ^ !!(type & GPOS_impl::ATTACH_TYPE_CURSIVE));
100100
@@ -110,17 +110,37 @@ propagate_attachment_offsets (hb_glyph_position_t *pos,
110110 pos[i].x_offset += pos[j].x_offset ;
111111 pos[i].y_offset += pos[j].y_offset ;
112112
113- assert (j < i);
114- if (HB_DIRECTION_IS_FORWARD (direction))
115- for (unsigned int k = j; k < i; k++) {
116- pos[i].x_offset -= pos[k].x_advance ;
117- pos[i].y_offset -= pos[k].y_advance ;
118- }
119- else
120- for (unsigned int k = j + 1 ; k < i + 1 ; k++) {
121- pos[i].x_offset += pos[k].x_advance ;
122- pos[i].y_offset += pos[k].y_advance ;
123- }
113+ // i is the position of the mark; j is the base.
114+ if (j < i)
115+ {
116+ /* This is the common case: mark follows base.
117+ * And currently the only way in OpenType. */
118+ if (HB_DIRECTION_IS_FORWARD (direction))
119+ for (unsigned int k = j; k < i; k++) {
120+ pos[i].x_offset -= pos[k].x_advance ;
121+ pos[i].y_offset -= pos[k].y_advance ;
122+ }
123+ else
124+ for (unsigned int k = j + 1 ; k < i + 1 ; k++) {
125+ pos[i].x_offset += pos[k].x_advance ;
126+ pos[i].y_offset += pos[k].y_advance ;
127+ }
128+ }
129+ else // j > i
130+ {
131+ /* This can happen with `kerx`: a mark attaching
132+ * to a base after it in the logical order. */
133+ if (HB_DIRECTION_IS_FORWARD (direction))
134+ for (unsigned int k = i; k < j; k++) {
135+ pos[i].x_offset += pos[k].x_advance ;
136+ pos[i].y_offset += pos[k].y_advance ;
137+ }
138+ else
139+ for (unsigned int k = i + 1 ; k < j + 1 ; k++) {
140+ pos[i].x_offset -= pos[k].x_advance ;
141+ pos[i].y_offset -= pos[k].y_advance ;
142+ }
143+ }
124144 }
125145}
126146
@@ -149,8 +169,20 @@ GPOS::position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer)
149169
150170 /* Handle attachments */
151171 if (buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT)
152- for (unsigned i = 0 ; i < len; i++)
153- propagate_attachment_offsets (pos, len, i, direction);
172+ {
173+ auto *pos = buffer->pos ;
174+ // https://github.com/harfbuzz/harfbuzz/issues/5514
175+ if (HB_DIRECTION_IS_FORWARD (direction))
176+ {
177+ for (unsigned i = 0 ; i < len; i++)
178+ if (pos[i].attach_chain ())
179+ propagate_attachment_offsets (pos, len, i, direction);
180+ } else {
181+ for (unsigned i = len; i-- > 0 ; )
182+ if (pos[i].attach_chain ())
183+ propagate_attachment_offsets (pos, len, i, direction);
184+ }
185+ }
154186
155187 if (unlikely (font->slant_xy ) &&
156188 HB_DIRECTION_IS_HORIZONTAL (direction))
0 commit comments