@@ -21,7 +21,6 @@ use serde_lib as serde;
2121use serde_lib:: { Deserialize , Serialize } ;
2222use std:: {
2323 num:: { NonZeroU128 , NonZeroU64 } ,
24- ops:: Range ,
2524 sync:: Arc ,
2625} ;
2726
@@ -409,19 +408,6 @@ pub enum DropEffect {
409408 Popup ,
410409}
411410
412- #[ derive( Clone , Copy , Debug , PartialEq , Eq , Hash ) ]
413- #[ cfg_attr( feature = "serde" , derive( Serialize , Deserialize ) ) ]
414- #[ cfg_attr( feature = "schemars" , derive( JsonSchema ) ) ]
415- #[ cfg_attr( feature = "serde" , serde( crate = "serde" ) ) ]
416- #[ cfg_attr( feature = "serde" , serde( rename_all = "camelCase" ) ) ]
417- pub enum MarkerType {
418- SpellingError ,
419- GrammarError ,
420- SearchMatch ,
421- ActiveSuggestion ,
422- Suggestion ,
423- }
424-
425411#[ derive( Clone , Copy , Debug , PartialEq , Eq , Hash ) ]
426412#[ cfg_attr( feature = "serde" , derive( Serialize , Deserialize ) ) ]
427413#[ cfg_attr( feature = "schemars" , derive( JsonSchema ) ) ]
@@ -606,19 +592,6 @@ impl From<NonZeroU64> for NodeId {
606592 }
607593}
608594
609- /// A marker spanning a range within text.
610- #[ derive( Clone , Debug , PartialEq , Eq ) ]
611- #[ cfg_attr( feature = "serde" , derive( Serialize , Deserialize ) ) ]
612- #[ cfg_attr( feature = "schemars" , derive( JsonSchema ) ) ]
613- #[ cfg_attr( feature = "serde" , serde( crate = "serde" ) ) ]
614- #[ cfg_attr( feature = "serde" , serde( deny_unknown_fields) ) ]
615- #[ cfg_attr( feature = "serde" , serde( rename_all = "camelCase" ) ) ]
616- pub struct TextMarker {
617- pub marker_type : MarkerType ,
618- /// Indices are in UTF-8 code units.
619- pub range : Range < usize > ,
620- }
621-
622595/// Defines a custom action for a UI element.
623596///
624597/// For example, a list UI can allow a user to reorder items in the list by dragging the
@@ -646,18 +619,36 @@ fn is_empty<T>(slice: &[T]) -> bool {
646619 slice. is_empty ( )
647620}
648621
649- /// Offsets are in UTF-8 code units.
622+ #[ derive( Clone , Copy , Debug , PartialEq , Eq ) ]
623+ #[ cfg_attr( feature = "serde" , derive( Serialize , Deserialize ) ) ]
624+ #[ cfg_attr( feature = "schemars" , derive( JsonSchema ) ) ]
625+ #[ cfg_attr( feature = "serde" , serde( crate = "serde" ) ) ]
626+ #[ cfg_attr( feature = "serde" , serde( deny_unknown_fields) ) ]
627+ #[ cfg_attr( feature = "serde" , serde( rename_all = "camelCase" ) ) ]
628+ pub struct TextPosition {
629+ /// The node's role must be [`Role::InlineTextBox`].
630+ pub node : NodeId ,
631+ /// The index of an item in [`Node::character_lengths`], or the length
632+ /// of that slice if the position is at the end of the line.
633+ pub character_index : usize ,
634+ }
635+
650636#[ derive( Clone , Copy , Debug , PartialEq , Eq ) ]
651637#[ cfg_attr( feature = "serde" , derive( Serialize , Deserialize ) ) ]
652638#[ cfg_attr( feature = "schemars" , derive( JsonSchema ) ) ]
653639#[ cfg_attr( feature = "serde" , serde( crate = "serde" ) ) ]
654640#[ cfg_attr( feature = "serde" , serde( deny_unknown_fields) ) ]
655641#[ cfg_attr( feature = "serde" , serde( rename_all = "camelCase" ) ) ]
656642pub struct TextSelection {
657- anchor_node : NodeId ,
658- anchor_offset : usize ,
659- focus_node : NodeId ,
660- focus_offset : usize ,
643+ /// The position where the selection started, and which does not change
644+ /// as the selection is expanded or contracted. If there is no selection
645+ /// but only a caret, this must be equal to [`focus`]. This is also known
646+ /// as a degenerate selection.
647+ pub anchor : TextPosition ,
648+ /// The active end of the selection, which changes as the selection
649+ /// is expanded or contracted, or the position of the caret if there is
650+ /// no selection.
651+ pub focus : TextPosition ,
661652}
662653
663654/// A single accessible object. A complete UI is represented as a tree of these.
@@ -925,25 +916,96 @@ pub struct Node {
925916 pub radio_group : Vec < NodeId > ,
926917
927918 #[ cfg_attr( feature = "serde" , serde( default ) ) ]
928- #[ cfg_attr( feature = "serde" , serde( skip_serializing_if = "is_empty" ) ) ]
929- pub markers : Box < [ TextMarker ] > ,
919+ #[ cfg_attr( feature = "serde" , serde( skip_serializing_if = "is_false" ) ) ]
920+ pub is_spelling_error : bool ,
921+ #[ cfg_attr( feature = "serde" , serde( default ) ) ]
922+ #[ cfg_attr( feature = "serde" , serde( skip_serializing_if = "is_false" ) ) ]
923+ pub is_grammar_error : bool ,
924+ #[ cfg_attr( feature = "serde" , serde( default ) ) ]
925+ #[ cfg_attr( feature = "serde" , serde( skip_serializing_if = "is_false" ) ) ]
926+ pub is_search_match : bool ,
927+ #[ cfg_attr( feature = "serde" , serde( default ) ) ]
928+ #[ cfg_attr( feature = "serde" , serde( skip_serializing_if = "is_false" ) ) ]
929+ pub is_suggestion : bool ,
930930
931931 #[ cfg_attr( feature = "serde" , serde( skip_serializing_if = "Option::is_none" ) ) ]
932932 pub text_direction : Option < TextDirection > ,
933- /// For inline text. This is the pixel position of the end of each
934- /// character within the bounding rectangle of this object, in the
935- /// direction given by [`Node::text_direction`]. For example, for left-to-right
936- /// text, the first offset is the right coordinate of the first
937- /// character within the object's bounds, the second offset
938- /// is the right coordinate of the second character, and so on.
933+
934+ /// For inline text. The length (non-inclusive) of each character
935+ /// in UTF-8 code units (bytes). The sum of these lengths must equal
936+ /// the length of [`Node::value`], also in bytes.
937+ ///
938+ /// A character is defined as the smallest unit of text that
939+ /// can be selected. This isn't necessarily a single Unicode
940+ /// scalar value (code point). This is why AccessKit can't compute
941+ /// the lengths of the characters from the text itself; this information
942+ /// must be provided by the text editing implementation.
943+ ///
944+ /// If this node is the last text box in a line that ends with a hard
945+ /// line break, that line break should be included at the end of this
946+ /// node's value as either a CRLF or LF; in both cases, the line break
947+ /// should be counted as a single character for the sake of this slice.
948+ /// When the caret is at the end of such a line, the focus of the text
949+ /// selection should be on the line break, not after it.
939950 #[ cfg_attr( feature = "serde" , serde( default ) ) ]
940951 #[ cfg_attr( feature = "serde" , serde( skip_serializing_if = "is_empty" ) ) ]
941- pub character_offsets : Box < [ f32 ] > ,
952+ pub character_lengths : Box < [ u8 ] > ,
953+ /// For inline text. This is the position of each character within
954+ /// the node's bounding box, in the direction given by
955+ /// [`Node::text_direction`], in the coordinate space of this node.
956+ ///
957+ /// When present, the length of this slice should be the same as the length
958+ /// of [`Node::character_lengths`], including for lines that end
959+ /// with a hard line break. The position of such a line break should
960+ /// be the position where an end-of-paragraph marker would be rendered.
961+ ///
962+ /// This field is optional. Without it, AccessKit can't support some
963+ /// use cases, such as screen magnifiers that track the caret position
964+ /// or screen readers that display a highlight cursor. However,
965+ /// most text functionality still works without this information.
966+ #[ cfg_attr( feature = "serde" , serde( skip_serializing_if = "Option::is_none" ) ) ]
967+ pub character_positions : Option < Box < [ f32 ] > > ,
968+ /// For inline text. This is the advance width of each character,
969+ /// in the direction given by [`Node::text_direction`], in the coordinate
970+ /// space of this node.
971+ ///
972+ /// When present, the length of this slice should be the same as the length
973+ /// of [`Node::character_lengths`], including for lines that end
974+ /// with a hard line break. The width of such a line break should
975+ /// be non-zero if selecting the line break by itself results in
976+ /// a visible highlight (as in Microsoft Word), or zero if not
977+ /// (as in Windows Notepad).
978+ ///
979+ /// This field is optional. Without it, AccessKit can't support some
980+ /// use cases, such as screen magnifiers that track the caret position
981+ /// or screen readers that display a highlight cursor. However,
982+ /// most text functionality still works without this information.
983+ #[ cfg_attr( feature = "serde" , serde( skip_serializing_if = "Option::is_none" ) ) ]
984+ pub character_widths : Option < Box < [ f32 ] > > ,
942985
943- /// For inline text. The indices of each word, in UTF-8 code units.
986+ /// For inline text. The length of each word in characters, as defined
987+ /// in [`Node::character_lengths`]. The sum of these lengths must equal
988+ /// the length of [`Node::character_lengths`].
989+ ///
990+ /// The end of each word is the beginning of the next word; there are no
991+ /// characters that are not considered part of a word. Trailing whitespace
992+ /// is typically considered part of the word that precedes it, while
993+ /// a line's leading whitespace is considered its own word. Whether
994+ /// punctuation is considered a separate word or part of the preceding
995+ /// word depends on the particular text editing implementation.
996+ /// Some editors may have their own definition of a word; for example,
997+ /// in an IDE, words may correspond to programming language tokens.
998+ ///
999+ /// Not all assistive technologies require information about word
1000+ /// boundaries, and not all platform accessibility APIs even expose
1001+ /// this information, but for assistive technologies that do use
1002+ /// this information, users will get unpredictable results if the word
1003+ /// boundaries exposed by the accessibility tree don't match
1004+ /// the editor's behavior. This is why AccessKit does not determine
1005+ /// word boundaries itself.
9441006 #[ cfg_attr( feature = "serde" , serde( default ) ) ]
9451007 #[ cfg_attr( feature = "serde" , serde( skip_serializing_if = "is_empty" ) ) ]
946- pub words : Box < [ Range < usize > ] > ,
1008+ pub word_lengths : Box < [ u8 ] > ,
9471009
9481010 #[ cfg_attr( feature = "serde" , serde( default ) ) ]
9491011 #[ cfg_attr( feature = "serde" , serde( skip_serializing_if = "is_empty" ) ) ]
0 commit comments