1
0
mirror of https://github.com/godotengine/godot.git synced 2025-11-29 16:16:38 +00:00

Base accessibility API.

This commit is contained in:
Pāvels Nadtočajevs
2025-03-21 16:42:23 +02:00
parent af2c713971
commit b106dfd4f9
124 changed files with 7631 additions and 181 deletions

View File

@@ -3105,6 +3105,8 @@ void TextServerFallback::invalidate(ShapedTextDataFallback *p_shaped) {
p_shaped->uthk = 0.0;
p_shaped->glyphs.clear();
p_shaped->glyphs_logical.clear();
p_shaped->runs.clear();
p_shaped->runs_dirty = true;
}
void TextServerFallback::full_copy(ShapedTextDataFallback *p_shaped) {
@@ -3339,6 +3341,212 @@ Variant TextServerFallback::_shaped_get_span_embedded_object(const RID &p_shaped
}
}
String TextServerFallback::_shaped_get_span_text(const RID &p_shaped, int64_t p_index) const {
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_NULL_V(sd, String());
ShapedTextDataFallback *span_sd = sd;
if (sd->parent.is_valid()) {
span_sd = shaped_owner.get_or_null(sd->parent);
ERR_FAIL_NULL_V(span_sd, String());
}
ERR_FAIL_INDEX_V(p_index, span_sd->spans.size(), String());
return span_sd->text.substr(span_sd->spans[p_index].start, span_sd->spans[p_index].end - span_sd->spans[p_index].start);
}
Variant TextServerFallback::_shaped_get_span_object(const RID &p_shaped, int64_t p_index) const {
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_NULL_V(sd, Variant());
ShapedTextDataFallback *span_sd = sd;
if (sd->parent.is_valid()) {
span_sd = shaped_owner.get_or_null(sd->parent);
ERR_FAIL_NULL_V(span_sd, Variant());
}
ERR_FAIL_INDEX_V(p_index, span_sd->spans.size(), Variant());
return span_sd->spans[p_index].embedded_key;
}
void TextServerFallback::_generate_runs(ShapedTextDataFallback *p_sd) const {
ERR_FAIL_NULL(p_sd);
p_sd->runs.clear();
ShapedTextDataFallback *span_sd = p_sd;
if (p_sd->parent.is_valid()) {
span_sd = shaped_owner.get_or_null(p_sd->parent);
ERR_FAIL_NULL(span_sd);
}
int sd_size = p_sd->glyphs.size();
Glyph *sd_gl = p_sd->glyphs.ptrw();
int span_count = span_sd->spans.size();
int span = -1;
int span_start = -1;
int span_end = -1;
TextRun run;
for (int i = 0; i < sd_size; i += sd_gl[i].count) {
const Glyph &gl = sd_gl[i];
if (gl.start < 0 || gl.end < 0) {
continue;
}
if (gl.start < span_start || gl.start >= span_end) {
span = -1;
span_start = -1;
span_end = -1;
for (int j = 0; j < span_count; j++) {
if (gl.start >= span_sd->spans[j].start && gl.end <= span_sd->spans[j].end) {
span = j;
span_start = span_sd->spans[j].start;
span_end = span_sd->spans[j].end;
break;
}
}
}
if (run.font_rid != gl.font_rid || run.font_size != gl.font_size || run.span_index != span) {
if (run.span_index >= 0) {
p_sd->runs.push_back(run);
}
run.range = Vector2i(gl.start, gl.end);
run.font_rid = gl.font_rid;
run.font_size = gl.font_size;
run.span_index = span;
}
run.range.x = MIN(run.range.x, gl.start);
run.range.y = MAX(run.range.y, gl.end);
}
if (run.span_index >= 0) {
p_sd->runs.push_back(run);
}
p_sd->runs_dirty = false;
}
int64_t TextServerFallback::_shaped_get_run_count(const RID &p_shaped) const {
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_NULL_V(sd, 0);
MutexLock lock(sd->mutex);
if (!sd->valid.is_set()) {
const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped);
}
if (sd->runs_dirty) {
_generate_runs(sd);
}
return sd->runs.size();
}
String TextServerFallback::_shaped_get_run_text(const RID &p_shaped, int64_t p_index) const {
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_NULL_V(sd, String());
MutexLock lock(sd->mutex);
if (!sd->valid.is_set()) {
const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped);
}
if (sd->runs_dirty) {
_generate_runs(sd);
}
ERR_FAIL_INDEX_V(p_index, sd->runs.size(), String());
return sd->text.substr(sd->runs[p_index].range.x - sd->start, sd->runs[p_index].range.y - sd->runs[p_index].range.x);
}
Vector2i TextServerFallback::_shaped_get_run_range(const RID &p_shaped, int64_t p_index) const {
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_NULL_V(sd, Vector2i());
MutexLock lock(sd->mutex);
if (!sd->valid.is_set()) {
const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped);
}
if (sd->runs_dirty) {
_generate_runs(sd);
}
ERR_FAIL_INDEX_V(p_index, sd->runs.size(), Vector2i());
return sd->runs[p_index].range;
}
RID TextServerFallback::_shaped_get_run_font_rid(const RID &p_shaped, int64_t p_index) const {
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_NULL_V(sd, RID());
MutexLock lock(sd->mutex);
if (!sd->valid.is_set()) {
const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped);
}
if (sd->runs_dirty) {
_generate_runs(sd);
}
ERR_FAIL_INDEX_V(p_index, sd->runs.size(), RID());
return sd->runs[p_index].font_rid;
}
int TextServerFallback::_shaped_get_run_font_size(const RID &p_shaped, int64_t p_index) const {
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_NULL_V(sd, 0);
MutexLock lock(sd->mutex);
if (!sd->valid.is_set()) {
const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped);
}
if (sd->runs_dirty) {
_generate_runs(sd);
}
ERR_FAIL_INDEX_V(p_index, sd->runs.size(), 0);
return sd->runs[p_index].font_size;
}
String TextServerFallback::_shaped_get_run_language(const RID &p_shaped, int64_t p_index) const {
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_NULL_V(sd, String());
MutexLock lock(sd->mutex);
if (!sd->valid.is_set()) {
const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped);
}
if (sd->runs_dirty) {
_generate_runs(sd);
}
ERR_FAIL_INDEX_V(p_index, sd->runs.size(), String());
int span_idx = sd->runs[p_index].span_index;
ShapedTextDataFallback *span_sd = sd;
if (sd->parent.is_valid()) {
span_sd = shaped_owner.get_or_null(sd->parent);
ERR_FAIL_NULL_V(span_sd, String());
}
ERR_FAIL_INDEX_V(span_idx, span_sd->spans.size(), String());
return span_sd->spans[span_idx].language;
}
TextServer::Direction TextServerFallback::_shaped_get_run_direction(const RID &p_shaped, int64_t p_index) const {
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_NULL_V(sd, TextServer::DIRECTION_LTR);
MutexLock lock(sd->mutex);
if (!sd->valid.is_set()) {
const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped);
}
if (sd->runs_dirty) {
_generate_runs(sd);
}
ERR_FAIL_INDEX_V(p_index, sd->runs.size(), TextServer::DIRECTION_LTR);
return TextServer::DIRECTION_LTR;
}
Variant TextServerFallback::_shaped_get_run_object(const RID &p_shaped, int64_t p_index) const {
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_NULL_V(sd, Variant());
MutexLock lock(sd->mutex);
if (!sd->valid.is_set()) {
const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped);
}
if (sd->runs_dirty) {
_generate_runs(sd);
}
ERR_FAIL_INDEX_V(p_index, sd->runs.size(), Variant());
int span_idx = sd->runs[p_index].span_index;
ShapedTextDataFallback *span_sd = sd;
if (sd->parent.is_valid()) {
span_sd = shaped_owner.get_or_null(sd->parent);
ERR_FAIL_NULL_V(span_sd, Variant());
}
ERR_FAIL_INDEX_V(span_idx, span_sd->spans.size(), Variant());
return span_sd->spans[span_idx].embedded_key;
}
void TextServerFallback::_shaped_set_span_update_font(const RID &p_shaped, int64_t p_index, const TypedArray<RID> &p_fonts, int64_t p_size, const Dictionary &p_opentype_features) {
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_NULL(sd);
@@ -3450,6 +3658,13 @@ bool TextServerFallback::_shaped_text_add_object(const RID &p_shaped, const Vari
return true;
}
String TextServerFallback::_shaped_get_text(const RID &p_shaped) const {
const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_NULL_V(sd, String());
return sd->text;
}
bool TextServerFallback::_shaped_text_resize_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align, double p_baseline) {
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_NULL_V(sd, false);
@@ -4385,6 +4600,8 @@ bool TextServerFallback::_shaped_text_shape(const RID &p_shaped) {
sd->descent = 0.0;
sd->width = 0.0;
sd->glyphs.clear();
sd->runs.clear();
sd->runs_dirty = true;
if (sd->text.length() == 0) {
sd->valid.set();