Bug 1450927 - add getBoundsInCSSPixels XPCOM method. r=surkov r=jld

MozReview-Commit-ID: CTANPVQw1sG
This commit is contained in:
Yura Zenevich 2018-04-24 15:07:03 -04:00
Родитель 26e3ed3050
Коммит db18588465
29 изменённых файлов: 239 добавлений и 62 удалений

Просмотреть файл

@ -144,6 +144,12 @@ Accessible::InsertAfter(Accessible* aNewChild, Accessible* aRefChild)
aNewChild);
}
inline nsIntRect
Accessible::Bounds() const
{
return BoundsInAppUnits().ToNearestPixels(mDoc->PresContext()->AppUnitsPerDevPixel());
}
} // namespace a11y
} // namespace mozilla

Просмотреть файл

@ -670,32 +670,31 @@ Accessible::RelativeBounds(nsIFrame** aBoundingFrame) const
return nsRect();
}
nsIntRect
Accessible::Bounds() const
nsRect
Accessible::BoundsInAppUnits() const
{
nsIFrame* boundingFrame = nullptr;
nsRect unionRectTwips = RelativeBounds(&boundingFrame);
if (!boundingFrame)
return nsIntRect();
nsIntRect screenRect;
nsPresContext* presContext = mDoc->PresContext();
screenRect.SetRect(presContext->AppUnitsToDevPixels(unionRectTwips.X()),
presContext->AppUnitsToDevPixels(unionRectTwips.Y()),
presContext->AppUnitsToDevPixels(unionRectTwips.Width()),
presContext->AppUnitsToDevPixels(unionRectTwips.Height()));
if (!boundingFrame) {
return nsRect();
}
// We need to take into account a non-1 resolution set on the presshell.
// This happens in mobile platforms with async pinch zooming. Here we
// scale the bounds before adding the screen-relative offset.
screenRect.ScaleRoundOut(presContext->PresShell()->GetResolution());
unionRectTwips.ScaleRoundOut(mDoc->PresContext()->PresShell()->GetResolution());
// We have the union of the rectangle, now we need to put it in absolute
// screen coords.
nsIntRect orgRectPixels = boundingFrame->GetScreenRectInAppUnits().
ToNearestPixels(presContext->AppUnitsPerDevPixel());
screenRect.MoveBy(orgRectPixels.X(), orgRectPixels.Y());
nsRect orgRectPixels = boundingFrame->GetScreenRectInAppUnits();
unionRectTwips.MoveBy(orgRectPixels.X(), orgRectPixels.Y());
return screenRect;
return unionRectTwips;
}
nsIntRect
Accessible::BoundsInCSSPixels() const
{
return BoundsInAppUnits().ToNearestPixels(mDoc->PresContext()->AppUnitsPerCSSPixel());
}
void

Просмотреть файл

@ -509,10 +509,20 @@ public:
virtual void AppendTextTo(nsAString& aText, uint32_t aStartOffset = 0,
uint32_t aLength = UINT32_MAX);
/**
* Return boundaries in screen coordinates in app units.
*/
virtual nsRect BoundsInAppUnits() const;
/**
* Return boundaries in screen coordinates.
*/
virtual nsIntRect Bounds() const;
nsIntRect Bounds() const;
/**
* Return boundaries in screen coordinates in CSS pixels.
*/
virtual nsIntRect BoundsInCSSPixels() const;
/**
* Return boundaries rect relative the bounding frame.

Просмотреть файл

@ -116,10 +116,10 @@ ApplicationAccessible::RelationByType(RelationType aRelationType)
return Relation();
}
nsIntRect
ApplicationAccessible::Bounds() const
nsRect
ApplicationAccessible::BoundsInAppUnits() const
{
return nsIntRect();
return nsRect();
}
////////////////////////////////////////////////////////////////////////////////

Просмотреть файл

@ -36,7 +36,7 @@ public:
// Accessible
virtual void Shutdown() override;
virtual nsIntRect Bounds() const override;
virtual nsRect BoundsInAppUnits() const override;
virtual already_AddRefed<nsIPersistentProperties> NativeAttributes() override;
virtual GroupPos GroupPosition() override;
virtual ENameValueFlag Name(nsString& aName) override;

Просмотреть файл

@ -74,15 +74,15 @@ HTMLLIAccessible::NativeState()
return HyperTextAccessibleWrap::NativeState() | states::READONLY;
}
nsIntRect
HTMLLIAccessible::Bounds() const
nsRect
HTMLLIAccessible::BoundsInAppUnits() const
{
nsIntRect rect = AccessibleWrap::Bounds();
if (rect.IsEmpty() || !mBullet || mBullet->IsInside())
nsRect rect = AccessibleWrap::BoundsInAppUnits();
if (rect.IsEmpty() || !mBullet || mBullet->IsInside()) {
return rect;
}
nsIntRect bulletRect = mBullet->Bounds();
nsRect bulletRect = mBullet->BoundsInAppUnits();
// Move x coordinate of list item over to cover bullet as well
rect.SetLeftEdge(bulletRect.X());
return rect;

Просмотреть файл

@ -51,7 +51,7 @@ public:
// Accessible
virtual void Shutdown() override;
virtual nsIntRect Bounds() const override;
virtual nsRect BoundsInAppUnits() const override;
virtual a11y::role NativeRole() override;
virtual uint64_t NativeState() override;

Просмотреть файл

@ -12,6 +12,10 @@ interface IGeckoCustom : IUnknown
{
[propget] HRESULT ID([out, retval] unsigned __int64* aID);
[propget] HRESULT anchorCount([out, retval] long* aCount);
[propget] HRESULT boundsInCSSPixels([out] long* aX,
[out] long* aY,
[out] long* aWidth,
[out, retval] long* aHeight);
[propget] HRESULT DOMNodeID([out, retval] BSTR* aID);
[propget] HRESULT minimumIncrement([out, retval] double* aIncrement);
[propget] HRESULT mozState([out, retval] unsigned __int64* aState);

Просмотреть файл

@ -20,11 +20,11 @@ class Accessible;
%}
/**
* A cross-platform interface that supports platform-specific
* A cross-platform interface that supports platform-specific
* accessibility APIs like MSAA and ATK. Contains the sum of what's needed
* to support IAccessible as well as ATK's generic accessibility objects.
* Can also be used by in-process accessibility clients to get information
* about objects in the accessible tree. The accessible tree is a subset of
* about objects in the accessible tree. The accessible tree is a subset of
* nodes in the DOM tree -- such as documents, focusable elements and text.
* Mozilla creates the implementations of nsIAccessible on demand.
* See http://www.mozilla.org/projects/ui/accessibility for more information.
@ -56,7 +56,7 @@ interface nsIAccessible : nsISupports
* Last child in accessible tree
*/
readonly attribute nsIAccessible lastChild;
/**
* Array of all this element's children.
*/
@ -124,7 +124,7 @@ interface nsIAccessible : nsISupports
/**
* Provides localized string of accesskey name, such as Alt+D.
* The modifier may be affected by user and platform preferences.
* Usually alt+letter, or just the letter alone for menu items.
* Usually alt+letter, or just the letter alone for menu items.
*/
readonly attribute AString accessKey;
@ -226,10 +226,16 @@ interface nsIAccessible : nsISupports
/**
* Return accessible's x and y coordinates relative to the screen and
* accessible's width and height.
* accessible's width and height in Dev pixels.
*/
void getBounds(out long x, out long y, out long width, out long height);
/**
* Return accessible's x and y coordinates relative to the screen and
* accessible's width and height in CSS pixels.
*/
void getBoundsInCSSPixels(out long aX, out long aY, out long aWidth, out long aHeight);
/**
* Add or remove this accessible to the current selection
*/

Просмотреть файл

@ -253,6 +253,7 @@ ProxyAccessible* FocusedChild();
ProxyAccessible* ChildAtPoint(int32_t aX, int32_t aY,
Accessible::EWhichChildAtPoint aWhichChild);
nsIntRect Bounds();
nsIntRect BoundsInCSSPixels();
void Language(nsString& aLocale);
void DocType(nsString& aType);

Просмотреть файл

@ -1983,6 +1983,30 @@ DocAccessibleChild::RecvExtents(const uint64_t& aID,
return IPC_OK();
}
mozilla::ipc::IPCResult
DocAccessibleChild::RecvExtentsInCSSPixels(const uint64_t& aID,
int32_t* aX,
int32_t* aY,
int32_t* aWidth,
int32_t* aHeight)
{
*aX = 0;
*aY = 0;
*aWidth = 0;
*aHeight = 0;
Accessible* acc = IdToAccessible(aID);
if (acc && !acc->IsDefunct()) {
nsIntRect screenRect = acc->BoundsInCSSPixels();
if (!screenRect.IsEmpty()) {
*aX = screenRect.x;
*aY = screenRect.y;
*aWidth = screenRect.width;
*aHeight = screenRect.height;
}
}
return IPC_OK();
}
mozilla::ipc::IPCResult
DocAccessibleChild::RecvDOMNodeID(const uint64_t& aID, nsString* aDOMNodeID)
{

Просмотреть файл

@ -470,6 +470,11 @@ public:
int32_t* aY,
int32_t* aWidth,
int32_t* aHeight) override;
virtual mozilla::ipc::IPCResult RecvExtentsInCSSPixels(const uint64_t& aID,
int32_t* aX,
int32_t* aY,
int32_t* aWidth,
int32_t* aHeight) override;
virtual mozilla::ipc::IPCResult RecvDOMNodeID(const uint64_t& aID, nsString* aDOMNodeID) override;
private:

Просмотреть файл

@ -265,6 +265,8 @@ child:
nested(inside_sync) sync Extents(uint64_t aID, bool aNeedsScreenCoords)
returns(int32_t aX, int32_t aY, int32_t aWidth, int32_t aHeight);
nested(inside_sync) sync ExtentsInCSSPixels(uint64_t aID)
returns(int32_t aX, int32_t aY, int32_t aWidth, int32_t aHeight);
nested(inside_sync) sync DOMNodeID(uint64_t aID) returns(nsString aDOMNodeID);
};

Просмотреть файл

@ -1013,6 +1013,16 @@ ProxyAccessible::Bounds()
return rect;
}
nsIntRect
ProxyAccessible::BoundsInCSSPixels()
{
nsIntRect rect;
Unused << mDoc->SendExtentsInCSSPixels(mID,
&rect.x, &rect.y,
&rect.width, &rect.height);
return rect;
}
void
ProxyAccessible::Language(nsString& aLocale)
{

Просмотреть файл

@ -235,6 +235,19 @@ ProxyAccessible::Bounds()
return rect;
}
nsIntRect
ProxyAccessible::BoundsInCSSPixels()
{
RefPtr<IGeckoCustom> custom = QueryInterface<IGeckoCustom>(this);
if (!custom) {
return nsIntRect();
}
nsIntRect rect;
HRESULT hr = custom->get_boundsInCSSPixels(&rect.x, &rect.y, &rect.width, &rect.height);
return rect;
}
void
ProxyAccessible::Language(nsString& aLocale)
{

Просмотреть файл

@ -6,6 +6,8 @@
/* import-globals-from ../../mochitest/layout.js */
/* global getContentDPR */
async function getContentBoundsForDOMElm(browser, id) {
return ContentTask.spawn(browser, id, contentId => {
this.ok = ok;
@ -17,12 +19,13 @@ async function testContentBounds(browser, acc) {
let [expectedX, expectedY, expectedWidth, expectedHeight] =
await getContentBoundsForDOMElm(browser, getAccessibleDOMNodeID(acc));
let [x, y, width, height] = getBounds(acc);
let contentDPR = await getContentDPR(browser);
let [x, y, width, height] = getBounds(acc, contentDPR);
let prettyAccName = prettyName(acc);
is(x, expectedX, "Wrong x coordinate of " + prettyAccName);
is(y, expectedY, "Wrong y coordinate of " + prettyAccName);
is(width, expectedWidth, "Wrong width of " + prettyAccName);
is(height, expectedHeight, "Wrong height of " + prettyAccName);
ok(height >= expectedHeight, "Wrong height of " + prettyAccName);
}
async function runTests(browser, accDoc) {

Просмотреть файл

@ -6,26 +6,29 @@
/* import-globals-from ../../mochitest/layout.js */
/* global getContentDPR */
async function runTests(browser, accDoc) {
function testTextNode(id) {
async function testTextNode(id) {
let hyperTextNode = findAccessibleChildByID(accDoc, id);
let textNode = hyperTextNode.firstChild;
let [x, y, width, height] = getBounds(textNode);
let contentDPR = await getContentDPR(browser);
let [x, y, width, height] = getBounds(textNode, contentDPR);
testTextBounds(hyperTextNode, 0, -1, [x, y, width, height],
COORDTYPE_SCREEN_RELATIVE);
}
loadFrameScripts(browser, { name: "layout.js", dir: MOCHITESTS_DIR });
testTextNode("p1");
testTextNode("p2");
await testTextNode("p1");
await testTextNode("p2");
await ContentTask.spawn(browser, {}, () => {
zoomDocument(document, 2.0);
});
testTextNode("p1");
await testTextNode("p1");
await ContentTask.spawn(browser, {}, () => {
zoomDocument(document, 1.0);

Просмотреть файл

@ -6,6 +6,9 @@
// Load the shared-head file first.
/* import-globals-from ../shared-head.js */
/* exported getContentDPR */
Services.scriptloader.loadSubScript(
"chrome://mochitests/content/browser/accessible/tests/browser/shared-head.js",
this);
@ -14,3 +17,10 @@ Services.scriptloader.loadSubScript(
// well as events.js.
loadScripts({ name: "common.js", dir: MOCHITESTS_DIR },
{ name: "layout.js", dir: MOCHITESTS_DIR }, "events.js");
/**
* Get content window DPR that can be different from parent window DPR.
*/
async function getContentDPR(browser) {
return ContentTask.spawn(browser, null, () => content.window.devicePixelRatio);
}

Просмотреть файл

@ -46,8 +46,8 @@
"Outside list item y should match to list item element y");
ok(widthLI > widthLIElm,
"Outside list item width=" + widthLI + " should be greater than list item element width=" + widthLIElm);
is(heightLI, heightLIElm,
"Outside list item height should match to list item element height");
ok(heightLI > heightLIElm,
"Outside list item height=" + heightLI + " should be greater than list item element height=" + heightLIElm);
SimpleTest.finish();
}

Просмотреть файл

@ -199,12 +199,25 @@ function getPos(aID) {
/**
* Return the accessible coordinates and size relative to the screen in device
* pixels.
* pixels. This methods also retrieves coordinates in CSS pixels and ensures that they
* match Dev pixels with a given device pixel ratio.
*/
function getBounds(aID) {
var accessible = getAccessible(aID);
var x = {}, y = {}, width = {}, height = {};
function getBounds(aID, aDPR = window.devicePixelRatio) {
const accessible = getAccessible(aID);
let x = {}, y = {}, width = {}, height = {};
let xInCSS = {}, yInCSS = {}, widthInCSS = {}, heightInCSS = {};
accessible.getBounds(x, y, width, height);
accessible.getBoundsInCSSPixels(xInCSS, yInCSS, widthInCSS, heightInCSS);
ok(Math.trunc(x.value / aDPR) <= xInCSS.value,
"X in CSS pixels is calculated correctly");
ok(Math.trunc(y.value / aDPR) <= yInCSS.value,
"Y in CSS pixels is calculated correctly");
ok(Math.trunc(width.value / aDPR) <= widthInCSS.value,
"Width in CSS pixels is calculated correctly");
ok(Math.trunc(height.value / aDPR) <= heightInCSS.value,
"Heights in CSS pixels is calculated correctly");
return [x.value, y.value, width.value, height.value];
}

Просмотреть файл

@ -20,6 +20,20 @@ GeckoCustom::get_anchorCount(long* aCount)
return S_OK;
}
HRESULT
GeckoCustom::get_boundsInCSSPixels(long* aX, long* aY, long* aWidth, long* aHeight)
{
nsIntRect bounds = mAcc->BoundsInCSSPixels();
if (!bounds.IsEmpty()) {
*aX = bounds.X();
*aY = bounds.Y();
*aWidth = bounds.Width();
*aHeight = bounds.Height();
}
return S_OK;
}
HRESULT
GeckoCustom::get_DOMNodeID(BSTR* aID)
{

Просмотреть файл

@ -27,6 +27,7 @@ public:
DECL_IUNKNOWN
virtual STDMETHODIMP get_anchorCount(long* aCount);
virtual STDMETHODIMP get_boundsInCSSPixels(long* aX, long* aY, long* aWidth, long* aHeight);
virtual STDMETHODIMP get_DOMNodeID(BSTR* aID);
virtual STDMETHODIMP get_ID(uint64_t* aID);
virtual STDMETHODIMP get_minimumIncrement(double* aIncrement);

Просмотреть файл

@ -456,6 +456,34 @@ xpcAccessible::GetBounds(int32_t* aX, int32_t* aY,
return NS_OK;
}
NS_IMETHODIMP
xpcAccessible::GetBoundsInCSSPixels(int32_t* aX, int32_t* aY,
int32_t* aWidth, int32_t* aHeight)
{
NS_ENSURE_ARG_POINTER(aX);
*aX = 0;
NS_ENSURE_ARG_POINTER(aY);
*aY = 0;
NS_ENSURE_ARG_POINTER(aWidth);
*aWidth = 0;
NS_ENSURE_ARG_POINTER(aHeight);
*aHeight = 0;
if (IntlGeneric().IsNull()) {
return NS_ERROR_FAILURE;
}
nsIntRect rect;
if (Accessible* acc = IntlGeneric().AsAccessible()) {
rect = acc->BoundsInCSSPixels();
} else {
rect = IntlGeneric().AsProxy()->BoundsInCSSPixels();
}
rect.GetRect(aX, aY, aWidth, aHeight);
return NS_OK;
}
NS_IMETHODIMP
xpcAccessible::GroupPosition(int32_t* aGroupLevel,
int32_t* aSimilarItemsInGroup,

Просмотреть файл

@ -60,6 +60,8 @@ public:
final;
NS_IMETHOD GetBounds(int32_t* aX, int32_t* aY,
int32_t* aWidth, int32_t* aHeight) final;
NS_IMETHOD GetBoundsInCSSPixels(int32_t* aX, int32_t* aY,
int32_t* aWidth, int32_t* aHeight) final;
NS_IMETHOD GroupPosition(int32_t* aGroupLevel, int32_t* aSimilarItemsInGroup,
int32_t* aPositionInGroup) final;
NS_IMETHOD GetRelationByType(uint32_t aType,

Просмотреть файл

@ -723,22 +723,24 @@ XULTreeItemAccessibleBase::FocusedChild()
}
nsIntRect
XULTreeItemAccessibleBase::Bounds() const
XULTreeItemAccessibleBase::BoundsInCSSPixels() const
{
// Get x coordinate and width from treechildren element, get y coordinate and
// height from tree cell.
nsCOMPtr<nsIBoxObject> boxObj = nsCoreUtils::GetTreeBodyBoxObject(mTree);
if (!boxObj)
if (!boxObj) {
return nsIntRect();
}
nsCOMPtr<nsITreeColumn> column = nsCoreUtils::GetFirstSensibleColumn(mTree);
int32_t x = 0, y = 0, width = 0, height = 0;
nsresult rv = mTree->GetCoordsForCellItem(mRow, column, EmptyString(),
&x, &y, &width, &height);
if (NS_FAILED(rv))
if (NS_FAILED(rv)) {
return nsIntRect();
}
boxObj->GetWidth(&width);
@ -749,11 +751,18 @@ XULTreeItemAccessibleBase::Bounds() const
x = tcX;
y += tcY;
return nsIntRect(x, y, width, height);
}
nsRect
XULTreeItemAccessibleBase::BoundsInAppUnits() const
{
nsIntRect bounds = BoundsInCSSPixels();
nsPresContext* presContext = mDoc->PresContext();
return nsIntRect(presContext->CSSPixelsToDevPixels(x),
presContext->CSSPixelsToDevPixels(y),
presContext->CSSPixelsToDevPixels(width),
presContext->CSSPixelsToDevPixels(height));
return nsRect(presContext->CSSPixelsToAppUnits(bounds.X()),
presContext->CSSPixelsToAppUnits(bounds.Y()),
presContext->CSSPixelsToAppUnits(bounds.Width()),
presContext->CSSPixelsToAppUnits(bounds.Height()));
}
void

Просмотреть файл

@ -146,7 +146,8 @@ public:
// Accessible
virtual void Shutdown() override;
virtual nsIntRect Bounds() const override;
virtual nsRect BoundsInAppUnits() const override;
virtual nsIntRect BoundsInCSSPixels() const override;
virtual GroupPos GroupPosition() override;
virtual uint64_t NativeState() override;
virtual uint64_t NativeInteractiveState() const override;

Просмотреть файл

@ -495,20 +495,22 @@ XULTreeGridCellAccessible::Name(nsString& aName)
}
nsIntRect
XULTreeGridCellAccessible::Bounds() const
XULTreeGridCellAccessible::BoundsInCSSPixels() const
{
// Get bounds for tree cell and add x and y of treechildren element to
// x and y of the cell.
nsCOMPtr<nsIBoxObject> boxObj = nsCoreUtils::GetTreeBodyBoxObject(mTree);
if (!boxObj)
if (!boxObj) {
return nsIntRect();
}
int32_t x = 0, y = 0, width = 0, height = 0;
nsresult rv = mTree->GetCoordsForCellItem(mRow, mColumn,
NS_LITERAL_STRING("cell"),
&x, &y, &width, &height);
if (NS_FAILED(rv))
if (NS_FAILED(rv)) {
return nsIntRect();
}
int32_t tcX = 0, tcY = 0;
boxObj->GetScreenX(&tcX);
@ -516,11 +518,18 @@ XULTreeGridCellAccessible::Bounds() const
x += tcX;
y += tcY;
return nsIntRect(x, y, width, height);
}
nsRect
XULTreeGridCellAccessible::BoundsInAppUnits() const
{
nsIntRect bounds = BoundsInCSSPixels();
nsPresContext* presContext = mDoc->PresContext();
return nsIntRect(presContext->CSSPixelsToDevPixels(x),
presContext->CSSPixelsToDevPixels(y),
presContext->CSSPixelsToDevPixels(width),
presContext->CSSPixelsToDevPixels(height));
return nsRect(presContext->CSSPixelsToAppUnits(bounds.X()),
presContext->CSSPixelsToAppUnits(bounds.Y()),
presContext->CSSPixelsToAppUnits(bounds.Width()),
presContext->CSSPixelsToAppUnits(bounds.Height()));
}
uint8_t

Просмотреть файл

@ -126,7 +126,8 @@ public:
// Accessible
virtual void Shutdown() override;
virtual TableCellAccessible* AsTableCell() override { return this; }
virtual nsIntRect Bounds() const override;
virtual nsRect BoundsInAppUnits() const override;
virtual nsIntRect BoundsInCSSPixels() const override;
virtual ENameValueFlag Name(nsString& aName) override;
virtual Accessible* FocusedChild() override;
virtual already_AddRefed<nsIPersistentProperties> NativeAttributes() override;

Просмотреть файл

@ -594,6 +594,9 @@ platform = notwin
[PDocAccessible::Extents]
description =
platform = notwin
[PDocAccessible::ExtentsInCSSPixels]
description =
platform = notwin
[PDocAccessible::DOMNodeID]
description =
platform = notwin