Some hopefully final flat review touch ups.

This commit is contained in:
Storm Dragon committed 2026-10-22 16:39:44 -04:00
1 parent fb2c5b818d
commit d7b1efeba0
5 files changed
+71 -4

No files matched your search

@@ -203,6 +203,7 @@ func test_native_review_provider(t *testing.T, mode string) {
}
if mode == "bounds" {
command("largest", "largest 128")
command("repeated", "repeated 0")
}
if mode == "lines" && text.Ranges[0].Start <= maxReviewCharacters {
t.Fatalf("line viewport did not seek scrolled native offsets: %d", text.Ranges[0].Start)
+29
View File
@@ -88,3 +88,32 @@ func TestBoundedReviewBoundsStopsOnFailureOrCancellation(t *testing.T) {
t.Fatalf("cancellation: %v queries=%d", err, queries)
}
}
// Even a block entirely inside the viewport can contain zero-area glyphs.
// A horizontally clipped line must retain its existing per-glyph exclusions.
type zeroGlyphReviewText struct{ longReviewText }
func (source *zeroGlyphReviewText) bounds(ctx context.Context, start, end int) (Rectangle, error) {
if start == 5 && end == 6 {
return Rectangle{}, ctx.Err()
}
return source.longReviewText.bounds(ctx, start, end)
}
func TestCaptureVisibleTextClippedInteriorBlockExcludesZeroAreaGlyph(t *testing.T) {
source := &zeroGlyphReviewText{longReviewText: longReviewText{runes: []rune(strings.Repeat("x", 400))}}
got, err := captureVisibleText(context.Background(), source, Rectangle{Width: 2000, Height: 20})
if err != nil || !got.Known || got.Limited {
t.Fatalf("capture: %+v, %v", got, err)
}
characters := 0
for _, span := range got.Ranges {
if span.Start <= 5 && span.End > 5 {
t.Fatalf("zero-area glyph included: %+v", span)
}
characters += span.End - span.Start
}
if characters != 199 {
t.Fatalf("visible characters=%d, want 199", characters)
}
}
+17 -3
View File
@@ -129,6 +129,9 @@ func expandNativeEmbeddedChild(source *C.AtspiAccessible, offset, depth int, bud
type nativeReviewText struct {
text *C.AtspiText
terminal bool
// Exact range rectangles belong to one synchronous text capture. Reuse
// block measurements during clipping without retaining state across commands.
boundsCache map[[2]int]Rectangle
}
func (source nativeReviewText) count(ctx context.Context) (int, error) {
@@ -250,6 +253,10 @@ func (source nativeReviewText) range_bounds(ctx context.Context, start, end int)
if err := ctx.Err(); err != nil {
return Rectangle{}, err
}
key := [2]int{start, end}
if bounds, known := source.boundsCache[key]; known {
return bounds, nil
}
var nativeErr *C.GError
bounds := C.atspi_text_get_range_extents(source.text, C.gint(start), C.gint(end), C.ATSPI_COORD_TYPE_SCREEN, &nativeErr)
if bounds != nil {
@@ -264,7 +271,13 @@ func (source nativeReviewText) range_bounds(ctx context.Context, start, end int)
return Rectangle{}, errors.New("missing review range bounds")
}
rect := Rectangle{int32(bounds.x), int32(bounds.y), int32(bounds.width), int32(bounds.height)}
return rect, ctx.Err()
if err := ctx.Err(); err != nil {
return Rectangle{}, err
}
if source.boundsCache != nil {
source.boundsCache[key] = rect
}
return rect, nil
}
// Only called from captureNativeTree on the adapter's GLib thread. Unsupported,
@@ -281,7 +294,8 @@ func textFromNative(ctx context.Context, accessible *C.AtspiAccessible, geometry
return VisibleText{}, ctx.Err()
}
defer C.g_object_unref(C.gpointer(text))
result, err := captureVisibleText(ctx, nativeReviewText{text: text, terminal: snapshot.Role == "terminal"}, clip)
source := nativeReviewText{text: text, terminal: snapshot.Role == "terminal", boundsCache: make(map[[2]int]Rectangle)}
result, err := captureVisibleText(ctx, source, clip)
if err != nil {
if ctx.Err() != nil {
return VisibleText{}, ctx.Err()
@@ -292,7 +306,7 @@ func textFromNative(ctx context.Context, accessible *C.AtspiAccessible, geometry
// Some providers advertise Text on component-only controls and
// containers. Verify their bounded content before allowing the
// established accessible-name/child-content path to handle them.
if recovered, ok := recover_review_component(ctx, nativeReviewText{text: text}, snapshot, geometry, clip); ok {
if recovered, ok := recover_review_component(ctx, source, snapshot, geometry, clip); ok {
result = recovered
}
}