diff --git a/accessible/mac/MOXAccessibleProtocol.h b/accessible/mac/MOXAccessibleProtocol.h index ab8315d6441b..78cfe00a2ec6 100644 --- a/accessible/mac/MOXAccessibleProtocol.h +++ b/accessible/mac/MOXAccessibleProtocol.h @@ -111,6 +111,9 @@ // AXWindow - (id _Nullable)moxWindow; +// AXFrame +- (NSValue* _Nullable)moxFrame; + // AXTitleUIElement - (id _Nullable)moxTitleUIElement; diff --git a/accessible/mac/mozAccessible.h b/accessible/mac/mozAccessible.h index bffe6c998efa..07633bc8aa37 100644 --- a/accessible/mac/mozAccessible.h +++ b/accessible/mac/mozAccessible.h @@ -193,6 +193,9 @@ inline mozAccessible* GetNativeFromGeckoAccessible( // override - (NSNumber*)moxSelected; +// override +- (NSValue*)moxFrame; + // override - (NSString*)moxARIACurrent; diff --git a/accessible/mac/mozAccessible.mm b/accessible/mac/mozAccessible.mm index fc1532f5e679..de683e1d4e15 100644 --- a/accessible/mac/mozAccessible.mm +++ b/accessible/mac/mozAccessible.mm @@ -354,35 +354,16 @@ static const uint64_t kCacheInitialized = ((uint64_t)0x1) << 63; } - (NSValue*)moxPosition { - MOZ_ASSERT(!mGeckoAccessible.IsNull()); + CGRect frame = [[self moxFrame] rectValue]; - nsIntRect rect = mGeckoAccessible.IsAccessible() - ? mGeckoAccessible.AsAccessible()->Bounds() - : mGeckoAccessible.AsProxy()->Bounds(); - - NSScreen* mainView = [[NSScreen screens] objectAtIndex:0]; - CGFloat scaleFactor = nsCocoaUtils::GetBackingScaleFactor(mainView); - NSPoint p = - NSMakePoint(static_cast(rect.x) / scaleFactor, - [mainView frame].size.height - - static_cast(rect.y + rect.height) / scaleFactor); - - return [NSValue valueWithPoint:p]; + return [NSValue valueWithPoint:NSMakePoint(frame.origin.x, frame.origin.y)]; } - (NSValue*)moxSize { - MOZ_ASSERT(!mGeckoAccessible.IsNull()); + CGRect frame = [[self moxFrame] rectValue]; - nsIntRect rect = mGeckoAccessible.IsAccessible() - ? mGeckoAccessible.AsAccessible()->Bounds() - : mGeckoAccessible.AsProxy()->Bounds(); - - CGFloat scaleFactor = - nsCocoaUtils::GetBackingScaleFactor([[NSScreen screens] objectAtIndex:0]); - return [NSValue - valueWithSize:NSMakeSize( - static_cast(rect.width) / scaleFactor, - static_cast(rect.height) / scaleFactor)]; + return + [NSValue valueWithSize:NSMakeSize(frame.size.width, frame.size.height)]; } - (NSString*)moxRole { @@ -712,6 +693,25 @@ struct RoleDescrComparator { return @NO; } +- (NSValue*)moxFrame { + MOZ_ASSERT(!mGeckoAccessible.IsNull()); + + nsIntRect rect = mGeckoAccessible.IsAccessible() + ? mGeckoAccessible.AsAccessible()->Bounds() + : mGeckoAccessible.AsProxy()->Bounds(); + NSScreen* mainView = [[NSScreen screens] objectAtIndex:0]; + CGFloat scaleFactor = nsCocoaUtils::GetBackingScaleFactor(mainView); + + return [NSValue + valueWithRect:NSMakeRect( + static_cast(rect.x) / scaleFactor, + [mainView frame].size.height - + static_cast(rect.y + rect.height) / + scaleFactor, + static_cast(rect.width) / scaleFactor, + static_cast(rect.height) / scaleFactor)]; +} + - (NSString*)moxARIACurrent { if (![self stateWithMask:states::CURRENT]) { return nil; diff --git a/accessible/tests/browser/mac/browser.ini b/accessible/tests/browser/mac/browser.ini index eae052e1dda3..df0fd9cdf5c9 100644 --- a/accessible/tests/browser/mac/browser.ini +++ b/accessible/tests/browser/mac/browser.ini @@ -49,3 +49,4 @@ skip-if = os == 'mac' && debug # Bug 1664577 [browser_aria_busy.js] [browser_aria_controls_flowto.js] [browser_attributed_text.js] +[browser_bounds.js] diff --git a/accessible/tests/browser/mac/browser_bounds.js b/accessible/tests/browser/mac/browser_bounds.js new file mode 100644 index 000000000000..09343d7c9daa --- /dev/null +++ b/accessible/tests/browser/mac/browser_bounds.js @@ -0,0 +1,77 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +/** + * Test position, size for onscreen content + */ +addAccessibleTask( + `I am some extra content
+
hello

+
hello world
I am some text
`, + async (browser, accDoc) => { + const hello = getNativeInterface(accDoc, "hello"); + const world = getNativeInterface(accDoc, "world"); + ok(hello.getAttributeValue("AXFrame"), "Hello's frame attr is not null"); + ok(world.getAttributeValue("AXFrame"), "World's frame attr is not null"); + + // AXSize and AXPosition are composed of AXFrame components, so we + // test them here instead of calling AXFrame directly. + const [helloWidth, helloHeight] = hello.getAttributeValue("AXSize"); + const [worldWidth, worldHeight] = world.getAttributeValue("AXSize"); + ok(helloWidth > 0, "Hello has a positive width"); + ok(helloHeight > 0, "Hello has a positive height"); + ok(worldWidth > 0, "World has a positive width"); + ok(worldHeight > 0, "World has a positive height"); + ok(helloHeight < worldHeight, "Hello has a smaller height than world"); + ok(helloWidth < worldWidth, "Hello has a smaller width than world"); + + // Note: these are mac screen coords, so our origin is bottom left + const [helloX, helloY] = hello.getAttributeValue("AXPosition"); + const [worldX, worldY] = world.getAttributeValue("AXPosition"); + ok(helloX > 0, "Hello has a positive X"); + ok(helloY > 0, "Hello has a positive Y"); + ok(worldX > 0, "World has a positive X"); + ok(worldY > 0, "World has a positive Y"); + ok(helloY > worldY, "Hello has a larger Y than world"); + ok(helloX == worldX, "Hello and world have the same X"); + } +); + +/** + * Test position, size for offscreen content + */ +addAccessibleTask( + `I am some extra content
+
hello

+
hello world
I am some text
`, + async (browser, accDoc) => { + const hello = getNativeInterface(accDoc, "hello"); + const world = getNativeInterface(accDoc, "world"); + ok(hello.getAttributeValue("AXFrame"), "Hello's frame attr is not null"); + ok(world.getAttributeValue("AXFrame"), "World's frame attr is not null"); + + // AXSize and AXPosition are composed of AXFrame components, so we + // test them here instead of calling AXFrame directly. + const [helloWidth, helloHeight] = hello.getAttributeValue("AXSize"); + const [worldWidth, worldHeight] = world.getAttributeValue("AXSize"); + ok(helloWidth > 0, "Hello has a positive width"); + ok(helloHeight > 0, "Hello has a positive height"); + ok(worldWidth > 0, "World has a positive width"); + ok(worldHeight > 0, "World has a positive height"); + ok(helloHeight < worldHeight, "Hello has a smaller height than world"); + ok(helloWidth < worldWidth, "Hello has a smaller width than world"); + + // Note: these are mac screen coords, so our origin is bottom left + const [helloX, helloY] = hello.getAttributeValue("AXPosition"); + const [worldX, worldY] = world.getAttributeValue("AXPosition"); + ok(helloX < 0, "Hello has a negative X"); + ok(helloY > 0, "Hello has a positive Y"); + ok(worldX < 0, "World has a negative X"); + ok(worldY > 0, "World has a positive Y"); + ok(helloY > worldY, "Hello has a larger Y than world"); + ok(helloX == worldX, "Hello and world have the same X"); + } +);