michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "ImageAccessible.h" michael@0: michael@0: #include "nsAccUtils.h" michael@0: #include "Role.h" michael@0: #include "AccIterator.h" michael@0: #include "States.h" michael@0: michael@0: #include "imgIContainer.h" michael@0: #include "imgIRequest.h" michael@0: #include "nsGenericHTMLElement.h" michael@0: #include "nsIDocument.h" michael@0: #include "nsIImageLoadingContent.h" michael@0: #include "nsIPresShell.h" michael@0: #include "nsIServiceManager.h" michael@0: #include "nsIDOMHTMLImageElement.h" michael@0: #include "nsIPersistentProperties2.h" michael@0: #include "nsPIDOMWindow.h" michael@0: #include "nsIURI.h" michael@0: michael@0: using namespace mozilla::a11y; michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // ImageAccessible michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: ImageAccessible:: michael@0: ImageAccessible(nsIContent* aContent, DocAccessible* aDoc) : michael@0: LinkableAccessible(aContent, aDoc) michael@0: { michael@0: mType = eImageType; michael@0: } michael@0: michael@0: NS_IMPL_ISUPPORTS_INHERITED(ImageAccessible, Accessible, michael@0: nsIAccessibleImage) michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // Accessible public michael@0: michael@0: uint64_t michael@0: ImageAccessible::NativeState() michael@0: { michael@0: // The state is a bitfield, get our inherited state, then logically OR it with michael@0: // states::ANIMATED if this is an animated image. michael@0: michael@0: uint64_t state = LinkableAccessible::NativeState(); michael@0: michael@0: nsCOMPtr content(do_QueryInterface(mContent)); michael@0: nsCOMPtr imageRequest; michael@0: michael@0: if (content) michael@0: content->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST, michael@0: getter_AddRefs(imageRequest)); michael@0: michael@0: nsCOMPtr imgContainer; michael@0: if (imageRequest) michael@0: imageRequest->GetImage(getter_AddRefs(imgContainer)); michael@0: michael@0: if (imgContainer) { michael@0: bool animated; michael@0: imgContainer->GetAnimated(&animated); michael@0: if (animated) michael@0: state |= states::ANIMATED; michael@0: } michael@0: michael@0: return state; michael@0: } michael@0: michael@0: ENameValueFlag michael@0: ImageAccessible::NativeName(nsString& aName) michael@0: { michael@0: bool hasAltAttrib = michael@0: mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::alt, aName); michael@0: if (!aName.IsEmpty()) michael@0: return eNameOK; michael@0: michael@0: ENameValueFlag nameFlag = Accessible::NativeName(aName); michael@0: if (!aName.IsEmpty()) michael@0: return nameFlag; michael@0: michael@0: // No accessible name but empty 'alt' attribute is present. If further name michael@0: // computation algorithm doesn't provide non empty name then it means michael@0: // an empty 'alt' attribute was used to indicate a decorative image (see michael@0: // Accessible::Name() method for details). michael@0: return hasAltAttrib ? eNoNameOnPurpose : eNameOK; michael@0: } michael@0: michael@0: role michael@0: ImageAccessible::NativeRole() michael@0: { michael@0: return roles::GRAPHIC; michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // nsIAccessible michael@0: michael@0: uint8_t michael@0: ImageAccessible::ActionCount() michael@0: { michael@0: uint8_t actionCount = LinkableAccessible::ActionCount(); michael@0: return HasLongDesc() ? actionCount + 1 : actionCount; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: ImageAccessible::GetActionName(uint8_t aIndex, nsAString& aName) michael@0: { michael@0: aName.Truncate(); michael@0: michael@0: if (IsDefunct()) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: if (IsLongDescIndex(aIndex) && HasLongDesc()) { michael@0: aName.AssignLiteral("showlongdesc"); michael@0: return NS_OK; michael@0: } michael@0: return LinkableAccessible::GetActionName(aIndex, aName); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: ImageAccessible::DoAction(uint8_t aIndex) michael@0: { michael@0: if (IsDefunct()) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: // Get the long description uri and open in a new window. michael@0: if (!IsLongDescIndex(aIndex)) michael@0: return LinkableAccessible::DoAction(aIndex); michael@0: michael@0: nsCOMPtr uri = GetLongDescURI(); michael@0: if (!uri) michael@0: return NS_ERROR_INVALID_ARG; michael@0: michael@0: nsAutoCString utf8spec; michael@0: uri->GetSpec(utf8spec); michael@0: NS_ConvertUTF8toUTF16 spec(utf8spec); michael@0: michael@0: nsIDocument* document = mContent->OwnerDoc(); michael@0: nsCOMPtr piWindow = document->GetWindow(); michael@0: nsCOMPtr win = do_QueryInterface(piWindow); michael@0: NS_ENSURE_STATE(win); michael@0: michael@0: nsCOMPtr tmp; michael@0: return win->Open(spec, EmptyString(), EmptyString(), michael@0: getter_AddRefs(tmp)); michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // nsIAccessibleImage michael@0: michael@0: NS_IMETHODIMP michael@0: ImageAccessible::GetImagePosition(uint32_t aCoordType, int32_t* aX, int32_t* aY) michael@0: { michael@0: int32_t width, height; michael@0: nsresult rv = GetBounds(aX, aY, &width, &height); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: nsAccUtils::ConvertScreenCoordsTo(aX, aY, aCoordType, this); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: ImageAccessible::GetImageSize(int32_t* aWidth, int32_t* aHeight) michael@0: { michael@0: int32_t x, y; michael@0: return GetBounds(&x, &y, aWidth, aHeight); michael@0: } michael@0: michael@0: // Accessible michael@0: already_AddRefed michael@0: ImageAccessible::NativeAttributes() michael@0: { michael@0: nsCOMPtr attributes = michael@0: LinkableAccessible::NativeAttributes(); michael@0: michael@0: nsAutoString src; michael@0: mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::src, src); michael@0: if (!src.IsEmpty()) michael@0: nsAccUtils::SetAccAttr(attributes, nsGkAtoms::src, src); michael@0: michael@0: return attributes.forget(); michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // Private methods michael@0: michael@0: already_AddRefed michael@0: ImageAccessible::GetLongDescURI() const michael@0: { michael@0: if (mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::longdesc)) { michael@0: nsGenericHTMLElement* element = michael@0: nsGenericHTMLElement::FromContent(mContent); michael@0: if (element) { michael@0: nsCOMPtr uri; michael@0: element->GetURIAttr(nsGkAtoms::longdesc, nullptr, getter_AddRefs(uri)); michael@0: return uri.forget(); michael@0: } michael@0: } michael@0: michael@0: DocAccessible* document = Document(); michael@0: if (document) { michael@0: IDRefsIterator iter(document, mContent, nsGkAtoms::aria_describedby); michael@0: while (nsIContent* target = iter.NextElem()) { michael@0: if ((target->IsHTML(nsGkAtoms::a) || target->IsHTML(nsGkAtoms::area)) && michael@0: target->HasAttr(kNameSpaceID_None, nsGkAtoms::href)) { michael@0: nsGenericHTMLElement* element = michael@0: nsGenericHTMLElement::FromContent(target); michael@0: michael@0: nsCOMPtr uri; michael@0: element->GetURIAttr(nsGkAtoms::href, nullptr, getter_AddRefs(uri)); michael@0: return uri.forget(); michael@0: } michael@0: } michael@0: } michael@0: michael@0: return nullptr; michael@0: } michael@0: michael@0: bool michael@0: ImageAccessible::IsLongDescIndex(uint8_t aIndex) michael@0: { michael@0: return aIndex == LinkableAccessible::ActionCount(); michael@0: } michael@0: