Bug 1499209 - Refactor AccessibleWrap::ToBundle 1/2. r=Jamie

This refactor does a few things:
1. Unifies the composition of the GeckoBundle, so that some tricky edge
cases don't need to be implemented twice.
2. Allows us to be more frugal with round trip sync ipc calls. Instead
of retrieving everything from the start, only progressivley retrieve
what we need.
3. Sets the groundwork for the next patch that will return from this
function earlier with a smaller bundle.

Differential Revision: https://phabricator.services.mozilla.com/D8778

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Eitan Isaacson 2018-10-19 23:26:02 +00:00
parent 310cf60a08
commit af39427a8f
4 changed files with 257 additions and 227 deletions

View File

@ -206,154 +206,6 @@ AccessibleWrap::GetSelectionBounds(int32_t* aStartOffset, int32_t* aEndOffset) {
return false;
}
mozilla::java::GeckoBundle::LocalRef
AccessibleWrap::CreateBundle(int32_t aParentID,
role aRole,
uint64_t aState,
const nsString& aName,
const nsString& aTextValue,
const nsString& aDOMNodeID,
const nsIntRect& aBounds,
double aCurVal,
double aMinVal,
double aMaxVal,
double aStep,
nsIPersistentProperties* aAttributes,
const nsTArray<int32_t>& aChildren) const
{
GECKOBUNDLE_START(nodeInfo);
GECKOBUNDLE_PUT(nodeInfo, "id", java::sdk::Integer::ValueOf(VirtualViewID()));
GECKOBUNDLE_PUT(nodeInfo, "parentId", java::sdk::Integer::ValueOf(aParentID));
uint64_t flags = GetFlags(aRole, aState);
GECKOBUNDLE_PUT(nodeInfo, "flags", java::sdk::Integer::ValueOf(flags));
nsAutoString geckoRole;
nsAutoString roleDescription;
int32_t androidClass = java::SessionAccessibility::CLASSNAME_VIEW;
if (VirtualViewID() == kNoID) {
androidClass = java::SessionAccessibility::CLASSNAME_WEBVIEW;
} else {
GetRoleDescription(aRole, geckoRole, roleDescription);
androidClass = GetAndroidClass(aRole);
}
GECKOBUNDLE_PUT(
nodeInfo, "roleDescription", jni::StringParam(roleDescription));
GECKOBUNDLE_PUT(nodeInfo, "geckoRole", jni::StringParam(geckoRole));
GECKOBUNDLE_PUT(nodeInfo, "className", java::sdk::Integer::ValueOf(androidClass));
if (!aTextValue.IsEmpty() &&
(flags & java::SessionAccessibility::FLAG_EDITABLE)) {
GECKOBUNDLE_PUT(nodeInfo, "hint", jni::StringParam(aName));
GECKOBUNDLE_PUT(nodeInfo, "text", jni::StringParam(aTextValue));
} else {
GECKOBUNDLE_PUT(nodeInfo, "text", jni::StringParam(aName));
}
if (!aDOMNodeID.IsEmpty()) {
GECKOBUNDLE_PUT(
nodeInfo, "viewIdResourceName", jni::StringParam(aDOMNodeID));
}
const int32_t data[4] = {
aBounds.x, aBounds.y, aBounds.x + aBounds.width, aBounds.y + aBounds.height
};
GECKOBUNDLE_PUT(nodeInfo, "bounds", jni::IntArray::New(data, 4));
if (HasNumericValue()) {
GECKOBUNDLE_START(rangeInfo);
if (aMaxVal == 1 && aMinVal == 0) {
GECKOBUNDLE_PUT(
rangeInfo, "type", java::sdk::Integer::ValueOf(2)); // percent
} else if (std::round(aStep) != aStep) {
GECKOBUNDLE_PUT(
rangeInfo, "type", java::sdk::Integer::ValueOf(1)); // float
} else {
GECKOBUNDLE_PUT(
rangeInfo, "type", java::sdk::Integer::ValueOf(0)); // integer
}
if (!IsNaN(aCurVal)) {
GECKOBUNDLE_PUT(rangeInfo, "current", java::sdk::Double::New(aCurVal));
}
if (!IsNaN(aMinVal)) {
GECKOBUNDLE_PUT(rangeInfo, "min", java::sdk::Double::New(aMinVal));
}
if (!IsNaN(aMaxVal)) {
GECKOBUNDLE_PUT(rangeInfo, "max", java::sdk::Double::New(aMaxVal));
}
GECKOBUNDLE_FINISH(rangeInfo);
GECKOBUNDLE_PUT(nodeInfo, "rangeInfo", rangeInfo);
}
nsString inputTypeAttr;
nsAccUtils::GetAccAttr(aAttributes, nsGkAtoms::textInputType, inputTypeAttr);
int32_t inputType = GetInputType(inputTypeAttr);
if (inputType) {
GECKOBUNDLE_PUT(nodeInfo, "inputType", java::sdk::Integer::ValueOf(inputType));
}
nsString posinset;
nsresult rv = aAttributes->GetStringProperty(NS_LITERAL_CSTRING("posinset"), posinset);
if (NS_SUCCEEDED(rv)) {
int32_t rowIndex;
if (sscanf(NS_ConvertUTF16toUTF8(posinset).get(), "%d", &rowIndex) > 0) {
GECKOBUNDLE_START(collectionItemInfo);
GECKOBUNDLE_PUT(
collectionItemInfo, "rowIndex", java::sdk::Integer::ValueOf(rowIndex));
GECKOBUNDLE_PUT(
collectionItemInfo, "columnIndex", java::sdk::Integer::ValueOf(0));
GECKOBUNDLE_PUT(
collectionItemInfo, "rowSpan", java::sdk::Integer::ValueOf(1));
GECKOBUNDLE_PUT(
collectionItemInfo, "columnSpan", java::sdk::Integer::ValueOf(1));
GECKOBUNDLE_FINISH(collectionItemInfo);
GECKOBUNDLE_PUT(nodeInfo, "collectionItemInfo", collectionItemInfo);
}
}
nsString colSize;
rv = aAttributes->GetStringProperty(NS_LITERAL_CSTRING("child-item-count"),
colSize);
if (NS_SUCCEEDED(rv)) {
int32_t rowCount;
if (sscanf(NS_ConvertUTF16toUTF8(colSize).get(), "%d", &rowCount) > 0) {
GECKOBUNDLE_START(collectionInfo);
GECKOBUNDLE_PUT(
collectionInfo, "rowCount", java::sdk::Integer::ValueOf(rowCount));
GECKOBUNDLE_PUT(
collectionInfo, "columnCount", java::sdk::Integer::ValueOf(1));
nsString unused;
rv = aAttributes->GetStringProperty(NS_LITERAL_CSTRING("hierarchical"),
unused);
if (NS_SUCCEEDED(rv)) {
GECKOBUNDLE_PUT(
collectionInfo, "isHierarchical", java::sdk::Boolean::TRUE());
}
if (IsSelect()) {
int32_t selectionMode = (aState & states::MULTISELECTABLE) ? 2 : 1;
GECKOBUNDLE_PUT(collectionInfo,
"selectionMode",
java::sdk::Integer::ValueOf(selectionMode));
}
GECKOBUNDLE_FINISH(collectionInfo);
GECKOBUNDLE_PUT(nodeInfo, "collectionInfo", collectionInfo);
}
}
GECKOBUNDLE_PUT(nodeInfo,
"children",
jni::IntArray::New(aChildren.Elements(), aChildren.Length()));
GECKOBUNDLE_FINISH(nodeInfo);
return nodeInfo;
}
uint64_t
AccessibleWrap::GetFlags(role aRole, uint64_t aState)
{
@ -495,7 +347,7 @@ AccessibleWrap::GetInputType(const nsString& aInputTypeAttr)
}
void
AccessibleWrap::DOMNodeID(nsString& aDOMNodeID)
AccessibleWrap::WrapperDOMNodeID(nsString& aDOMNodeID)
{
if (mContent) {
nsAtom* id = mContent->GetID();
@ -505,25 +357,170 @@ AccessibleWrap::DOMNodeID(nsString& aDOMNodeID)
}
}
bool
AccessibleWrap::WrapperRangeInfo(double* aCurVal, double* aMinVal,
double* aMaxVal, double* aStep)
{
if (HasNumericValue()) {
*aCurVal = CurValue();
*aMinVal = MinValue();
*aMaxVal = MaxValue();
*aStep = Step();
return true;
}
return false;
}
mozilla::java::GeckoBundle::LocalRef
AccessibleWrap::ToBundle()
{
if (IsDefunct()) {
if (!Proxy() && IsDefunct()) {
return nullptr;
}
AccessibleWrap* parent = static_cast<AccessibleWrap*>(Parent());
nsAutoString name;
Name(name);
GECKOBUNDLE_START(nodeInfo);
GECKOBUNDLE_PUT(nodeInfo, "id", java::sdk::Integer::ValueOf(VirtualViewID()));
nsAutoString value;
Value(value);
AccessibleWrap* parent = WrapperParent();
GECKOBUNDLE_PUT(nodeInfo, "parentId",
java::sdk::Integer::ValueOf(parent ? parent->VirtualViewID() : 0));
role role = WrapperRole();
uint64_t state = State();
uint64_t flags = GetFlags(role, state);
GECKOBUNDLE_PUT(nodeInfo, "flags", java::sdk::Integer::ValueOf(flags));
nsAutoString geckoRole;
nsAutoString roleDescription;
if (VirtualViewID() != kNoID) {
GetRoleDescription(role, geckoRole, roleDescription);
}
GECKOBUNDLE_PUT(
nodeInfo, "roleDescription", jni::StringParam(roleDescription));
GECKOBUNDLE_PUT(nodeInfo, "geckoRole", jni::StringParam(geckoRole));
GECKOBUNDLE_PUT(nodeInfo, "className", java::sdk::Integer::ValueOf(AndroidClass()));
nsAutoString text;
if (state & states::EDITABLE) {
Value(text);
}
if (!text.IsEmpty()) {
nsAutoString hint;
Name(hint);
GECKOBUNDLE_PUT(nodeInfo, "hint", jni::StringParam(hint));
} else {
Name(text);
}
GECKOBUNDLE_PUT(nodeInfo, "text", jni::StringParam(text));
nsAutoString viewIdResourceName;
DOMNodeID(viewIdResourceName);
WrapperDOMNodeID(viewIdResourceName);
if (!viewIdResourceName.IsEmpty()) {
GECKOBUNDLE_PUT(
nodeInfo, "viewIdResourceName", jni::StringParam(viewIdResourceName));
}
nsIntRect bounds = Bounds();
const int32_t data[4] = {
bounds.x, bounds.y, bounds.x + bounds.width, bounds.y + bounds.height
};
GECKOBUNDLE_PUT(nodeInfo, "bounds", jni::IntArray::New(data, 4));
double curValue = 0;
double minValue = 0;
double maxValue = 0;
double step = 0;
if (WrapperRangeInfo(&curValue, &minValue, &maxValue, &step)) {
GECKOBUNDLE_START(rangeInfo);
if (maxValue == 1 && minValue == 0) {
GECKOBUNDLE_PUT(
rangeInfo, "type", java::sdk::Integer::ValueOf(2)); // percent
} else if (std::round(step) != step) {
GECKOBUNDLE_PUT(
rangeInfo, "type", java::sdk::Integer::ValueOf(1)); // float
} else {
GECKOBUNDLE_PUT(
rangeInfo, "type", java::sdk::Integer::ValueOf(0)); // integer
}
if (!IsNaN(curValue)) {
GECKOBUNDLE_PUT(rangeInfo, "current", java::sdk::Double::New(curValue));
}
if (!IsNaN(minValue)) {
GECKOBUNDLE_PUT(rangeInfo, "min", java::sdk::Double::New(minValue));
}
if (!IsNaN(maxValue)) {
GECKOBUNDLE_PUT(rangeInfo, "max", java::sdk::Double::New(maxValue));
}
GECKOBUNDLE_FINISH(rangeInfo);
GECKOBUNDLE_PUT(nodeInfo, "rangeInfo", rangeInfo);
}
nsCOMPtr<nsIPersistentProperties> attributes = Attributes();
nsString inputTypeAttr;
nsAccUtils::GetAccAttr(attributes, nsGkAtoms::textInputType, inputTypeAttr);
int32_t inputType = GetInputType(inputTypeAttr);
if (inputType) {
GECKOBUNDLE_PUT(nodeInfo, "inputType", java::sdk::Integer::ValueOf(inputType));
}
nsString posinset;
nsresult rv = attributes->GetStringProperty(NS_LITERAL_CSTRING("posinset"), posinset);
if (NS_SUCCEEDED(rv)) {
int32_t rowIndex;
if (sscanf(NS_ConvertUTF16toUTF8(posinset).get(), "%d", &rowIndex) > 0) {
GECKOBUNDLE_START(collectionItemInfo);
GECKOBUNDLE_PUT(
collectionItemInfo, "rowIndex", java::sdk::Integer::ValueOf(rowIndex));
GECKOBUNDLE_PUT(
collectionItemInfo, "columnIndex", java::sdk::Integer::ValueOf(0));
GECKOBUNDLE_PUT(
collectionItemInfo, "rowSpan", java::sdk::Integer::ValueOf(1));
GECKOBUNDLE_PUT(
collectionItemInfo, "columnSpan", java::sdk::Integer::ValueOf(1));
GECKOBUNDLE_FINISH(collectionItemInfo);
GECKOBUNDLE_PUT(nodeInfo, "collectionItemInfo", collectionItemInfo);
}
}
nsString colSize;
rv = attributes->GetStringProperty(NS_LITERAL_CSTRING("child-item-count"),
colSize);
if (NS_SUCCEEDED(rv)) {
int32_t rowCount;
if (sscanf(NS_ConvertUTF16toUTF8(colSize).get(), "%d", &rowCount) > 0) {
GECKOBUNDLE_START(collectionInfo);
GECKOBUNDLE_PUT(
collectionInfo, "rowCount", java::sdk::Integer::ValueOf(rowCount));
GECKOBUNDLE_PUT(
collectionInfo, "columnCount", java::sdk::Integer::ValueOf(1));
nsString unused;
rv = attributes->GetStringProperty(NS_LITERAL_CSTRING("hierarchical"),
unused);
if (NS_SUCCEEDED(rv)) {
GECKOBUNDLE_PUT(
collectionInfo, "isHierarchical", java::sdk::Boolean::TRUE());
}
if (IsSelect()) {
int32_t selectionMode = (state & states::MULTISELECTABLE) ? 2 : 1;
GECKOBUNDLE_PUT(collectionInfo,
"selectionMode",
java::sdk::Integer::ValueOf(selectionMode));
}
GECKOBUNDLE_FINISH(collectionInfo);
GECKOBUNDLE_PUT(nodeInfo, "collectionInfo", collectionInfo);
}
}
auto childCount = ChildCount();
nsTArray<int32_t> children(childCount);
for (uint32_t i = 0; i < childCount; i++) {
@ -531,17 +528,10 @@ AccessibleWrap::ToBundle()
children.AppendElement(child->VirtualViewID());
}
return CreateBundle(parent ? parent->VirtualViewID() : 0,
Role(),
State(),
name,
value,
viewIdResourceName,
Bounds(),
CurValue(),
MinValue(),
MaxValue(),
Step(),
attributes,
children);
GECKOBUNDLE_PUT(nodeInfo,
"children",
jni::IntArray::New(children.Elements(), children.Length()));
GECKOBUNDLE_FINISH(nodeInfo);
return nodeInfo;
}

View File

@ -31,25 +31,17 @@ public:
virtual bool GetSelectionBounds(int32_t* aStartOffset, int32_t* aEndOffset);
virtual mozilla::java::GeckoBundle::LocalRef ToBundle();
mozilla::java::GeckoBundle::LocalRef ToBundle();
int32_t AndroidClass()
{
return mID == kNoID ? java::SessionAccessibility::CLASSNAME_WEBVIEW
: GetAndroidClass(WrapperRole());
}
static const int32_t kNoID = -1;
protected:
mozilla::java::GeckoBundle::LocalRef CreateBundle(
int32_t aParentID,
role aRole,
uint64_t aState,
const nsString& aName,
const nsString& aTextValue,
const nsString& aDOMNodeID,
const nsIntRect& aBounds,
double aCurVal,
double aMinVal,
double aMaxVal,
double aStep,
nsIPersistentProperties* aAttributes,
const nsTArray<int32_t>& aChildren) const;
// IDs should be a positive 32bit integer.
static int32_t AcquireID();
@ -62,7 +54,13 @@ protected:
int32_t mID;
private:
void DOMNodeID(nsString& aDOMNodeID);
virtual AccessibleWrap* WrapperParent() { return static_cast<AccessibleWrap*>(Parent()); }
virtual bool WrapperRangeInfo(double* aCurVal, double* aMinVal, double* aMaxVal, double* aStep);
virtual role WrapperRole() { return Role(); }
virtual void WrapperDOMNodeID(nsString& aDOMNodeID);
static void GetRoleDescription(role aRole,
nsAString& aGeckoRole,

View File

@ -72,6 +72,38 @@ ProxyAccessibleWrap::ChildCount() const
return Proxy()->ChildrenCount();
}
Accessible*
ProxyAccessibleWrap::GetChildAt(uint32_t aIndex) const
{
ProxyAccessible* child = Proxy()->ChildAt(aIndex);
return child ? WrapperFor(child) : nullptr;
}
ENameValueFlag
ProxyAccessibleWrap::Name(nsString& aName) const
{
Proxy()->Name(aName);
return eNameOK;
}
void
ProxyAccessibleWrap::Value(nsString& aValue) const
{
Proxy()->Value(aValue);
}
uint64_t
ProxyAccessibleWrap::State()
{
return Proxy()->State();
}
nsIntRect
ProxyAccessibleWrap::Bounds() const
{
return Proxy()->Bounds();
}
void
ProxyAccessibleWrap::ScrollTo(uint32_t aHow) const
{
@ -102,46 +134,38 @@ ProxyAccessibleWrap::GetSelectionBounds(int32_t* aStartOffset,
return Proxy()->SelectionBoundsAt(0, unused, aStartOffset, aEndOffset);
}
mozilla::java::GeckoBundle::LocalRef
ProxyAccessibleWrap::ToBundle()
role
ProxyAccessibleWrap::WrapperRole()
{
ProxyAccessible* proxy = Proxy();
if (!proxy) {
return nullptr;
}
int32_t parentID = proxy->Parent() ?
WrapperFor(proxy->Parent())->VirtualViewID() : 0;
nsAutoString name;
proxy->Name(name);
nsAutoString value;
proxy->Value(value);
nsAutoString viewIdResourceName;
proxy->DOMNodeID(viewIdResourceName);
nsCOMPtr<nsIPersistentProperties> attributes = Attributes();
auto childCount = proxy->ChildrenCount();
nsTArray<int32_t> children(childCount);
for (uint32_t i = 0; i < childCount; i++) {
auto child = WrapperFor(proxy->ChildAt(i));
children.AppendElement(child->VirtualViewID());
}
return CreateBundle(parentID,
proxy->Role(),
proxy->State(),
name,
value,
viewIdResourceName,
proxy->Bounds(),
proxy->CurValue(),
proxy->MinValue(),
proxy->MaxValue(),
proxy->Step(),
attributes,
children);
return Proxy()->Role();
}
AccessibleWrap*
ProxyAccessibleWrap::WrapperParent()
{
return Proxy()->Parent() ? WrapperFor(Proxy()->Parent()) : nullptr;
}
bool
ProxyAccessibleWrap::WrapperRangeInfo(double* aCurVal,
double* aMinVal,
double* aMaxVal,
double* aStep)
{
if (HasNumericValue()) {
ProxyAccessible* proxy = Proxy();
*aCurVal = proxy->CurValue();
*aMinVal = proxy->MinValue();
*aMaxVal = proxy->MaxValue();
*aStep = proxy->Step();
return true;
}
return false;
}
void
ProxyAccessibleWrap::WrapperDOMNodeID(nsString& aDOMNodeID)
{
Proxy()->DOMNodeID(aDOMNodeID);
}

View File

@ -34,6 +34,16 @@ public:
virtual uint32_t ChildCount() const override;
virtual Accessible* GetChildAt(uint32_t aIndex) const override;
virtual ENameValueFlag Name(nsString& aName) const override;
virtual void Value(nsString& aValue) const override;
virtual uint64_t State() override;
virtual nsIntRect Bounds() const override;
virtual void ScrollTo(uint32_t aHow) const override;
// AccessibleWrap
@ -44,7 +54,15 @@ public:
virtual bool GetSelectionBounds(int32_t* aStartOffset, int32_t* aEndOffset) override;
virtual mozilla::java::GeckoBundle::LocalRef ToBundle() override;
private:
virtual role WrapperRole() override;
virtual AccessibleWrap* WrapperParent() override;
virtual bool WrapperRangeInfo(double* aCurVal, double* aMinVal, double* aMaxVal, double* aStep) override;
virtual void WrapperDOMNodeID(nsString& aDOMNodeID) override;
};
class DocProxyAccessibleWrap : public ProxyAccessibleWrap