accessible/ipc/DocAccessibleParent.cpp
author Michael Ratcliffe <mratcliffe@mozilla.com>
Fri, 13 Mar 2015 11:52:45 +0000
changeset 251870 ec213bf54bcfdff4719f2b717fb75dbde8b98575
parent 244308 c46b0a95c754d1c0c33a761327a09fe65d5500f4
child 253724 063b559e525d0cbf43be0efb0ec4bcac3d9055b2
permissions -rw-r--r--
Bug 1046234 - Add more DevTools Telemetry measures (display size etc.) r=pbrosset, r=gijs

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* 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/. */

#include "DocAccessibleParent.h"
#include "nsAutoPtr.h"
#include "mozilla/a11y/Platform.h"
#include "ProxyAccessible.h"

namespace mozilla {
namespace a11y {

bool
DocAccessibleParent::RecvShowEvent(const ShowEventData& aData)
{
  if (mShutdown)
    return true;

  if (aData.NewTree().IsEmpty()) {
    NS_ERROR("no children being added");
    return false;
  }

  ProxyAccessible* parent = nullptr;
  if (aData.ID()) {
    ProxyEntry* e = mAccessibles.GetEntry(aData.ID());
    if (e)
      parent = e->mProxy;
  } else {
    parent = this;
  }

  // XXX This should really never happen, but sometimes we fail to fire the
  // required show events.
  if (!parent) {
    NS_ERROR("adding child to unknown accessible");
    return false;
  }

  uint32_t newChildIdx = aData.Idx();
  if (newChildIdx > parent->ChildrenCount()) {
    NS_ERROR("invalid index to add child at");
    return false;
  }

  uint32_t consumed = AddSubtree(parent, aData.NewTree(), 0, newChildIdx);
  MOZ_ASSERT(consumed == aData.NewTree().Length());
#ifdef DEBUG
  for (uint32_t i = 0; i < consumed; i++) {
    uint64_t id = aData.NewTree()[i].ID();
    MOZ_ASSERT(mAccessibles.GetEntry(id));
  }
#endif

  return consumed != 0;
}

uint32_t
DocAccessibleParent::AddSubtree(ProxyAccessible* aParent,
                                const nsTArray<a11y::AccessibleData>& aNewTree,
                                uint32_t aIdx, uint32_t aIdxInParent)
{
  if (aNewTree.Length() <= aIdx) {
    NS_ERROR("bad index in serialized tree!");
    return 0;
  }

  const AccessibleData& newChild = aNewTree[aIdx];
  if (newChild.Role() > roles::LAST_ROLE) {
    NS_ERROR("invalid role");
    return 0;
  }

  auto role = static_cast<a11y::role>(newChild.Role());
  ProxyAccessible* newProxy =
    new ProxyAccessible(newChild.ID(), aParent, this, role);
  aParent->AddChildAt(aIdxInParent, newProxy);
  mAccessibles.PutEntry(newChild.ID())->mProxy = newProxy;
  ProxyCreated(newProxy, newChild.Interfaces());

  uint32_t accessibles = 1;
  uint32_t kids = newChild.ChildrenCount();
  for (uint32_t i = 0; i < kids; i++) {
    uint32_t consumed = AddSubtree(newProxy, aNewTree, aIdx + accessibles, i);
    if (!consumed)
      return 0;

    accessibles += consumed;
  }

  MOZ_ASSERT(newProxy->ChildrenCount() == kids);

  return accessibles;
}

bool
DocAccessibleParent::RecvHideEvent(const uint64_t& aRootID)
{
  if (mShutdown)
    return true;

  ProxyEntry* rootEntry = mAccessibles.GetEntry(aRootID);
  if (!rootEntry) {
    NS_ERROR("invalid root being removed!");
    return true;
  }

  ProxyAccessible* root = rootEntry->mProxy;
  if (!root) {
    NS_ERROR("invalid root being removed!");
    return true;
  }

  ProxyAccessible* parent = root->Parent();
  parent->RemoveChild(root);
  root->Shutdown();

  return true;
}

bool
DocAccessibleParent::RecvEvent(const uint64_t& aID, const uint32_t& aEventType)
{
  if (!aID) {
    ProxyEvent(this, aEventType);
    return true;
  }

  ProxyEntry* e = mAccessibles.GetEntry(aID);
  if (!e) {
    NS_ERROR("no proxy for event!");
    return true;
  }

  ProxyEvent(e->mProxy, aEventType);
  return true;
}
bool
DocAccessibleParent::AddChildDoc(DocAccessibleParent* aChildDoc,
                                 uint64_t aParentID)
{
  ProxyAccessible* outerDoc = mAccessibles.GetEntry(aParentID)->mProxy;
  if (!outerDoc)
    return false;

  aChildDoc->mParent = outerDoc;
  outerDoc->SetChildDoc(aChildDoc);
  mChildDocs.AppendElement(aChildDoc);
  aChildDoc->mParentDoc = this;
  ProxyCreated(aChildDoc, 0);
  return true;
}

PLDHashOperator
DocAccessibleParent::ShutdownAccessibles(ProxyEntry* entry, void*)
{
  ProxyDestroyed(entry->mProxy);
  return PL_DHASH_REMOVE;
}

void
DocAccessibleParent::Destroy()
{
  NS_ASSERTION(mChildDocs.IsEmpty(),
               "why weren't the child docs destroyed already?");
  MOZ_ASSERT(!mShutdown);
  mShutdown = true;

  uint32_t childDocCount = mChildDocs.Length();
  for (uint32_t i = childDocCount - 1; i < childDocCount; i--)
    mChildDocs[i]->Destroy();

  mAccessibles.EnumerateEntries(ShutdownAccessibles, nullptr);
  ProxyDestroyed(this);
  mParentDoc ? mParentDoc->RemoveChildDoc(this)
    : GetAccService()->RemoteDocShutdown(this);
}
}
}