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 "HTMLImageMapAccessible.h" michael@0: michael@0: #include "ARIAMap.h" michael@0: #include "nsAccUtils.h" michael@0: #include "DocAccessible-inl.h" michael@0: #include "Role.h" michael@0: michael@0: #include "nsIDOMHTMLCollection.h" michael@0: #include "nsIServiceManager.h" michael@0: #include "nsIDOMElement.h" michael@0: #include "nsIDOMHTMLAreaElement.h" michael@0: #include "nsIFrame.h" michael@0: #include "nsImageFrame.h" michael@0: #include "nsImageMap.h" michael@0: #include "nsIURI.h" michael@0: michael@0: using namespace mozilla::a11y; michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // HTMLImageMapAccessible michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: HTMLImageMapAccessible:: michael@0: HTMLImageMapAccessible(nsIContent* aContent, DocAccessible* aDoc) : michael@0: ImageAccessibleWrap(aContent, aDoc) michael@0: { michael@0: mType = eImageMapType; michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // HTMLImageMapAccessible: nsISupports michael@0: michael@0: NS_IMPL_ISUPPORTS_INHERITED0(HTMLImageMapAccessible, ImageAccessible) michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // HTMLImageMapAccessible: Accessible public michael@0: michael@0: role michael@0: HTMLImageMapAccessible::NativeRole() michael@0: { michael@0: return roles::IMAGE_MAP; michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // HTMLImageMapAccessible: HyperLinkAccessible michael@0: michael@0: uint32_t michael@0: HTMLImageMapAccessible::AnchorCount() michael@0: { michael@0: return ChildCount(); michael@0: } michael@0: michael@0: Accessible* michael@0: HTMLImageMapAccessible::AnchorAt(uint32_t aAnchorIndex) michael@0: { michael@0: return GetChildAt(aAnchorIndex); michael@0: } michael@0: michael@0: already_AddRefed michael@0: HTMLImageMapAccessible::AnchorURIAt(uint32_t aAnchorIndex) michael@0: { michael@0: Accessible* area = GetChildAt(aAnchorIndex); michael@0: if (!area) michael@0: return nullptr; michael@0: michael@0: nsIContent* linkContent = area->GetContent(); michael@0: return linkContent ? linkContent->GetHrefURI() : nullptr; michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // HTMLImageMapAccessible: public michael@0: michael@0: void michael@0: HTMLImageMapAccessible::UpdateChildAreas(bool aDoFireEvents) michael@0: { michael@0: nsImageFrame* imageFrame = do_QueryFrame(mContent->GetPrimaryFrame()); michael@0: michael@0: // If image map is not initialized yet then we trigger one time more later. michael@0: nsImageMap* imageMapObj = imageFrame->GetExistingImageMap(); michael@0: if (!imageMapObj) michael@0: return; michael@0: michael@0: bool doReorderEvent = false; michael@0: nsRefPtr reorderEvent = new AccReorderEvent(this); michael@0: michael@0: // Remove areas that are not a valid part of the image map anymore. michael@0: for (int32_t childIdx = mChildren.Length() - 1; childIdx >= 0; childIdx--) { michael@0: Accessible* area = mChildren.ElementAt(childIdx); michael@0: if (area->GetContent()->GetPrimaryFrame()) michael@0: continue; michael@0: michael@0: if (aDoFireEvents) { michael@0: nsRefPtr event = new AccHideEvent(area, area->GetContent()); michael@0: mDoc->FireDelayedEvent(event); michael@0: reorderEvent->AddSubMutationEvent(event); michael@0: doReorderEvent = true; michael@0: } michael@0: michael@0: RemoveChild(area); michael@0: } michael@0: michael@0: // Insert new areas into the tree. michael@0: uint32_t areaElmCount = imageMapObj->AreaCount(); michael@0: for (uint32_t idx = 0; idx < areaElmCount; idx++) { michael@0: nsIContent* areaContent = imageMapObj->GetAreaAt(idx); michael@0: michael@0: Accessible* area = mChildren.SafeElementAt(idx); michael@0: if (!area || area->GetContent() != areaContent) { michael@0: nsRefPtr area = new HTMLAreaAccessible(areaContent, mDoc); michael@0: mDoc->BindToDocument(area, aria::GetRoleMap(areaContent)); michael@0: michael@0: if (!InsertChildAt(idx, area)) { michael@0: mDoc->UnbindFromDocument(area); michael@0: break; michael@0: } michael@0: michael@0: if (aDoFireEvents) { michael@0: nsRefPtr event = new AccShowEvent(area, areaContent); michael@0: mDoc->FireDelayedEvent(event); michael@0: reorderEvent->AddSubMutationEvent(event); michael@0: doReorderEvent = true; michael@0: } michael@0: } michael@0: } michael@0: michael@0: // Fire reorder event if needed. michael@0: if (doReorderEvent) michael@0: mDoc->FireDelayedEvent(reorderEvent); michael@0: } michael@0: michael@0: Accessible* michael@0: HTMLImageMapAccessible::GetChildAccessibleFor(const nsINode* aNode) const michael@0: { michael@0: uint32_t length = mChildren.Length(); michael@0: for (uint32_t i = 0; i < length; i++) { michael@0: Accessible* area = mChildren[i]; michael@0: if (area->GetContent() == aNode) michael@0: return area; michael@0: } michael@0: michael@0: return nullptr; michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // HTMLImageMapAccessible: Accessible protected michael@0: michael@0: void michael@0: HTMLImageMapAccessible::CacheChildren() michael@0: { michael@0: UpdateChildAreas(false); michael@0: } michael@0: michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // HTMLAreaAccessible michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: HTMLAreaAccessible:: michael@0: HTMLAreaAccessible(nsIContent* aContent, DocAccessible* aDoc) : michael@0: HTMLLinkAccessible(aContent, aDoc) michael@0: { michael@0: // Make HTML area DOM element not accessible. HTML image map accessible michael@0: // manages its tree itself. michael@0: mStateFlags |= eNotNodeMapEntry; michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // HTMLAreaAccessible: nsIAccessible michael@0: michael@0: ENameValueFlag michael@0: HTMLAreaAccessible::NativeName(nsString& aName) michael@0: { michael@0: ENameValueFlag nameFlag = Accessible::NativeName(aName); michael@0: if (!aName.IsEmpty()) michael@0: return nameFlag; michael@0: michael@0: if (!mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::alt, aName)) michael@0: GetValue(aName); michael@0: michael@0: return eNameOK; michael@0: } michael@0: michael@0: void michael@0: HTMLAreaAccessible::Description(nsString& aDescription) michael@0: { michael@0: aDescription.Truncate(); michael@0: michael@0: // Still to do - follow IE's standard here michael@0: nsCOMPtr area(do_QueryInterface(mContent)); michael@0: if (area) michael@0: area->GetShape(aDescription); michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // HTMLAreaAccessible: Accessible public michael@0: michael@0: Accessible* michael@0: HTMLAreaAccessible::ChildAtPoint(int32_t aX, int32_t aY, michael@0: EWhichChildAtPoint aWhichChild) michael@0: { michael@0: // Don't walk into area accessibles. michael@0: return this; michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // HTMLImageMapAccessible: HyperLinkAccessible michael@0: michael@0: uint32_t michael@0: HTMLAreaAccessible::StartOffset() michael@0: { michael@0: // Image map accessible is not hypertext accessible therefore michael@0: // StartOffset/EndOffset implementations of Accessible doesn't work here. michael@0: // We return index in parent because image map contains area links only which michael@0: // are embedded objects. michael@0: // XXX: image map should be a hypertext accessible. michael@0: return IndexInParent(); michael@0: } michael@0: michael@0: uint32_t michael@0: HTMLAreaAccessible::EndOffset() michael@0: { michael@0: return IndexInParent() + 1; michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // HTMLAreaAccessible: Accessible protected michael@0: michael@0: void michael@0: HTMLAreaAccessible::CacheChildren() michael@0: { michael@0: // No children for aria accessible. michael@0: } michael@0: michael@0: void michael@0: HTMLAreaAccessible::GetBoundsRect(nsRect& aBounds, nsIFrame** aBoundingFrame) michael@0: { michael@0: nsIFrame* frame = GetFrame(); michael@0: if (!frame) michael@0: return; michael@0: michael@0: nsImageFrame* imageFrame = do_QueryFrame(frame); michael@0: nsImageMap* map = imageFrame->GetImageMap(); michael@0: michael@0: nsresult rv = map->GetBoundsForAreaContent(mContent, aBounds); michael@0: if (NS_FAILED(rv)) michael@0: return; michael@0: michael@0: // XXX Areas are screwy; they return their rects as a pair of points, one pair michael@0: // stored into the width and height. michael@0: aBounds.width -= aBounds.x; michael@0: aBounds.height -= aBounds.y; michael@0: michael@0: *aBoundingFrame = frame; michael@0: }