accessible/html/HTMLListAccessible.cpp
author Dão Gottwald <dao@mozilla.com>
Wed, 20 Feb 2019 07:20:52 +0000
changeset 516104 b9fe883c6c1eb27d2e16aceba083b8081ec6f944
parent 508163 6f3709b3878117466168c40affa7bca0b60cf75b
child 527794 ae1731591a0a15582ecefc78ce087b0a096a54b6
permissions -rw-r--r--
Bug 1504766 - Let explicit Dark and Light themes ignore the Windows 10 setting for accent color in title bars. r=ntim,Gijs a=lizzard Differential Revision: https://phabricator.services.mozilla.com/D19764

/* -*- 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 "HTMLListAccessible.h"

#include "DocAccessible.h"
#include "nsAccUtils.h"
#include "Role.h"
#include "States.h"

#include "nsBlockFrame.h"
#include "nsBulletFrame.h"

using namespace mozilla;
using namespace mozilla::a11y;

////////////////////////////////////////////////////////////////////////////////
// HTMLListAccessible
////////////////////////////////////////////////////////////////////////////////

role HTMLListAccessible::NativeRole() const {
  a11y::role r = GetAccService()->MarkupRole(mContent);
  return r != roles::NOTHING ? r : roles::LIST;
}

uint64_t HTMLListAccessible::NativeState() const {
  return HyperTextAccessibleWrap::NativeState() | states::READONLY;
}

////////////////////////////////////////////////////////////////////////////////
// HTMLLIAccessible
////////////////////////////////////////////////////////////////////////////////

HTMLLIAccessible::HTMLLIAccessible(nsIContent* aContent, DocAccessible* aDoc)
    : HyperTextAccessibleWrap(aContent, aDoc), mBullet(nullptr) {
  mType = eHTMLLiType;

  nsBlockFrame* blockFrame = do_QueryFrame(GetFrame());
  if (blockFrame && blockFrame->HasBullet()) {
    mBullet = new HTMLListBulletAccessible(mContent, mDoc);
    Document()->BindToDocument(mBullet, nullptr);
    AppendChild(mBullet);
  }
}

void HTMLLIAccessible::Shutdown() {
  mBullet = nullptr;

  HyperTextAccessibleWrap::Shutdown();
}

role HTMLLIAccessible::NativeRole() const {
  a11y::role r = GetAccService()->MarkupRole(mContent);
  return r != roles::NOTHING ? r : roles::LISTITEM;
}

uint64_t HTMLLIAccessible::NativeState() const {
  return HyperTextAccessibleWrap::NativeState() | states::READONLY;
}

nsRect HTMLLIAccessible::BoundsInAppUnits() const {
  nsRect rect = AccessibleWrap::BoundsInAppUnits();
  if (rect.IsEmpty() || !mBullet || mBullet->IsInside()) {
    return rect;
  }

  nsRect bulletRect = mBullet->BoundsInAppUnits();
  // Move x coordinate of list item over to cover bullet as well
  rect.SetLeftEdge(bulletRect.X());
  return rect;
}

bool HTMLLIAccessible::InsertChildAt(uint32_t aIndex, Accessible* aChild) {
  // Adjust index if there's a bullet.
  if (mBullet && aIndex == 0 && aChild != mBullet) {
    return HyperTextAccessible::InsertChildAt(aIndex + 1, aChild);
  }

  return HyperTextAccessible::InsertChildAt(aIndex, aChild);
}

////////////////////////////////////////////////////////////////////////////////
// HTMLLIAccessible: public

void HTMLLIAccessible::UpdateBullet(bool aHasBullet) {
  if (aHasBullet == !!mBullet) {
    MOZ_ASSERT_UNREACHABLE("Bullet and accessible are in sync already!");
    return;
  }

  TreeMutation mt(this);
  if (aHasBullet) {
    mBullet = new HTMLListBulletAccessible(mContent, mDoc);
    mDoc->BindToDocument(mBullet, nullptr);
    InsertChildAt(0, mBullet);
    mt.AfterInsertion(mBullet);
  } else {
    mt.BeforeRemoval(mBullet);
    RemoveChild(mBullet);
    mBullet = nullptr;
  }
  mt.Done();
}

////////////////////////////////////////////////////////////////////////////////
// HTMLListBulletAccessible
////////////////////////////////////////////////////////////////////////////////
HTMLListBulletAccessible::HTMLListBulletAccessible(nsIContent* aContent,
                                                   DocAccessible* aDoc)
    : LeafAccessible(aContent, aDoc) {
  mGenericTypes |= eText;
  mStateFlags |= eSharedNode;
}

////////////////////////////////////////////////////////////////////////////////
// HTMLListBulletAccessible: Accessible

nsIFrame* HTMLListBulletAccessible::GetFrame() const {
  nsBlockFrame* blockFrame = do_QueryFrame(mContent->GetPrimaryFrame());
  return blockFrame ? blockFrame->GetBullet() : nullptr;
}

ENameValueFlag HTMLListBulletAccessible::Name(nsString& aName) const {
  aName.Truncate();

  // Native anonymous content, ARIA can't be used. Get list bullet text.
  nsBlockFrame* blockFrame = do_QueryFrame(mContent->GetPrimaryFrame());
  if (blockFrame) {
    blockFrame->GetSpokenBulletText(aName);
  }

  return eNameOK;
}

role HTMLListBulletAccessible::NativeRole() const { return roles::STATICTEXT; }

uint64_t HTMLListBulletAccessible::NativeState() const {
  return LeafAccessible::NativeState() | states::READONLY;
}

void HTMLListBulletAccessible::AppendTextTo(nsAString& aText,
                                            uint32_t aStartOffset,
                                            uint32_t aLength) {
  nsAutoString bulletText;
  nsBlockFrame* blockFrame = do_QueryFrame(mContent->GetPrimaryFrame());
  if (blockFrame) blockFrame->GetSpokenBulletText(bulletText);

  aText.Append(Substring(bulletText, aStartOffset, aLength));
}

////////////////////////////////////////////////////////////////////////////////
// HTMLListBulletAccessible: public

bool HTMLListBulletAccessible::IsInside() const {
  nsBlockFrame* blockFrame = do_QueryFrame(mContent->GetPrimaryFrame());
  return blockFrame ? blockFrame->HasInsideBullet() : false;
}