tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

HTMLImageMapAccessible.cpp (6900B)


      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 "EventTree.h"
     10 #include "mozilla/a11y/Role.h"
     11 
     12 #include "nsCoreUtils.h"
     13 #include "nsIFrame.h"
     14 #include "nsImageFrame.h"
     15 #include "nsImageMap.h"
     16 #include "nsLayoutUtils.h"
     17 #include "mozilla/dom/HTMLAreaElement.h"
     18 
     19 using namespace mozilla::a11y;
     20 
     21 ////////////////////////////////////////////////////////////////////////////////
     22 // HTMLImageMapAccessible
     23 ////////////////////////////////////////////////////////////////////////////////
     24 
     25 HTMLImageMapAccessible::HTMLImageMapAccessible(nsIContent* aContent,
     26                                               DocAccessible* aDoc)
     27    : ImageAccessible(aContent, aDoc) {
     28  mType = eImageMapType;
     29 
     30  UpdateChildAreas(false);
     31 }
     32 
     33 ////////////////////////////////////////////////////////////////////////////////
     34 // HTMLImageMapAccessible: LocalAccessible public
     35 
     36 role HTMLImageMapAccessible::NativeRole() const { return roles::IMAGE_MAP; }
     37 
     38 ////////////////////////////////////////////////////////////////////////////////
     39 // HTMLImageMapAccessible: public
     40 
     41 void HTMLImageMapAccessible::UpdateChildAreas(bool aDoFireEvents) {
     42  if (!mContent || !mContent->GetPrimaryFrame()) {
     43    return;
     44  }
     45  nsImageFrame* imageFrame = do_QueryFrame(mContent->GetPrimaryFrame());
     46 
     47  // If image map is not initialized yet then we trigger one time more later.
     48  nsImageMap* imageMapObj = imageFrame->GetExistingImageMap();
     49  if (!imageMapObj) return;
     50 
     51  TreeMutation mt(this, TreeMutation::kNoEvents & !aDoFireEvents);
     52 
     53  // Remove areas that are not a valid part of the image map anymore.
     54  for (int32_t childIdx = mChildren.Length() - 1; childIdx >= 0; childIdx--) {
     55    LocalAccessible* area = mChildren.ElementAt(childIdx);
     56    if (area->GetContent()->GetPrimaryFrame()) continue;
     57 
     58    mt.BeforeRemoval(area);
     59    RemoveChild(area);
     60  }
     61 
     62  // Insert new areas into the tree.
     63  uint32_t areaElmCount = imageMapObj->AreaCount();
     64  for (uint32_t idx = 0; idx < areaElmCount; idx++) {
     65    nsIContent* areaContent = imageMapObj->GetAreaAt(idx);
     66    LocalAccessible* area = mChildren.SafeElementAt(idx);
     67    if (!area || area->GetContent() != areaContent) {
     68      RefPtr<LocalAccessible> area = new HTMLAreaAccessible(areaContent, mDoc);
     69      mDoc->BindToDocument(area, aria::GetRoleMap(areaContent->AsElement()));
     70 
     71      if (!InsertChildAt(idx, area)) {
     72        mDoc->UnbindFromDocument(area);
     73        break;
     74      }
     75 
     76      mt.AfterInsertion(area);
     77    }
     78  }
     79 
     80  mt.Done();
     81 }
     82 
     83 LocalAccessible* HTMLImageMapAccessible::GetChildAccessibleFor(
     84    const nsINode* aNode) const {
     85  uint32_t length = mChildren.Length();
     86  for (uint32_t i = 0; i < length; i++) {
     87    LocalAccessible* area = mChildren[i];
     88    if (area->GetContent() == aNode) return area;
     89  }
     90 
     91  return nullptr;
     92 }
     93 
     94 ////////////////////////////////////////////////////////////////////////////////
     95 // HTMLAreaAccessible
     96 ////////////////////////////////////////////////////////////////////////////////
     97 
     98 HTMLAreaAccessible::HTMLAreaAccessible(nsIContent* aContent,
     99                                       DocAccessible* aDoc)
    100    : HTMLLinkAccessible(aContent, aDoc) {
    101  // Make HTML area DOM element not accessible. HTML image map accessible
    102  // manages its tree itself.
    103  mStateFlags |= eNotNodeMapEntry;
    104 }
    105 
    106 ////////////////////////////////////////////////////////////////////////////////
    107 // HTMLAreaAccessible: LocalAccessible
    108 
    109 role HTMLAreaAccessible::NativeRole() const {
    110  // A link element without an href attribute and without a click listener
    111  // should be reported as a generic.
    112  if (mContent->IsElement()) {
    113    dom::Element* element = mContent->AsElement();
    114    if (!element->HasAttr(nsGkAtoms::href) &&
    115        !nsCoreUtils::HasClickListener(element)) {
    116      return roles::TEXT;
    117    }
    118  }
    119  return HTMLLinkAccessible::NativeRole();
    120 }
    121 
    122 ENameValueFlag HTMLAreaAccessible::NativeName(nsString& aName) const {
    123  ENameValueFlag nameFlag = LocalAccessible::NativeName(aName);
    124  if (!aName.IsEmpty()) return nameFlag;
    125 
    126  if (!mContent->AsElement()->GetAttr(nsGkAtoms::alt, aName)) {
    127    Value(aName);
    128  }
    129 
    130  return eNameOK;
    131 }
    132 
    133 EDescriptionValueFlag HTMLAreaAccessible::Description(
    134    nsString& aDescription) const {
    135  aDescription.Truncate();
    136 
    137  // Still to do - follow IE's standard here
    138  RefPtr<dom::HTMLAreaElement> area =
    139      dom::HTMLAreaElement::FromNodeOrNull(mContent);
    140  if (area) area->GetShape(aDescription);
    141 
    142  return eDescriptionOK;
    143 }
    144 
    145 ////////////////////////////////////////////////////////////////////////////////
    146 // HTMLAreaAccessible: LocalAccessible public
    147 
    148 LocalAccessible* HTMLAreaAccessible::LocalChildAtPoint(
    149    int32_t aX, int32_t aY, EWhichChildAtPoint aWhichChild) {
    150  // Don't walk into area accessibles.
    151  return this;
    152 }
    153 
    154 ////////////////////////////////////////////////////////////////////////////////
    155 // HTMLImageMapAccessible: HyperLinkAccessible
    156 
    157 uint32_t HTMLAreaAccessible::StartOffset() {
    158  // Image map accessible is not hypertext accessible therefore
    159  // StartOffset/EndOffset implementations of LocalAccessible doesn't work here.
    160  // We return index in parent because image map contains area links only which
    161  // are embedded objects.
    162  // XXX: image map should be a hypertext accessible.
    163  return IndexInParent();
    164 }
    165 
    166 uint32_t HTMLAreaAccessible::EndOffset() { return IndexInParent() + 1; }
    167 
    168 nsRect HTMLAreaAccessible::RelativeBounds(nsIFrame** aBoundingFrame) const {
    169  nsIFrame* frame = GetFrame();
    170  if (!frame) return nsRect();
    171 
    172  nsImageFrame* imageFrame = do_QueryFrame(frame);
    173  nsImageMap* map = imageFrame->GetImageMap();
    174 
    175  nsRect bounds;
    176  nsresult rv = map->GetBoundsForAreaContent(mContent, bounds);
    177 
    178  if (NS_FAILED(rv)) return nsRect();
    179 
    180  // XXX Areas are screwy; they return their rects as a pair of points, one pair
    181  // stored into the width and height.
    182  *aBoundingFrame = frame;
    183  bounds.SizeTo(bounds.Width() - bounds.X(), bounds.Height() - bounds.Y());
    184  return bounds;
    185 }
    186 
    187 nsRect HTMLAreaAccessible::ParentRelativeBounds() {
    188  nsIFrame* boundingFrame = nullptr;
    189  nsRect relativeBoundsRect = RelativeBounds(&boundingFrame);
    190  if (MOZ_UNLIKELY(!boundingFrame)) {
    191    // Area is not attached to an image map?
    192    return nsRect();
    193  }
    194 
    195  // The relative bounds returned above are relative to this area's
    196  // image map, which is technically already "parent relative".
    197  // Because area elements are `display:none` to layout, they can't
    198  // have transforms or other styling applied directly, and so we
    199  // don't apply any additional transforms here. Any transform
    200  // at the image map layer will be taken care of when computing bounds
    201  // in the parent process.
    202  return relativeBoundsRect;
    203 }