From 9c6b92383f724e5fe868f24078f20c02b1a7d8e5 Mon Sep 17 00:00:00 2001 From: Alexander Surkov Date: Wed, 4 Mar 2015 22:56:57 -0500 Subject: [PATCH] Bug 1139576 - make accessible creation by tag name faster, r=marcoz --- accessible/base/MarkupMap.h | 111 +++++++++ accessible/base/nsAccessibilityService.cpp | 251 +++++++++------------ accessible/base/nsAccessibilityService.h | 11 +- 3 files changed, 225 insertions(+), 148 deletions(-) create mode 100644 accessible/base/MarkupMap.h diff --git a/accessible/base/MarkupMap.h b/accessible/base/MarkupMap.h new file mode 100644 index 00000000000..fb379375d24 --- /dev/null +++ b/accessible/base/MarkupMap.h @@ -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) diff --git a/accessible/base/nsAccessibilityService.cpp b/accessible/base/nsAccessibilityService.cpp index bd761694c93..21c61a835ac 100644 --- a/accessible/base/nsAccessibilityService.cpp +++ b/accessible/base/nsAccessibilityService.cpp @@ -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 -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 = - 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 = - new HTMLFigcaptionAccessible(aContent, document); - return accessible.forget(); - } - - if (aContent->IsHTMLElement(nsGkAtoms::figure)) { - nsRefPtr accessible = - new HTMLFigureAccessible(aContent, document); - return accessible.forget(); - } - - if (aContent->IsHTMLElement(nsGkAtoms::legend)) { - nsRefPtr accessible = - new HTMLLegendAccessible(aContent, document); - return accessible.forget(); - } - - if (aContent->IsHTMLElement(nsGkAtoms::option)) { - nsRefPtr accessible = - new HTMLSelectOptionAccessible(aContent, document); - return accessible.forget(); - } - - if (aContent->IsHTMLElement(nsGkAtoms::optgroup)) { - nsRefPtr accessible = - new HTMLSelectOptGroupAccessible(aContent, document); - return accessible.forget(); - } - - if (aContent->IsAnyOfHTMLElements(nsGkAtoms::ul, - nsGkAtoms::ol, - nsGkAtoms::dl)) { - nsRefPtr 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 = - new HyperTextAccessibleWrap(aContent, document); - return accessible.forget(); - } - - nsRefPtr 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 = - new HTMLLIAccessible(aContent, document); - return accessible.forget(); - } - - if (aContent->IsHTMLElement(nsGkAtoms::dd)) { - nsRefPtr 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 = - new HyperTextAccessibleWrap(aContent, document); - return accessible.forget(); - } - - if (aContent->IsHTMLElement(nsGkAtoms::label)) { - nsRefPtr accessible = - new HTMLLabelAccessible(aContent, document); - return accessible.forget(); - } - - if (aContent->IsHTMLElement(nsGkAtoms::output)) { - nsRefPtr accessible = - new HTMLOutputAccessible(aContent, document); - return accessible.forget(); - } - - if (aContent->IsHTMLElement(nsGkAtoms::progress)) { - nsRefPtr accessible = - new HTMLProgressMeterAccessible(aContent, document); - return accessible.forget(); - } - - return nullptr; - } - already_AddRefed nsAccessibilityService::CreateAccessibleByFrameType(nsIFrame* aFrame, nsIContent* aContent, diff --git a/accessible/base/nsAccessibilityService.h b/accessible/base/nsAccessibilityService.h index 28ef51ec261..dd5e72fae31 100644 --- a/accessible/base/nsAccessibilityService.h +++ b/accessible/base/nsAccessibilityService.h @@ -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 CreateAccessibleByType(nsIContent* aContent, DocAccessible* aDoc); - /** - * Create accessible for HTML node by tag name. - */ - already_AddRefed - 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, mozilla::a11y::New_Accessible*> mMarkupMap; + friend nsAccessibilityService* GetAccService(); friend mozilla::a11y::FocusManager* mozilla::a11y::FocusMgr(); friend mozilla::a11y::SelectionManager* mozilla::a11y::SelectionMgr();