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/. */
5
6 #include "HTMLImageMapAccessible.h"
7
8 #include "ARIAMap.h"
9 #include "nsAccUtils.h"
10 #include "DocAccessible-inl.h"
11 #include "Role.h"
12
13 #include "nsIFrame.h"
14 #include "nsImageFrame.h"
15 #include "nsImageMap.h"
16 #include "nsIURI.h"
17 #include "nsLayoutUtils.h"
18 #include "mozilla/dom/HTMLAreaElement.h"
19
20 using namespace mozilla::a11y;
21
22 ////////////////////////////////////////////////////////////////////////////////
23 // HTMLImageMapAccessible
24 ////////////////////////////////////////////////////////////////////////////////
25
HTMLImageMapAccessible(nsIContent * aContent,DocAccessible * aDoc)26 HTMLImageMapAccessible::HTMLImageMapAccessible(nsIContent* aContent,
27 DocAccessible* aDoc)
28 : ImageAccessibleWrap(aContent, aDoc) {
29 mType = eImageMapType;
30
31 UpdateChildAreas(false);
32 }
33
34 ////////////////////////////////////////////////////////////////////////////////
35 // HTMLImageMapAccessible: LocalAccessible public
36
NativeRole() const37 role HTMLImageMapAccessible::NativeRole() const { return roles::IMAGE_MAP; }
38
39 ////////////////////////////////////////////////////////////////////////////////
40 // HTMLImageMapAccessible: HyperLinkAccessible
41
AnchorCount()42 uint32_t HTMLImageMapAccessible::AnchorCount() { return ChildCount(); }
43
AnchorAt(uint32_t aAnchorIndex)44 LocalAccessible* HTMLImageMapAccessible::AnchorAt(uint32_t aAnchorIndex) {
45 return LocalChildAt(aAnchorIndex);
46 }
47
AnchorURIAt(uint32_t aAnchorIndex) const48 already_AddRefed<nsIURI> HTMLImageMapAccessible::AnchorURIAt(
49 uint32_t aAnchorIndex) const {
50 LocalAccessible* area = LocalChildAt(aAnchorIndex);
51 if (!area) return nullptr;
52
53 nsIContent* linkContent = area->GetContent();
54 return linkContent ? linkContent->GetHrefURI() : nullptr;
55 }
56
57 ////////////////////////////////////////////////////////////////////////////////
58 // HTMLImageMapAccessible: public
59
UpdateChildAreas(bool aDoFireEvents)60 void HTMLImageMapAccessible::UpdateChildAreas(bool aDoFireEvents) {
61 nsImageFrame* imageFrame = do_QueryFrame(mContent->GetPrimaryFrame());
62
63 // If image map is not initialized yet then we trigger one time more later.
64 nsImageMap* imageMapObj = imageFrame->GetExistingImageMap();
65 if (!imageMapObj) return;
66
67 TreeMutation mt(this, TreeMutation::kNoEvents & !aDoFireEvents);
68
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;
73
74 mt.BeforeRemoval(area);
75 RemoveChild(area);
76 }
77
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()));
86
87 if (!InsertChildAt(idx, area)) {
88 mDoc->UnbindFromDocument(area);
89 break;
90 }
91
92 mt.AfterInsertion(area);
93 }
94 }
95
96 mt.Done();
97 }
98
GetChildAccessibleFor(const nsINode * aNode) const99 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;
105 }
106
107 return nullptr;
108 }
109
110 ////////////////////////////////////////////////////////////////////////////////
111 // HTMLAreaAccessible
112 ////////////////////////////////////////////////////////////////////////////////
113
HTMLAreaAccessible(nsIContent * aContent,DocAccessible * aDoc)114 HTMLAreaAccessible::HTMLAreaAccessible(nsIContent* aContent,
115 DocAccessible* aDoc)
116 : HTMLLinkAccessible(aContent, aDoc) {
117 // Make HTML area DOM element not accessible. HTML image map accessible
118 // manages its tree itself.
119 mStateFlags |= eNotNodeMapEntry;
120 }
121
122 ////////////////////////////////////////////////////////////////////////////////
123 // HTMLAreaAccessible: LocalAccessible
124
NativeName(nsString & aName) const125 ENameValueFlag HTMLAreaAccessible::NativeName(nsString& aName) const {
126 ENameValueFlag nameFlag = LocalAccessible::NativeName(aName);
127 if (!aName.IsEmpty()) return nameFlag;
128
129 if (!mContent->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::alt,
130 aName)) {
131 Value(aName);
132 }
133
134 return eNameOK;
135 }
136
Description(nsString & aDescription) const137 void HTMLAreaAccessible::Description(nsString& aDescription) const {
138 aDescription.Truncate();
139
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);
144 }
145
146 ////////////////////////////////////////////////////////////////////////////////
147 // HTMLAreaAccessible: LocalAccessible public
148
LocalChildAtPoint(int32_t aX,int32_t aY,EWhichChildAtPoint aWhichChild)149 LocalAccessible* HTMLAreaAccessible::LocalChildAtPoint(
150 int32_t aX, int32_t aY, EWhichChildAtPoint aWhichChild) {
151 // Don't walk into area accessibles.
152 return this;
153 }
154
155 ////////////////////////////////////////////////////////////////////////////////
156 // HTMLImageMapAccessible: HyperLinkAccessible
157
StartOffset()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();
165 }
166
EndOffset()167 uint32_t HTMLAreaAccessible::EndOffset() { return IndexInParent() + 1; }
168
RelativeBounds(nsIFrame ** aBoundingFrame) const169 nsRect HTMLAreaAccessible::RelativeBounds(nsIFrame** aBoundingFrame) const {
170 nsIFrame* frame = GetFrame();
171 if (!frame) return nsRect();
172
173 nsImageFrame* imageFrame = do_QueryFrame(frame);
174 nsImageMap* map = imageFrame->GetImageMap();
175
176 nsRect bounds;
177 nsresult rv = map->GetBoundsForAreaContent(mContent, bounds);
178
179 if (NS_FAILED(rv)) return nsRect();
180
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());
185 return bounds;
186 }
187
ParentRelativeBounds()188 nsRect HTMLAreaAccessible::ParentRelativeBounds() {
189 nsIFrame* boundingFrame = nullptr;
190 nsRect relativeBoundsRect = RelativeBounds(&boundingFrame);
191
192 nsIFrame* parentBoundingFrame = nullptr;
193 if (mParent) {
194 parentBoundingFrame = mParent->GetFrame();
195 }
196
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);
202 }
203
204 nsLayoutUtils::TransformRect(boundingFrame, parentBoundingFrame,
205 relativeBoundsRect);
206
207 return relativeBoundsRect;
208 }
209