|
|
Created:
4 years, 4 months ago by nektarios Modified:
4 years, 2 months ago CC:
aboxhall+watch_chromium.org, chromium-reviews, dmazzoni+watch_chromium.org, dtseng+watch_chromium.org, je_julie, nektar+watch_chromium.org, yuzo+watch_chromium.org Base URL:
https://chromium.googlesource.com/chromium/src.git@master Target Ref:
refs/pending/heads/master Project:
chromium Visibility:
Public. |
DescriptionCreates AXPosition to uniquely identify a position in the accessibility tree.
TESTED=manually, unit tests
BUG=644604, 530826
R=dmazzoni@chromium.org, dtseng@chromium.org, avi@chromium.org, ellyjones@chromium.org
Committed: https://crrev.com/9de71d4067f24c4e333b5bef4f1210c9395ba847
Cr-Commit-Position: refs/heads/master@{#426906}
Patch Set 1 #
Total comments: 8
Patch Set 2 : Re-wrote implementation to include tree_id and platform specific AXPosition. #
Total comments: 4
Patch Set 3 : Created a factory. #
Total comments: 2
Patch Set 4 : Switched to using templates. #Patch Set 5 : Switched to using templates. #Patch Set 6 : Added more overrides. #Patch Set 7 : Added test skeleton. #
Total comments: 5
Patch Set 8 : Implemented AXNodePosition. #Patch Set 9 : Added overrides for parent and childAtIndex for BrowserAccessibility. #
Total comments: 16
Patch Set 10 : Implemented curiously recurring template pattern. #Patch Set 11 : Added comment explaining curiously recursive template and fixed base types. #Patch Set 12 : Added static casts where needed. #Patch Set 13 : Addressed some of the comments by David and Dominic. #
Total comments: 1
Patch Set 14 : Fixed compilation error. #Patch Set 15 : Fixed compilation error. #Patch Set 16 : Fixed includes on the Mac. #Patch Set 17 : Added a number of unit tests. #
Total comments: 8
Patch Set 18 : Made some improvements to tests. #Patch Set 19 : Fixed most tests except CommonAncestor. #Patch Set 20 : Added a few more tests. #Patch Set 21 : Fixed all memory leaks. #Patch Set 22 : Removed AXRange class. #
Total comments: 2
Patch Set 23 : Removed AXRange from build. #Patch Set 24 : Made platform positions treat platform leaves correctly. #Patch Set 25 : Strengthened unit tests for next/previous character a bit. #Patch Set 26 : Fixed some compilation errors on the Mac. #Messages
Total messages: 60 (26 generated)
This is looking like it's on the right track. Consider trying to implement Mac TextMarkers and some Windows functions in terms of this. That might give you some ideas of what's missing in terms of API design. https://codereview.chromium.org/2271893002/diff/1/ui/accessibility/ax_position.h File ui/accessibility/ax_position.h (right): https://codereview.chromium.org/2271893002/diff/1/ui/accessibility/ax_positio... ui/accessibility/ax_position.h:19: class AX_EXPORT AXPosition { Do you want this class to handle embedded object characters? It seems like you probably want to build that into the class to make implementing a lot of Windows functions easier https://codereview.chromium.org/2271893002/diff/1/ui/accessibility/ax_positio... ui/accessibility/ax_position.h:22: static AXPosition CreateTreePosition(AXNode* anchor); Should probably pass the tree in https://codereview.chromium.org/2271893002/diff/1/ui/accessibility/ax_positio... ui/accessibility/ax_position.h:47: AXPosition ToLeafTextPosition() const; Could you define these two more clearly? https://codereview.chromium.org/2271893002/diff/1/ui/accessibility/ax_positio... ui/accessibility/ax_position.h:62: AXPosition GetNextWordStartPosition() const; It might be better to just have a single function Find() that takes a direction (next, previous), and a granularity (character, word, sentence, paragraph, line) https://codereview.chromium.org/2271893002/diff/1/ui/accessibility/ax_positio... ui/accessibility/ax_position.h:75: AXPosition GetPreviousParagraphEndPosition() const; I'm not sure para is as interesting, but line should probably be included https://codereview.chromium.org/2271893002/diff/1/ui/accessibility/ax_positio... ui/accessibility/ax_position.h:88: virtual std::vector<int> GetWordStartOffsets() = 0; I'm not sure these need to be abstract. You can get them from node->data(). I think what might need to be abstract is something like IsLeafNode(), because BrowserAccessibility might have its own logic there. https://codereview.chromium.org/2271893002/diff/1/ui/accessibility/ax_positio... ui/accessibility/ax_position.h:102: AXNode* anchor_; You probably need to store the AXTree here, since AXNode doesn't store its tree. https://codereview.chromium.org/2271893002/diff/1/ui/accessibility/ax_positio... ui/accessibility/ax_position.h:104: AXPositionType type_; I think this class needs to store the affinity. We need a way to distinguish between the end of the previous line and the start of the next line.
https://codereview.chromium.org/2271893002/diff/20001/content/browser/accessi... File content/browser/accessibility/ax_platform_position.h (right): https://codereview.chromium.org/2271893002/diff/20001/content/browser/accessi... content/browser/accessibility/ax_platform_position.h:22: ui::AXTextAffinity get_affinity() { return affinity_; } I think this needs to be part of AXPosition. It won't be possible to implement something like GetStartOfLine or GetEndOfLine correctly if you don't have affinity in AXPosition. https://codereview.chromium.org/2271893002/diff/20001/content/browser/accessi... File content/browser/accessibility/browser_accessibility_cocoa.mm (right): https://codereview.chromium.org/2271893002/diff/20001/content/browser/accessi... content/browser/accessibility/browser_accessibility_cocoa.mm:137: if (!object.instance_active()) I think you should finish updating this file before we're ready to check this in. It will be great proof that it works. https://codereview.chromium.org/2271893002/diff/20001/content/browser/accessi... content/browser/accessibility/browser_accessibility_cocoa.mm:142: AXPosition marker_data = AXPlatformPosition::CreateTextPosition(manager->ax_tree_id(), object.node_id(), offset); Where is AXPlatformPosition::CreateTextPosition defined? Also, a lot of functions in AXPosition return other AXPositions. How are they going to return a AXPlatformPosition? Are you going to use some sort of factory? https://codereview.chromium.org/2271893002/diff/20001/content/browser/accessi... content/browser/accessibility/browser_accessibility_cocoa.mm:143: marker_data.set_affinity(affinity); Don't you need an object of type AXPlatformPosition to do this?
https://codereview.chromium.org/2271893002/diff/40001/content/browser/accessi... File content/browser/accessibility/ax_platform_position.h (right): https://codereview.chromium.org/2271893002/diff/40001/content/browser/accessi... content/browser/accessibility/ax_platform_position.h:33: std::unique_ptr<ui::AXPositionFactory> factory = It's not necessarily a bad idea to have an object have a reference to some object that owns it or manages it, but as currently designed every AXPosition has to have its own unique factory. I don't see why we need so many factories. At a minimum couldn't this be a shared_ptr? https://codereview.chromium.org/2271893002/diff/40001/ui/accessibility/ax_ran... File ui/accessibility/ax_range.h (right): https://codereview.chromium.org/2271893002/diff/40001/ui/accessibility/ax_ran... ui/accessibility/ax_range.h:15: : anchor(AXPosition::CreateNullPosition()), I don't see AXPosition::CreateNullPosition(), I don't think this even compiles Maybe remove AXRange for now?
The CQ bit was checked by nektar@chromium.org to run a CQ dry run
Dry run: CQ is trying da patch. Follow status at https://chromium-cq-status.appspot.com/v2/patch-status/codereview.chromium.or...
The CQ bit was unchecked by commit-bot@chromium.org
Dry run: Try jobs failed on following builders: win_clang on master.tryserver.chromium.win (JOB_FAILED, http://build.chromium.org/p/tryserver.chromium.win/builders/win_clang/builds/...)
https://codereview.chromium.org/2271893002/diff/120001/content/browser/access... File content/browser/accessibility/browser_accessibility_cocoa.mm (right): https://codereview.chromium.org/2271893002/diff/120001/content/browser/access... content/browser/accessibility/browser_accessibility_cocoa.mm:142: const AXPlatformPositionFactory factory; I'm assuming this needs to be updated? I think creating an instance of AXPosition<BrowserAccessibility> will probably result in a lot of compile errors that will help clean up the design https://codereview.chromium.org/2271893002/diff/120001/ui/accessibility/BUILD.gn File ui/accessibility/BUILD.gn (right): https://codereview.chromium.org/2271893002/diff/120001/ui/accessibility/BUILD... ui/accessibility/BUILD.gn:125: "ax_generated_tree_unittest.cc", I think you need to add ax_position_unittest here https://codereview.chromium.org/2271893002/diff/120001/ui/accessibility/ax_po... File ui/accessibility/ax_position.cc (right): https://codereview.chromium.org/2271893002/diff/120001/ui/accessibility/ax_po... ui/accessibility/ax_position.cc:240: AXNodeType* parent_anchor = GetAnchor()->parent(); This assumes that AXNodeType has a method parent(), but BrowserAccessibility doesn't. How does this even compile? I think it would be cleaner if you had an abstract interface that BrowserAccessibility could inherit from, so it's clear what methods on AXNodeType it's expecting to be able to call. https://codereview.chromium.org/2271893002/diff/120001/ui/accessibility/ax_po... File ui/accessibility/ax_position.h (right): https://codereview.chromium.org/2271893002/diff/120001/ui/accessibility/ax_po... ui/accessibility/ax_position.h:28: static typename AXNodeType::AXPosition CreateTreePosition(int tree_id, Why is it returning a typename AXNodeType::AXPosition? That seems confusing to me. I think it should return a AXPosition<AXNodeType> https://codereview.chromium.org/2271893002/diff/120001/ui/accessibility/ax_po... ui/accessibility/ax_position.h:80: return GetAnchor() ? GetAnchor()->child_count() : -1; BrowserAccessibility doesn't have a method called child_count.
nektar@chromium.org changed reviewers: + ellyjones@chromium.org
I'm a bit confused now because it seems like you have both templatization AND subclassing, but no factory. So it makes sense to have AXPosition<BrowserAccessibility>, but I don't understand how you can then have AXPlatformPosition subclassing AXPosition<BrowserAccessibility> without just having the whole factory problem again.
The idea was, as ingeniously suggested by Elly, to have: template<AXNodeType> static typename AXNodeType::AXPosition AXPosition<AXNodeType>::Create...(...) {...} And inside every AXNodeType, e.g. BrowserAccessibility, place the specific AXPosition subclass as an inner class. class BrowserAccessibility { using AXPosition = AXPlatformPosition; } However, with the help of Avi we found a better design: Curiously recurring template pattern https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern When using polymorphism, one sometimes needs to create copies of objects by the base class pointer. A commonly used idiom for this is adding a virtual clone function that is defined in every derived class. The CRTP can be used to avoid having to duplicate that function or other similar functions in every derived class.
On 2016/10/06 16:34:25, nektarios wrote: > The idea was, as ingeniously suggested by Elly, to have: > template<AXNodeType> static typename AXNodeType::AXPosition > AXPosition<AXNodeType>::Create...(...) {...} > And inside every AXNodeType, e.g. BrowserAccessibility, place the specific > AXPosition subclass as an inner class. > class BrowserAccessibility { > using AXPosition = AXPlatformPosition; > } > > However, with the help of Avi we found a better design: > Curiously recurring template pattern > https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern > When using polymorphism, one sometimes needs to create copies of objects by the > base class pointer. A commonly used idiom for this is adding a virtual > clone function that is defined in every derived class. The CRTP can be used to > avoid having to duplicate that function or other similar functions in every > derived class. I have a meta-request about this CL: Since it took you, me, nico, dominic, and avi collectively several hours to figure out how to design this, there should be an enormous block comment describing and justifying the design for future readers.
Hi Elly, The template pattern seems to work but I have a compilation error I can't figure out. ui\accessibility\ax_position.h(307): error C2248: 'ui::AXNodePos ition::GetChildPositionAt': cannot access protected member declared in class 'ui ::AXNodePosition'
dtseng@chromium.org changed reviewers: + dtseng@chromium.org
Good start! Driving by as a potential customer/bug fixer. I am wondering, is AXPosition/AXRange defined here useful beyond the one time use in BrowserAccessibilityCocoa? It seems like the way Windows and Automation are both structured, that a more functional api would make more sense. e.g. STDMETHODIMP BrowserAccessibilityWin::get_textAfterOffset( LONG offset, IA2TextBoundaryType boundary_type, LONG* start_offset, LONG* end_offset, BSTR* text) { You'll just end up creating a position and making one function call to then unpack all of the resulting values again. Similarly, automation interacts with js via functions and not objects, so in the end, everything's functional. not to make you change directions from what you've got now. As far as the CRTP design, I noticed you don't actually use the derived template class in the base AXPosition class. I'm wondering what the motivation was to get you here? Also, please add a full description to this cl with BUG= and TEST= lines. https://codereview.chromium.org/2271893002/diff/160001/content/browser/access... File content/browser/accessibility/ax_platform_position.h (right): https://codereview.chromium.org/2271893002/diff/160001/content/browser/access... content/browser/accessibility/ax_platform_position.h:26: int text_offset, Can you think of a way to combine text_offset and child_index? One can be derived from the other. https://codereview.chromium.org/2271893002/diff/160001/content/browser/access... content/browser/accessibility/ax_platform_position.h:29: int AnchorChildCount() const override { AXPosition<BrowserAccessibility> overrides https://codereview.chromium.org/2271893002/diff/160001/content/browser/access... content/browser/accessibility/ax_platform_position.h:30: return GetAnchor() ? static_cast<int>(GetAnchor()->PlatformChildCount()) This isn't a simple getter; put in .cc https://codereview.chromium.org/2271893002/diff/160001/content/browser/access... content/browser/accessibility/ax_platform_position.h:31: : -1; Name this special constant https://codereview.chromium.org/2271893002/diff/160001/ui/accessibility/ax_po... File ui/accessibility/ax_position.h (right): https://codereview.chromium.org/2271893002/diff/160001/ui/accessibility/ax_po... ui/accessibility/ax_position.h:16: enum class AXPositionType { NullPosition, TreePosition, TextPosition }; Please expand a little on these. What exactly is a null position? https://codereview.chromium.org/2271893002/diff/160001/ui/accessibility/ax_po... ui/accessibility/ax_position.h:20: // text node and a character offset. What is a text node? https://codereview.chromium.org/2271893002/diff/160001/ui/accessibility/ax_po... ui/accessibility/ax_position.h:34: int get_tree_id() const { return tree_id_; } Remove the get_ here https://codereview.chromium.org/2271893002/diff/160001/ui/accessibility/ax_po... ui/accessibility/ax_position.h:35: int32_t get_anchor_id() const { return anchor_id_; } Remove the get_ here https://codereview.chromium.org/2271893002/diff/160001/ui/accessibility/ax_po... ui/accessibility/ax_position.h:38: int get_text_offset() const { return text_offset_; } I think we should re-think the design here. either: - don't explicitly include tree vs text positions and simply have one offset (i.e. yuou could have two methods, IsTextPosition/IsTreePosition which simply checks the node is/isn't a text node). - create subclasses AXTextPosition/AXTreePosition. https://codereview.chromium.org/2271893002/diff/160001/ui/accessibility/ax_po... ui/accessibility/ax_position.h:40: void set_affinity(ui::AXTextAffinity affinity) { affinity_ = affinity; } I think it would make more sense to make all properties read-only (i.e. set on construction). https://codereview.chromium.org/2271893002/diff/160001/ui/accessibility/ax_po... ui/accessibility/ax_position.h:49: return GetAnchor() && type_ == AXPositionType::TextPosition; So, in theory, I could construct an AXPosition (w char offset) on a non-text node? I thought that wasn't allowed: +// It could either indicate a non-textual node in the accessibility tree, or a +// text node and a character offset. https://codereview.chromium.org/2271893002/diff/160001/ui/accessibility/ax_po... ui/accessibility/ax_position.h:53: bool AtEndOfAnchor() const; In Blink, the position types are: offsetInAnchor, beforeAnchor, afterAnchor, beforeChildren, afterChildren. Every time we deviate from what Blink does, it will make it that much harder to map a position back to the DOM. https://codereview.chromium.org/2271893002/diff/160001/ui/accessibility/ax_po... ui/accessibility/ax_position.h:57: bool operator<(const AXPosition& position) const; Please add some comments for all of these and above. https://codereview.chromium.org/2271893002/diff/160001/ui/accessibility/ax_po... ui/accessibility/ax_position.h:78: // Uses depth-first pre-order traversal. What does this mean? The next tree or character position? https://codereview.chromium.org/2271893002/diff/160001/ui/accessibility/ax_po... ui/accessibility/ax_position.h:83: virtual AXPosition* GetChildPositionAt(int child_index) const = 0; The more I read this, the more I thnk we should separate into AXTextPosition and AXTreePosition. https://codereview.chromium.org/2271893002/diff/160001/ui/accessibility/ax_po... ui/accessibility/ax_position.h:88: virtual int MaxTextOffset() const = 0; Definitely needs comment.
Description was changed from ========== Initial design of AXPosition class. R=dmazzoni@chromium.org ========== to ========== Initial design of AXPosition class. R=dmazzoni@chromium.org, dtseng@chromium.org, avi@chromium.org, ellyjones@chromium.org ==========
nektar@chromium.org changed reviewers: + avi@chromium.org
Adding Avi to the reviewers.
> > However, with the help of Avi we found a better design: > Curiously recurring template pattern > https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern > I'm not sure that's the pattern we're using. If we were using that pattern, BrowserAccessibility would inherit from AXPosition<BrowserAccessibility>. However, having a clone() method instead of a factory sounds fine. Perhaps we should just call it create(...) and have it take the same arguments as the constructor? After seeing David's comments I keep coming back to this idea that we're making it way more complicated than it needs to be. Did you consider the idea of having AXPosition operate on an AXTree and AXNode directly and only allow it to be allocated on the stack so we can use it temporarily? I do think there are some advantages of a class over a functional interface, but I think that all of the templatizing and subclassing and converting between IDs and nodes is a lot of complication, and I'm not convinced we couldn't do something a lot simpler. -- You received this message because you are subscribed to the Google Groups "Chromium-reviews" group. To unsubscribe from this group and stop receiving emails from it, send an email to chromium-reviews+unsubscribe@chromium.org.
On 10/10/2016 1:21 PM, Dominic Mazzoni wrote: > > However, with the help of Avi we found a better design: > Curiously recurring template pattern > https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern > > > I'm not sure that's the pattern we're using. If we were using that > pattern, BrowserAccessibility would inherit from > AXPosition<BrowserAccessibility>. > I think we are using this pattern because AXPlatformPosition inherits from AXPosition<AXPlatformPosition, BrowserAccessibility> That's why it's recursive. > However, having a clone() method instead of a factory sounds fine. > Perhaps we should just call it create(...) and have it take the same > arguments as the constructor? > I have three Create methods now, one per kind of position, text position, tree position and null position. I prefer if I hide the position's kind from the users of this class, so that we could add conversions between tree position and text positions that look more natural. I mean, instead of modifying the kind, we would call a method such as ToTextPosition(). > After seeing David's comments I keep coming back to this idea that > we're making it way more complicated than it needs to be. Did you > consider the idea of having AXPosition operate on an AXTree and AXNode > directly and only allow it to be allocated on the stack so we can use > it temporarily? > How is that different from AXTextMarker we already have on the Mac? It's just a struct without any logic. I thought we wanted something smarter. I spoke to David on the phone and explained and I think he agrees with this design safe some details. However, we'll work together when he is in New York on Thursday, to make this work across ChromeVox, in addition to Mac and Win. > I do think there are some advantages of a class over a functional > interface, but I think that all of the templatizing and subclassing > and converting between IDs and nodes is a lot of complication, and I'm > not convinced we couldn't do something a lot simpler. > Essentially, a functional interface is what we already have and it's messy, isn't that so? I think that there would be multiple functions and it would be even more complicated, because every function needs to get at least a node and an offset and then validate them. Then, we'd need functions for word, character and line for example, and different overrides for Windows and Mac, to handle text positions vs. tree positions. And all those functions would go on BrowserAccessibilityManager? What about ChromeVox and Automation, don't we want to share logic with that part of the code? All these functions are nothing less than some methods that operate on the same data, i.e. a node, some offsets and a tree. This is a class. Plus, we do need to keep state, isn't it? What if I want all the lines instead of only the next one. I'll call GetNextLinePosition and keep calling it until I get the Null position. Unless we'd have another function for getting all the lines? Another example is on Windows there are cases we want to get both the next boundary (e.g. word) and the previous one, hence we'd need to compute state for the current position. Then, there is the idea of caching. If we have a class we'd have a better chance optimizing performance down the line. Also, if we get lines and words and characters etc. working, I was thinking of making selections and bounding rectangles be part of AXRange, so that you get a range and then call a method to get the selection or the bounding rectangle. This would allow us to put validation and kanonicalization code in one place. However, I do agree it's somewhat complicated,. -- You received this message because you are subscribed to the Google Groups "Chromium-reviews" group. To unsubscribe from this group and stop receiving emails from it, send an email to chromium-reviews+unsubscribe@chromium.org.
On Mon, Oct 10, 2016 at 11:14 AM 'Nektarios Paisios' via Chromium-reviews < chromium-reviews@chromium.org> wrote: > However, having a clone() method instead of a factory sounds fine. Perhaps > we should just call it create(...) and have it take the same arguments as > the constructor? > > I have three Create methods now, one per kind of position, text position, > tree position and null position. > I prefer if I hide the position's kind from the users of this class, so > that we could add conversions between tree position and text positions that > look more natural. > I mean, instead of modifying the kind, we would call a method such as > ToTextPosition(). > Wouldn't clone() be protected? I was imagining that clone would just be used so that implementations in the base AXPosition class could return an appropriate AXPosition subclass as a return value. Do you think it'd be better to call clone() and then modify the resulting object? > After seeing David's comments I keep coming back to this idea that we're > making it way more complicated than it needs to be. Did you consider the > idea of having AXPosition operate on an AXTree and AXNode directly and only > allow it to be allocated on the stack so we can use it temporarily? > > How is that different from AXTextMarker we already have on the Mac? It's > just a struct without any logic. I thought we wanted something smarter. > I think we're all in agreement that we want functionality like converting between deep positions and shallow positions, and finding the next line break, and stuff like that. Essentially, a functional interface is what we already have and it's messy, > isn't that so? > I feel like what we have right now is that every time we need to walk the tree for text positions we write custom code to do so. The advantage of AXPosition is that it would consolidate a lot of the tree walking code for text positions into a single class. I'm not saying I want a functional interface, I'm saying I want an object that's used only on the stack to do temporary manipulations of positions, not a persistent object that stores a position for a long time. Then, there is the idea of caching. If we have a class we'd have a better > chance optimizing performance down the line. > I'm not sure where we could cache these. Think about all of the Windows API calls. In lots of the IAccessibleText functions we're given a position and asked to return some other position. There's nothing to cache. > Also, if we get lines and words and characters etc. working, I was > thinking of making selections and bounding rectangles be part of AXRange, > so that you get a range and then call a method to get the selection or the > bounding rectangle. This would allow us to put validation and > kanonicalization code in one place. > That sounds good, I'm not disagreeing with any of that. However I think this is another example of why we just want a temporary object, not a persistent one. -- You received this message because you are subscribed to the Google Groups "Chromium-reviews" group. To unsubscribe from this group and stop receiving emails from it, send an email to chromium-reviews+unsubscribe@chromium.org.
Addressed some of David's comments. On 10/10/2016 2:27 PM, Dominic Mazzoni wrote: > On Mon, Oct 10, 2016 at 11:14 AM 'Nektarios Paisios' via > Chromium-reviews <chromium-reviews@chromium.org > <mailto:chromium-reviews@chromium.org>> wrote: > >> However, having a clone() method instead of a factory sounds >> fine. Perhaps we should just call it create(...) and have it take >> the same arguments as the constructor? >> > I have three Create methods now, one per kind of position, text > position, tree position and null position. > I prefer if I hide the position's kind from the users of this > class, so that we could add conversions between tree position and > text positions that look more natural. > I mean, instead of modifying the kind, we would call a method such > as ToTextPosition(). > > > Wouldn't clone() be protected? I was imagining that clone would just > be used so that implementations in the base AXPosition class could > return an appropriate AXPosition subclass as a return value. > > Do you think it'd be better to call clone() and then modify the > resulting object? With my current implementation Create... methods could be called from both inside the base class and its sub-classes, as well as from outside the class with the same effect. I used "new AXNodeType()" and then Initialize(...). I don't feel that comfortable cloning and then modifying even though I know it will work, because it might be tricky to maintain in the future. > > I'm not saying I want a functional interface, I'm saying I want an > object that's used only on the stack to do temporary manipulations of > positions, not a persistent object that stores a position for a long time. > Okay, but the complexity doesn't arise from looking up node IDs, does it? We had an issue with object construction from sub-classes. Now it's solved. This is what created the complexity and took time to design. Using temporary vs. persistent nodes is one more virtual method override |GetNodeInTree|. That's not that bad, isn't it? I could change it back to get pointers to nodes instead of IDs, but how much of the complexity will go away? -- You received this message because you are subscribed to the Google Groups "Chromium-reviews" group. To unsubscribe from this group and stop receiving emails from it, send an email to chromium-reviews+unsubscribe@chromium.org.
OK, I see how it works now. I was confused because in your comment it sounded like you were going to use the clone() pattern. Now I see that you can just construct a new AXPositionType because that's guaranteed to be the right subclass. OK, I'm happy with the recursive template pattern. Go ahead and work on tests and cleaning this up.
https://codereview.chromium.org/2271893002/diff/240001/ui/accessibility/ax_po... File ui/accessibility/ax_position.h (right): https://codereview.chromium.org/2271893002/diff/240001/ui/accessibility/ax_po... ui/accessibility/ax_position.h:341: virtual AXPosition<AXPositionType, AXNodeType>* GetChildPositionAt( Would it be simpler to have this return the AXNodeType* for a child rather than a position? It seems like you have some duplicate code between ax_node_position and ax_platform_position that doesn't seem necessary. You could implement GetChildPositionAt here as a function of GetChildNodeAt, which would be abstract.
The CQ bit was checked by nektar@chromium.org to run a CQ dry run
Dry run: CQ is trying da patch. Follow status at https://chromium-cq-status.appspot.com/v2/patch-status/codereview.chromium.or...
The CQ bit was unchecked by commit-bot@chromium.org
Dry run: Try jobs failed on following builders: chromeos_amd64-generic_chromium_compile_only_ng on master.tryserver.chromium.linux (JOB_FAILED, http://build.chromium.org/p/tryserver.chromium.linux/builders/chromeos_amd64-...) linux_chromium_chromeos_ozone_rel_ng on master.tryserver.chromium.linux (JOB_FAILED, http://build.chromium.org/p/tryserver.chromium.linux/builders/linux_chromium_...)
The CQ bit was checked by nektar@chromium.org to run a CQ dry run
Dry run: CQ is trying da patch. Follow status at https://chromium-cq-status.appspot.com/v2/patch-status/codereview.chromium.or...
The CQ bit was unchecked by commit-bot@chromium.org
Dry run: Try jobs failed on following builders: cast_shell_android on master.tryserver.chromium.android (JOB_FAILED, https://build.chromium.org/p/tryserver.chromium.android/builders/cast_shell_a...)
The CQ bit was checked by nektar@chromium.org to run a CQ dry run
Dry run: CQ is trying da patch. Follow status at https://chromium-cq-status.appspot.com/v2/patch-status/codereview.chromium.or...
The CQ bit was unchecked by commit-bot@chromium.org
Dry run: Try jobs failed on following builders: mac_chromium_rel_ng on master.tryserver.chromium.mac (JOB_FAILED, http://build.chromium.org/p/tryserver.chromium.mac/builders/mac_chromium_rel_...)
https://codereview.chromium.org/2271893002/diff/320001/ui/accessibility/ax_no... File ui/accessibility/ax_node_position.h (right): https://codereview.chromium.org/2271893002/diff/320001/ui/accessibility/ax_no... ui/accessibility/ax_node_position.h:17: class AX_EXPORT AXNodePosition : public AXPosition<AXNodePosition, AXNode> { Is this intended only for testing? It can't really work without SetTreeForTesting. https://codereview.chromium.org/2271893002/diff/320001/ui/accessibility/ax_no... File ui/accessibility/ax_node_position_unittest.cc (right): https://codereview.chromium.org/2271893002/diff/320001/ui/accessibility/ax_no... ui/accessibility/ax_node_position_unittest.cc:151: std::unique_ptr<AXPosition<AXNodePosition, AXNode>> null_position( How about a typedef for AXPosition<AXNodePosition, AXNode>? https://codereview.chromium.org/2271893002/diff/320001/ui/accessibility/ax_po... File ui/accessibility/ax_position.h (right): https://codereview.chromium.org/2271893002/diff/320001/ui/accessibility/ax_po... ui/accessibility/ax_position.h:231: // TODO(nektar): Not yet implemented for tree positions. As you walk the tree won't you go between tree positions and text positions? It seems like this class needs another virtual method that returns whether or not a node is a text node or not. https://codereview.chromium.org/2271893002/diff/320001/ui/accessibility/ax_po... ui/accessibility/ax_position.h:317: virtual AXPosition<AXPositionType, AXNodeType>* GetPreviousAnchorPosition() Shouldn't this return the end of the previous anchor? I don't see where it does that. https://codereview.chromium.org/2271893002/diff/320001/ui/accessibility/ax_po... ui/accessibility/ax_position.h:336: leaf->GetChildPositionAt(0); It doesn't look like you're doing anything with the return value here, this could loop forever https://codereview.chromium.org/2271893002/diff/320001/ui/accessibility/ax_po... ui/accessibility/ax_position.h:342: virtual AXPosition<AXPositionType, AXNodeType>* GetChildPositionAt( As I said in a previous comment, I think it would be better to have this be GetChildAt() and return an AXNodeType, because then you could implement GetChildPositionAt in terms of that and not need to duplicate all of the logic in two subclasses. https://codereview.chromium.org/2271893002/diff/320001/ui/accessibility/ax_po... ui/accessibility/ax_position.h:344: virtual AXPosition<AXPositionType, AXNodeType>* GetParentPosition() const = 0; Same, this should return an AXNodeType. https://codereview.chromium.org/2271893002/diff/320001/ui/accessibility/ax_ra... File ui/accessibility/ax_range.h (right): https://codereview.chromium.org/2271893002/diff/320001/ui/accessibility/ax_ra... ui/accessibility/ax_range.h:12: struct AXRange { I suggest you delete it from this change since you're not using it or testing it anywhere
On 2016/10/12 at 20:45:41, dmazzoni wrote: > https://codereview.chromium.org/2271893002/diff/320001/ui/accessibility/ax_no... > File ui/accessibility/ax_node_position.h (right): > > https://codereview.chromium.org/2271893002/diff/320001/ui/accessibility/ax_no... > ui/accessibility/ax_node_position.h:17: class AX_EXPORT AXNodePosition : public AXPosition<AXNodePosition, AXNode> { > Is this intended only for testing? It can't really > work without SetTreeForTesting. For now yes, but my intention is to use it for the Automation Tree. Automation uses an AXNode internally and so we could make use of this class there. That doesn't mean that I might not need to tweak it a bit to add the logic for AXTree management, but let's do this in another patch. > > https://codereview.chromium.org/2271893002/diff/320001/ui/accessibility/ax_no... > File ui/accessibility/ax_node_position_unittest.cc (right): > > https://codereview.chromium.org/2271893002/diff/320001/ui/accessibility/ax_no... > ui/accessibility/ax_node_position_unittest.cc:151: std::unique_ptr<AXPosition<AXNodePosition, AXNode>> null_position( > How about a typedef for AXPosition<AXNodePosition, AXNode>? Done. Called TestPositionType. > > https://codereview.chromium.org/2271893002/diff/320001/ui/accessibility/ax_po... > File ui/accessibility/ax_position.h (right): > > https://codereview.chromium.org/2271893002/diff/320001/ui/accessibility/ax_po... > ui/accessibility/ax_position.h:231: // TODO(nektar): Not yet implemented for tree positions. > As you walk the tree won't you go between tree positions > and text positions? It seems like this class needs another > virtual method that returns whether or not a node is a > text node or not. I don't know if my latest patch fixed this or if it was correct from before, but basically I chose to skip having something like |IsTextOnlyNode| and simply check if the node has any children. If it doesn't then I assume it is a text node because all inline text boxes are leaves. Also, in the cases when a leaf node is not an inline text box, we would want to traverse its text anyway, e.g. when an image has alt text. > > https://codereview.chromium.org/2271893002/diff/320001/ui/accessibility/ax_po... > ui/accessibility/ax_position.h:317: virtual AXPosition<AXPositionType, AXNodeType>* GetPreviousAnchorPosition() > Shouldn't this return the end of the previous anchor? I don't see where it does that. Fixed. > > https://codereview.chromium.org/2271893002/diff/320001/ui/accessibility/ax_po... > ui/accessibility/ax_position.h:336: leaf->GetChildPositionAt(0); > It doesn't look like you're doing anything with the return value here, > this could loop forever Fixed. > > https://codereview.chromium.org/2271893002/diff/320001/ui/accessibility/ax_po... > ui/accessibility/ax_position.h:342: virtual AXPosition<AXPositionType, AXNodeType>* GetChildPositionAt( > As I said in a previous comment, I think it would be better > to have this be GetChildAt() and return an AXNodeType, because then > you could implement GetChildPositionAt in terms of that and not > need to duplicate all of the logic in two subclasses. Done but with a tweak. Since sometimes I need an AXNodeType and at other times I need an ID, so I implemented |AnchorChildID| and |AnchorParentID| to get the IDs and I can easily convert those to nodes using |AXNodeInTree|. > > https://codereview.chromium.org/2271893002/diff/320001/ui/accessibility/ax_po... > ui/accessibility/ax_position.h:344: virtual AXPosition<AXPositionType, AXNodeType>* GetParentPosition() const = 0; > Same, this should return an AXNodeType. Done but see above. > > https://codereview.chromium.org/2271893002/diff/320001/ui/accessibility/ax_ra... > File ui/accessibility/ax_range.h (right): > > https://codereview.chromium.org/2271893002/diff/320001/ui/accessibility/ax_ra... > ui/accessibility/ax_range.h:12: struct AXRange { > I suggest you delete it from this change since you're > not using it or testing it anywhere I'll delete it before checking in and you could have a final look then. I'll also delete all operators and CommonAncestor. I wanted to make sure that I don't introduce a breaking change to that file or functions with all these rewrites.
BUG and TESTED lines added. https://codereview.chromium.org/2271893002/diff/160001/content/browser/access... > File content/browser/accessibility/ax_platform_position.h (right): > > https://codereview.chromium.org/2271893002/diff/160001/content/browser/access... > content/browser/accessibility/ax_platform_position.h:26: int text_offset, > Can you think of a way to combine text_offset and child_index? One can be derived from the other. Currently it might be a good idea to have both so that we can quickly switch between the two kinds of positions, but I am open to combining them after I try to use this on Windows and see if there are any performance benefits in having both or not. Also, I am not sure if I'll eventually keep the distinction between tree and text position internally in the class. It might be better for a position to have both a child_index and a text_offset, e.g. when you want to point to a character inside a child of the anchor. > > https://codereview.chromium.org/2271893002/diff/160001/content/browser/access... > content/browser/accessibility/ax_platform_position.h:29: int AnchorChildCount() const override { > AXPosition<BrowserAccessibility> overrides > > https://codereview.chromium.org/2271893002/diff/160001/content/browser/access... > content/browser/accessibility/ax_platform_position.h:30: return GetAnchor() ? static_cast<int>(GetAnchor()->PlatformChildCount()) > This isn't a simple getter; put in .cc I wish I could, but the style guide says that all the code of a templated class should go in a header file. > > https://codereview.chromium.org/2271893002/diff/160001/content/browser/access... > content/browser/accessibility/ax_platform_position.h:31: : -1; > Name this special constant All special constants have been named. > > https://codereview.chromium.org/2271893002/diff/160001/ui/accessibility/ax_po... > File ui/accessibility/ax_position.h (right): > > https://codereview.chromium.org/2271893002/diff/160001/ui/accessibility/ax_po... > ui/accessibility/ax_position.h:16: enum class AXPositionType { NullPosition, TreePosition, TextPosition }; > Please expand a little on these. What exactly is a null position? Wrote a comment. > > https://codereview.chromium.org/2271893002/diff/160001/ui/accessibility/ax_po... > ui/accessibility/ax_position.h:20: // text node and a character offset. > What is a text node? Wrote a comment. > > https://codereview.chromium.org/2271893002/diff/160001/ui/accessibility/ax_po... > ui/accessibility/ax_position.h:34: int get_tree_id() const { return tree_id_; } > Remove the get_ here > > https://codereview.chromium.org/2271893002/diff/160001/ui/accessibility/ax_po... > ui/accessibility/ax_position.h:35: int32_t get_anchor_id() const { return anchor_id_; } > Remove the get_ here Simple geters should be preceded with a "get_" isn't it? In Blink they are not, but in Chromium they are. > > https://codereview.chromium.org/2271893002/diff/160001/ui/accessibility/ax_po... > ui/accessibility/ax_position.h:38: int get_text_offset() const { return text_offset_; } > I think we should re-think the design here. > > either: > - don't explicitly include tree vs text positions and simply have one offset (i.e. yuou could have two methods, IsTextPosition/IsTreePosition which simply checks the node is/isn't a text node). > - create subclasses AXTextPosition/AXTreePosition. I understand the subclasses idea, but it would become too complicated, because then I would need two subclasses per platform, i.e. two subclasses for Automation and two for Win / Mac. Essentially, I think I would need to create two sub-templates as it were, |AXTextPosition<AXTextPositionType, AXNodeType>| and |AXTreePosition<AXTreePositionType, AXNodeType>|, that would inherit from a single base template. That sounds hard. A better idea is to drop the distinction and have the position class include both a child index and a text offset. Clients could simply use either or both, depending on the use case. > > https://codereview.chromium.org/2271893002/diff/160001/ui/accessibility/ax_po... > ui/accessibility/ax_position.h:40: void set_affinity(ui::AXTextAffinity affinity) { affinity_ = affinity; } > I think it would make more sense to make all properties read-only (i.e. set on construction). I agree but I want to get rid of affinity and so I don't want to promote it unnecessarily to something you need to provide at construction. Affinity should go away eventually. > > https://codereview.chromium.org/2271893002/diff/160001/ui/accessibility/ax_po... > ui/accessibility/ax_position.h:49: return GetAnchor() && type_ == AXPositionType::TextPosition; > So, in theory, I could construct an AXPosition (w char offset) on a non-text node? I thought that wasn't allowed: > +// It could either indicate a non-textual node in the accessibility tree, or a > +// text node and a character offset. Yes, the text offset would refer to the text inside the object, either directly or from all its children. > > https://codereview.chromium.org/2271893002/diff/160001/ui/accessibility/ax_po... > ui/accessibility/ax_position.h:53: bool AtEndOfAnchor() const; > In Blink, the position types are: > offsetInAnchor, beforeAnchor, afterAnchor, beforeChildren, afterChildren. > > Every time we deviate from what Blink does, it will make it that much harder to map a position back to the DOM. Eventually I could implement more types. > > https://codereview.chromium.org/2271893002/diff/160001/ui/accessibility/ax_po... > ui/accessibility/ax_position.h:57: bool operator<(const AXPosition& position) const; > Please add some comments for all of these and above. I thought operators were self explanatory. > > https://codereview.chromium.org/2271893002/diff/160001/ui/accessibility/ax_po... > ui/accessibility/ax_position.h:78: // Uses depth-first pre-order traversal. > What does this mean? The next tree or character position? No, constructs a new position using the next anchor in the tree found using depth-first traversal. The kind of position is not changed. > > https://codereview.chromium.org/2271893002/diff/160001/ui/accessibility/ax_po... > ui/accessibility/ax_position.h:83: virtual AXPosition* GetChildPositionAt(int child_index) const = 0; > The more I read this, the more I thnk we should separate into AXTextPosition and AXTreePosition. See above. It would be too complicated. > > https://codereview.chromium.org/2271893002/diff/160001/ui/accessibility/ax_po... > ui/accessibility/ax_position.h:88: virtual int MaxTextOffset() const = 0; > Definitely needs comment. Done.
Description was changed from ========== Initial design of AXPosition class. R=dmazzoni@chromium.org, dtseng@chromium.org, avi@chromium.org, ellyjones@chromium.org ========== to ========== Creates AXPosition to uniquely identify a position in the accessibility tree. TESTED=manually, unit tests BUG=644604,530826 R=dmazzoni@chromium.org, dtseng@chromium.org, avi@chromium.org, ellyjones@chromium.org ==========
> > > https://codereview.chromium.org/2271893002/diff/160001/ui/accessibility/ax_po... > > ui/accessibility/ax_position.h:35: int32_t get_anchor_id() const { return > anchor_id_; } > > Remove the get_ here > > Simple geters should be preceded with a "get_" isn't it? In Blink they are > not, > but in Chromium they are. > Chromium uses the Google C++ style guide, if it's a simple getter with no side effects, no "get_foo" is needed, just "foo". If it's a virtual method or something that computes a value, use GetFoo() with camel case. I'm pretty sure that cases in Chromium and Blink where you've seen Get being added is because they're virtual. > - don't explicitly include tree vs text positions and simply have one > offset > (i.e. yuou could have two methods, IsTextPosition/IsTreePosition which > simply > checks the node is/isn't a text node). > > - create subclasses AXTextPosition/AXTreePosition. > I agree with Nektarios, subclasses for text position and tree position would be overkill. Eventually we might only need one offset, but I think the advantage of this approach is that it adds a bit of extra type safety and forces you to acknowledge what type of position you're getting. I vote that we stick with this for now. https://codereview.chromium.org/2271893002/diff/160001/ui/accessibility/ax_po... > > ui/accessibility/ax_position.h:40: void set_affinity(ui::AXTextAffinity > affinity) { affinity_ = affinity; } > > I think it would make more sense to make all properties read-only (i.e. > set on > construction). > > I agree but I want to get rid of affinity and so I don't want to promote it > unnecessarily to something you need to provide at construction. Affinity > should > go away eventually. > I think I agree with David here that until affinity goes away, I'd rather not make it a weird special case. Just put it in the constructor. It won't be that hard to refactor it later. Until affinity goes away I'd rather try to force us to deal with affinity correctly. > Every time we deviate from what Blink does, it will make it that much > harder > to map a position back to the DOM. > I don't think the primary goal of this class is to represent Blink selection, this class is to represent positions and selection as exposed to platform accessibility APIs. Those APIs tend to be a lot simpler than Blink's model of selection. I suspect we'll need to keep modifying this code as we rewrite the rest of the Mac and Windows APIs in terms of AXPosition, so I'm okay with just keeping this for now. -- You received this message because you are subscribed to the Google Groups "Chromium-reviews" group. To unsubscribe from this group and stop receiving emails from it, send an email to chromium-reviews+unsubscribe@chromium.org.
Tentative looks good, but would prefer to see you remove the unused code and upload a final version. I'm okay with putting off other feedback to land this and start iterating on it. It will be much easier to see the pros and cons of various approaches once you start implementing API functions in terms of this class.
Tentative looks good, but would prefer to see you remove the unused code and upload a final version. I'm okay with putting off other feedback to land this and start iterating on it. It will be much easier to see the pros and cons of various approaches once you start implementing API functions in terms of this class.
1. I removed all irrelevant code. 2. I changed all "get_..." methods and dropped the "get_". 3. I added affinity to the constructor of the text position. 4. Serious! I fixed all memory leaks.
https://codereview.chromium.org/2271893002/diff/420001/content/browser/access... File content/browser/accessibility/ax_platform_position.cc (right): https://codereview.chromium.org/2271893002/diff/420001/content/browser/access... content/browser/accessibility/ax_platform_position.cc:15: int32_t AXPlatformPosition::AnchorChildID(int child_index) const { I just realized that this won't work across iframes, because the tree ID of the child will be different. Also PlatformGetChild() probably isn't what you want anyway, because it excludes inline text boxes (on all platforms). Maybe you should be using InternalGetChild / InternalChildCount, and handle iframes separately? https://codereview.chromium.org/2271893002/diff/420001/ui/accessibility/BUILD.gn File ui/accessibility/BUILD.gn (right): https://codereview.chromium.org/2271893002/diff/420001/ui/accessibility/BUILD... ui/accessibility/BUILD.gn:24: "ax_range.h", Get rid of this
https://codereview.chromium.org/2271893002/diff/420001/content/browser/access... > File content/browser/accessibility/ax_platform_position.cc (right): > > https://codereview.chromium.org/2271893002/diff/420001/content/browser/access... > content/browser/accessibility/ax_platform_position.cc:15: int32_t > AXPlatformPosition::AnchorChildID(int child_index) const { > I just realized that this won't work across iframes, because the > tree ID of the child will be different. > Fixed by returning both a tree ID and a child ID. > Also PlatformGetChild() probably isn't what you want anyway, because > it excludes inline text boxes (on all platforms). > > Maybe you should be using InternalGetChild / InternalChildCount, and > handle iframes separately? > Fixed by using both depending on the situation. > https://codereview.chromium.org/2271893002/diff/420001/ui/accessibility/BUILD.gn > File ui/accessibility/BUILD.gn (right): > > https://codereview.chromium.org/2271893002/diff/420001/ui/accessibility/BUILD... > ui/accessibility/BUILD.gn:24: "ax_range.h", > Get rid of this Done. -- You received this message because you are subscribed to the Google Groups "Chromium-reviews" group. To unsubscribe from this group and stop receiving emails from it, send an email to chromium-reviews+unsubscribe@chromium.org.
lgtm
The CQ bit was checked by nektar@chromium.org
The patchset sent to the CQ was uploaded after l-g-t-m from dmazzoni@chromium.org Link to the patchset: https://codereview.chromium.org/2271893002/#ps500001 (title: "Fixed some compilation errors on the Mac.")
CQ is trying da patch. Follow status at https://chromium-cq-status.appspot.com/v2/patch-status/codereview.chromium.or...
The CQ bit was unchecked by commit-bot@chromium.org
Try jobs failed on following builders: chromium_presubmit on master.tryserver.chromium.linux (JOB_FAILED, http://build.chromium.org/p/tryserver.chromium.linux/builders/chromium_presub...)
stampity stamp lgtm
The CQ bit was checked by nektar@chromium.org
CQ is trying da patch. Follow status at https://chromium-cq-status.appspot.com/v2/patch-status/codereview.chromium.or...
Message was sent while issue was closed.
Committed patchset #26 (id:500001)
Message was sent while issue was closed.
Description was changed from ========== Creates AXPosition to uniquely identify a position in the accessibility tree. TESTED=manually, unit tests BUG=644604,530826 R=dmazzoni@chromium.org, dtseng@chromium.org, avi@chromium.org, ellyjones@chromium.org ========== to ========== Creates AXPosition to uniquely identify a position in the accessibility tree. TESTED=manually, unit tests BUG=644604,530826 R=dmazzoni@chromium.org, dtseng@chromium.org, avi@chromium.org, ellyjones@chromium.org Committed: https://crrev.com/9de71d4067f24c4e333b5bef4f1210c9395ba847 Cr-Commit-Position: refs/heads/master@{#426906} ==========
Message was sent while issue was closed.
Patchset 26 (id:??) landed as https://crrev.com/9de71d4067f24c4e333b5bef4f1210c9395ba847 Cr-Commit-Position: refs/heads/master@{#426906} |