diff --git a/src/hb-shape.cc b/src/hb-shape.cc index 52047877d..89d354fc0 100644 --- a/src/hb-shape.cc +++ b/src/hb-shape.cc @@ -246,6 +246,9 @@ reset_buffer (hb_buffer_t *buffer, * In addition, justify the shaping results such that the shaping results reach * the target advance width/height, depending on the buffer direction. * + * If the advance of the buffer shaped with hb_shape_full() is already known, + * put that in *advance. Otherwise set *advance to zero. + * * This API is currently experimental and will probably change in the future. * * Return value: false if all shapers failed, true otherwise @@ -266,6 +269,7 @@ hb_shape_justify (hb_font_t *font, { // TODO Negative font scales? + /* If default advance already matches target, nothing to do. Shape and return. */ if (min_target_advance <= *advance && *advance <= max_target_advance) return hb_shape_full (font, buffer, features, num_features, @@ -273,6 +277,8 @@ hb_shape_justify (hb_font_t *font, hb_face_t *face = font->face; + /* Choose variation tag to use for justification. */ + hb_tag_t tag = HB_TAG_NONE; hb_ot_var_axis_info_t axis_info; @@ -288,6 +294,7 @@ hb_shape_justify (hb_font_t *font, break; } + /* If no suitable variation axis found, can't justify. Just shape and return. */ if (!tag) { if (hb_shape_full (font, buffer, @@ -301,6 +308,7 @@ hb_shape_justify (hb_font_t *font, return false; } + /* Copy buffer text as we need it so we can shape multiple times. */ unsigned text_len = buffer->len; auto *text_info = (hb_glyph_info_t *) hb_malloc (text_len * sizeof (buffer->info[0])); if (unlikely (text_len && !text_info)) @@ -308,6 +316,7 @@ hb_shape_justify (hb_font_t *font, hb_memcpy (text_info, buffer->info, text_len * sizeof (buffer->info[0])); auto text = hb_array (text_info, text_len); + /* If default advance was not provided to us, calculate it. */ if (!*advance) { hb_font_set_variation (font, tag, axis_info.default_value); @@ -318,16 +327,23 @@ hb_shape_justify (hb_font_t *font, *advance = buffer_advance (buffer); } + /* If default advance already matches target, nothing to do. Shape and return. + * Do this again, in case advance was just calculated. + */ if (min_target_advance <= *advance && *advance <= max_target_advance) return true; + /* Prepare for running the solver. */ double a, b, ya, yb; if (*advance < min_target_advance) { + /* Need to expand. */ ya = (double) *advance; a = (double) axis_info.default_value; b = (double) axis_info.max_value; + /* Shape buffer for maximum expansion to use as other + * starting point for the solver. */ hb_font_set_variation (font, tag, (float) b); reset_buffer (buffer, text); if (!hb_shape_full (font, buffer, @@ -335,6 +351,8 @@ hb_shape_justify (hb_font_t *font, shaper_list)) return false; yb = (double) buffer_advance (buffer); + /* If the maximum expansion is less than max target, + * there's nothing to solve for. Just return it. */ if (yb <= (double) max_target_advance) { *advance = (float) yb; @@ -343,10 +361,13 @@ hb_shape_justify (hb_font_t *font, } else { + /* Need to shrink. */ yb = (double) *advance; a = (double) axis_info.min_value; b = (double) axis_info.default_value; + /* Shape buffer for maximum shrinkate to use as other + * starting point for the solver. */ hb_font_set_variation (font, tag, (float) a); reset_buffer (buffer, text); if (!hb_shape_full (font, buffer, @@ -354,6 +375,8 @@ hb_shape_justify (hb_font_t *font, shaper_list)) return false; ya = (double) buffer_advance (buffer); + /* If the maximum shrinkate is more than min target, + * there's nothing to solve for. Just return it. */ if (ya >= (double) min_target_advance) { *advance = (float) ya; @@ -361,6 +384,9 @@ hb_shape_justify (hb_font_t *font, } } + /* Run the solver to find a var axis value that hits + * the desired width. */ + double epsilon = (b - a) / (1<<14); bool failed = false;