Merge pull request #43981 from bruvzg/ctl_font_spacing

[Complex Text Layouts] Adds missing Font::SPACING_* to the controls, align glyphs to pixel grid.
This commit is contained in:
Rémi Verschelde
2020-12-07 11:08:34 +01:00
committed by GitHub
15 changed files with 374 additions and 242 deletions

View File

@ -625,7 +625,11 @@ bool TextServerFallback::shaped_text_resize_object(RID p_shaped, Variant p_key,
sd->width = 0;
sd->upos = 0;
sd->uthk = 0;
for (int i = 0; i < sd->glyphs.size(); i++) {
int sd_size = sd->glyphs.size();
const FontDataFallback *fd = nullptr;
RID prev_rid = RID();
for (int i = 0; i < sd_size; i++) {
Glyph gl = sd->glyphs[i];
Variant key;
if (gl.count == 1) {
@ -645,8 +649,8 @@ bool TextServerFallback::shaped_text_resize_object(RID p_shaped, Variant p_key,
sd->ascent = MAX(sd->ascent, sd->objects[key].rect.size.y);
} break;
case VALIGN_CENTER: {
sd->ascent = MAX(sd->ascent, sd->objects[key].rect.size.y / 2);
sd->descent = MAX(sd->descent, sd->objects[key].rect.size.y / 2);
sd->ascent = MAX(sd->ascent, Math::round(sd->objects[key].rect.size.y / 2));
sd->descent = MAX(sd->descent, Math::round(sd->objects[key].rect.size.y / 2));
} break;
case VALIGN_BOTTOM: {
sd->descent = MAX(sd->descent, sd->objects[key].rect.size.y);
@ -661,8 +665,8 @@ bool TextServerFallback::shaped_text_resize_object(RID p_shaped, Variant p_key,
sd->ascent = MAX(sd->ascent, sd->objects[key].rect.size.x);
} break;
case VALIGN_CENTER: {
sd->ascent = MAX(sd->ascent, sd->objects[key].rect.size.x / 2);
sd->descent = MAX(sd->descent, sd->objects[key].rect.size.x / 2);
sd->ascent = MAX(sd->ascent, Math::round(sd->objects[key].rect.size.x / 2));
sd->descent = MAX(sd->descent, Math::round(sd->objects[key].rect.size.x / 2));
} break;
case VALIGN_BOTTOM: {
sd->descent = MAX(sd->descent, sd->objects[key].rect.size.x);
@ -671,25 +675,28 @@ bool TextServerFallback::shaped_text_resize_object(RID p_shaped, Variant p_key,
sd->glyphs.write[i].advance = sd->objects[key].rect.size.y;
}
} else {
const FontDataFallback *fd = font_owner.getornull(gl.font_rid);
if (prev_rid != gl.font_rid) {
fd = font_owner.getornull(gl.font_rid);
prev_rid = gl.font_rid;
}
if (fd != nullptr) {
if (sd->orientation == ORIENTATION_HORIZONTAL) {
sd->ascent = MAX(sd->ascent, fd->get_ascent(gl.font_size));
sd->descent = MAX(sd->descent, fd->get_descent(gl.font_size));
} else {
sd->ascent = MAX(sd->ascent, fd->get_advance(gl.index, gl.font_size).x * 0.5);
sd->descent = MAX(sd->descent, fd->get_advance(gl.index, gl.font_size).x * 0.5);
sd->ascent = MAX(sd->ascent, Math::round(fd->get_advance(gl.index, gl.font_size).x * 0.5));
sd->descent = MAX(sd->descent, Math::round(fd->get_advance(gl.index, gl.font_size).x * 0.5));
}
sd->upos = MAX(sd->upos, font_get_underline_position(gl.font_rid, gl.font_size));
sd->uthk = MAX(sd->uthk, font_get_underline_thickness(gl.font_rid, gl.font_size));
} else if (sd->preserve_invalid || (sd->preserve_control && is_control(gl.index))) {
// Glyph not found, replace with hex code box.
if (sd->orientation == ORIENTATION_HORIZONTAL) {
sd->ascent = MAX(sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.75f);
sd->descent = MAX(sd->descent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.25f);
sd->ascent = MAX(sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.75f));
sd->descent = MAX(sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.25f));
} else {
sd->ascent = MAX(sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f);
sd->descent = MAX(sd->descent, get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f);
sd->ascent = MAX(sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f));
sd->descent = MAX(sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f));
}
}
sd->width += gl.advance * gl.repeat;
@ -760,21 +767,25 @@ RID TextServerFallback::shaped_text_substr(RID p_shaped, int p_start, int p_leng
if (p_length > 0) {
new_sd->text = sd->text.substr(p_start, p_length);
int sd_size = sd->glyphs.size();
const Glyph *sd_glyphs = sd->glyphs.ptr();
for (int i = 0; i < sd->glyphs.size(); i++) {
if ((sd->glyphs[i].start >= new_sd->start) && (sd->glyphs[i].end <= new_sd->end)) {
Glyph gl = sd->glyphs[i];
for (int i = 0; i < sd_size; i++) {
if ((sd_glyphs[i].start >= new_sd->start) && (sd_glyphs[i].end <= new_sd->end)) {
Glyph gl = sd_glyphs[i];
Variant key;
bool find_embedded = false;
if (gl.count == 1) {
for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = sd->objects.front(); E; E = E->next()) {
if (E->get().pos == gl.start) {
find_embedded = true;
key = E->key();
new_sd->objects[key] = E->get();
break;
}
}
}
if (key != Variant()) {
if (find_embedded) {
if (new_sd->orientation == ORIENTATION_HORIZONTAL) {
new_sd->objects[key].rect.position.x = new_sd->width;
new_sd->width += new_sd->objects[key].rect.size.x;
@ -783,8 +794,8 @@ RID TextServerFallback::shaped_text_substr(RID p_shaped, int p_start, int p_leng
new_sd->ascent = MAX(new_sd->ascent, new_sd->objects[key].rect.size.y);
} break;
case VALIGN_CENTER: {
new_sd->ascent = MAX(new_sd->ascent, new_sd->objects[key].rect.size.y / 2);
new_sd->descent = MAX(new_sd->descent, new_sd->objects[key].rect.size.y / 2);
new_sd->ascent = MAX(new_sd->ascent, Math::round(new_sd->objects[key].rect.size.y / 2));
new_sd->descent = MAX(new_sd->descent, Math::round(new_sd->objects[key].rect.size.y / 2));
} break;
case VALIGN_BOTTOM: {
new_sd->descent = MAX(new_sd->descent, new_sd->objects[key].rect.size.y);
@ -798,8 +809,8 @@ RID TextServerFallback::shaped_text_substr(RID p_shaped, int p_start, int p_leng
new_sd->ascent = MAX(new_sd->ascent, new_sd->objects[key].rect.size.x);
} break;
case VALIGN_CENTER: {
new_sd->ascent = MAX(new_sd->ascent, new_sd->objects[key].rect.size.x / 2);
new_sd->descent = MAX(new_sd->descent, new_sd->objects[key].rect.size.x / 2);
new_sd->ascent = MAX(new_sd->ascent, Math::round(new_sd->objects[key].rect.size.x / 2));
new_sd->descent = MAX(new_sd->descent, Math::round(new_sd->objects[key].rect.size.x / 2));
} break;
case VALIGN_BOTTOM: {
new_sd->descent = MAX(new_sd->descent, new_sd->objects[key].rect.size.x);
@ -813,17 +824,17 @@ RID TextServerFallback::shaped_text_substr(RID p_shaped, int p_start, int p_leng
new_sd->ascent = MAX(new_sd->ascent, fd->get_ascent(gl.font_size));
new_sd->descent = MAX(new_sd->descent, fd->get_descent(gl.font_size));
} else {
new_sd->ascent = MAX(new_sd->ascent, fd->get_advance(gl.index, gl.font_size).x * 0.5);
new_sd->descent = MAX(new_sd->descent, fd->get_advance(gl.index, gl.font_size).x * 0.5);
new_sd->ascent = MAX(new_sd->ascent, Math::round(fd->get_advance(gl.index, gl.font_size).x * 0.5));
new_sd->descent = MAX(new_sd->descent, Math::round(fd->get_advance(gl.index, gl.font_size).x * 0.5));
}
} else if (new_sd->preserve_invalid || (new_sd->preserve_control && is_control(gl.index))) {
// Glyph not found, replace with hex code box.
if (new_sd->orientation == ORIENTATION_HORIZONTAL) {
new_sd->ascent = MAX(new_sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.75f);
new_sd->descent = MAX(new_sd->descent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.25f);
new_sd->ascent = MAX(new_sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.75f));
new_sd->descent = MAX(new_sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.25f));
} else {
new_sd->ascent = MAX(new_sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f);
new_sd->descent = MAX(new_sd->descent, get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f);
new_sd->ascent = MAX(new_sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f));
new_sd->descent = MAX(new_sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f));
}
}
new_sd->width += gl.advance * gl.repeat;
@ -943,7 +954,7 @@ float TextServerFallback::shaped_text_fit_to_width(RID p_shaped, float p_width,
if (gl.count > 0) {
if ((gl.flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE) {
float old_adv = gl.advance;
gl.advance = MAX(gl.advance + delta_width_per_space, 0.05 * gl.font_size);
gl.advance = Math::round(MAX(gl.advance + delta_width_per_space, 0.05 * gl.font_size));
sd->width += (gl.advance - old_adv);
}
}
@ -978,8 +989,10 @@ float TextServerFallback::shaped_text_tab_align(RID p_shaped, const Vector<float
delta = -1;
}
Glyph *gl = sd->glyphs.ptrw();
for (int i = start; i != end; i += delta) {
if ((sd->glyphs[i].flags & GRAPHEME_IS_TAB) == GRAPHEME_IS_TAB) {
if ((gl[i].flags & GRAPHEME_IS_TAB) == GRAPHEME_IS_TAB) {
float tab_off = 0.f;
while (tab_off <= off) {
tab_off += p_tab_stops[tab_index];
@ -988,13 +1001,13 @@ float TextServerFallback::shaped_text_tab_align(RID p_shaped, const Vector<float
tab_index = 0;
}
}
float old_adv = sd->glyphs.write[i].advance;
sd->glyphs.write[i].advance = (tab_off - off);
sd->width += sd->glyphs.write[i].advance - old_adv;
float old_adv = gl[i].advance;
gl[i].advance = tab_off - off;
sd->width += gl[i].advance - old_adv;
off = 0;
continue;
}
off += sd->glyphs[i].advance * sd->glyphs[i].repeat;
off += gl[i].advance * gl[i].repeat;
}
return 0.f;
@ -1012,7 +1025,8 @@ bool TextServerFallback::shaped_text_update_breaks(RID p_shaped) {
return true; // Noting to do.
}
for (int i = 0; i < sd->glyphs.size(); i++) {
int sd_size = sd->glyphs.size();
for (int i = 0; i < sd_size; i++) {
if (sd->glyphs[i].count > 0) {
char32_t c = sd->text[sd->glyphs[i].start];
if (is_whitespace(c) && !is_linebreak(c)) {
@ -1086,8 +1100,8 @@ bool TextServerFallback::shaped_text_shape(RID p_shaped) {
sd->ascent = MAX(sd->ascent, sd->objects[span.embedded_key].rect.size.y);
} break;
case VALIGN_CENTER: {
sd->ascent = MAX(sd->ascent, sd->objects[span.embedded_key].rect.size.y / 2);
sd->descent = MAX(sd->descent, sd->objects[span.embedded_key].rect.size.y / 2);
sd->ascent = MAX(sd->ascent, Math::round(sd->objects[span.embedded_key].rect.size.y / 2));
sd->descent = MAX(sd->descent, Math::round(sd->objects[span.embedded_key].rect.size.y / 2));
} break;
case VALIGN_BOTTOM: {
sd->descent = MAX(sd->descent, sd->objects[span.embedded_key].rect.size.y);
@ -1101,8 +1115,8 @@ bool TextServerFallback::shaped_text_shape(RID p_shaped) {
sd->ascent = MAX(sd->ascent, sd->objects[span.embedded_key].rect.size.x);
} break;
case VALIGN_CENTER: {
sd->ascent = MAX(sd->ascent, sd->objects[span.embedded_key].rect.size.x / 2);
sd->descent = MAX(sd->descent, sd->objects[span.embedded_key].rect.size.x / 2);
sd->ascent = MAX(sd->ascent, Math::round(sd->objects[span.embedded_key].rect.size.x / 2));
sd->descent = MAX(sd->descent, Math::round(sd->objects[span.embedded_key].rect.size.x / 2));
} break;
case VALIGN_BOTTOM: {
sd->descent = MAX(sd->descent, sd->objects[span.embedded_key].rect.size.x);
@ -1157,14 +1171,14 @@ bool TextServerFallback::shaped_text_shape(RID p_shaped) {
sd->descent = MAX(sd->descent, fd->get_descent(gl.font_size));
} else {
gl.advance = fd->get_advance(gl.index, gl.font_size).y;
gl.x_off = -fd->get_advance(gl.index, gl.font_size).x * 0.5;
gl.x_off = -Math::round(fd->get_advance(gl.index, gl.font_size).x * 0.5);
gl.y_off = fd->get_ascent(gl.font_size);
sd->ascent = MAX(sd->ascent, fd->get_advance(gl.index, gl.font_size).x * 0.5);
sd->descent = MAX(sd->descent, fd->get_advance(gl.index, gl.font_size).x * 0.5);
sd->ascent = MAX(sd->ascent, Math::round(fd->get_advance(gl.index, gl.font_size).x * 0.5));
sd->descent = MAX(sd->descent, Math::round(fd->get_advance(gl.index, gl.font_size).x * 0.5));
}
}
sd->upos = MAX(sd->upos, font_get_underline_position(gl.font_rid, gl.font_size));
sd->uthk = MAX(sd->uthk, font_get_underline_thickness(gl.font_rid, gl.font_size));
sd->upos = MAX(sd->upos, fd->get_underline_position(gl.font_size));
sd->uthk = MAX(sd->uthk, fd->get_underline_thickness(gl.font_size));
// Add kerning to previous glyph.
if (sd->glyphs.size() > 0) {
@ -1181,12 +1195,12 @@ bool TextServerFallback::shaped_text_shape(RID p_shaped) {
// Glyph not found, replace with hex code box.
if (sd->orientation == ORIENTATION_HORIZONTAL) {
gl.advance = get_hex_code_box_size(gl.font_size, gl.index).x;
sd->ascent = MAX(sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.75f);
sd->descent = MAX(sd->descent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.25f);
sd->ascent = MAX(sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.75f));
sd->descent = MAX(sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.25f));
} else {
gl.advance = get_hex_code_box_size(gl.font_size, gl.index).y;
sd->ascent = MAX(sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f);
sd->descent = MAX(sd->descent, get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f);
sd->ascent = MAX(sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f));
sd->descent = MAX(sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f));
}
}
sd->width += gl.advance;