1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "HTMLImageMapAccessible.h"
10 #include "mozilla/a11y/Role.h"
12 #include "nsCoreUtils.h"
14 #include "nsImageFrame.h"
15 #include "nsImageMap.h"
16 #include "nsLayoutUtils.h"
17 #include "mozilla/dom/HTMLAreaElement.h"
19 using namespace mozilla::a11y
;
21 ////////////////////////////////////////////////////////////////////////////////
22 // HTMLImageMapAccessible
23 ////////////////////////////////////////////////////////////////////////////////
25 HTMLImageMapAccessible::HTMLImageMapAccessible(nsIContent
* aContent
,
27 : ImageAccessible(aContent
, aDoc
) {
28 mType
= eImageMapType
;
30 UpdateChildAreas(false);
33 ////////////////////////////////////////////////////////////////////////////////
34 // HTMLImageMapAccessible: LocalAccessible public
36 role
HTMLImageMapAccessible::NativeRole() const { return roles::IMAGE_MAP
; }
38 ////////////////////////////////////////////////////////////////////////////////
39 // HTMLImageMapAccessible: public
41 void HTMLImageMapAccessible::UpdateChildAreas(bool aDoFireEvents
) {
42 if (!mContent
|| !mContent
->GetPrimaryFrame()) {
45 nsImageFrame
* imageFrame
= do_QueryFrame(mContent
->GetPrimaryFrame());
47 // If image map is not initialized yet then we trigger one time more later.
48 nsImageMap
* imageMapObj
= imageFrame
->GetExistingImageMap();
49 if (!imageMapObj
) return;
51 TreeMutation
mt(this, TreeMutation::kNoEvents
& !aDoFireEvents
);
53 // Remove areas that are not a valid part of the image map anymore.
54 for (int32_t childIdx
= mChildren
.Length() - 1; childIdx
>= 0; childIdx
--) {
55 LocalAccessible
* area
= mChildren
.ElementAt(childIdx
);
56 if (area
->GetContent()->GetPrimaryFrame()) continue;
58 mt
.BeforeRemoval(area
);
62 // Insert new areas into the tree.
63 uint32_t areaElmCount
= imageMapObj
->AreaCount();
64 for (uint32_t idx
= 0; idx
< areaElmCount
; idx
++) {
65 nsIContent
* areaContent
= imageMapObj
->GetAreaAt(idx
);
66 LocalAccessible
* area
= mChildren
.SafeElementAt(idx
);
67 if (!area
|| area
->GetContent() != areaContent
) {
68 RefPtr
<LocalAccessible
> area
= new HTMLAreaAccessible(areaContent
, mDoc
);
69 mDoc
->BindToDocument(area
, aria::GetRoleMap(areaContent
->AsElement()));
71 if (!InsertChildAt(idx
, area
)) {
72 mDoc
->UnbindFromDocument(area
);
76 mt
.AfterInsertion(area
);
83 LocalAccessible
* HTMLImageMapAccessible::GetChildAccessibleFor(
84 const nsINode
* aNode
) const {
85 uint32_t length
= mChildren
.Length();
86 for (uint32_t i
= 0; i
< length
; i
++) {
87 LocalAccessible
* area
= mChildren
[i
];
88 if (area
->GetContent() == aNode
) return area
;
94 ////////////////////////////////////////////////////////////////////////////////
96 ////////////////////////////////////////////////////////////////////////////////
98 HTMLAreaAccessible::HTMLAreaAccessible(nsIContent
* aContent
,
100 : HTMLLinkAccessible(aContent
, aDoc
) {
101 // Make HTML area DOM element not accessible. HTML image map accessible
102 // manages its tree itself.
103 mStateFlags
|= eNotNodeMapEntry
;
106 ////////////////////////////////////////////////////////////////////////////////
107 // HTMLAreaAccessible: LocalAccessible
109 role
HTMLAreaAccessible::NativeRole() const {
110 // A link element without an href attribute and without a click listener
111 // should be reported as a generic.
112 if (mContent
->IsElement()) {
113 dom::Element
* element
= mContent
->AsElement();
114 if (!element
->HasAttr(nsGkAtoms::href
) &&
115 !nsCoreUtils::HasClickListener(element
)) {
119 return HTMLLinkAccessible::NativeRole();
122 ENameValueFlag
HTMLAreaAccessible::NativeName(nsString
& aName
) const {
123 ENameValueFlag nameFlag
= LocalAccessible::NativeName(aName
);
124 if (!aName
.IsEmpty()) return nameFlag
;
126 if (!mContent
->AsElement()->GetAttr(nsGkAtoms::alt
, aName
)) {
133 void HTMLAreaAccessible::Description(nsString
& aDescription
) const {
134 aDescription
.Truncate();
136 // Still to do - follow IE's standard here
137 RefPtr
<dom::HTMLAreaElement
> area
=
138 dom::HTMLAreaElement::FromNodeOrNull(mContent
);
139 if (area
) area
->GetShape(aDescription
);
142 ////////////////////////////////////////////////////////////////////////////////
143 // HTMLAreaAccessible: LocalAccessible public
145 LocalAccessible
* HTMLAreaAccessible::LocalChildAtPoint(
146 int32_t aX
, int32_t aY
, EWhichChildAtPoint aWhichChild
) {
147 // Don't walk into area accessibles.
151 ////////////////////////////////////////////////////////////////////////////////
152 // HTMLImageMapAccessible: HyperLinkAccessible
154 uint32_t HTMLAreaAccessible::StartOffset() {
155 // Image map accessible is not hypertext accessible therefore
156 // StartOffset/EndOffset implementations of LocalAccessible doesn't work here.
157 // We return index in parent because image map contains area links only which
158 // are embedded objects.
159 // XXX: image map should be a hypertext accessible.
160 return IndexInParent();
163 uint32_t HTMLAreaAccessible::EndOffset() { return IndexInParent() + 1; }
165 nsRect
HTMLAreaAccessible::RelativeBounds(nsIFrame
** aBoundingFrame
) const {
166 nsIFrame
* frame
= GetFrame();
167 if (!frame
) return nsRect();
169 nsImageFrame
* imageFrame
= do_QueryFrame(frame
);
170 nsImageMap
* map
= imageFrame
->GetImageMap();
173 nsresult rv
= map
->GetBoundsForAreaContent(mContent
, bounds
);
175 if (NS_FAILED(rv
)) return nsRect();
177 // XXX Areas are screwy; they return their rects as a pair of points, one pair
178 // stored into the width and height.
179 *aBoundingFrame
= frame
;
180 bounds
.SizeTo(bounds
.Width() - bounds
.X(), bounds
.Height() - bounds
.Y());
184 nsRect
HTMLAreaAccessible::ParentRelativeBounds() {
185 nsIFrame
* boundingFrame
= nullptr;
186 nsRect relativeBoundsRect
= RelativeBounds(&boundingFrame
);
187 if (MOZ_UNLIKELY(!boundingFrame
)) {
188 // Area is not attached to an image map?
192 // The relative bounds returned above are relative to this area's
193 // image map, which is technically already "parent relative".
194 // Because area elements are `display:none` to layout, they can't
195 // have transforms or other styling applied directly, and so we
196 // don't apply any additional transforms here. Any transform
197 // at the image map layer will be taken care of when computing bounds
198 // in the parent process.
199 return relativeBoundsRect
;