dom/html/HTMLMarqueeElement.cpp
author Timothy Guan-tin Chien <timdream@gmail.com>
Fri, 25 Jan 2019 14:24:43 +0000
changeset 455689 951448bcc1fcebcad89deb2a7d03770a261eb79b
parent 452446 f0a91d36587266d7454a450c6044d573664fbed5
child 455708 033f90fc955948781a05b175d92aab568e1fd8f5
permissions -rw-r--r--
Bug 1507895 - Part III, Remove the marquee binding r=smaug This patch removes the XBL marquee binding and always uses UA Widget for the internal "gut" of the marquee element. Depends on D17572 Differential Revision: https://phabricator.services.mozilla.com/D17573

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/HTMLMarqueeElement.h"
#include "nsGenericHTMLElement.h"
#include "nsStyleConsts.h"
#include "nsMappedAttributes.h"
#include "mozilla/AsyncEventDispatcher.h"
#include "mozilla/dom/HTMLMarqueeElementBinding.h"
#include "mozilla/dom/CustomEvent.h"
// This is to pick up the definition of FunctionStringCallback:
#include "mozilla/dom/DataTransferItemBinding.h"
#include "mozilla/dom/ShadowRoot.h"

NS_IMPL_NS_NEW_HTML_ELEMENT(Marquee)

namespace mozilla {
namespace dom {

HTMLMarqueeElement::~HTMLMarqueeElement() {}

NS_IMPL_ELEMENT_CLONE(HTMLMarqueeElement)

static const nsAttrValue::EnumTable kBehaviorTable[] = {
    {"scroll", 1}, {"slide", 2}, {"alternate", 3}, {nullptr, 0}};

// Default behavior value is "scroll".
static const nsAttrValue::EnumTable* kDefaultBehavior = &kBehaviorTable[0];

static const nsAttrValue::EnumTable kDirectionTable[] = {
    {"left", 1}, {"right", 2}, {"up", 3}, {"down", 4}, {nullptr, 0}};

// Default direction value is "left".
static const nsAttrValue::EnumTable* kDefaultDirection = &kDirectionTable[0];

bool HTMLMarqueeElement::IsEventAttributeNameInternal(nsAtom* aName) {
  return nsContentUtils::IsEventAttributeName(
      aName, EventNameType_HTML | EventNameType_HTMLMarqueeOnly);
}

JSObject* HTMLMarqueeElement::WrapNode(JSContext* aCx,
                                       JS::Handle<JSObject*> aGivenProto) {
  return dom::HTMLMarqueeElement_Binding::Wrap(aCx, this, aGivenProto);
}

nsresult HTMLMarqueeElement::BindToTree(Document* aDocument,
                                        nsIContent* aParent,
                                        nsIContent* aBindingParent) {
  nsresult rv =
      nsGenericHTMLElement::BindToTree(aDocument, aParent, aBindingParent);
  NS_ENSURE_SUCCESS(rv, rv);

  if (IsInComposedDoc()) {
    AttachAndSetUAShadowRoot();
    NotifyUAWidgetSetupOrChange();
  }

  return rv;
}

void HTMLMarqueeElement::UnbindFromTree(bool aDeep, bool aNullParent) {
  if (IsInComposedDoc()) {
    // We don't want to unattach the shadow root because it used to
    // contain a <slot>.
    NotifyUAWidgetTeardown(UnattachShadowRoot::No);
  }

  nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
}

void HTMLMarqueeElement::GetBehavior(nsAString& aValue) {
  GetEnumAttr(nsGkAtoms::behavior, kDefaultBehavior->tag, aValue);
}

void HTMLMarqueeElement::GetDirection(nsAString& aValue) {
  GetEnumAttr(nsGkAtoms::direction, kDefaultDirection->tag, aValue);
}

bool HTMLMarqueeElement::ParseAttribute(int32_t aNamespaceID,
                                        nsAtom* aAttribute,
                                        const nsAString& aValue,
                                        nsIPrincipal* aMaybeScriptedPrincipal,
                                        nsAttrValue& aResult) {
  if (aNamespaceID == kNameSpaceID_None) {
    if ((aAttribute == nsGkAtoms::width) || (aAttribute == nsGkAtoms::height)) {
      return aResult.ParseSpecialIntValue(aValue);
    }
    if (aAttribute == nsGkAtoms::bgcolor) {
      return aResult.ParseColor(aValue);
    }
    if (aAttribute == nsGkAtoms::behavior) {
      return aResult.ParseEnumValue(aValue, kBehaviorTable, false,
                                    kDefaultBehavior);
    }
    if (aAttribute == nsGkAtoms::direction) {
      return aResult.ParseEnumValue(aValue, kDirectionTable, false,
                                    kDefaultDirection);
    }
    if ((aAttribute == nsGkAtoms::hspace) ||
        (aAttribute == nsGkAtoms::vspace)) {
      return aResult.ParseIntWithBounds(aValue, 0);
    }

    if (aAttribute == nsGkAtoms::loop) {
      return aResult.ParseIntValue(aValue);
    }

    if (aAttribute == nsGkAtoms::scrollamount ||
        aAttribute == nsGkAtoms::scrolldelay) {
      return aResult.ParseNonNegativeIntValue(aValue);
    }
  }

  return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
                                              aMaybeScriptedPrincipal, aResult);
}

nsresult HTMLMarqueeElement::AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName,
                                          const nsAttrValue* aValue,
                                          const nsAttrValue* aOldValue,
                                          nsIPrincipal* aMaybeScriptedPrincipal,
                                          bool aNotify) {
  if (IsInComposedDoc() &&
      aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::direction) {
    NotifyUAWidgetSetupOrChange();
  }
  return nsGenericHTMLElement::AfterSetAttr(
      aNameSpaceID, aName, aValue, aOldValue, aMaybeScriptedPrincipal, aNotify);
}

void HTMLMarqueeElement::MapAttributesIntoRule(
    const nsMappedAttributes* aAttributes, MappedDeclarations& aDecls) {
  nsGenericHTMLElement::MapImageMarginAttributeInto(aAttributes, aDecls);
  nsGenericHTMLElement::MapImageSizeAttributesInto(aAttributes, aDecls);
  nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aDecls);
  nsGenericHTMLElement::MapBGColorInto(aAttributes, aDecls);
}

NS_IMETHODIMP_(bool)
HTMLMarqueeElement::IsAttributeMapped(const nsAtom* aAttribute) const {
  static const MappedAttributeEntry* const map[] = {
      sImageMarginSizeAttributeMap, sBackgroundColorAttributeMap,
      sCommonAttributeMap};
  return FindAttributeDependence(aAttribute, map);
}

nsMapRuleToAttributesFunc HTMLMarqueeElement::GetAttributeMappingFunction()
    const {
  return &MapAttributesIntoRule;
}

void HTMLMarqueeElement::DispatchEventToShadowRoot(
    const nsAString& aEventTypeArg) {
  // Dispatch the event to the UA Widget Shadow Root, make it inaccessible to
  // document.
  RefPtr<nsINode> shadow = GetShadowRoot();
  MOZ_ASSERT(shadow);
  RefPtr<Event> event = new Event(shadow, nullptr, nullptr);
  event->InitEvent(aEventTypeArg, false, false);
  event->SetTrusted(true);
  shadow->DispatchEvent(*event, IgnoreErrors());
}

void HTMLMarqueeElement::Start() {
  if (GetShadowRoot()) {
    DispatchEventToShadowRoot(NS_LITERAL_STRING("marquee-start"));
  }
}

void HTMLMarqueeElement::Stop() {
  if (GetShadowRoot()) {
    DispatchEventToShadowRoot(NS_LITERAL_STRING("marquee-stop"));
  }
}

}  // namespace dom
}  // namespace mozilla