Line data Source code
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 "ImageAccessible.h"
7 :
8 : #include "nsAccUtils.h"
9 : #include "Role.h"
10 : #include "AccIterator.h"
11 : #include "States.h"
12 :
13 : #include "imgIContainer.h"
14 : #include "imgIRequest.h"
15 : #include "nsGenericHTMLElement.h"
16 : #include "nsIDocument.h"
17 : #include "nsIImageLoadingContent.h"
18 : #include "nsIPresShell.h"
19 : #include "nsIServiceManager.h"
20 : #include "nsIDOMHTMLImageElement.h"
21 : #include "nsIPersistentProperties2.h"
22 : #include "nsPIDOMWindow.h"
23 : #include "nsIURI.h"
24 :
25 : using namespace mozilla::a11y;
26 :
27 : ////////////////////////////////////////////////////////////////////////////////
28 : // ImageAccessible
29 : ////////////////////////////////////////////////////////////////////////////////
30 :
31 0 : ImageAccessible::
32 0 : ImageAccessible(nsIContent* aContent, DocAccessible* aDoc) :
33 0 : LinkableAccessible(aContent, aDoc)
34 : {
35 0 : mType = eImageType;
36 0 : }
37 :
38 0 : ImageAccessible::~ImageAccessible()
39 : {
40 0 : }
41 :
42 : ////////////////////////////////////////////////////////////////////////////////
43 : // Accessible public
44 :
45 : uint64_t
46 0 : ImageAccessible::NativeState()
47 : {
48 : // The state is a bitfield, get our inherited state, then logically OR it with
49 : // states::ANIMATED if this is an animated image.
50 :
51 0 : uint64_t state = LinkableAccessible::NativeState();
52 :
53 0 : nsCOMPtr<nsIImageLoadingContent> content(do_QueryInterface(mContent));
54 0 : nsCOMPtr<imgIRequest> imageRequest;
55 :
56 0 : if (content)
57 0 : content->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
58 0 : getter_AddRefs(imageRequest));
59 :
60 0 : nsCOMPtr<imgIContainer> imgContainer;
61 0 : if (imageRequest)
62 0 : imageRequest->GetImage(getter_AddRefs(imgContainer));
63 :
64 0 : if (imgContainer) {
65 : bool animated;
66 0 : imgContainer->GetAnimated(&animated);
67 0 : if (animated)
68 0 : state |= states::ANIMATED;
69 : }
70 :
71 0 : return state;
72 : }
73 :
74 : ENameValueFlag
75 0 : ImageAccessible::NativeName(nsString& aName)
76 : {
77 : bool hasAltAttrib =
78 0 : mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::alt, aName);
79 0 : if (!aName.IsEmpty())
80 0 : return eNameOK;
81 :
82 0 : ENameValueFlag nameFlag = Accessible::NativeName(aName);
83 0 : if (!aName.IsEmpty())
84 0 : return nameFlag;
85 :
86 : // No accessible name but empty 'alt' attribute is present. If further name
87 : // computation algorithm doesn't provide non empty name then it means
88 : // an empty 'alt' attribute was used to indicate a decorative image (see
89 : // Accessible::Name() method for details).
90 0 : return hasAltAttrib ? eNoNameOnPurpose : eNameOK;
91 : }
92 :
93 : role
94 0 : ImageAccessible::NativeRole()
95 : {
96 0 : return roles::GRAPHIC;
97 : }
98 :
99 : ////////////////////////////////////////////////////////////////////////////////
100 : // Accessible
101 :
102 : uint8_t
103 0 : ImageAccessible::ActionCount()
104 : {
105 0 : uint8_t actionCount = LinkableAccessible::ActionCount();
106 0 : return HasLongDesc() ? actionCount + 1 : actionCount;
107 : }
108 :
109 : void
110 0 : ImageAccessible::ActionNameAt(uint8_t aIndex, nsAString& aName)
111 : {
112 0 : aName.Truncate();
113 0 : if (IsLongDescIndex(aIndex) && HasLongDesc())
114 0 : aName.AssignLiteral("showlongdesc");
115 : else
116 0 : LinkableAccessible::ActionNameAt(aIndex, aName);
117 0 : }
118 :
119 : bool
120 0 : ImageAccessible::DoAction(uint8_t aIndex)
121 : {
122 : // Get the long description uri and open in a new window.
123 0 : if (!IsLongDescIndex(aIndex))
124 0 : return LinkableAccessible::DoAction(aIndex);
125 :
126 0 : nsCOMPtr<nsIURI> uri = GetLongDescURI();
127 0 : if (!uri)
128 0 : return false;
129 :
130 0 : nsAutoCString utf8spec;
131 0 : uri->GetSpec(utf8spec);
132 0 : NS_ConvertUTF8toUTF16 spec(utf8spec);
133 :
134 0 : nsIDocument* document = mContent->OwnerDoc();
135 0 : nsCOMPtr<nsPIDOMWindowOuter> piWindow = document->GetWindow();
136 0 : if (!piWindow)
137 0 : return false;
138 :
139 0 : nsCOMPtr<nsPIDOMWindowOuter> tmp;
140 0 : return NS_SUCCEEDED(piWindow->Open(spec, EmptyString(), EmptyString(),
141 : /* aLoadInfo = */ nullptr,
142 : /* aForceNoOpener = */ false,
143 : getter_AddRefs(tmp)));
144 : }
145 :
146 : ////////////////////////////////////////////////////////////////////////////////
147 : // ImageAccessible
148 :
149 : nsIntPoint
150 0 : ImageAccessible::Position(uint32_t aCoordType)
151 : {
152 0 : nsIntRect rect = Bounds();
153 0 : nsAccUtils::ConvertScreenCoordsTo(&rect.x, &rect.y, aCoordType, this);
154 0 : return rect.TopLeft();
155 : }
156 :
157 : nsIntSize
158 0 : ImageAccessible::Size()
159 : {
160 0 : return Bounds().Size();
161 : }
162 :
163 : // Accessible
164 : already_AddRefed<nsIPersistentProperties>
165 0 : ImageAccessible::NativeAttributes()
166 : {
167 : nsCOMPtr<nsIPersistentProperties> attributes =
168 0 : LinkableAccessible::NativeAttributes();
169 :
170 0 : nsAutoString src;
171 0 : mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::src, src);
172 0 : if (!src.IsEmpty())
173 0 : nsAccUtils::SetAccAttr(attributes, nsGkAtoms::src, src);
174 :
175 0 : return attributes.forget();
176 : }
177 :
178 : ////////////////////////////////////////////////////////////////////////////////
179 : // Private methods
180 :
181 : already_AddRefed<nsIURI>
182 0 : ImageAccessible::GetLongDescURI() const
183 : {
184 0 : if (mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::longdesc)) {
185 : // To check if longdesc contains an invalid url.
186 0 : nsAutoString longdesc;
187 0 : mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::longdesc, longdesc);
188 0 : if (longdesc.FindChar(' ') != -1 || longdesc.FindChar('\t') != -1 ||
189 0 : longdesc.FindChar('\r') != -1 || longdesc.FindChar('\n') != -1) {
190 0 : return nullptr;
191 : }
192 0 : nsCOMPtr<nsIURI> baseURI = mContent->GetBaseURI();
193 0 : nsCOMPtr<nsIURI> uri;
194 0 : nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(uri), longdesc,
195 0 : mContent->OwnerDoc(), baseURI);
196 0 : return uri.forget();
197 : }
198 :
199 0 : DocAccessible* document = Document();
200 0 : if (document) {
201 0 : IDRefsIterator iter(document, mContent, nsGkAtoms::aria_describedby);
202 0 : while (nsIContent* target = iter.NextElem()) {
203 0 : if ((target->IsHTMLElement(nsGkAtoms::a) ||
204 0 : target->IsHTMLElement(nsGkAtoms::area)) &&
205 0 : target->HasAttr(kNameSpaceID_None, nsGkAtoms::href)) {
206 : nsGenericHTMLElement* element =
207 0 : nsGenericHTMLElement::FromContent(target);
208 :
209 0 : nsCOMPtr<nsIURI> uri;
210 0 : element->GetURIAttr(nsGkAtoms::href, nullptr, getter_AddRefs(uri));
211 0 : return uri.forget();
212 : }
213 0 : }
214 : }
215 :
216 0 : return nullptr;
217 : }
218 :
219 : bool
220 0 : ImageAccessible::IsLongDescIndex(uint8_t aIndex)
221 : {
222 0 : return aIndex == LinkableAccessible::ActionCount();
223 : }
224 :
|