Bug 1479039 - Update cached focus path bounds on scroll. r=snorp,yzen a=jcristau

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

--HG--
extra : source : b47fdd1194c70c21906769611e2abf1d3e8a0781
extra : histedit_source : 896e567a19427b716dec3de3942ee97ec7ff1ac0
This commit is contained in:
Eitan Isaacson 2018-11-12 16:42:03 +00:00
Родитель 683a26d69e
Коммит 1738380f30
6 изменённых файлов: 101 добавлений и 6 удалений

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

@ -76,6 +76,9 @@ DocAccessibleWrap::HandleAccEvent(AccEvent* aEvent)
case nsIAccessibleEvent::EVENT_SCROLLING_END:
CacheViewport();
break;
case nsIAccessibleEvent::EVENT_SCROLLING:
UpdateFocusPathBounds();
break;
default:
break;
}
@ -195,6 +198,7 @@ DocAccessibleWrap::GetTopLevelContentDoc(AccessibleWrap* aAccessible) {
void
DocAccessibleWrap::CacheFocusPath(AccessibleWrap* aAccessible)
{
mFocusPath.Clear();
if (IPCAccessibilityActive()) {
DocAccessibleChild* ipcDoc = IPCDoc();
nsTArray<BatchData> cacheData;
@ -223,6 +227,7 @@ DocAccessibleWrap::CacheFocusPath(AccessibleWrap* aAccessible)
acc->MaxValue(),
acc->Step(),
attributes));
mFocusPath.Put(acc->UniqueID(), acc);
}
ipcDoc->SendBatch(eBatch_FocusPath, cacheData);
@ -236,3 +241,42 @@ DocAccessibleWrap::CacheFocusPath(AccessibleWrap* aAccessible)
sessionAcc->ReplaceFocusPathCache(accessibles);
}
}
void
DocAccessibleWrap::UpdateFocusPathBounds()
{
if (!mFocusPath.Count()) {
return;
}
if (IPCAccessibilityActive()) {
DocAccessibleChild* ipcDoc = IPCDoc();
nsTArray<BatchData> boundsData(mFocusPath.Count());
for (auto iter = mFocusPath.Iter(); !iter.Done(); iter.Next()) {
Accessible* accessible = iter.Data();
auto uid = accessible->IsDoc() && accessible->AsDoc()->IPCDoc() ? 0
: reinterpret_cast<uint64_t>(accessible->UniqueID());
boundsData.AppendElement(BatchData(accessible->Document()->IPCDoc(),
uid,
0,
accessible->Bounds(),
nsString(),
nsString(),
nsString(),
UnspecifiedNaN<double>(),
UnspecifiedNaN<double>(),
UnspecifiedNaN<double>(),
UnspecifiedNaN<double>(),
nsTArray<Attribute>()));
}
ipcDoc->SendBatch(eBatch_BoundsUpdate, boundsData);
} else if (SessionAccessibility* sessionAcc = SessionAccessibility::GetInstanceFor(this)) {
nsTArray<AccessibleWrap*> accessibles(mFocusPath.Count());
for (auto iter = mFocusPath.Iter(); !iter.Done(); iter.Next()) {
accessibles.AppendElement(static_cast<AccessibleWrap*>(iter.Data().get()));
}
sessionAcc->UpdateCachedBounds(accessibles);
}
}

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

@ -37,6 +37,7 @@ public:
enum {
eBatch_Viewport = 0,
eBatch_FocusPath = 1,
eBatch_BoundsUpdate = 2,
};
protected:
@ -50,9 +51,13 @@ protected:
private:
void CacheViewport();
void UpdateFocusPathBounds();
static void CacheViewportCallback(nsITimer* aTimer, void* aDocAccParam);
nsCOMPtr<nsITimer> mCacheRefreshTimer;
AccessibleHashtable mFocusPath;
};
} // namespace a11y

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

@ -224,6 +224,9 @@ a11y::ProxyBatch(ProxyAccessible* aDocument,
case DocAccessibleWrap::eBatch_FocusPath:
sessionAcc->ReplaceFocusPathCache(accWraps, aData);
break;
case DocAccessibleWrap::eBatch_BoundsUpdate:
sessionAcc->UpdateCachedBounds(accWraps, aData);
break;
default:
MOZ_ASSERT_UNREACHABLE("Unknown batch type.");
break;

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

@ -373,3 +373,22 @@ SessionAccessibility::ReplaceFocusPathCache(const nsTArray<AccessibleWrap*>& aAc
mSessionAccessibility->ReplaceFocusPathCache(infos);
}
void
SessionAccessibility::UpdateCachedBounds(const nsTArray<AccessibleWrap*>& aAccessibles,
const nsTArray<BatchData>& aData)
{
auto infos = jni::ObjectArray::New<java::GeckoBundle>(aAccessibles.Length());
for (size_t i = 0; i < aAccessibles.Length(); i++) {
AccessibleWrap* acc = aAccessibles.ElementAt(i);
if (aData.Length() == aAccessibles.Length()) {
const BatchData& data = aData.ElementAt(i);
auto bundle = acc->ToSmallBundle(data.State(), data.Bounds());
infos->SetElement(i, bundle);
} else {
infos->SetElement(i, acc->ToSmallBundle());
}
}
mSessionAccessibility->UpdateCachedBounds(infos);
}

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

@ -112,6 +112,9 @@ public:
void ReplaceFocusPathCache(const nsTArray<AccessibleWrap*>& aAccessibles,
const nsTArray<BatchData>& aData = nsTArray<BatchData>());
void UpdateCachedBounds(const nsTArray<AccessibleWrap*>& aAccessibles,
const nsTArray<BatchData>& aData = nsTArray<BatchData>());
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SessionAccessibility)
private:

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

@ -33,6 +33,7 @@ import android.view.accessibility.AccessibilityNodeInfo.CollectionItemInfo;
import android.view.accessibility.AccessibilityNodeInfo.CollectionInfo;
import android.view.accessibility.AccessibilityNodeProvider;
import java.util.Iterator;
import java.util.LinkedList;
public class SessionAccessibility {
@ -250,10 +251,6 @@ public class SessionAccessibility {
return node;
}
private boolean isNodeCached(final int virtualViewId) {
return mViewportCache.get(virtualViewId) != null || mFocusPathCache.get(virtualViewId) != null;
}
private synchronized AccessibilityNodeInfo getNodeFromCache(final int virtualViewId) {
AccessibilityNodeInfo node = null;
for (SparseArray<GeckoBundle> cache : mCaches) {
@ -352,7 +349,7 @@ public class SessionAccessibility {
int[] children = nodeInfo.getIntArray("children");
if (children != null) {
for (int childId : children) {
if (!fromCache || isNodeCached(childId)) {
if (!fromCache || getMostRecentBundle(childId) != null) {
// If this node is from cache, only populate with children that are cached as well.
node.addChild(mView, childId);
}
@ -664,6 +661,18 @@ public class SessionAccessibility {
((ViewParent) mView).requestSendAccessibilityEvent(mView, event);
}
private synchronized GeckoBundle getMostRecentBundle(final int virtualViewId) {
Iterator<SparseArray<GeckoBundle>> iter = mCaches.descendingIterator();
while (iter.hasNext()) {
GeckoBundle bundle = iter.next().get(virtualViewId);
if (bundle != null) {
return bundle;
}
}
return null;
}
/* package */ final class NativeProvider extends JNIObject {
@WrapForJNI(calledFrom = "ui")
private void setAttached(final boolean attached) {
@ -713,5 +722,17 @@ public class SessionAccessibility {
mCaches.remove(mFocusPathCache);
mCaches.add(mFocusPathCache);
}
@WrapForJNI(calledFrom = "gecko")
private synchronized void updateCachedBounds(final GeckoBundle[] bundles) {
for (GeckoBundle bundle : bundles) {
GeckoBundle cachedBundle = getMostRecentBundle(bundle.getInt("id"));
if (cachedBundle == null) {
Log.e(LOGTAG, "Can't update bounds of uncached node " + bundle.getInt("id"));
continue;
}
cachedBundle.putIntArray("bounds", bundle.getIntArray("bounds"));
}
}
}
}