Files

62 lines
2.1 KiB
Go

// Copyright (c) 2026 Storm Dragon
// Authors: Storm Dragon, Angus Kola
// SPDX-License-Identifier: GPL-3.0-or-later
package atspi
import (
"fmt"
"strings"
)
// A removed Chromium generated-text object can return zero characters before
// its removal event reaches us. Refresh its metadata and parent's child order
// rather than silently skipping text from an obsolete snapshot. Empty text
// alone does not prove removal, so keep identities and live siblings intact.
func (adapter *Adapter) document_text_became_empty(object ObjectID) error {
adapter.treeMutex.Lock()
tree := adapter.documentTree
adapter.treeMutex.Unlock()
if tree != nil {
tree.mu.RLock()
entry := tree.nodes[object]
tree.mu.RUnlock()
adapter.treeInvalidations.Add(uint64(tree.InvalidateSnapshot(object)))
if entry.hasParent {
adapter.treeInvalidations.Add(uint64(tree.MarkChildrenChanged(entry.parent)))
}
}
delete(adapter.documentLineCache, object)
return ErrStaleText
}
// libatspi forwards Chromium's missing-object response as an untyped GError.
// Match the queried path exactly; a timeout or unsupported caret is not proof
// that the virtual reading position has disappeared.
func (adapter *Adapter) document_object_error(object ObjectID, err error) error {
if err == nil || !object.Valid() || !strings.HasSuffix(strings.TrimSpace(err.Error()),
"could not be processed as object "+object.Path+" does not exist") {
return err
}
adapter.treeMutex.Lock()
trees := []*AccessibleTree{adapter.tree, adapter.documentTree, adapter.documentTextTree}
adapter.treeMutex.Unlock()
for _, tree := range trees {
if tree == nil {
continue
}
tree.mu.RLock()
entry := tree.nodes[object]
tree.mu.RUnlock()
adapter.treeInvalidations.Add(uint64(tree.Invalidate(object)))
if entry.hasParent {
// Virtualized pages can replace the enclosing post or feed, not
// just this target. Refresh every ancestor's child list so capture
// reaches the live replacement rather than reusing stale branches.
adapter.treeInvalidations.Add(uint64(tree.markAncestorChildrenChanged(entry.parent)))
}
}
clear(adapter.documentLineCache)
return fmt.Errorf("%w: %w", ErrDeadObject, err)
}