60 lines
1.7 KiB
Go
60 lines
1.7 KiB
Go
// Copyright (c) 2026 Storm Dragon
|
|
// Authors: Storm Dragon, Angus Kola
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
package atspi
|
|
|
|
func documentNavigationEchoBit(event Event, offset int, selectionOffsets map[int]bool) uint8 {
|
|
switch event.Type {
|
|
case FocusEvent:
|
|
return 1
|
|
case FocusedStateEvent:
|
|
return 2
|
|
case CaretEvent:
|
|
// New native selection is user input, even if its endpoint happens
|
|
// to match a previously requested caret or collapsed selection.
|
|
if event.Source.TextCaretKnown && event.Source.SelectionEnd > event.Source.SelectionStart {
|
|
return 0
|
|
}
|
|
if event.Detail1 == offset {
|
|
return 4
|
|
}
|
|
if event.Source.TextCaretKnown && selectionOffsets[event.Detail1] {
|
|
return 8
|
|
}
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// Chromium can echo a static text caret on its enclosing label/paragraph.
|
|
// Include only a single-child chain sharing the complete text offset domain.
|
|
// Composite parents have their own hypertext offsets and cannot be matched.
|
|
func documentCaretEchoAncestors(tree *AccessibleTree, reference ObjectReference) []ObjectID {
|
|
var ids []ObjectID
|
|
child, err := tree.Resolve(reference)
|
|
if err != nil || child.CharacterCount <= 0 {
|
|
return nil
|
|
}
|
|
for attempts := 0; attempts < maxTreeNodes; attempts++ {
|
|
parent, ok, err := tree.Parent(reference)
|
|
if err != nil || !ok {
|
|
break
|
|
}
|
|
snapshot, err := tree.Resolve(parent)
|
|
if err != nil || IsWebDocumentRole(snapshot.Role) || snapshot.Editable || snapshot.CharacterCount != child.CharacterCount {
|
|
break
|
|
}
|
|
first, ok, err := tree.FirstChild(parent)
|
|
if err != nil || !ok || first != reference {
|
|
break
|
|
}
|
|
last, ok, err := tree.LastChild(parent)
|
|
if err != nil || !ok || last != reference {
|
|
break
|
|
}
|
|
ids = append(ids, parent.ID())
|
|
reference, child = parent, snapshot
|
|
}
|
|
return ids
|
|
}
|