58 lines
2.3 KiB
C
58 lines
2.3 KiB
C
// Copyright (c) 2026 Storm Dragon
|
|
// Authors: Storm Dragon, Angus Kola
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
#include "adapter_native.h"
|
|
#include <string.h>
|
|
|
|
AtspiTextRange *cthulhu_text_get_string_at_offset(AtspiText *text, gint offset,
|
|
AtspiTextGranularity unit, GError **error) {
|
|
if (unit != ATSPI_TEXT_GRANULARITY_LINE || offset < 0) {
|
|
return atspi_text_get_string_at_offset(text, offset, unit, error);
|
|
}
|
|
|
|
// Chromium can retain layout boundaries past truncated hypertext. In a
|
|
// captured crash, LINE at the final U+2026 (140 of 141 characters) tried
|
|
// to take a substring starting at 146 and aborted the entire browser.
|
|
// Checking returned boundaries is too late: use bounded GetText for an
|
|
// ellipsis before invoking the provider's boundary calculation.
|
|
GError *probeError = NULL;
|
|
guint character = atspi_text_get_character_at_offset(text, offset, &probeError);
|
|
if (probeError != NULL) {
|
|
g_propagate_error(error, probeError);
|
|
return NULL;
|
|
}
|
|
if (character != 0x2026) {
|
|
return atspi_text_get_string_at_offset(text, offset, unit, error);
|
|
}
|
|
gint count = atspi_text_get_character_count(text, &probeError);
|
|
if (probeError != NULL) {
|
|
g_propagate_error(error, probeError);
|
|
return NULL;
|
|
}
|
|
if (count <= 0 || offset != count - 1) {
|
|
return atspi_text_get_string_at_offset(text, offset, unit, error);
|
|
}
|
|
|
|
gint start = MAX(0, offset - 4095);
|
|
gchar *content = atspi_text_get_text(text, start, offset + 1, error);
|
|
if (content == NULL) return NULL;
|
|
if (!g_utf8_validate(content, -1, NULL) ||
|
|
g_utf8_strlen(content, -1) != offset + 1 - start ||
|
|
!g_str_has_suffix(content, "\342\200\246")) {
|
|
g_free(content);
|
|
return NULL;
|
|
}
|
|
|
|
// Preserve explicit line breaks. A provider's visual wrapping is unsafe
|
|
// at this character; retain the bounded logical line and native offsets.
|
|
gchar *line = strrchr(content, '\n');
|
|
line = line != NULL ? line + 1 : content;
|
|
AtspiTextRange *range = g_new0(AtspiTextRange, 1);
|
|
range->start_offset = start + g_utf8_pointer_to_offset(content, line);
|
|
range->end_offset = offset + 1;
|
|
range->content = g_strdup(line);
|
|
g_free(content);
|
|
return range;
|
|
}
|