package atspi import ( "strings" "unicode/utf8" ) // DocumentCaretUnit selects the AT-SPI text granularity for virtual browsing. type DocumentCaretUnit uint8 const ( DocumentCaretCharacter DocumentCaretUnit = iota + 1 DocumentCaretWord DocumentCaretLine DocumentCaretLineRemainder // DocumentCaretBrailleLine preserves native spacing for display offsets. DocumentCaretBrailleLine // DocumentCaretCharacters returns a bounded block of raw characters for // whitespace traversal. It does not normalize spaces or query line geometry. DocumentCaretCharacters ) func (unit DocumentCaretUnit) Valid() bool { return unit >= DocumentCaretCharacter && unit <= DocumentCaretCharacters } type DocumentCaretText struct { TextAttributeRuns []TextAttributeRun Start int End int Text string RawText string Misspelled bool // Expanded reports that embedded-object placeholders in Text were // replaced by their descendant text. Start, End, selections, attribute // runs, and RawText still describe the unexpanded native line, so // native offsets no longer map one-to-one into Text. Expanded bool CharacterCount int SelectionStart, SelectionEnd int // Bounds describe this native line, including offscreen document text. Bounds Rectangle } func (line *DocumentCaretText) applyExpandedText(expanded, name string, incomplete bool) { line.RawText = line.Text // An accessible name describes the whole object. It can recover a failed // descendant read only when this range covers that entire object; using it // on a wrapped line would repeat unrelated text and move the reading point. if incomplete && line.CharacterCount > 0 && line.Start == 0 && line.End == line.CharacterCount && strings.TrimSpace(name) != "" && !strings.ContainsRune(name, '\ufffc') { expanded = name } line.Text, line.Expanded = expanded, expanded != line.RawText } func (snapshot *Snapshot) applyDocumentCaretLine(line DocumentCaretText, offset int) { // A caret capture already expanded this exact native line. Preserve that // text instead of replacing it with the raw line used for offset repair. if snapshot.BrailleLine != line.RawText || snapshot.BrailleLineStart != line.Start || snapshot.CharacterCount != line.CharacterCount { snapshot.Text = sanitizeSnapshotField(line.Text) } snapshot.BrailleLine, snapshot.BrailleLineStart, snapshot.BrailleCaret = line.RawText, line.Start, offset snapshot.CharacterCount = line.CharacterCount } func documentCaretCharacter(value string) string { if value == "" { return "" } character, _ := utf8.DecodeRuneInString(value) return string(character) }