123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349 |
- /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
- /* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
- #include "mozilla/dom/SVGAElement.h"
- #include "mozilla/Attributes.h"
- #include "mozilla/EventDispatcher.h"
- #include "mozilla/EventStates.h"
- #include "mozilla/dom/SVGAElementBinding.h"
- #include "nsCOMPtr.h"
- #include "nsContentUtils.h"
- #include "nsGkAtoms.h"
- #include "nsSVGString.h"
- #include "nsIURI.h"
- NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(A)
- namespace mozilla {
- namespace dom {
- JSObject*
- SVGAElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
- {
- return SVGAElementBinding::Wrap(aCx, this, aGivenProto);
- }
- nsSVGElement::StringInfo SVGAElement::sStringInfo[3] =
- {
- { &nsGkAtoms::href, kNameSpaceID_None, true },
- { &nsGkAtoms::href, kNameSpaceID_XLink, true },
- { &nsGkAtoms::target, kNameSpaceID_None, true }
- };
- //----------------------------------------------------------------------
- // nsISupports methods
- NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(SVGAElement)
- NS_INTERFACE_TABLE_INHERITED(SVGAElement,
- nsIDOMNode,
- nsIDOMElement,
- nsIDOMSVGElement,
- Link)
- NS_INTERFACE_TABLE_TAIL_INHERITING(SVGAElementBase)
- NS_IMPL_CYCLE_COLLECTION_CLASS(SVGAElement)
- NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(SVGAElement,
- SVGAElementBase)
- NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
- NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(SVGAElement,
- SVGAElementBase)
- NS_IMPL_CYCLE_COLLECTION_UNLINK_END
- NS_IMPL_ADDREF_INHERITED(SVGAElement, SVGAElementBase)
- NS_IMPL_RELEASE_INHERITED(SVGAElement, SVGAElementBase)
- //----------------------------------------------------------------------
- // Implementation
- SVGAElement::SVGAElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
- : SVGAElementBase(aNodeInfo)
- , Link(this)
- {
- }
- SVGAElement::~SVGAElement()
- {
- }
- already_AddRefed<SVGAnimatedString>
- SVGAElement::Href()
- {
- return mStringAttributes[HREF].IsExplicitlySet()
- ? mStringAttributes[HREF].ToDOMAnimatedString(this)
- : mStringAttributes[XLINK_HREF].ToDOMAnimatedString(this);
- }
- //----------------------------------------------------------------------
- // nsINode methods
- nsresult
- SVGAElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
- {
- nsresult rv = Element::GetEventTargetParent(aVisitor);
- NS_ENSURE_SUCCESS(rv, rv);
- return GetEventTargetParentForLinks(aVisitor);
- }
- nsresult
- SVGAElement::PostHandleEvent(EventChainPostVisitor& aVisitor)
- {
- return PostHandleEventForLinks(aVisitor);
- }
- NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGAElement)
- //----------------------------------------------------------------------
- already_AddRefed<SVGAnimatedString>
- SVGAElement::Target()
- {
- return mStringAttributes[TARGET].ToDOMAnimatedString(this);
- }
- void
- SVGAElement::GetDownload(nsAString & aDownload)
- {
- GetAttr(kNameSpaceID_None, nsGkAtoms::download, aDownload);
- }
- void
- SVGAElement::SetDownload(const nsAString & aDownload, ErrorResult& rv)
- {
- rv = SetAttr(kNameSpaceID_None, nsGkAtoms::download, aDownload, true);
- }
- //----------------------------------------------------------------------
- // nsIContent methods
- nsresult
- SVGAElement::BindToTree(nsIDocument *aDocument, nsIContent *aParent,
- nsIContent *aBindingParent,
- bool aCompileEventHandlers)
- {
- Link::ResetLinkState(false, Link::ElementHasHref());
- nsresult rv = SVGAElementBase::BindToTree(aDocument, aParent,
- aBindingParent,
- aCompileEventHandlers);
- NS_ENSURE_SUCCESS(rv, rv);
- nsIDocument* doc = GetComposedDoc();
- if (doc) {
- doc->RegisterPendingLinkUpdate(this);
- }
- return NS_OK;
- }
- void
- SVGAElement::UnbindFromTree(bool aDeep, bool aNullParent)
- {
- // If this link is ever reinserted into a document, it might
- // be under a different xml:base, so forget the cached state now.
- Link::ResetLinkState(false, Link::ElementHasHref());
- // Note, we need to use OwnerDoc() here since GetComposedDoc() may
- // return null already at this point.
- nsIDocument* doc = OwnerDoc();
- if (doc) {
- doc->UnregisterPendingLinkUpdate(this);
- }
- SVGAElementBase::UnbindFromTree(aDeep, aNullParent);
- }
- already_AddRefed<nsIURI>
- SVGAElement::GetHrefURI() const
- {
- nsCOMPtr<nsIURI> hrefURI;
- return IsLink(getter_AddRefs(hrefURI)) ? hrefURI.forget() : nullptr;
- }
- NS_IMETHODIMP_(bool)
- SVGAElement::IsAttributeMapped(const nsIAtom* name) const
- {
- static const MappedAttributeEntry* const map[] = {
- sFEFloodMap,
- sFiltersMap,
- sFontSpecificationMap,
- sGradientStopMap,
- sLightingEffectsMap,
- sMarkersMap,
- sTextContentElementsMap,
- sViewportsMap
- };
- return FindAttributeDependence(name, map) ||
- SVGAElementBase::IsAttributeMapped(name);
- }
- bool
- SVGAElement::IsFocusableInternal(int32_t *aTabIndex, bool aWithMouse)
- {
- nsCOMPtr<nsIURI> uri;
- if (IsLink(getter_AddRefs(uri))) {
- if (aTabIndex) {
- *aTabIndex = ((sTabFocusModel & eTabFocus_linksMask) == 0 ? -1 : 0);
- }
- return true;
- }
- if (nsSVGElement::IsFocusableInternal(aTabIndex, aWithMouse)) {
- return true;
- }
- if (aTabIndex) {
- *aTabIndex = -1;
- }
- return false;
- }
- bool
- SVGAElement::IsLink(nsIURI** aURI) const
- {
- // To be a clickable XLink for styling and interaction purposes, we require:
- //
- // xlink:href - must be set
- // xlink:type - must be unset or set to "" or set to "simple"
- // xlink:show - must be unset or set to "", "new" or "replace"
- // xlink:actuate - must be unset or set to "" or "onRequest"
- //
- // For any other values, we're either not a *clickable* XLink, or the end
- // result is poorly specified. Either way, we return false.
- static nsIContent::AttrValuesArray sTypeVals[] =
- { &nsGkAtoms::_empty, &nsGkAtoms::simple, nullptr };
- static nsIContent::AttrValuesArray sShowVals[] =
- { &nsGkAtoms::_empty, &nsGkAtoms::_new, &nsGkAtoms::replace, nullptr };
- static nsIContent::AttrValuesArray sActuateVals[] =
- { &nsGkAtoms::_empty, &nsGkAtoms::onRequest, nullptr };
- // Optimization: check for href first for early return
- bool useXLink = !HasAttr(kNameSpaceID_None, nsGkAtoms::href);
- const nsAttrValue* href =
- useXLink
- ? mAttrsAndChildren.GetAttr(nsGkAtoms::href, kNameSpaceID_XLink)
- : mAttrsAndChildren.GetAttr(nsGkAtoms::href, kNameSpaceID_None);
- if (href &&
- FindAttrValueIn(kNameSpaceID_XLink, nsGkAtoms::type,
- sTypeVals, eCaseMatters) !=
- nsIContent::ATTR_VALUE_NO_MATCH &&
- FindAttrValueIn(kNameSpaceID_XLink, nsGkAtoms::show,
- sShowVals, eCaseMatters) !=
- nsIContent::ATTR_VALUE_NO_MATCH &&
- FindAttrValueIn(kNameSpaceID_XLink, nsGkAtoms::actuate,
- sActuateVals, eCaseMatters) !=
- nsIContent::ATTR_VALUE_NO_MATCH) {
- nsCOMPtr<nsIURI> baseURI = GetBaseURI();
- // Get absolute URI
- nsAutoString str;
- const uint8_t idx = useXLink ? XLINK_HREF : HREF;
- mStringAttributes[idx].GetAnimValue(str, this);
- nsContentUtils::NewURIWithDocumentCharset(aURI, str, OwnerDoc(), baseURI);
- // must promise out param is non-null if we return true
- return !!*aURI;
- }
- *aURI = nullptr;
- return false;
- }
- void
- SVGAElement::GetLinkTarget(nsAString& aTarget)
- {
- mStringAttributes[TARGET].GetAnimValue(aTarget, this);
- if (aTarget.IsEmpty()) {
- static nsIContent::AttrValuesArray sShowVals[] =
- { &nsGkAtoms::_new, &nsGkAtoms::replace, nullptr };
- switch (FindAttrValueIn(kNameSpaceID_XLink, nsGkAtoms::show,
- sShowVals, eCaseMatters)) {
- case 0:
- aTarget.AssignLiteral("_blank");
- return;
- case 1:
- return;
- }
- nsIDocument* ownerDoc = OwnerDoc();
- if (ownerDoc) {
- ownerDoc->GetBaseTarget(aTarget);
- }
- }
- }
- EventStates
- SVGAElement::IntrinsicState() const
- {
- return Link::LinkState() | SVGAElementBase::IntrinsicState();
- }
- nsresult
- SVGAElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- nsIAtom* aPrefix, const nsAString& aValue,
- bool aNotify)
- {
- nsresult rv = SVGAElementBase::SetAttr(aNameSpaceID, aName, aPrefix,
- aValue, aNotify);
- // The ordering of the parent class's SetAttr call and Link::ResetLinkState
- // is important here! The attribute is not set until SetAttr returns, and
- // we will need the updated attribute value because notifying the document
- // that content states have changed will call IntrinsicState, which will try
- // to get updated information about the visitedness from Link.
- if (aName == nsGkAtoms::href &&
- (aNameSpaceID == kNameSpaceID_XLink ||
- aNameSpaceID == kNameSpaceID_None)) {
- Link::ResetLinkState(!!aNotify, true);
- }
- return rv;
- }
- nsresult
- SVGAElement::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttr,
- bool aNotify)
- {
- nsresult rv = nsSVGElement::UnsetAttr(aNameSpaceID, aAttr, aNotify);
- // The ordering of the parent class's UnsetAttr call and Link::ResetLinkState
- // is important here! The attribute is not unset until UnsetAttr returns, and
- // we will need the updated attribute value because notifying the document
- // that content states have changed will call IntrinsicState, which will try
- // to get updated information about the visitedness from Link.
- if (aAttr == nsGkAtoms::href &&
- (aNameSpaceID == kNameSpaceID_XLink ||
- aNameSpaceID == kNameSpaceID_None)) {
- bool hasHref = HasAttr(kNameSpaceID_None, nsGkAtoms::href) ||
- HasAttr(kNameSpaceID_XLink, nsGkAtoms::href);
- Link::ResetLinkState(!!aNotify, hasHref);
- }
- return rv;
- }
- //----------------------------------------------------------------------
- // nsSVGElement methods
- nsSVGElement::StringAttributesInfo
- SVGAElement::GetStringInfo()
- {
- return StringAttributesInfo(mStringAttributes, sStringInfo,
- ArrayLength(sStringInfo));
- }
- } // namespace dom
- } // namespace mozilla
|