Commit 42a555ab authored by Katie Dektar's avatar Katie Dektar Committed by Commit Bot

Smoothly speak non-paragraph inline items.

Don't highlight whitespace-only nodes.

Bug: 753022
Cq-Include-Trybots: master.tryserver.chromium.linux:closure_compilation
Change-Id: Iaac62b135512ba95ea6dfaabc9450802e939e621
Reviewed-on: https://chromium-review.googlesource.com/719763
Commit-Queue: Katie Dektar <katydek@google.com>
Reviewed-by: default avatarDominic Mazzoni <dmazzoni@chromium.org>
Cr-Commit-Position: refs/heads/master@{#509298}
parent ab1291fb
...@@ -6,32 +6,33 @@ var AutomationNode = chrome.automation.AutomationNode; ...@@ -6,32 +6,33 @@ var AutomationNode = chrome.automation.AutomationNode;
var RoleType = chrome.automation.RoleType; var RoleType = chrome.automation.RoleType;
/** /**
* Gets the parent paragraph of a node, or null if it is not in a paragraph. * Gets the first ancestor of a node which is a paragraph, or display:block,
* or the root node if none is found.
* @param { AutomationNode } node The node to get the parent for. * @param { AutomationNode } node The node to get the parent for.
* @return { ?AutomationNode } the parent paragraph or null if there is none. * @return { ?AutomationNode } the parent paragraph or null if there is none.
*/ */
function getParagraphParent(node) { function getFirstBlockAncestor(node) {
let parent = node.parent; let parent = node.parent;
let root = node.root;
while (parent != null) { while (parent != null) {
if (parent == root) {
return parent;
}
if (parent.role == RoleType.PARAGRAPH) { if (parent.role == RoleType.PARAGRAPH) {
return parent; return parent;
} }
if ((parent.display == 'block' || parent.display == 'inline-block') &&
parent.role != RoleType.STATIC_TEXT) {
return parent;
}
parent = parent.parent; parent = parent.parent;
} }
return null; return null;
} }
/** /**
* Determines whether a node is inside of a paragraph. * Determines whether two nodes are in the same block-like ancestor, i.e.
* @param { AutomationNode } node The node to test * whether they are in the same paragraph.
* @return { boolean } whether the node is in a paragraph
*/
function isInParagraph(node) {
return getParagraphParent(node) != null;
}
/**
* Determines whether two nodes are in the same paragraph.
* @param { AutomationNode|undefined } first The first node to compare. * @param { AutomationNode|undefined } first The first node to compare.
* @param { AutomationNode|undefined } second The second node to compare. * @param { AutomationNode|undefined } second The second node to compare.
* @return { boolean } whether two nodes are in the same paragraph. * @return { boolean } whether two nodes are in the same paragraph.
...@@ -41,17 +42,33 @@ function inSameParagraph(first, second) { ...@@ -41,17 +42,33 @@ function inSameParagraph(first, second) {
return false; return false;
} }
// TODO: Clean up this check after crbug.com/774308 is resolved. // TODO: Clean up this check after crbug.com/774308 is resolved.
// At that point we will only need to check for display:block. // At that point we will only need to check for display:block or inline-block.
if ((first.display == 'block' && first.role != RoleType.STATIC_TEXT && if (((first.display == 'block' || first.display == 'inline-block') &&
first.role != RoleType.STATIC_TEXT &&
first.role != RoleType.INLINE_TEXT_BOX) || first.role != RoleType.INLINE_TEXT_BOX) ||
(second.display == 'block' && second.role != RoleType.STATIC_TEXT && ((second.display == 'block' || second.display == 'inline-block') &&
second.role != RoleType.STATIC_TEXT &&
second.role != RoleType.INLINE_TEXT_BOX)) { second.role != RoleType.INLINE_TEXT_BOX)) {
// 'block' elements cannot be in the same paragraph. // 'block' or 'inline-block' elements cannot be in the same paragraph.
return false; return false;
} }
let firstParent = getParagraphParent(first); let firstBlock = getFirstBlockAncestor(first);
let secondParent = getParagraphParent(second); let secondBlock = getFirstBlockAncestor(second);
return firstParent != undefined && firstParent == secondParent; return firstBlock != undefined && firstBlock == secondBlock;
}
/**
* Determines whether a string is only whitespace.
* @param { string } name A string to test
* @return { boolean } whether the string is only whitespace
*/
function isWhitespace(name) {
if (name.length == 0) {
return true;
}
// Search for one or more whitespace characters
let re = /^\s+$/;
return re.exec(name) != null;
} }
/** /**
...@@ -77,7 +94,7 @@ function buildNodeGroup(nodes, index) { ...@@ -77,7 +94,7 @@ function buildNodeGroup(nodes, index) {
index += 1; index += 1;
node = next; node = next;
next = nodes[index + 1]; next = nodes[index + 1];
if (node.name === undefined || node.name == '') { if (node.name === undefined || isWhitespace(node.name)) {
// Don't bother with unnamed or empty nodes. // Don't bother with unnamed or empty nodes.
continue; continue;
} }
......
...@@ -21,31 +21,31 @@ SelectToSpeakParagraphUnitTest.prototype = { ...@@ -21,31 +21,31 @@ SelectToSpeakParagraphUnitTest.prototype = {
] ]
}; };
TEST_F('SelectToSpeakParagraphUnitTest', 'IsInParagraph', function() { TEST_F('SelectToSpeakParagraphUnitTest', 'GetFirstBlockAncestor', function() {
let root = {role: 'rootWebArea'}; let root = {role: 'rootWebArea'};
let paragraph = {role: 'paragraph', parent: 'rootWebArea'}; let paragraph = {role: 'paragraph', parent: root, root: root};
let text1 = {role: 'staticText', parent: paragraph}; let text1 = {role: 'staticText', parent: paragraph, display: 'block',
let text2 = {role: 'staticText', parent: 'rootWebArea'}; root: root};
assertTrue(isInParagraph(text1)); let text2 = {role: 'staticText', parent: root, root: root};
assertFalse(isInParagraph(text2)); let text3 = {role: 'inlineTextBox', parent: text1, root: root};
}); let div = {role: 'genericContainer', parent: paragraph, display: 'block',
root: root};
TEST_F('SelectToSpeakParagraphUnitTest', 'GetParagraphParent', function() { let text4 = {role: 'staticText', parent: div, root: root};
let root = {role: 'rootWebArea'}; assertEquals(paragraph, getFirstBlockAncestor(text1));
let paragraph = {role: 'paragraph', parent: 'rootWebArea'}; assertEquals(root, getFirstBlockAncestor(text2));
let text1 = {role: 'staticText', parent: paragraph}; assertEquals(paragraph, getFirstBlockAncestor(text3));
let text2 = {role: 'staticText', parent: 'rootWebArea'}; assertEquals(div, getFirstBlockAncestor(text4));
assertEquals(paragraph, getParagraphParent(text1));
assertEquals(null, getParagraphParent(text2));
}); });
TEST_F('SelectToSpeakParagraphUnitTest', 'InSameParagraph', function() { TEST_F('SelectToSpeakParagraphUnitTest', 'InSameParagraph', function() {
let root = {role: 'rootWebArea'}; let root = {role: 'rootWebArea'};
let paragraph1 = {role: 'paragraph', parent: 'rootWebArea'}; let paragraph1 = {role: 'paragraph', display: 'block', parent: 'rootWebArea',
let text1 = {role: 'staticText', parent: paragraph1}; root: root};
let text2 = {role: 'staticText', parent: paragraph1}; let text1 = {role: 'staticText', parent: paragraph1, root: root};
let paragraph2 = {role: 'paragraph', parent: 'rootWebArea'}; let text2 = {role: 'staticText', parent: paragraph1, root: root};
let text3 = {role: 'staticText', parent: paragraph2}; let paragraph2 = {role: 'paragraph', display: 'block', parent: 'rootWebArea',
root: root};
let text3 = {role: 'staticText', parent: paragraph2, root: root};
assertTrue(inSameParagraph(text1, text2)); assertTrue(inSameParagraph(text1, text2));
assertFalse(inSameParagraph(text1, text3)); assertFalse(inSameParagraph(text1, text3));
}); });
...@@ -53,24 +53,38 @@ TEST_F('SelectToSpeakParagraphUnitTest', 'InSameParagraph', function() { ...@@ -53,24 +53,38 @@ TEST_F('SelectToSpeakParagraphUnitTest', 'InSameParagraph', function() {
TEST_F('SelectToSpeakParagraphUnitTest', 'BlockDivBreaksSameParagraph', TEST_F('SelectToSpeakParagraphUnitTest', 'BlockDivBreaksSameParagraph',
function() { function() {
let root = {role: 'rootWebArea'}; let root = {role: 'rootWebArea'};
let paragraph1 = {role: 'paragraph', parent: 'rootWebArea'}; let paragraph1 = {role: 'paragraph', display: 'block', parent: 'rootWebArea',
let text1 = {role: 'staticText', parent: paragraph1}; root: root};
let text2 = {role: 'image', parent: paragraph1, display: 'block'}; let text1 = {role: 'staticText', parent: paragraph1, root: root};
let text3 = {role: 'image', parent: paragraph1, display: 'inline'}; let text2 = {role: 'image', parent: paragraph1, display: 'block', root: root};
let text4 = {role: 'staticText', parent: paragraph1}; let text3 = {role: 'image', parent: paragraph1, display: 'inline', root: root};
let text4 = {role: 'staticText', parent: paragraph1, root: root};
assertFalse(inSameParagraph(text1, text2)); assertFalse(inSameParagraph(text1, text2));
assertFalse(inSameParagraph(text2, text3)); assertFalse(inSameParagraph(text2, text3));
assertTrue(inSameParagraph(text3, text4)); assertTrue(inSameParagraph(text3, text4));
}); });
TEST_F('SelectToSpeakParagraphUnitTest', 'IsWhitespace', function() {
assertTrue(isWhitespace(''));
assertTrue(isWhitespace(' '));
assertTrue(isWhitespace(' \n \t '));
assertFalse(isWhitespace('cats'));
assertFalse(isWhitespace(' cats '));
});
TEST_F('SelectToSpeakParagraphUnitTest', 'BuildNodeGroupStopsAtNewParagraph', TEST_F('SelectToSpeakParagraphUnitTest', 'BuildNodeGroupStopsAtNewParagraph',
function() { function() {
let root = {role: 'rootWebArea'}; let root = {role: 'rootWebArea'};
let paragraph1 = {role: 'paragraph', parent: 'rootWebArea'}; let paragraph1 = {role: 'paragraph', display: 'block', parent: root,
let text1 = {role: 'staticText', parent: paragraph1, name: 'text1'}; root: root};
let text2 = {role: 'staticText', parent: paragraph1, name: 'text2'}; let text1 = {role: 'staticText', parent: paragraph1, name: 'text1',
let paragraph2 = {role: 'paragraph', parent: 'rootWebArea'}; root: root};
let text3 = {role: 'staticText', parent: paragraph2, name: 'text3'}; let text2 = {role: 'staticText', parent: paragraph1, name: 'text2',
root: root};
let paragraph2 = {role: 'paragraph', display: 'block', parent: root,
root: root};
let text3 = {role: 'staticText', parent: paragraph2, name: 'text3',
root: root};
let result = buildNodeGroup([text1, text2, text3], 0); let result = buildNodeGroup([text1, text2, text3], 0);
assertEquals('text1 text2', result.text); assertEquals('text1 text2', result.text);
assertEquals(1, result.endIndex); assertEquals(1, result.endIndex);
...@@ -84,13 +98,19 @@ TEST_F('SelectToSpeakParagraphUnitTest', 'BuildNodeGroupStopsAtNewParagraph', ...@@ -84,13 +98,19 @@ TEST_F('SelectToSpeakParagraphUnitTest', 'BuildNodeGroupStopsAtNewParagraph',
TEST_F('SelectToSpeakParagraphUnitTest', 'BuildNodeGroupIncludesLinks', TEST_F('SelectToSpeakParagraphUnitTest', 'BuildNodeGroupIncludesLinks',
function() { function() {
let root = {role: 'rootWebArea'}; let root = {role: 'rootWebArea'};
let paragraph1 = {role: 'paragraph', parent: 'rootWebArea'}; let paragraph1 = {role: 'paragraph', display: 'block', parent: root,
let text1 = {role: 'staticText', parent: paragraph1, name: 'text1'}; root: root};
let link = {role: 'link', parent: paragraph1}; let text1 = {role: 'staticText', parent: paragraph1, name: 'text1',
let linkText = {role: 'staticText', parent: link, name: 'linkText'}; root: root};
let result = buildNodeGroup([text1, linkText], 0); // Whitespace-only nodes should be ignored.
let text2 = {role: 'staticText', parent: paragraph1, name: '\n',
root: root};
let link = {role: 'link', parent: paragraph1, root: root};
let linkText = {role: 'staticText', parent: link, name: 'linkText',
root: root};
let result = buildNodeGroup([text1, text2, linkText], 0);
assertEquals('text1 linkText', result.text); assertEquals('text1 linkText', result.text);
assertEquals(1, result.endIndex); assertEquals(2, result.endIndex);
assertEquals(2, result.nodes.length); assertEquals(2, result.nodes.length);
assertEquals(0, result.nodes[0].startChar); assertEquals(0, result.nodes[0].startChar);
assertEquals(text1, result.nodes[0].node); assertEquals(text1, result.nodes[0].node);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment