Changeset 215975 in webkit
- Timestamp:
- Apr 29, 2017 11:55:18 AM (7 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r215973 r215975 1 2017-04-29 Nan Wang <n_wang@apple.com> 2 3 AX: Improve performance of addChildren()/childrenChanged() 4 https://bugs.webkit.org/show_bug.cgi?id=171443 5 6 Reviewed by Chris Fleizach. 7 8 There's a lot of unnecessary work happening when childrenChanged() is being called. 9 Some of the improvements here: 10 1. When childrenChanged() is being called on some element, we are marking its parent 11 chain dirty. However, in the addChild() method we are then clearing each child of 12 that 'dirty' parent, eventually making the entire tree dirty. 13 Added a m_subTreeDirty flag and using the needsToUpdateChildren() check to make sure 14 we are only clearing the right chain without updating the unchanged siblings. 15 2. In the addChild() method we are calling accessibilityIsIgnored() on each child and that 16 might lead to going up the parent chain again to get necessary information. 17 Since we are already traversing the tree from top to bottom to add children, added a 18 struct to store the information and pass it to the child so to avoid unnecessary traversal. 19 3. Reduced the amount work of ARIA text controls perform when updating its parents in childrenChanged() 20 so that we don't update a big portion of the tree while typing. 21 22 No new tests since this didn't change any functionality. 23 24 * accessibility/AccessibilityNodeObject.cpp: 25 (WebCore::AccessibilityNodeObject::AccessibilityNodeObject): 26 (WebCore::AccessibilityNodeObject::childrenChanged): 27 (WebCore::AccessibilityNodeObject::insertChild): 28 (WebCore::AccessibilityNodeObject::addChildren): 29 (WebCore::AccessibilityNodeObject::isDescendantOfBarrenParent): 30 * accessibility/AccessibilityNodeObject.h: 31 * accessibility/AccessibilityObject.cpp: 32 (WebCore::AccessibilityObject::AccessibilityObject): 33 (WebCore::AccessibilityObject::defaultObjectInclusion): 34 (WebCore::AccessibilityObject::setIsIgnoredFromParentDataForChild): 35 * accessibility/AccessibilityObject.h: 36 (WebCore::AccessibilityIsIgnoredFromParentData::AccessibilityIsIgnoredFromParentData): 37 (WebCore::AccessibilityIsIgnoredFromParentData::isNull): 38 (WebCore::AccessibilityObject::setNeedsToUpdateSubTree): 39 (WebCore::AccessibilityObject::needsToUpdateChildren): 40 (WebCore::AccessibilityObject::setIsIgnoredFromParentData): 41 * accessibility/AccessibilityRenderObject.cpp: 42 (WebCore::AccessibilityRenderObject::updateChildrenIfNecessary): 43 (WebCore::AccessibilityRenderObject::addChildren): 44 * accessibility/AccessibilityRenderObject.h: 45 (WebCore::AccessibilityRenderObject::setRenderObject): 46 (WebCore::AccessibilityRenderObject::needsToUpdateChildren): Deleted. 47 1 48 2017-04-29 Yusuke Suzuki <utatane.tea@gmail.com> 2 49 -
trunk/Source/WebCore/accessibility/AccessibilityNodeObject.cpp
r215968 r215975 86 86 , m_ariaRole(UnknownRole) 87 87 , m_childrenDirty(false) 88 , m_subtreeDirty(false) 88 89 , m_roleForMSAA(UnknownRole) 89 90 #ifndef NDEBUG … … 130 131 return; 131 132 cache->postNotification(this, document(), AXObjectCache::AXChildrenChanged); 133 134 // Should make the sub tree dirty so that everything below will be updated correctly. 135 this->setNeedsToUpdateSubtree(); 136 bool shouldStopUpdatingParent = false; 132 137 133 138 // Go up the accessibility parent chain, but only if the element already exists. This method is … … 136 141 // At the same time, process ARIA live region changes. 137 142 for (AccessibilityObject* parent = this; parent; parent = parent->parentObjectIfExists()) { 138 parent->setNeedsToUpdateChildren(); 143 if (!shouldStopUpdatingParent) 144 parent->setNeedsToUpdateChildren(); 145 139 146 140 147 // These notifications always need to be sent because screenreaders are reliant on them to perform. … … 149 156 150 157 // If this element is an ARIA text control, notify the AT of changes. 151 if (parent->isNonNativeTextControl()) 158 if (parent->isNonNativeTextControl()) { 152 159 cache->postNotification(parent, parent->document(), AXObjectCache::AXValueChanged); 160 161 // Do not let the parent that's above the editable ancestor update its children 162 // since we already notify the AT of changes. 163 shouldStopUpdatingParent = true; 164 } 153 165 } 154 166 } … … 334 346 // or its visibility has changed. In the latter case, this child may have a stale child cached. 335 347 // This can prevent aria-hidden changes from working correctly. Hence, whenever a parent is getting children, ensure data is not stale. 336 child->clearChildren(); 337 348 // Only clear the child's children when we know it's in the updating chain in order to avoid unnecessary work. 349 if (child->needsToUpdateChildren() || m_subtreeDirty) { 350 child->clearChildren(); 351 // Pass m_subtreeDirty flag down to the child so that children cache gets reset properly. 352 if (m_subtreeDirty) 353 child->setNeedsToUpdateSubtree(); 354 } else { 355 // For some reason the grand children might be detached so that we need to regenerate the 356 // children list of this child. 357 for (const auto& grandChild : child->children(false)) { 358 if (grandChild->isDetachedFromParent()) { 359 child->clearChildren(); 360 break; 361 } 362 } 363 } 364 365 setIsIgnoredFromParentDataForChild(child); 338 366 if (child->accessibilityIsIgnored()) { 339 367 const auto& children = child->children(); … … 345 373 m_children.insert(index, child); 346 374 } 375 376 // Reset the child's m_isIgnoredFromParentData since we are done adding that child and its children. 377 child->clearIsIgnoredFromParentData(); 347 378 } 348 379 … … 369 400 for (Node* child = m_node->firstChild(); child; child = child->nextSibling()) 370 401 addChild(axObjectCache()->getOrCreate(child)); 402 403 m_subtreeDirty = false; 371 404 } 372 405 … … 1060 1093 bool AccessibilityNodeObject::isDescendantOfBarrenParent() const 1061 1094 { 1095 if (!m_isIgnoredFromParentData.isNull()) 1096 return m_isIgnoredFromParentData.isDescendantOfBarrenParent; 1097 1062 1098 for (AccessibilityObject* object = parentObject(); object; object = object->parentObject()) { 1063 1099 if (!object->canHaveChildren()) -
trunk/Source/WebCore/accessibility/AccessibilityNodeObject.h
r208179 r215975 147 147 AccessibilityRole m_ariaRole; 148 148 bool m_childrenDirty; 149 bool m_subtreeDirty; 149 150 mutable AccessibilityRole m_roleForMSAA; 150 151 #ifndef NDEBUG -
trunk/Source/WebCore/accessibility/AccessibilityObject.cpp
r215968 r215975 87 87 , m_role(UnknownRole) 88 88 , m_lastKnownIsIgnoredValue(DefaultBehavior) 89 , m_isIgnoredFromParentData(AccessibilityIsIgnoredFromParentData()) 89 90 #if PLATFORM(GTK) 90 91 , m_wrapper(nullptr) … … 3098 3099 AccessibilityObjectInclusion AccessibilityObject::defaultObjectInclusion() const 3099 3100 { 3100 if (isARIAHidden()) 3101 bool useParentData = !m_isIgnoredFromParentData.isNull(); 3102 3103 if (useParentData ? m_isIgnoredFromParentData.isARIAHidden : isARIAHidden()) 3101 3104 return IgnoreObject; 3102 3105 … … 3104 3107 return IgnoreObject; 3105 3108 3106 if ( isPresentationalChildOfAriaRole())3109 if (useParentData ? m_isIgnoredFromParentData.isPresentationalChildOfAriaRole : isPresentationalChildOfAriaRole()) 3107 3110 return IgnoreObject; 3108 3111 … … 3296 3299 } 3297 3300 3301 void AccessibilityObject::setIsIgnoredFromParentDataForChild(AccessibilityObject* child) 3302 { 3303 if (!child || child->parentObject() != this) 3304 return; 3305 3306 AccessibilityIsIgnoredFromParentData result = AccessibilityIsIgnoredFromParentData(this); 3307 if (!m_isIgnoredFromParentData.isNull()) { 3308 result.isARIAHidden = m_isIgnoredFromParentData.isARIAHidden || equalLettersIgnoringASCIICase(child->getAttribute(aria_hiddenAttr), "true"); 3309 result.isPresentationalChildOfAriaRole = m_isIgnoredFromParentData.isPresentationalChildOfAriaRole || ariaRoleHasPresentationalChildren(); 3310 result.isDescendantOfBarrenParent = m_isIgnoredFromParentData.isDescendantOfBarrenParent || !canHaveChildren(); 3311 } else { 3312 result.isARIAHidden = child->isARIAHidden(); 3313 result.isPresentationalChildOfAriaRole = child->isPresentationalChildOfAriaRole(); 3314 result.isDescendantOfBarrenParent = child->isDescendantOfBarrenParent(); 3315 } 3316 3317 child->setIsIgnoredFromParentData(result); 3318 } 3319 3298 3320 } // namespace WebCore -
trunk/Source/WebCore/accessibility/AccessibilityObject.h
r215968 r215975 286 286 { } 287 287 }; 288 289 // Use this struct to store the isIgnored data that depends on the parents, so that in addChildren() 290 // we avoid going up the parent chain for each element while traversing the tree with useful information already. 291 struct AccessibilityIsIgnoredFromParentData { 292 AccessibilityObject* parent; 293 bool isARIAHidden; 294 bool isPresentationalChildOfAriaRole; 295 bool isDescendantOfBarrenParent; 296 297 AccessibilityIsIgnoredFromParentData(AccessibilityObject* parent = nullptr) 298 : parent(parent) 299 , isARIAHidden(false) 300 , isPresentationalChildOfAriaRole(false) 301 , isDescendantOfBarrenParent(false) 302 { } 303 304 bool isNull() const { return !parent; } 305 }; 288 306 289 307 enum AccessibilityOrientation { … … 823 841 virtual void updateChildrenIfNecessary(); 824 842 virtual void setNeedsToUpdateChildren() { } 843 virtual void setNeedsToUpdateSubtree() { } 825 844 virtual void clearChildren(); 845 virtual bool needsToUpdateChildren() const { return false; } 826 846 #if PLATFORM(COCOA) 827 847 virtual void detachFromParent(); … … 1079 1099 static const AccessibilityObject* matchedParent(const AccessibilityObject&, bool includeSelf, const std::function<bool(const AccessibilityObject&)>&); 1080 1100 1101 void clearIsIgnoredFromParentData() { m_isIgnoredFromParentData = AccessibilityIsIgnoredFromParentData(); } 1102 void setIsIgnoredFromParentDataForChild(AccessibilityObject*); 1103 1081 1104 protected: 1082 1105 AXID m_id; … … 1085 1108 AccessibilityRole m_role; 1086 1109 AccessibilityObjectInclusion m_lastKnownIsIgnoredValue; 1110 AccessibilityIsIgnoredFromParentData m_isIgnoredFromParentData; 1111 1112 void setIsIgnoredFromParentData(AccessibilityIsIgnoredFromParentData& data) { m_isIgnoredFromParentData = data; } 1087 1113 1088 1114 virtual bool computeAccessibilityIsIgnored() const { return true; } -
trunk/Source/WebCore/accessibility/AccessibilityRenderObject.cpp
r215971 r215975 2983 2983 { 2984 2984 if (needsToUpdateChildren()) 2985 clearChildren(); 2985 clearChildren(); 2986 2986 2987 2987 AccessibilityObject::updateChildrenIfNecessary(); … … 3207 3207 for (RefPtr<AccessibilityObject> obj = firstChild(); obj; obj = obj->nextSibling()) 3208 3208 addChild(obj.get()); 3209 3210 m_subtreeDirty = false; 3209 3211 3210 3212 addHiddenChildren(); -
trunk/Source/WebCore/accessibility/AccessibilityRenderObject.h
r208929 r215975 203 203 explicit AccessibilityRenderObject(RenderObject*); 204 204 void setRenderObject(RenderObject* renderer) { m_renderer = renderer; } 205 bool needsToUpdateChildren() const { return m_childrenDirty; }206 205 ScrollableArea* getScrollableAreaIfScrollable() const override; 207 206 void scrollTo(const IntPoint&) const override; … … 229 228 bool nodeIsTextControl(const Node*) const; 230 229 void setNeedsToUpdateChildren() override { m_childrenDirty = true; } 230 bool needsToUpdateChildren() const override { return m_childrenDirty; } 231 void setNeedsToUpdateSubtree() override { m_subtreeDirty = true; } 231 232 Path elementPath() const override; 232 233
Note: See TracChangeset
for help on using the changeset viewer.