Bug 1139576 - make accessible creation by tag name faster, r=marcoz

This commit is contained in:
Alexander Surkov 2015-03-04 22:56:57 -05:00
parent 008bcbebc1
commit 9c6b92383f
3 changed files with 225 additions and 148 deletions

111
accessible/base/MarkupMap.h Normal file
View File

@ -0,0 +1,111 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:expandtab:shiftwidth=2:tabstop=2:
*/
/* 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/. */
MARKUPMAP(a,
New_HTMLLink)
MARKUPMAP(abbr,
New_HyperText)
MARKUPMAP(acronym,
New_HyperText)
MARKUPMAP(article,
New_HyperText)
MARKUPMAP(aside,
New_HyperText)
MARKUPMAP(blockquote,
New_HyperText)
MARKUPMAP(dd,
New_HTMLDefinition)
MARKUPMAP(dl,
New_HTMLList)
MARKUPMAP(dt,
New_HTMLListitem)
MARKUPMAP(figcaption,
New_HTMLFigcaption)
MARKUPMAP(figure,
New_HTMLFigure)
MARKUPMAP(form,
New_HyperText)
MARKUPMAP(footer,
New_HyperText)
MARKUPMAP(header,
New_HyperText)
MARKUPMAP(h1,
New_HyperText)
MARKUPMAP(h2,
New_HyperText)
MARKUPMAP(h3,
New_HyperText)
MARKUPMAP(h4,
New_HyperText)
MARKUPMAP(h5,
New_HyperText)
MARKUPMAP(h6,
New_HyperText)
MARKUPMAP(label,
New_HTMLLabel)
MARKUPMAP(legend,
New_HTMLLegend)
MARKUPMAP(li,
New_HTMLListitem)
MARKUPMAP(nav,
New_HyperText)
MARKUPMAP(ol,
New_HTMLList)
MARKUPMAP(option,
New_HTMLOption)
MARKUPMAP(optgroup,
New_HTMLOptgroup)
MARKUPMAP(output,
New_HTMLOutput)
MARKUPMAP(progress,
New_HTMLProgress)
MARKUPMAP(q,
New_HyperText)
MARKUPMAP(section,
New_HyperText)
MARKUPMAP(time,
New_HyperText)
MARKUPMAP(td,
New_HTMLTableHeaderCellIfScope)
MARKUPMAP(th,
New_HTMLTableHeaderCell)
MARKUPMAP(ul,
New_HTMLList)

View File

@ -133,6 +133,107 @@ MustBeAccessible(nsIContent* aContent, DocAccessible* aDocument)
return false;
}
////////////////////////////////////////////////////////////////////////////////
// Accessible constructors
Accessible*
New_HTMLLink(nsIContent* aContent, Accessible* aContext)
{
// Only some roles truly enjoy life as HTMLLinkAccessibles, for details
// see closed bug 494807.
nsRoleMapEntry* roleMapEntry = aria::GetRoleMap(aContent);
if (roleMapEntry && roleMapEntry->role != roles::NOTHING &&
roleMapEntry->role != roles::LINK) {
return new HyperTextAccessibleWrap(aContent, aContext->Document());
}
return new HTMLLinkAccessible(aContent, aContext->Document());
}
Accessible* New_HyperText(nsIContent* aContent, Accessible* aContext)
{ return new HyperTextAccessibleWrap(aContent, aContext->Document()); }
Accessible* New_HTMLFigcaption(nsIContent* aContent, Accessible* aContext)
{ return new HTMLFigcaptionAccessible(aContent, aContext->Document()); }
Accessible* New_HTMLFigure(nsIContent* aContent, Accessible* aContext)
{ return new HTMLFigureAccessible(aContent, aContext->Document()); }
Accessible* New_HTMLLegend(nsIContent* aContent, Accessible* aContext)
{ return new HTMLLegendAccessible(aContent, aContext->Document()); }
Accessible* New_HTMLOption(nsIContent* aContent, Accessible* aContext)
{ return new HTMLSelectOptionAccessible(aContent, aContext->Document()); }
Accessible* New_HTMLOptgroup(nsIContent* aContent, Accessible* aContext)
{ return new HTMLSelectOptGroupAccessible(aContent, aContext->Document()); }
Accessible* New_HTMLList(nsIContent* aContent, Accessible* aContext)
{ return new HTMLListAccessible(aContent, aContext->Document()); }
Accessible*
New_HTMLListitem(nsIContent* aContent, Accessible* aContext)
{
// If list item is a child of accessible list then create an accessible for
// it unconditionally by tag name. nsBlockFrame creates the list item
// accessible for other elements styled as list items.
if (aContext->IsList() && aContext->GetContent() == aContent->GetParent())
return new HTMLLIAccessible(aContent, aContext->Document());
return nullptr;
}
Accessible*
New_HTMLDefinition(nsIContent* aContent, Accessible* aContext)
{
if (aContext->IsList())
return new HyperTextAccessibleWrap(aContent, aContext->Document());
return nullptr;
}
Accessible* New_HTMLLabel(nsIContent* aContent, Accessible* aContext)
{ return new HTMLLabelAccessible(aContent, aContext->Document()); }
Accessible* New_HTMLOutput(nsIContent* aContent, Accessible* aContext)
{ return new HTMLOutputAccessible(aContent, aContext->Document()); }
Accessible* New_HTMLProgress(nsIContent* aContent, Accessible* aContext)
{ return new HTMLProgressMeterAccessible(aContent, aContext->Document()); }
Accessible*
New_HTMLTableHeaderCell(nsIContent* aContent, Accessible* aContext)
{
if (aContext->IsTableRow() && aContext->GetContent() == aContent->GetParent())
return new HTMLTableHeaderCellAccessibleWrap(aContent, aContext->Document());
return nullptr;
}
Accessible*
New_HTMLTableHeaderCellIfScope(nsIContent* aContent, Accessible* aContext)
{
if (aContext->IsTableRow() && aContext->GetContent() == aContent->GetParent() &&
aContent->HasAttr(kNameSpaceID_None, nsGkAtoms::scope))
return new HTMLTableHeaderCellAccessibleWrap(aContent, aContext->Document());
return nullptr;
}
////////////////////////////////////////////////////////////////////////////////
// Markup maps array.
struct MarkupMapInfo {
nsIAtom** tag;
New_Accessible* new_func;
};
#define MARKUPMAP(atom, new_func) \
{ &nsGkAtoms::atom, new_func },
static const MarkupMapInfo sMarkupMapList[] = {
#include "MarkupMap.h"
};
#undef MARKUPMAP
////////////////////////////////////////////////////////////////////////////////
// nsAccessibilityService
////////////////////////////////////////////////////////////////////////////////
@ -143,7 +244,7 @@ xpcAccessibleApplication* nsAccessibilityService::gXPCApplicationAccessible = nu
bool nsAccessibilityService::gIsShutdown = true;
nsAccessibilityService::nsAccessibilityService() :
DocManager(), FocusManager()
DocManager(), FocusManager(), mMarkupMap(ArrayLength(sMarkupMapList))
{
}
@ -977,9 +1078,11 @@ nsAccessibilityService::GetOrCreateAccessible(nsINode* aNode,
if (!isARIATableOrCell ||
frame->AccessibleType() == eHTMLTableCellType ||
frame->AccessibleType() == eHTMLTableType) {
// Prefer to use markup (mostly tag name, perhaps attributes) to decide if
// and what kind of accessible to create,
newAcc = CreateHTMLAccessibleByMarkup(frame, content, aContext);
// Prefer to use markup to decide if and what kind of accessible to create,
New_Accessible* new_func = mMarkupMap.Get(content->NodeInfo()->NameAtom());
if (new_func)
newAcc = new_func(content, aContext);
if (!newAcc) // try by frame accessible type.
newAcc = CreateAccessibleByFrameType(frame, content, aContext);
}
@ -1116,6 +1219,9 @@ nsAccessibilityService::Init()
static const char16_t kInitIndicator[] = { '1', 0 };
observerService->NotifyObservers(nullptr, "a11y-init-or-shutdown", kInitIndicator);
for (uint32_t i = 0; i < ArrayLength(sMarkupMapList); i++)
mMarkupMap.Put(*sMarkupMapList[i].tag, sMarkupMapList[i].new_func);
#ifdef A11Y_LOG
logging::CheckEnv();
#endif
@ -1373,143 +1479,6 @@ nsAccessibilityService::CreateAccessibleByType(nsIContent* aContent,
return accessible.forget();
}
already_AddRefed<Accessible>
nsAccessibilityService::CreateHTMLAccessibleByMarkup(nsIFrame* aFrame,
nsIContent* aContent,
Accessible* aContext)
{
DocAccessible* document = aContext->Document();
if (aContext->IsTableRow()) {
if (nsCoreUtils::IsHTMLTableHeader(aContent) &&
aContext->GetContent() == aContent->GetParent()) {
nsRefPtr<Accessible> accessible =
new HTMLTableHeaderCellAccessibleWrap(aContent, document);
return accessible.forget();
}
return nullptr;
}
// This method assumes we're in an HTML namespace.
if (aContent->IsHTMLElement(nsGkAtoms::figcaption)) {
nsRefPtr<Accessible> accessible =
new HTMLFigcaptionAccessible(aContent, document);
return accessible.forget();
}
if (aContent->IsHTMLElement(nsGkAtoms::figure)) {
nsRefPtr<Accessible> accessible =
new HTMLFigureAccessible(aContent, document);
return accessible.forget();
}
if (aContent->IsHTMLElement(nsGkAtoms::legend)) {
nsRefPtr<Accessible> accessible =
new HTMLLegendAccessible(aContent, document);
return accessible.forget();
}
if (aContent->IsHTMLElement(nsGkAtoms::option)) {
nsRefPtr<Accessible> accessible =
new HTMLSelectOptionAccessible(aContent, document);
return accessible.forget();
}
if (aContent->IsHTMLElement(nsGkAtoms::optgroup)) {
nsRefPtr<Accessible> accessible =
new HTMLSelectOptGroupAccessible(aContent, document);
return accessible.forget();
}
if (aContent->IsAnyOfHTMLElements(nsGkAtoms::ul,
nsGkAtoms::ol,
nsGkAtoms::dl)) {
nsRefPtr<Accessible> accessible =
new HTMLListAccessible(aContent, document);
return accessible.forget();
}
if (aContent->IsHTMLElement(nsGkAtoms::a)) {
// Only some roles truly enjoy life as HTMLLinkAccessibles, for details
// see closed bug 494807.
nsRoleMapEntry* roleMapEntry = aria::GetRoleMap(aContent);
if (roleMapEntry && roleMapEntry->role != roles::NOTHING &&
roleMapEntry->role != roles::LINK) {
nsRefPtr<Accessible> accessible =
new HyperTextAccessibleWrap(aContent, document);
return accessible.forget();
}
nsRefPtr<Accessible> accessible =
new HTMLLinkAccessible(aContent, document);
return accessible.forget();
}
if (aContext->IsList()) {
// If list item is a child of accessible list then create an accessible for
// it unconditionally by tag name. nsBlockFrame creates the list item
// accessible for other elements styled as list items.
if (aContext->GetContent() == aContent->GetParent()) {
if (aContent->IsAnyOfHTMLElements(nsGkAtoms::dt, nsGkAtoms::li)) {
nsRefPtr<Accessible> accessible =
new HTMLLIAccessible(aContent, document);
return accessible.forget();
}
if (aContent->IsHTMLElement(nsGkAtoms::dd)) {
nsRefPtr<Accessible> accessible =
new HyperTextAccessibleWrap(aContent, document);
return accessible.forget();
}
}
return nullptr;
}
if (aContent->IsAnyOfHTMLElements(nsGkAtoms::abbr,
nsGkAtoms::acronym,
nsGkAtoms::article,
nsGkAtoms::aside,
nsGkAtoms::blockquote,
nsGkAtoms::form,
nsGkAtoms::footer,
nsGkAtoms::header,
nsGkAtoms::h1,
nsGkAtoms::h2,
nsGkAtoms::h3,
nsGkAtoms::h4,
nsGkAtoms::h5,
nsGkAtoms::h6,
nsGkAtoms::nav,
nsGkAtoms::q,
nsGkAtoms::section,
nsGkAtoms::time)) {
nsRefPtr<Accessible> accessible =
new HyperTextAccessibleWrap(aContent, document);
return accessible.forget();
}
if (aContent->IsHTMLElement(nsGkAtoms::label)) {
nsRefPtr<Accessible> accessible =
new HTMLLabelAccessible(aContent, document);
return accessible.forget();
}
if (aContent->IsHTMLElement(nsGkAtoms::output)) {
nsRefPtr<Accessible> accessible =
new HTMLOutputAccessible(aContent, document);
return accessible.forget();
}
if (aContent->IsHTMLElement(nsGkAtoms::progress)) {
nsRefPtr<Accessible> accessible =
new HTMLProgressMeterAccessible(aContent, document);
return accessible.forget();
}
return nullptr;
}
already_AddRefed<Accessible>
nsAccessibilityService::CreateAccessibleByFrameType(nsIFrame* aFrame,
nsIContent* aContent,

View File

@ -41,6 +41,8 @@ SelectionManager* SelectionMgr();
ApplicationAccessible* ApplicationAcc();
xpcAccessibleApplication* XPCApplicationAcc();
typedef Accessible* (New_Accessible)(nsIContent* aContent, Accessible* aContext);
} // namespace a11y
} // namespace mozilla
@ -190,13 +192,6 @@ private:
already_AddRefed<Accessible>
CreateAccessibleByType(nsIContent* aContent, DocAccessible* aDoc);
/**
* Create accessible for HTML node by tag name.
*/
already_AddRefed<Accessible>
CreateHTMLAccessibleByMarkup(nsIFrame* aFrame, nsIContent* aContent,
Accessible* aContext);
/**
* Create an accessible whose type depends on the given frame.
*/
@ -228,6 +223,8 @@ private:
*/
static bool gIsShutdown;
nsDataHashtable<nsPtrHashKey<const nsIAtom>, mozilla::a11y::New_Accessible*> mMarkupMap;
friend nsAccessibilityService* GetAccService();
friend mozilla::a11y::FocusManager* mozilla::a11y::FocusMgr();
friend mozilla::a11y::SelectionManager* mozilla::a11y::SelectionMgr();