Re: Adding VO-pressable links to NSTextField
Re: Adding VO-pressable links to NSTextField
- Subject: Re: Adding VO-pressable links to NSTextField
- From: Boris Dušek <email@hidden>
- Date: Fri, 15 Aug 2014 20:34:34 +0200
>> You could also use std::map of link proxies to have more effective search of the link proxies, but that would pay off only for really large texts.
>
> Well, they’re already in an NSDictionary mapped by their ranges. I see now, though, that the link enumeration is far less efficient than it should be because it’s always stepping through all the links. I think the solution to that is to build the relevant proxy objects when they’re requested instead of caching them.
I would still prefer caching them, as there might be some issues with considering 2 objects “the same” when they correspond to the same link but are 2 separate subsequent instantiations of the link. It’s not only about returning the links in the AXAttributedStringForRange, but you should also return the same links in the AXChildren attribute value. Maybe you could deal with this by properly implementing isEqual: and hash for the LinkProxyObject class (instead of caching the link objects) so that 2 non-identical objects representing the same link are considered “the same” by the accessibility infrastructure, but I have not much experience with that.
But to the std::map (in our case std::map<NSRange, LinkProxyObject*> - the point is in NSDictionary you can search only for exact match of key - i.e. if you have a link at range (100, 7) and VO requests AXAttributedStringForRange for (102, 10), you would have no way to get at the link at (100, 7) without walking all values in the NSDictionary (valueForKey:(102, whatever) would return nil, under reasonable assumption there are no overlapping links), and you do need to add part of that link at (102, 5) to the returned attributed string for (102, 10). But with std::map, you can ask for first value (in our case link) whose key (in our case the range) satisfies an inequality (I mean the lower_bound and upper_bound member functions), so with this you could get all links that intersect with a certain range in O(log N) (N is the length of the whole text), if for the comparison function of the std::map you use numerical comparison of the location of the range. But if we are speaking about some text that fits into one screen, I think you should not bother with this yet (however make your own performance measurements :-).
One more thing I noticed in your code: please use addAttributes:range: instead of setAttributes:range: (in the enumerate… block of your AXAttributedStringForRange implementation) - the latter erases attributes that `super` puts into the attributed string (e.g. in our case the AXForegroundColor of the link, as it is blue), the former only adds to them (which is what we want).
I have not yet discovered what is left for the links to work in your sample code, but I think I was exactly there one year ago (“I return correct AXAttributedString but VO doesn’t detect the links"), and finally it was some very subtle bug, but for the life of me I can’t remember what exactly the bug was :-) but it was in an AXTextArea and an editable one, so not 1:1 analogue.
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Accessibility-dev mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden