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"
9 #include "nsAccUtils.h"
10 #include "DocAccessible-inl.h"
14 #include "nsImageFrame.h"
15 #include "nsImageMap.h"
17 #include "nsLayoutUtils.h"
18 #include "mozilla/dom/HTMLAreaElement.h"
20 using namespace mozilla::a11y
;
22 ////////////////////////////////////////////////////////////////////////////////
23 // HTMLImageMapAccessible
24 ////////////////////////////////////////////////////////////////////////////////
26 HTMLImageMapAccessible::HTMLImageMapAccessible(nsIContent
* aContent
,
28 : ImageAccessibleWrap(aContent
, aDoc
) {
29 mType
= eImageMapType
;
31 UpdateChildAreas(false);
34 ////////////////////////////////////////////////////////////////////////////////
35 // HTMLImageMapAccessible: LocalAccessible public
37 role
HTMLImageMapAccessible::NativeRole() const { return roles::IMAGE_MAP
; }
39 ////////////////////////////////////////////////////////////////////////////////
40 // HTMLImageMapAccessible: HyperLinkAccessible
42 uint32_t HTMLImageMapAccessible::AnchorCount() { return ChildCount(); }
44 LocalAccessible
* HTMLImageMapAccessible::AnchorAt(uint32_t aAnchorIndex
) {
45 return LocalChildAt(aAnchorIndex
);
48 already_AddRefed
<nsIURI
> HTMLImageMapAccessible::AnchorURIAt(
49 uint32_t aAnchorIndex
) const {
50 LocalAccessible
* area
= LocalChildAt(aAnchorIndex
);
51 if (!area
) return nullptr;
53 nsIContent
* linkContent
= area
->GetContent();
54 return linkContent
? linkContent
->GetHrefURI() : nullptr;
57 ////////////////////////////////////////////////////////////////////////////////
58 // HTMLImageMapAccessible: public
60 void HTMLImageMapAccessible::UpdateChildAreas(bool aDoFireEvents
) {
61 nsImageFrame
* imageFrame
= do_QueryFrame(mContent
->GetPrimaryFrame());
63 // If image map is not initialized yet then we trigger one time more later.
64 nsImageMap
* imageMapObj
= imageFrame
->GetExistingImageMap();
65 if (!imageMapObj
) return;
67 TreeMutation
mt(this, TreeMutation::kNoEvents
& !aDoFireEvents
);
69 // Remove areas that are not a valid part of the image map anymore.
70 for (int32_t childIdx
= mChildren
.Length() - 1; childIdx
>= 0; childIdx
--) {
71 LocalAccessible
* area
= mChildren
.ElementAt(childIdx
);
72 if (area
->GetContent()->GetPrimaryFrame()) continue;
74 mt
.BeforeRemoval(area
);
78 // Insert new areas into the tree.
79 uint32_t areaElmCount
= imageMapObj
->AreaCount();
80 for (uint32_t idx
= 0; idx
< areaElmCount
; idx
++) {
81 nsIContent
* areaContent
= imageMapObj
->GetAreaAt(idx
);
82 LocalAccessible
* area
= mChildren
.SafeElementAt(idx
);
83 if (!area
|| area
->GetContent() != areaContent
) {
84 RefPtr
<LocalAccessible
> area
= new HTMLAreaAccessible(areaContent
, mDoc
);
85 mDoc
->BindToDocument(area
, aria::GetRoleMap(areaContent
->AsElement()));
87 if (!InsertChildAt(idx
, area
)) {
88 mDoc
->UnbindFromDocument(area
);
92 mt
.AfterInsertion(area
);
99 LocalAccessible
* HTMLImageMapAccessible::GetChildAccessibleFor(
100 const nsINode
* aNode
) const {
101 uint32_t length
= mChildren
.Length();
102 for (uint32_t i
= 0; i
< length
; i
++) {
103 LocalAccessible
* area
= mChildren
[i
];
104 if (area
->GetContent() == aNode
) return area
;
110 ////////////////////////////////////////////////////////////////////////////////
111 // HTMLAreaAccessible
112 ////////////////////////////////////////////////////////////////////////////////
114 HTMLAreaAccessible::HTMLAreaAccessible(nsIContent
* aContent
,
116 : HTMLLinkAccessible(aContent
, aDoc
) {
117 // Make HTML area DOM element not accessible. HTML image map accessible
118 // manages its tree itself.
119 mStateFlags
|= eNotNodeMapEntry
;
122 ////////////////////////////////////////////////////////////////////////////////
123 // HTMLAreaAccessible: LocalAccessible
125 ENameValueFlag
HTMLAreaAccessible::NativeName(nsString
& aName
) const {
126 ENameValueFlag nameFlag
= LocalAccessible::NativeName(aName
);
127 if (!aName
.IsEmpty()) return nameFlag
;
129 if (!mContent
->AsElement()->GetAttr(kNameSpaceID_None
, nsGkAtoms::alt
,
137 void HTMLAreaAccessible::Description(nsString
& aDescription
) const {
138 aDescription
.Truncate();
140 // Still to do - follow IE's standard here
141 RefPtr
<dom::HTMLAreaElement
> area
=
142 dom::HTMLAreaElement::FromNodeOrNull(mContent
);
143 if (area
) area
->GetShape(aDescription
);
146 ////////////////////////////////////////////////////////////////////////////////
147 // HTMLAreaAccessible: LocalAccessible public
149 LocalAccessible
* HTMLAreaAccessible::LocalChildAtPoint(
150 int32_t aX
, int32_t aY
, EWhichChildAtPoint aWhichChild
) {
151 // Don't walk into area accessibles.
155 ////////////////////////////////////////////////////////////////////////////////
156 // HTMLImageMapAccessible: HyperLinkAccessible
158 uint32_t HTMLAreaAccessible::StartOffset() {
159 // Image map accessible is not hypertext accessible therefore
160 // StartOffset/EndOffset implementations of LocalAccessible doesn't work here.
161 // We return index in parent because image map contains area links only which
162 // are embedded objects.
163 // XXX: image map should be a hypertext accessible.
164 return IndexInParent();
167 uint32_t HTMLAreaAccessible::EndOffset() { return IndexInParent() + 1; }
169 nsRect
HTMLAreaAccessible::RelativeBounds(nsIFrame
** aBoundingFrame
) const {
170 nsIFrame
* frame
= GetFrame();
171 if (!frame
) return nsRect();
173 nsImageFrame
* imageFrame
= do_QueryFrame(frame
);
174 nsImageMap
* map
= imageFrame
->GetImageMap();
177 nsresult rv
= map
->GetBoundsForAreaContent(mContent
, bounds
);
179 if (NS_FAILED(rv
)) return nsRect();
181 // XXX Areas are screwy; they return their rects as a pair of points, one pair
182 // stored into the width and height.
183 *aBoundingFrame
= frame
;
184 bounds
.SizeTo(bounds
.Width() - bounds
.X(), bounds
.Height() - bounds
.Y());
188 nsRect
HTMLAreaAccessible::ParentRelativeBounds() {
189 nsIFrame
* boundingFrame
= nullptr;
190 nsRect relativeBoundsRect
= RelativeBounds(&boundingFrame
);
192 nsIFrame
* parentBoundingFrame
= nullptr;
194 parentBoundingFrame
= mParent
->GetFrame();
197 if (!parentBoundingFrame
) {
198 // if we can't get the bounding frame, use the pres shell root for the
199 // bounding frame RelativeBounds returned
200 parentBoundingFrame
=
201 nsLayoutUtils::GetContainingBlockForClientRect(boundingFrame
);
204 nsLayoutUtils::TransformRect(boundingFrame
, parentBoundingFrame
,
207 return relativeBoundsRect
;