Skip to content

Commit

Permalink
Apply patch. rdar://103616732
Browse files Browse the repository at this point in the history
Identifier: 272448.852@safari-7618-branch
  • Loading branch information
Dan Robson committed Apr 2, 2024
1 parent 57a4cf5 commit 7def06c
Show file tree
Hide file tree
Showing 11 changed files with 191 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
This test ensures we don't make incorrect updates to the accessibility tree when an iframe has dirty layout.

Dumping initial AX tree search traversal.

{AXRole: AXScrollArea}

{AXRole: AXWebArea}

{#main AXRole: AXGroup}


Dumping new AX tree search traversal.

{AXRole: AXScrollArea}

{AXRole: AXWebArea}

{#main AXRole: AXGroup}

{AXRole: AXTable}

{AXRole: AXRow}

{AXRole: AXCell}

{AXRole: AXStaticText AXValue: Cell 1}

{AXRole: AXCell}

{AXRole: AXStaticText AXValue: Cell 2}

{AXRole: AXRow}

{AXRole: AXCell}

{AXRole: AXStaticText AXValue: Cell 3}

{AXRole: AXCell}

{AXRole: AXStaticText AXValue: Cell 4}

PASS successfullyParsed is true

TEST COMPLETE

Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<script src="../resources/accessibility-helper.js"></script>
<script src="../resources/js-test.js"></script>
</head>
<body>

<iframe id="iframe" onload="runTest()" srcdoc="<main id='main'></main>"></iframe>

<script>
var output = "This test ensures we don't make incorrect updates to the accessibility tree when an iframe has dirty layout.\n\n";
window.jsTestIsAsync = true;

function runTest() {
if (!window.accessibilityController)
return;

// Touch the tree to ensure the AXObjectCache is created.
touchAccessibilityTree(accessibilityController.rootElement);
output += "Dumping initial AX tree search traversal.\n";
var webarea = accessibilityController.rootElement.childAtIndex(0);
output += dumpAXSearchTraversal(webarea, { excludeRoles: ["scrollbar"] });
output += "\n\n";

var traversalOutput;
setTimeout(async function() {
const iframeDocument = document.getElementById("iframe").contentWindow.document;
let newTable = iframeDocument.createElement("table");
newTable.innerHTML = "<tr><th>Cell 1</th><th>Cell 2</th></tr><tr><td>Cell 3</td><td>Cell 4</td></tr>";
iframeDocument.getElementById("main").appendChild(newTable);

await waitFor(() => {
// The placement of this forced update is intentionally within this waitFor block as placing it elsewhere
// causes the timing to be different, and the bug not to be triggered.
internals.forceAXObjectCacheUpdate();
return true;
});

await waitFor(() => {
traversalOutput = dumpAXSearchTraversal(webarea, { excludeRoles: ["scrollbar"] });
return traversalOutput.includes("Cell 1")
&& traversalOutput.includes("Cell 2")
&& traversalOutput.includes("Cell 3")
&& traversalOutput.includes("Cell 4");
});

output += "Dumping new AX tree search traversal.\n";
output += traversalOutput;

debug(output);
finishJSTest();
}, 0);
}
</script>
</body>
</html>

1 change: 1 addition & 0 deletions LayoutTests/platform/glib/TestExpectations
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,7 @@ accessibility/table-search-traversal.html [ Skip ]
accessibility/tree-update-with-dirty-layout.html [ Skip ]
accessibility/dynamically-changing-iframe-remains-accessible.html [ Skip ]
accessibility/ignore-modals-without-any-content.html [ Skip ]
accessibility/iframe-tree-update-with-dirty-layout.html [ Skip ]
accessibility/iframe-with-role.html [ Skip ]

accessibility/editable-webpage-focused-ui-element.html [ Skip ]
Expand Down
1 change: 1 addition & 0 deletions LayoutTests/platform/ios/TestExpectations
Original file line number Diff line number Diff line change
Expand Up @@ -2220,6 +2220,7 @@ accessibility/element-haspopup.html [ Pass ]
accessibility/empty-text-under-element-cached.html [ Pass ]
accessibility/heading-level.html [ Pass ]
accessibility/html5-required-attribute.html [ Pass ]
accessibility/iframe-tree-update-with-dirty-layout.html [ Pass ]
accessibility/iframe-with-role.html [ Pass ]
accessibility/input-type-hidden-in-aria-hidden-false.html [ Pass ]
accessibility/invalid-inputs.html [ Pass ]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
This test ensures we don't make incorrect updates to the accessibility tree when an iframe has dirty layout.

Dumping initial AX tree search traversal.

{WebArea}

{#main LandmarkMain}


Dumping new AX tree search traversal.

{WebArea}

{StaticText AXLabel: Cell 1}

{StaticText AXLabel: Cell 2}

{StaticText AXLabel: Cell 3}

{StaticText AXLabel: Cell 4}

PASS successfullyParsed is true

TEST COMPLETE

Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
This test ensures we don't make incorrect updates to the accessibility tree when an iframe has dirty layout.

Dumping initial AX tree search traversal.

{AXRole: AXWebArea}

{#main AXRole: AXGroup}


Dumping new AX tree search traversal.

{AXRole: AXWebArea}

{#main AXRole: AXGroup}

{AXRole: AXTable}

{AXRole: AXRow}

{AXRole: AXCell}

{AXRole: AXStaticText AXValue: Cell 1}

{AXRole: AXCell}

{AXRole: AXStaticText AXValue: Cell 2}

{AXRole: AXRow}

{AXRole: AXCell}

{AXRole: AXStaticText AXValue: Cell 3}

{AXRole: AXCell}

{AXRole: AXStaticText AXValue: Cell 4}

PASS successfullyParsed is true

TEST COMPLETE

11 changes: 11 additions & 0 deletions Source/WebCore/accessibility/AXObjectCache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3982,6 +3982,17 @@ void AXObjectCache::performDeferredCacheUpdate(ForceLayout forceLayout)
}
}

RefPtr<Frame> frame = document().frame();
if (frame && frame->isMainFrame()) {
// The layout of subframes must also be clean (assuming we're processing objects from those subframes), so force it here if necessary.
for (; frame; frame = frame->tree().traverseNext()) {
auto* localFrame = dynamicDowncast<LocalFrame>(frame.get());
RefPtr subDocument = localFrame ? localFrame->document() : nullptr;
if (subDocument && subDocument->view() && subDocument->view()->needsLayout())
subDocument->updateLayoutIgnorePendingStylesheets();
}
}

bool markedRelationsDirty = false;
auto markRelationsDirty = [&] () {
if (!markedRelationsDirty) {
Expand Down
2 changes: 1 addition & 1 deletion Source/WebCore/accessibility/AXObjectCache.h
Original file line number Diff line number Diff line change
Expand Up @@ -489,7 +489,7 @@ class AXObjectCache : public CanMakeWeakPtr<AXObjectCache>, public CanMakeChecke
void deferRecomputeTableCellSlots(AccessibilityTable&);
void deferTextChangedIfNeeded(Node*);
void deferSelectedChildrenChangedIfNeeded(Element&);
void performDeferredCacheUpdate(ForceLayout);
WEBCORE_EXPORT void performDeferredCacheUpdate(ForceLayout);
void deferTextReplacementNotificationForTextControl(HTMLTextFormControlElement&, const String& previousValue);

std::optional<SimpleRange> rangeMatchesTextNearRange(const SimpleRange&, const String&);
Expand Down
6 changes: 6 additions & 0 deletions Source/WebCore/testing/Internals.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4168,6 +4168,12 @@ void Internals::setUsesOverlayScrollbars(bool enabled)
}
#endif

void Internals::forceAXObjectCacheUpdate() const
{
if (RefPtr document = contextDocument())
document->axObjectCache()->performDeferredCacheUpdate(ForceLayout::Yes);
}

void Internals::forceReload(bool endToEnd)
{
OptionSet<ReloadOption> reloadOptions;
Expand Down
1 change: 1 addition & 0 deletions Source/WebCore/testing/Internals.h
Original file line number Diff line number Diff line change
Expand Up @@ -673,6 +673,7 @@ class Internals final : public RefCounted<Internals>, private ContextDestruction

String toolTipFromElement(Element&) const;

void forceAXObjectCacheUpdate() const;
void forceReload(bool endToEnd);
void reloadExpiredOnly();

Expand Down
1 change: 1 addition & 0 deletions Source/WebCore/testing/Internals.idl
Original file line number Diff line number Diff line change
Expand Up @@ -854,6 +854,7 @@ typedef (FetchRequest or FetchResponse) FetchObject;

undefined setUsesOverlayScrollbars(boolean enabled);

undefined forceAXObjectCacheUpdate();
undefined forceReload(boolean endToEnd);
undefined reloadExpiredOnly();

Expand Down

0 comments on commit 7def06c

Please sign in to comment.