Commit 0f91b110 authored by Anastasia Helfinstein's avatar Anastasia Helfinstein Committed by Commit Bot

[Switch Access] Add additional functions to RectHelper

This changes adds additional functions for operation on rectangles.
They will be used in a follow-up change.

Bug: None
Change-Id: I82d52a041e91660514db8f1376a034ed3514e5c3
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1910866
Commit-Queue: Anastasia Helfinstein <anastasi@google.com>
Auto-Submit: Anastasia Helfinstein <anastasi@google.com>
Reviewed-by: default avatarAran Gilman <gilmanmh@google.com>
Cr-Commit-Position: refs/heads/master@{#715064}
parent ac91598a
......@@ -7,6 +7,12 @@ const RectHelper = {
/** @type {!chrome.accessibilityPrivate.ScreenRect} */
ZERO_RECT: {top: 0, left: 0, width: 0, height: 0},
/**
* @param {chrome.accessibilityPrivate.ScreenRect|undefined} rect
* @return {number}
*/
area: (rect) => rect ? rect.width * rect.height : 0,
/**
* Returns true if the two rects are equal.
*
......@@ -44,6 +50,20 @@ const RectHelper = {
return {x, y};
},
/**
* @param {chrome.accessibilityPrivate.ScreenRect} outer
* @param {chrome.accessibilityPrivate.ScreenRect} inner
* @return {boolean}
*/
contains: (outer, inner) => {
if (!outer || !inner) {
return false;
}
return outer.left <= inner.left && outer.top <= inner.top &&
RectHelper.right(outer) >= RectHelper.right(inner) &&
RectHelper.bottom(outer) >= RectHelper.bottom(inner);
},
/**
* @param {!chrome.accessibilityPrivate.ScreenRect} rect
* @return {!chrome.accessibilityPrivate.ScreenRect}
......@@ -53,6 +73,88 @@ const RectHelper = {
return /** @type {!chrome.accessibilityPrivate.ScreenRect} */ (copy);
},
/**
* Returns the largest rectangle contained within the outer rect that does not
* overlap with the subtrahend (what is being subtracted).
* @param {chrome.accessibilityPrivate.ScreenRect|undefined} outer
* @param {chrome.accessibilityPrivate.ScreenRect|undefined} subtrahend
* @return {chrome.accessibilityPrivate.ScreenRect|undefined}
*/
difference: (outer, subtrahend) => {
if (!outer || !subtrahend) {
return outer;
}
if (outer.left >= RectHelper.right(subtrahend) ||
RectHelper.right(outer) <= subtrahend.left ||
outer.top >= RectHelper.bottom(subtrahend) ||
RectHelper.bottom(outer) <= subtrahend.top) {
// If the rectangles do not overlap, return the outer rect.
return outer;
}
if (RectHelper.contains(subtrahend, outer)) {
// If the subtrahend contains the outer rect, there is no region that does
// not overlap. Return the zero rect.
return RectHelper.ZERO_RECT;
}
let above, below, toTheLeft, toTheRight;
if (outer.top < subtrahend.top) {
above = {
top: outer.top,
left: outer.left,
width: outer.width,
height: (subtrahend.top - outer.top)
};
}
if (RectHelper.bottom(outer) > RectHelper.bottom(subtrahend)) {
below = {
top: RectHelper.bottom(subtrahend),
left: outer.left,
width: outer.width,
height: (RectHelper.bottom(outer) - RectHelper.bottom(subtrahend))
};
}
if (outer.left < subtrahend.left) {
toTheLeft = {
top: outer.top,
left: outer.left,
width: (subtrahend.left - outer.left),
height: outer.height
};
}
if (RectHelper.right(outer) > RectHelper.right(subtrahend)) {
toTheRight = {
top: outer.top,
left: RectHelper.right(subtrahend),
width: (RectHelper.right(outer) - RectHelper.right(subtrahend)),
height: outer.height
};
}
// Of the four rects calculated above, find the one with the greatest area.
const areaAbove = RectHelper.area(above);
const areaBelow = RectHelper.area(below);
const areaToTheLeft = RectHelper.area(toTheLeft);
const areaToTheRight = RectHelper.area(toTheRight);
if (areaAbove > areaBelow && areaAbove > areaToTheLeft &&
areaAbove > areaToTheRight) {
return above;
}
if (areaBelow > areaToTheLeft && areaBelow > areaToTheRight) {
return below;
}
return areaToTheLeft > areaToTheRight ? toTheLeft : toTheRight;
},
/**
* Increases the size of |outer| to entirely enclose |inner|, with |padding|
* buffer on each side.
......@@ -88,6 +190,31 @@ const RectHelper = {
return newOuter;
},
/**
* @param {chrome.accessibilityPrivate.ScreenRect=} rect1
* @param {chrome.accessibilityPrivate.ScreenRect=} rect2
* @return {chrome.accessibilityPrivate.ScreenRect}
*/
intersection: (rect1, rect2) => {
if (!rect1 || !rect2) {
return RectHelper.ZERO_RECT;
}
const left = Math.max(rect1.left, rect2.left);
const top = Math.max(rect1.top, rect2.top);
const right = Math.min(RectHelper.right(rect1), RectHelper.right(rect2));
const bottom = Math.min(RectHelper.bottom(rect1), RectHelper.bottom(rect2));
if (right <= left || bottom <= top) {
return RectHelper.ZERO_RECT;
}
const width = right - left;
const height = bottom - top;
return {left, top, width, height};
},
/**
* Finds the right of a rect.
* @param {!chrome.accessibilityPrivate.ScreenRect} rect
......
......@@ -150,3 +150,136 @@ TEST_F('SwitchAccessRectHelperUnitTest', 'ExpandToFitWithPadding', function() {
'When outer contains inner but without sufficient padding, ' +
'expandToFitWithPadding does not match expected value');
});
TEST_F('SwitchAccessRectHelperUnitTest', 'Contains', function() {
const outer = {left: 10, top: 10, width: 10, height: 10};
assertTrue(RectHelper.contains(outer, outer), 'Rect should contain itself');
let inner = {left: 10, top: 12, width: 10, height: 5};
assertTrue(RectHelper.contains(outer, inner),
'Rect should contain rect with same left/right bounds');
inner = {left: 12, top: 10, width: 5, height: 10};
assertTrue(RectHelper.contains(outer, inner),
'Rect should contain rect with same top/bottom bounds');
inner = {left: 12, top: 12, width: 5, height: 5};
assertTrue(RectHelper.contains(outer,inner),
'Rect should contain rect that is entirely within its bounds');
inner = {left: 5, top: 12, width: 10, height: 5};
assertFalse(RectHelper.contains(outer, inner),
'Rect should not contain rect that extends past the left edge');
inner = {left: 12, top: 8, width: 5, height: 10};
assertFalse(RectHelper.contains(outer, inner),
'Rect should not contain rect that extends past the top edge');
inner = {left: 15, top: 5, width: 10, height: 20};
assertFalse(RectHelper.contains(outer,inner),
'Rect should not contain rect that extends past right edge and has ' +
'larger height');
inner = {left: 5, top: 15, width: 10, height: 10};
assertFalse(RectHelper.contains(outer,inner),
'Rect should not contain rect that extends below and left of it');
inner = {left: 2, top: 12, width: 5, height: 5};
assertFalse(RectHelper.contains(outer,inner),
'Rect should not contain rect directly to its left');
inner = {left: 12, top: 22, width: 5, height: 5};
assertFalse(RectHelper.contains(outer,inner),
'Rect should not contain rect directly below it');
inner = {left: 22, top: 2, width: 5, height: 5};
assertFalse(RectHelper.contains(outer,inner),
'Rect should not contain rect above the the top-right corner');
inner = {left: 12, top: 2, width: 5, height: 20};
assertFalse(RectHelper.contains(outer,inner),
'Rect should not contain rect that has a greater height');
inner = {left: 2, top: 12, width: 20, height: 5};
assertFalse(RectHelper.contains(outer,inner),
'Rect should not contain rect that has a larger width');
});
TEST_F('SwitchAccessRectHelperUnitTest', 'Difference', function() {
const outer = {left: 10, top: 10, width: 10, height: 10};
assertTrue(RectHelper.areEqual(RectHelper.ZERO_RECT,
RectHelper.difference(outer, outer)),
'Difference of rect with itself should the zero rect');
let subtrahend = {left: 2, top: 2, width: 5, height: 5};
assertTrue(RectHelper.areEqual(outer,
RectHelper.difference(outer, subtrahend)),
'Difference of non-overlapping rects should be the outer rect');
subtrahend = {left: 5, top: 5, width: 20, height: 20};
assertTrue(RectHelper.areEqual(RectHelper.ZERO_RECT,
RectHelper.difference(outer, subtrahend)),
'Difference where subtrahend contains outer should be the zero rect');
subtrahend = {left: 12, top: 15, width: 6, height: 3};
let expected = {left: 10, top: 10, width: 10, height: 5};
assertTrue(RectHelper.areEqual(expected,
RectHelper.difference(outer, subtrahend)),
'Difference above should be largest');
subtrahend = {left: 15, top: 8, width: 3, height: 10};
expected = {left: 10, top: 10, width: 5, height: 10};
assertTrue(RectHelper.areEqual(expected,
RectHelper.difference(outer, subtrahend)),
'Difference to the left should be the largest');
subtrahend = {left: 5, top: 5, width: 13, height: 10};
expected = {left: 10, top: 15, width: 10, height: 5};
assertTrue(RectHelper.areEqual(expected,
RectHelper.difference(outer, subtrahend)),
'Difference below should be the largest');
subtrahend = {left: 8, top: 8, width: 10, height: 15};
expected = {left: 18, top: 10, width: 2, height: 10};
assertTrue(RectHelper.areEqual(expected,
RectHelper.difference(outer, subtrahend)),
'Difference to the right should be the largest');
});
TEST_F('SwitchAccessRectHelperUnitTest', 'Intersection', function() {
const rect1 = {left: 10, top: 10, width: 10, height: 10};
assertTrue(RectHelper.areEqual(rect1, RectHelper.intersection(rect1, rect1)),
'Intersection of a rectangle with itself should be itself');
let rect2 = {left: 12, top: 12, width: 5, height: 5};
assertTrue(RectHelper.areEqual(rect2, RectHelper.intersection(rect1, rect2)),
'When one rect contains another, intersection should be the inner rect');
assertTrue(RectHelper.areEqual(rect2, RectHelper.intersection(rect2, rect1)),
'Intersection should be symmetric');
rect2 = {left: 5, top: 5, width: 20, height: 20};
assertTrue(RectHelper.areEqual(rect1, RectHelper.intersection(rect1, rect2)),
'When one rect contains another, intersection should be the inner rect');
assertTrue(RectHelper.areEqual(rect1, RectHelper.intersection(rect2, rect1)),
'Intersection should be symmetric');
rect2 = {left: 30, top: 10, width: 10, height: 10};
assertTrue(RectHelper.areEqual(RectHelper.ZERO_RECT,
RectHelper.intersection(rect1, rect2)),
'Intersection of non-overlapping rects should be zero rect');
assertTrue(RectHelper.areEqual(RectHelper.ZERO_RECT,
RectHelper.intersection(rect2, rect1)),
'Intersection should be symmetric');
rect2 = {left: 15, top: 10, width: 10, height: 10};
let expected = {left: 15, top: 10, width: 5, height: 10};
assertTrue(RectHelper.areEqual(expected, RectHelper.intersection(rect1, rect2)),
'Side-by-side overlap is not computed correctly');
assertTrue(RectHelper.areEqual(expected, RectHelper.intersection(rect2, rect1)),
'Intersection should be symmetric');
rect2 = {left: 15, top: 5, width: 10, height: 10};
expected = {left: 15, top: 10, width: 5, height: 5};
assertTrue(RectHelper.areEqual(expected, RectHelper.intersection(rect1, rect2)),
'Top corner overlap is not computed correctly');
assertTrue(RectHelper.areEqual(expected, RectHelper.intersection(rect2, rect1)),
'Intersection should be symmetric');
rect2 = {left: 5, top: 15, width: 20, height: 10};
expected = {left: 10, top: 15, width: 10, height: 5};
assertTrue(RectHelper.areEqual(expected, RectHelper.intersection(rect1, rect2)),
'Bottom overlap is not computed correctly');
assertTrue(RectHelper.areEqual(expected, RectHelper.intersection(rect2, rect1)),
'Intersection should be symmetric');
});
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