Skip to content

Commit ad017a2

Browse files
committed
[TextServer] Implement soft hyphen handling.
1 parent 60b927b commit ad017a2

File tree

5 files changed

+63
-22
lines changed

5 files changed

+63
-22
lines changed

doc/classes/TextServer.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1924,6 +1924,9 @@
19241924
<constant name="GRAPHEME_IS_EMBEDDED_OBJECT" value="4096" enum="GraphemeFlag" is_bitfield="true">
19251925
Grapheme is an object replacement character for the embedded object.
19261926
</constant>
1927+
<constant name="GRAPHEME_IS_SOFT_HYPHEN" value="8192" enum="GraphemeFlag" is_bitfield="true">
1928+
Grapheme is a soft hyphen.
1929+
</constant>
19271930
<constant name="HINTING_NONE" value="0" enum="Hinting">
19281931
Disables font hinting (smoother but less crisp).
19291932
</constant>

modules/text_server_adv/text_server_adv.cpp

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4588,6 +4588,12 @@ bool TextServerAdvanced::_shape_substr(ShapedTextDataAdvanced *p_new_sd, const S
45884588
if ((sd_glyphs[j].start >= bidi_run_start) && (sd_glyphs[j].end <= bidi_run_end)) {
45894589
// Copy glyphs.
45904590
Glyph gl = sd_glyphs[j];
4591+
if (gl.end == p_start + p_length && ((gl.flags & GRAPHEME_IS_SOFT_HYPHEN) == GRAPHEME_IS_SOFT_HYPHEN)) {
4592+
uint32_t index = font_get_glyph_index(gl.font_rid, gl.font_size, 0x00ad, 0);
4593+
float w = font_get_glyph_advance(gl.font_rid, gl.font_size, index)[(p_new_sd->orientation == ORIENTATION_HORIZONTAL) ? 0 : 1];
4594+
gl.index = index;
4595+
gl.advance = w;
4596+
}
45914597
Variant key;
45924598
bool find_embedded = false;
45934599
if (gl.count == 1) {
@@ -4708,22 +4714,22 @@ double TextServerAdvanced::_shaped_text_fit_to_width(const RID &p_shaped, double
47084714

47094715
if (p_jst_flags.has_flag(JUSTIFICATION_TRIM_EDGE_SPACES)) {
47104716
// Trim spaces.
4711-
while ((start_pos < end_pos) && ((sd->glyphs[start_pos].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE || (sd->glyphs[start_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (sd->glyphs[start_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) {
4717+
while ((start_pos < end_pos) && ((sd->glyphs[start_pos].flags & GRAPHEME_IS_SOFT_HYPHEN) != GRAPHEME_IS_SOFT_HYPHEN) && ((sd->glyphs[start_pos].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE || (sd->glyphs[start_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (sd->glyphs[start_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) {
47124718
justification_width -= sd->glyphs[start_pos].advance * sd->glyphs[start_pos].repeat;
47134719
sd->glyphs.write[start_pos].advance = 0;
47144720
start_pos += sd->glyphs[start_pos].count;
47154721
}
4716-
while ((start_pos < end_pos) && ((sd->glyphs[end_pos].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE || (sd->glyphs[end_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (sd->glyphs[end_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) {
4722+
while ((start_pos < end_pos) && ((sd->glyphs[end_pos].flags & GRAPHEME_IS_SOFT_HYPHEN) != GRAPHEME_IS_SOFT_HYPHEN) && ((sd->glyphs[end_pos].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE || (sd->glyphs[end_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (sd->glyphs[end_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) {
47174723
justification_width -= sd->glyphs[end_pos].advance * sd->glyphs[end_pos].repeat;
47184724
sd->glyphs.write[end_pos].advance = 0;
47194725
end_pos -= sd->glyphs[end_pos].count;
47204726
}
47214727
} else {
47224728
// Skip breaks, but do not reset size.
4723-
while ((start_pos < end_pos) && ((sd->glyphs[start_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (sd->glyphs[start_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) {
4729+
while ((start_pos < end_pos) && ((sd->glyphs[start_pos].flags & GRAPHEME_IS_SOFT_HYPHEN) != GRAPHEME_IS_SOFT_HYPHEN) && ((sd->glyphs[start_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (sd->glyphs[start_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) {
47244730
start_pos += sd->glyphs[start_pos].count;
47254731
}
4726-
while ((start_pos < end_pos) && ((sd->glyphs[end_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (sd->glyphs[end_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) {
4732+
while ((start_pos < end_pos) && ((sd->glyphs[end_pos].flags & GRAPHEME_IS_SOFT_HYPHEN) != GRAPHEME_IS_SOFT_HYPHEN) && ((sd->glyphs[end_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (sd->glyphs[end_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) {
47274733
end_pos -= sd->glyphs[end_pos].count;
47284734
}
47294735
}
@@ -4739,7 +4745,7 @@ double TextServerAdvanced::_shaped_text_fit_to_width(const RID &p_shaped, double
47394745
elongation_count++;
47404746
}
47414747
}
4742-
if ((gl.flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE && (gl.flags & GRAPHEME_IS_PUNCTUATION) != GRAPHEME_IS_PUNCTUATION) {
4748+
if ((gl.flags & GRAPHEME_IS_SOFT_HYPHEN) != GRAPHEME_IS_SOFT_HYPHEN && (gl.flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE && (gl.flags & GRAPHEME_IS_PUNCTUATION) != GRAPHEME_IS_PUNCTUATION) {
47434749
space_count++;
47444750
}
47454751
}
@@ -4772,7 +4778,7 @@ double TextServerAdvanced::_shaped_text_fit_to_width(const RID &p_shaped, double
47724778
for (int i = start_pos; i <= end_pos; i++) {
47734779
Glyph &gl = sd->glyphs.write[i];
47744780
if (gl.count > 0) {
4775-
if ((gl.flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE && (gl.flags & GRAPHEME_IS_PUNCTUATION) != GRAPHEME_IS_PUNCTUATION) {
4781+
if ((gl.flags & GRAPHEME_IS_SOFT_HYPHEN) != GRAPHEME_IS_SOFT_HYPHEN && (gl.flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE && (gl.flags & GRAPHEME_IS_PUNCTUATION) != GRAPHEME_IS_PUNCTUATION) {
47764782
double old_adv = gl.advance;
47774783
double new_advance;
47784784
if ((gl.flags & GRAPHEME_IS_VIRTUAL) == GRAPHEME_IS_VIRTUAL) {
@@ -5420,6 +5426,9 @@ bool TextServerAdvanced::_shaped_text_update_breaks(const RID &p_shaped) {
54205426
if (c == 0x0009 || c == 0x000b) {
54215427
sd_glyphs_new[sd_shift + i].flags |= GRAPHEME_IS_TAB;
54225428
}
5429+
if (c == 0x00ad) {
5430+
sd_glyphs_new[sd_shift + i].flags |= GRAPHEME_IS_SOFT_HYPHEN;
5431+
}
54235432
if (is_whitespace(c)) {
54245433
sd_glyphs_new[sd_shift + i].flags |= GRAPHEME_IS_SPACE;
54255434
}
@@ -5441,7 +5450,7 @@ bool TextServerAdvanced::_shaped_text_update_breaks(const RID &p_shaped) {
54415450
if (sd->breaks.has(sd_glyphs[i].end)) {
54425451
if (sd->breaks[sd_glyphs[i].end] && (is_linebreak(c))) {
54435452
sd_glyphs_new[sd_shift + i].flags |= GRAPHEME_IS_BREAK_HARD;
5444-
} else if (is_whitespace(c)) {
5453+
} else if (is_whitespace(c) || c == 0x00ad) {
54455454
sd_glyphs_new[sd_shift + i].flags |= GRAPHEME_IS_BREAK_SOFT;
54465455
} else {
54475456
int count = sd_glyphs[i].count;
@@ -5660,7 +5669,7 @@ bool TextServerAdvanced::_shaped_text_update_justification_ops(const RID &p_shap
56605669
sd_glyphs[i].flags |= GRAPHEME_IS_ELONGATION;
56615670
}
56625671
if (sd->jstops.has(sd_glyphs[i].start)) {
5663-
if (c == 0xfffc) {
5672+
if (c == 0xfffc || c == 0x00ad) {
56645673
continue;
56655674
}
56665675
if (sd->jstops[sd_glyphs[i].start]) {

modules/text_server_fb/text_server_fb.cpp

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3367,6 +3367,10 @@ RID TextServerFallback::_shaped_text_substr(const RID &p_shaped, int64_t p_start
33673367
for (int i = 0; i < sd_size; i++) {
33683368
if ((sd_glyphs[i].start >= new_sd->start) && (sd_glyphs[i].end <= new_sd->end)) {
33693369
Glyph gl = sd_glyphs[i];
3370+
if (gl.end == p_start + p_length && ((gl.flags & GRAPHEME_IS_SOFT_HYPHEN) == GRAPHEME_IS_SOFT_HYPHEN)) {
3371+
gl.index = 0x00ad;
3372+
gl.advance = font_get_glyph_advance(gl.font_rid, gl.font_size, 0x00ad).x;
3373+
}
33703374
Variant key;
33713375
bool find_embedded = false;
33723376
if (gl.count == 1) {
@@ -3480,22 +3484,22 @@ double TextServerFallback::_shaped_text_fit_to_width(const RID &p_shaped, double
34803484

34813485
if (p_jst_flags.has_flag(JUSTIFICATION_TRIM_EDGE_SPACES)) {
34823486
// Trim spaces.
3483-
while ((start_pos < end_pos) && ((sd->glyphs[start_pos].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE || (sd->glyphs[start_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (sd->glyphs[start_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) {
3487+
while ((start_pos < end_pos) && ((sd->glyphs[start_pos].flags & GRAPHEME_IS_SOFT_HYPHEN) != GRAPHEME_IS_SOFT_HYPHEN) && ((sd->glyphs[start_pos].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE || (sd->glyphs[start_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (sd->glyphs[start_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) {
34843488
justification_width -= sd->glyphs[start_pos].advance * sd->glyphs[start_pos].repeat;
34853489
sd->glyphs.write[start_pos].advance = 0;
34863490
start_pos += sd->glyphs[start_pos].count;
34873491
}
3488-
while ((start_pos < end_pos) && ((sd->glyphs[end_pos].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE || (sd->glyphs[end_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (sd->glyphs[end_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) {
3492+
while ((start_pos < end_pos) && ((sd->glyphs[end_pos].flags & GRAPHEME_IS_SOFT_HYPHEN) != GRAPHEME_IS_SOFT_HYPHEN) && ((sd->glyphs[end_pos].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE || (sd->glyphs[end_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (sd->glyphs[end_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) {
34893493
justification_width -= sd->glyphs[end_pos].advance * sd->glyphs[end_pos].repeat;
34903494
sd->glyphs.write[end_pos].advance = 0;
34913495
end_pos -= sd->glyphs[end_pos].count;
34923496
}
34933497
} else {
34943498
// Skip breaks, but do not reset size.
3495-
while ((start_pos < end_pos) && ((sd->glyphs[start_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD)) {
3499+
while ((start_pos < end_pos) && ((sd->glyphs[start_pos].flags & GRAPHEME_IS_SOFT_HYPHEN) != GRAPHEME_IS_SOFT_HYPHEN) && ((sd->glyphs[start_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (sd->glyphs[start_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) {
34963500
start_pos += sd->glyphs[start_pos].count;
34973501
}
3498-
while ((start_pos < end_pos) && ((sd->glyphs[end_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD)) {
3502+
while ((start_pos < end_pos) && ((sd->glyphs[end_pos].flags & GRAPHEME_IS_SOFT_HYPHEN) != GRAPHEME_IS_SOFT_HYPHEN) && ((sd->glyphs[end_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (sd->glyphs[end_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) {
34993503
end_pos -= sd->glyphs[end_pos].count;
35003504
}
35013505
}
@@ -3504,7 +3508,7 @@ double TextServerFallback::_shaped_text_fit_to_width(const RID &p_shaped, double
35043508
for (int i = start_pos; i <= end_pos; i++) {
35053509
const Glyph &gl = sd->glyphs[i];
35063510
if (gl.count > 0) {
3507-
if ((gl.flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE && (gl.flags & GRAPHEME_IS_PUNCTUATION) != GRAPHEME_IS_PUNCTUATION) {
3511+
if ((gl.flags & GRAPHEME_IS_SOFT_HYPHEN) != GRAPHEME_IS_SOFT_HYPHEN && (gl.flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE && (gl.flags & GRAPHEME_IS_PUNCTUATION) != GRAPHEME_IS_PUNCTUATION) {
35083512
space_count++;
35093513
}
35103514
}
@@ -3515,7 +3519,7 @@ double TextServerFallback::_shaped_text_fit_to_width(const RID &p_shaped, double
35153519
for (int i = start_pos; i <= end_pos; i++) {
35163520
Glyph &gl = sd->glyphs.write[i];
35173521
if (gl.count > 0) {
3518-
if ((gl.flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE && (gl.flags & GRAPHEME_IS_PUNCTUATION) != GRAPHEME_IS_PUNCTUATION) {
3522+
if ((gl.flags & GRAPHEME_IS_SOFT_HYPHEN) != GRAPHEME_IS_SOFT_HYPHEN && (gl.flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE && (gl.flags & GRAPHEME_IS_PUNCTUATION) != GRAPHEME_IS_PUNCTUATION) {
35193523
double old_adv = gl.advance;
35203524
gl.advance = MAX(gl.advance + delta_width_per_space, Math::round(0.1 * gl.font_size));
35213525
justification_width += (gl.advance - old_adv);
@@ -3641,6 +3645,9 @@ bool TextServerFallback::_shaped_text_update_breaks(const RID &p_shaped) {
36413645
if (c == 0x0009 || c == 0x000b) {
36423646
sd_glyphs[i].flags |= GRAPHEME_IS_TAB;
36433647
}
3648+
if (c == 0x00ad) {
3649+
sd_glyphs[i].flags |= GRAPHEME_IS_SOFT_HYPHEN;
3650+
}
36443651

36453652
i += (sd_glyphs[i].count - 1);
36463653
}

servers/text_server.cpp

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -572,6 +572,7 @@ void TextServer::_bind_methods() {
572572
BIND_BITFIELD_FLAG(GRAPHEME_IS_CONNECTED);
573573
BIND_BITFIELD_FLAG(GRAPHEME_IS_SAFE_TO_INSERT_TATWEEL);
574574
BIND_BITFIELD_FLAG(GRAPHEME_IS_EMBEDDED_OBJECT);
575+
BIND_BITFIELD_FLAG(GRAPHEME_IS_SOFT_HYPHEN);
575576

576577
/* Hinting */
577578
BIND_ENUM_CONSTANT(HINTING_NONE);
@@ -733,6 +734,7 @@ PackedInt32Array TextServer::shaped_text_get_line_breaks_adv(const RID &p_shaped
733734

734735
ERR_FAIL_COND_V(p_width.is_empty(), lines);
735736

737+
TextServer::Orientation orientation = shaped_text_get_orientation(p_shaped);
736738
const_cast<TextServer *>(this)->shaped_text_update_breaks(p_shaped);
737739
const Vector2i &range = shaped_text_get_range(p_shaped);
738740

@@ -758,10 +760,10 @@ PackedInt32Array TextServer::shaped_text_get_line_breaks_adv(const RID &p_shaped
758760
if (p_break_flags.has_flag(BREAK_TRIM_EDGE_SPACES)) {
759761
int start_pos = prev_safe_break;
760762
int end_pos = last_safe_break;
761-
while (trim_next && (start_pos < end_pos) && ((l_gl[start_pos].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE || (l_gl[start_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (l_gl[start_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) {
763+
while (trim_next && (start_pos < end_pos) && ((l_gl[start_pos].flags & GRAPHEME_IS_SOFT_HYPHEN) != GRAPHEME_IS_SOFT_HYPHEN) && ((l_gl[start_pos].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE || (l_gl[start_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (l_gl[start_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) {
762764
start_pos += l_gl[start_pos].count;
763765
}
764-
while ((start_pos < end_pos) && ((l_gl[end_pos].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE || (l_gl[end_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (l_gl[end_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) {
766+
while ((start_pos < end_pos) && ((l_gl[end_pos].flags & GRAPHEME_IS_SOFT_HYPHEN) != GRAPHEME_IS_SOFT_HYPHEN) && ((l_gl[end_pos].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE || (l_gl[end_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (l_gl[end_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) {
765767
end_pos -= l_gl[end_pos].count;
766768
}
767769
if (last_end <= l_gl[start_pos].start) {
@@ -829,8 +831,17 @@ PackedInt32Array TextServer::shaped_text_get_line_breaks_adv(const RID &p_shaped
829831
}
830832
if (p_break_flags.has_flag(BREAK_WORD_BOUND)) {
831833
if ((l_gl[i].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT) {
832-
last_safe_break = i;
833-
word_count++;
834+
if ((l_gl[i].flags & GRAPHEME_IS_SOFT_HYPHEN) == GRAPHEME_IS_SOFT_HYPHEN) {
835+
uint32_t gl = font_get_glyph_index(l_gl[i].font_rid, l_gl[i].font_size, 0x00ad, 0);
836+
float w = font_get_glyph_advance(l_gl[i].font_rid, l_gl[i].font_size, gl)[(orientation == ORIENTATION_HORIZONTAL) ? 0 : 1];
837+
if (width + l_gl[i].advance + w <= p_width[chunk]) {
838+
last_safe_break = i;
839+
word_count++;
840+
}
841+
} else {
842+
last_safe_break = i;
843+
word_count++;
844+
}
834845
}
835846
}
836847
if (p_break_flags.has_flag(BREAK_GRAPHEME_BOUND) && word_count == 0) {
@@ -876,6 +887,7 @@ PackedInt32Array TextServer::shaped_text_get_line_breaks(const RID &p_shaped, do
876887
int word_count = 0;
877888
bool trim_next = false;
878889

890+
TextServer::Orientation orientation = shaped_text_get_orientation(p_shaped);
879891
int l_size = shaped_text_get_glyph_count(p_shaped);
880892
const Glyph *l_gl = const_cast<TextServer *>(this)->shaped_text_sort_logical(p_shaped);
881893

@@ -889,10 +901,10 @@ PackedInt32Array TextServer::shaped_text_get_line_breaks(const RID &p_shaped, do
889901
if (p_break_flags.has_flag(BREAK_TRIM_EDGE_SPACES)) {
890902
int start_pos = prev_safe_break;
891903
int end_pos = last_safe_break;
892-
while (trim_next && (start_pos < end_pos) && ((l_gl[start_pos].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE || (l_gl[start_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (l_gl[start_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) {
904+
while (trim_next && (start_pos < end_pos) && ((l_gl[start_pos].flags & GRAPHEME_IS_SOFT_HYPHEN) != GRAPHEME_IS_SOFT_HYPHEN) && ((l_gl[start_pos].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE || (l_gl[start_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (l_gl[start_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) {
893905
start_pos += l_gl[start_pos].count;
894906
}
895-
while ((start_pos < end_pos) && ((l_gl[end_pos].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE || (l_gl[end_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (l_gl[end_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) {
907+
while ((start_pos < end_pos) && ((l_gl[end_pos].flags & GRAPHEME_IS_SOFT_HYPHEN) != GRAPHEME_IS_SOFT_HYPHEN) && ((l_gl[end_pos].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE || (l_gl[end_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (l_gl[end_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) {
896908
end_pos -= l_gl[end_pos].count;
897909
}
898910
if (last_end <= l_gl[start_pos].start) {
@@ -949,8 +961,17 @@ PackedInt32Array TextServer::shaped_text_get_line_breaks(const RID &p_shaped, do
949961
}
950962
if (p_break_flags.has_flag(BREAK_WORD_BOUND)) {
951963
if ((l_gl[i].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT) {
952-
last_safe_break = i;
953-
word_count++;
964+
if ((l_gl[i].flags & GRAPHEME_IS_SOFT_HYPHEN) == GRAPHEME_IS_SOFT_HYPHEN) {
965+
uint32_t gl = font_get_glyph_index(l_gl[i].font_rid, l_gl[i].font_size, 0x00AD, 0);
966+
float w = font_get_glyph_advance(l_gl[i].font_rid, l_gl[i].font_size, gl)[(orientation == ORIENTATION_HORIZONTAL) ? 0 : 1];
967+
if (width + l_gl[i].advance + w <= p_width) {
968+
last_safe_break = i;
969+
word_count++;
970+
}
971+
} else {
972+
last_safe_break = i;
973+
word_count++;
974+
}
954975
}
955976
if (p_break_flags.has_flag(BREAK_ADAPTIVE) && word_count == 0) {
956977
last_safe_break = i;

servers/text_server.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ class TextServer : public RefCounted {
141141
GRAPHEME_IS_CONNECTED = 1 << 10, // Connected to previous grapheme.
142142
GRAPHEME_IS_SAFE_TO_INSERT_TATWEEL = 1 << 11, // It is safe to insert a U+0640 before this grapheme for elongation.
143143
GRAPHEME_IS_EMBEDDED_OBJECT = 1 << 12, // Grapheme is an object replacement character for the embedded object.
144+
GRAPHEME_IS_SOFT_HYPHEN = 1 << 13, // Grapheme is a soft hyphen.
144145
};
145146

146147
enum Hinting {

0 commit comments

Comments
 (0)