mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-01 12:57:31 +09:00
import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo
This commit is contained in:
commit
dcd9973243
150858 changed files with 23884658 additions and 0 deletions
211
dom/html/HTMLAllCollection.cpp
Normal file
211
dom/html/HTMLAllCollection.cpp
Normal file
|
|
@ -0,0 +1,211 @@
|
|||
/* -*- 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/HTMLAllCollection.h"
|
||||
|
||||
#include "mozilla/dom/HTMLAllCollectionBinding.h"
|
||||
#include "mozilla/dom/Nullable.h"
|
||||
#include "nsHTMLDocument.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
HTMLAllCollection::HTMLAllCollection(nsHTMLDocument* aDocument)
|
||||
: mDocument(aDocument)
|
||||
{
|
||||
MOZ_ASSERT(mDocument);
|
||||
}
|
||||
|
||||
HTMLAllCollection::~HTMLAllCollection()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(HTMLAllCollection,
|
||||
mDocument,
|
||||
mCollection,
|
||||
mNamedMap)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(HTMLAllCollection)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(HTMLAllCollection)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(HTMLAllCollection)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
nsINode*
|
||||
HTMLAllCollection::GetParentObject() const
|
||||
{
|
||||
return mDocument;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
HTMLAllCollection::Length()
|
||||
{
|
||||
return Collection()->Length(true);
|
||||
}
|
||||
|
||||
nsIContent*
|
||||
HTMLAllCollection::Item(uint32_t aIndex)
|
||||
{
|
||||
return Collection()->Item(aIndex);
|
||||
}
|
||||
|
||||
nsContentList*
|
||||
HTMLAllCollection::Collection()
|
||||
{
|
||||
if (!mCollection) {
|
||||
nsIDocument* document = mDocument;
|
||||
mCollection = document->GetElementsByTagName(NS_LITERAL_STRING("*"));
|
||||
MOZ_ASSERT(mCollection);
|
||||
}
|
||||
return mCollection;
|
||||
}
|
||||
|
||||
static bool
|
||||
IsAllNamedElement(nsIContent* aContent)
|
||||
{
|
||||
return aContent->IsAnyOfHTMLElements(nsGkAtoms::a,
|
||||
nsGkAtoms::applet,
|
||||
nsGkAtoms::button,
|
||||
nsGkAtoms::embed,
|
||||
nsGkAtoms::form,
|
||||
nsGkAtoms::iframe,
|
||||
nsGkAtoms::img,
|
||||
nsGkAtoms::input,
|
||||
nsGkAtoms::map,
|
||||
nsGkAtoms::meta,
|
||||
nsGkAtoms::object,
|
||||
nsGkAtoms::select,
|
||||
nsGkAtoms::textarea,
|
||||
nsGkAtoms::frame,
|
||||
nsGkAtoms::frameset);
|
||||
}
|
||||
|
||||
static bool
|
||||
DocAllResultMatch(nsIContent* aContent, int32_t aNamespaceID, nsIAtom* aAtom,
|
||||
void* aData)
|
||||
{
|
||||
if (aContent->GetID() == aAtom) {
|
||||
return true;
|
||||
}
|
||||
|
||||
nsGenericHTMLElement* elm = nsGenericHTMLElement::FromContent(aContent);
|
||||
if (!elm) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!IsAllNamedElement(elm)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const nsAttrValue* val = elm->GetParsedAttr(nsGkAtoms::name);
|
||||
return val && val->Type() == nsAttrValue::eAtom &&
|
||||
val->GetAtomValue() == aAtom;
|
||||
}
|
||||
|
||||
nsContentList*
|
||||
HTMLAllCollection::GetDocumentAllList(const nsAString& aID)
|
||||
{
|
||||
if (nsContentList* docAllList = mNamedMap.GetWeak(aID)) {
|
||||
return docAllList;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIAtom> id = NS_Atomize(aID);
|
||||
RefPtr<nsContentList> docAllList =
|
||||
new nsContentList(mDocument, DocAllResultMatch, nullptr, nullptr, true, id);
|
||||
mNamedMap.Put(aID, docAllList);
|
||||
return docAllList;
|
||||
}
|
||||
|
||||
void
|
||||
HTMLAllCollection::NamedGetter(const nsAString& aID,
|
||||
bool& aFound,
|
||||
Nullable<OwningNodeOrHTMLCollection>& aResult)
|
||||
{
|
||||
if (aID.IsEmpty()) {
|
||||
aFound = false;
|
||||
aResult.SetNull();
|
||||
return;
|
||||
}
|
||||
|
||||
nsContentList* docAllList = GetDocumentAllList(aID);
|
||||
if (!docAllList) {
|
||||
aFound = false;
|
||||
aResult.SetNull();
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if there are more than 1 entries. Do this by getting the second one
|
||||
// rather than the length since getting the length always requires walking
|
||||
// the entire document.
|
||||
if (docAllList->Item(1, true)) {
|
||||
aFound = true;
|
||||
aResult.SetValue().SetAsHTMLCollection() = docAllList;
|
||||
return;
|
||||
}
|
||||
|
||||
// There's only 0 or 1 items. Return the first one or null.
|
||||
if (nsIContent* node = docAllList->Item(0, true)) {
|
||||
aFound = true;
|
||||
aResult.SetValue().SetAsNode() = node;
|
||||
return;
|
||||
}
|
||||
|
||||
aFound = false;
|
||||
aResult.SetNull();
|
||||
}
|
||||
|
||||
void
|
||||
HTMLAllCollection::GetSupportedNames(nsTArray<nsString>& aNames)
|
||||
{
|
||||
// XXXbz this is very similar to nsContentList::GetSupportedNames,
|
||||
// but has to check IsAllNamedElement for the name case.
|
||||
AutoTArray<nsIAtom*, 8> atoms;
|
||||
for (uint32_t i = 0; i < Length(); ++i) {
|
||||
nsIContent *content = Item(i);
|
||||
if (content->HasID()) {
|
||||
nsIAtom* id = content->GetID();
|
||||
MOZ_ASSERT(id != nsGkAtoms::_empty,
|
||||
"Empty ids don't get atomized");
|
||||
if (!atoms.Contains(id)) {
|
||||
atoms.AppendElement(id);
|
||||
}
|
||||
}
|
||||
|
||||
nsGenericHTMLElement* el = nsGenericHTMLElement::FromContent(content);
|
||||
if (el) {
|
||||
// Note: nsINode::HasName means the name is exposed on the document,
|
||||
// which is false for options, so we don't check it here.
|
||||
const nsAttrValue* val = el->GetParsedAttr(nsGkAtoms::name);
|
||||
if (val && val->Type() == nsAttrValue::eAtom &&
|
||||
IsAllNamedElement(content)) {
|
||||
nsIAtom* name = val->GetAtomValue();
|
||||
MOZ_ASSERT(name != nsGkAtoms::_empty,
|
||||
"Empty names don't get atomized");
|
||||
if (!atoms.Contains(name)) {
|
||||
atoms.AppendElement(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t atomsLen = atoms.Length();
|
||||
nsString* names = aNames.AppendElements(atomsLen);
|
||||
for (uint32_t i = 0; i < atomsLen; ++i) {
|
||||
atoms[i]->ToString(names[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
JSObject*
|
||||
HTMLAllCollection::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return HTMLAllCollectionBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
87
dom/html/HTMLAllCollection.h
Normal file
87
dom/html/HTMLAllCollection.h
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_dom_HTMLAllCollection_h
|
||||
#define mozilla_dom_HTMLAllCollection_h
|
||||
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "nsRefPtrHashtable.h"
|
||||
#include "nsWrapperCache.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
class nsContentList;
|
||||
class nsHTMLDocument;
|
||||
class nsIContent;
|
||||
class nsINode;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class OwningNodeOrHTMLCollection;
|
||||
template<typename> struct Nullable;
|
||||
|
||||
class HTMLAllCollection final : public nsISupports
|
||||
, public nsWrapperCache
|
||||
{
|
||||
~HTMLAllCollection();
|
||||
|
||||
public:
|
||||
explicit HTMLAllCollection(nsHTMLDocument* aDocument);
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(HTMLAllCollection)
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
nsINode* GetParentObject() const;
|
||||
|
||||
uint32_t Length();
|
||||
nsIContent* Item(uint32_t aIndex);
|
||||
void Item(const nsAString& aName, Nullable<OwningNodeOrHTMLCollection>& aResult)
|
||||
{
|
||||
NamedItem(aName, aResult);
|
||||
}
|
||||
nsIContent* IndexedGetter(uint32_t aIndex, bool& aFound)
|
||||
{
|
||||
nsIContent* result = Item(aIndex);
|
||||
aFound = !!result;
|
||||
return result;
|
||||
}
|
||||
|
||||
void NamedItem(const nsAString& aName,
|
||||
Nullable<OwningNodeOrHTMLCollection>& aResult)
|
||||
{
|
||||
bool found = false;
|
||||
NamedGetter(aName, found, aResult);
|
||||
}
|
||||
void NamedGetter(const nsAString& aName,
|
||||
bool& aFound,
|
||||
Nullable<OwningNodeOrHTMLCollection>& aResult);
|
||||
void GetSupportedNames(nsTArray<nsString>& aNames);
|
||||
void LegacyCall(JS::Handle<JS::Value>, const nsAString& aName,
|
||||
Nullable<OwningNodeOrHTMLCollection>& aResult)
|
||||
{
|
||||
NamedItem(aName, aResult);
|
||||
}
|
||||
|
||||
private:
|
||||
nsContentList* Collection();
|
||||
|
||||
/**
|
||||
* Returns the HTMLCollection for document.all[aID], or null if there isn't one.
|
||||
*/
|
||||
nsContentList* GetDocumentAllList(const nsAString& aID);
|
||||
|
||||
RefPtr<nsHTMLDocument> mDocument;
|
||||
RefPtr<nsContentList> mCollection;
|
||||
nsRefPtrHashtable<nsStringHashKey, nsContentList> mNamedMap;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_HTMLAllCollection_h
|
||||
469
dom/html/HTMLAnchorElement.cpp
Normal file
469
dom/html/HTMLAnchorElement.cpp
Normal file
|
|
@ -0,0 +1,469 @@
|
|||
/* -*- 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/HTMLAnchorElement.h"
|
||||
|
||||
#include "mozilla/dom/HTMLAnchorElementBinding.h"
|
||||
#include "mozilla/EventDispatcher.h"
|
||||
#include "mozilla/EventStates.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsHTMLDNSPrefetch.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIPresShell.h"
|
||||
#include "nsPresContext.h"
|
||||
#include "nsIURI.h"
|
||||
|
||||
NS_IMPL_NS_NEW_HTML_ELEMENT(Anchor)
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
#define ANCHOR_ELEMENT_FLAG_BIT(n_) NODE_FLAG_BIT(ELEMENT_TYPE_SPECIFIC_BITS_OFFSET + (n_))
|
||||
|
||||
// Anchor element specific bits
|
||||
enum {
|
||||
// Indicates that a DNS Prefetch has been requested from this Anchor elem
|
||||
HTML_ANCHOR_DNS_PREFETCH_REQUESTED = ANCHOR_ELEMENT_FLAG_BIT(0),
|
||||
|
||||
// Indicates that a DNS Prefetch was added to the deferral queue
|
||||
HTML_ANCHOR_DNS_PREFETCH_DEFERRED = ANCHOR_ELEMENT_FLAG_BIT(1)
|
||||
};
|
||||
|
||||
ASSERT_NODE_FLAGS_SPACE(ELEMENT_TYPE_SPECIFIC_BITS_OFFSET + 2);
|
||||
|
||||
#undef ANCHOR_ELEMENT_FLAG_BIT
|
||||
|
||||
// static
|
||||
const DOMTokenListSupportedToken HTMLAnchorElement::sSupportedRelValues[] = {
|
||||
"noreferrer",
|
||||
"noopener",
|
||||
nullptr
|
||||
};
|
||||
|
||||
HTMLAnchorElement::~HTMLAnchorElement()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
HTMLAnchorElement::IsInteractiveHTMLContent(bool aIgnoreTabindex) const
|
||||
{
|
||||
return HasAttr(kNameSpaceID_None, nsGkAtoms::href) ||
|
||||
nsGenericHTMLElement::IsInteractiveHTMLContent(aIgnoreTabindex);
|
||||
}
|
||||
|
||||
NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(HTMLAnchorElement)
|
||||
NS_INTERFACE_TABLE_INHERITED(HTMLAnchorElement,
|
||||
nsIDOMHTMLAnchorElement,
|
||||
Link)
|
||||
NS_INTERFACE_TABLE_TAIL_INHERITING(nsGenericHTMLElement)
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(HTMLAnchorElement, Element)
|
||||
NS_IMPL_RELEASE_INHERITED(HTMLAnchorElement, Element)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(HTMLAnchorElement)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLAnchorElement,
|
||||
nsGenericHTMLElement)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRelList)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLAnchorElement,
|
||||
nsGenericHTMLElement)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mRelList)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_IMPL_ELEMENT_CLONE(HTMLAnchorElement)
|
||||
|
||||
JSObject*
|
||||
HTMLAnchorElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return HTMLAnchorElementBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
NS_IMPL_STRING_ATTR(HTMLAnchorElement, Charset, charset)
|
||||
NS_IMPL_STRING_ATTR(HTMLAnchorElement, Coords, coords)
|
||||
NS_IMPL_URI_ATTR(HTMLAnchorElement, Href, href)
|
||||
NS_IMPL_STRING_ATTR(HTMLAnchorElement, Hreflang, hreflang)
|
||||
NS_IMPL_STRING_ATTR(HTMLAnchorElement, Name, name)
|
||||
NS_IMPL_STRING_ATTR(HTMLAnchorElement, Rel, rel)
|
||||
NS_IMPL_STRING_ATTR(HTMLAnchorElement, Rev, rev)
|
||||
NS_IMPL_STRING_ATTR(HTMLAnchorElement, Shape, shape)
|
||||
NS_IMPL_STRING_ATTR(HTMLAnchorElement, Type, type)
|
||||
NS_IMPL_STRING_ATTR(HTMLAnchorElement, Download, download)
|
||||
|
||||
int32_t
|
||||
HTMLAnchorElement::TabIndexDefault()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool
|
||||
HTMLAnchorElement::Draggable() const
|
||||
{
|
||||
// links can be dragged as long as there is an href and the
|
||||
// draggable attribute isn't false
|
||||
if (!HasAttr(kNameSpaceID_None, nsGkAtoms::href)) {
|
||||
// no href, so just use the same behavior as other elements
|
||||
return nsGenericHTMLElement::Draggable();
|
||||
}
|
||||
|
||||
return !AttrValueIs(kNameSpaceID_None, nsGkAtoms::draggable,
|
||||
nsGkAtoms::_false, eIgnoreCase);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLAnchorElement::OnDNSPrefetchRequested()
|
||||
{
|
||||
UnsetFlags(HTML_ANCHOR_DNS_PREFETCH_DEFERRED);
|
||||
SetFlags(HTML_ANCHOR_DNS_PREFETCH_REQUESTED);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLAnchorElement::OnDNSPrefetchDeferred()
|
||||
{
|
||||
UnsetFlags(HTML_ANCHOR_DNS_PREFETCH_REQUESTED);
|
||||
SetFlags(HTML_ANCHOR_DNS_PREFETCH_DEFERRED);
|
||||
}
|
||||
|
||||
bool
|
||||
HTMLAnchorElement::HasDeferredDNSPrefetchRequest()
|
||||
{
|
||||
return HasFlag(HTML_ANCHOR_DNS_PREFETCH_DEFERRED);
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLAnchorElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
||||
nsIContent* aBindingParent,
|
||||
bool aCompileEventHandlers)
|
||||
{
|
||||
Link::ResetLinkState(false, Link::ElementHasHref());
|
||||
|
||||
nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent,
|
||||
aBindingParent,
|
||||
aCompileEventHandlers);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Prefetch links
|
||||
nsIDocument* doc = GetComposedDoc();
|
||||
if (doc) {
|
||||
doc->RegisterPendingLinkUpdate(this);
|
||||
TryDNSPrefetch();
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
void
|
||||
HTMLAnchorElement::UnbindFromTree(bool aDeep, bool aNullParent)
|
||||
{
|
||||
// Cancel any DNS prefetches
|
||||
// Note: Must come before ResetLinkState. If called after, it will recreate
|
||||
// mCachedURI based on data that is invalid - due to a call to GetHostname.
|
||||
CancelDNSPrefetch(HTML_ANCHOR_DNS_PREFETCH_DEFERRED,
|
||||
HTML_ANCHOR_DNS_PREFETCH_REQUESTED);
|
||||
|
||||
// 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() might
|
||||
// return null.
|
||||
nsIDocument* doc = OwnerDoc();
|
||||
if (doc) {
|
||||
doc->UnregisterPendingLinkUpdate(this);
|
||||
}
|
||||
|
||||
nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
|
||||
}
|
||||
|
||||
static bool
|
||||
IsNodeInEditableRegion(nsINode* aNode)
|
||||
{
|
||||
while (aNode) {
|
||||
if (aNode->IsEditable()) {
|
||||
return true;
|
||||
}
|
||||
aNode = aNode->GetParent();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
HTMLAnchorElement::IsHTMLFocusable(bool aWithMouse,
|
||||
bool *aIsFocusable, int32_t *aTabIndex)
|
||||
{
|
||||
if (nsGenericHTMLElement::IsHTMLFocusable(aWithMouse, aIsFocusable, aTabIndex)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// cannot focus links if there is no link handler
|
||||
nsIDocument* doc = GetComposedDoc();
|
||||
if (doc) {
|
||||
nsIPresShell* presShell = doc->GetShell();
|
||||
if (presShell) {
|
||||
nsPresContext* presContext = presShell->GetPresContext();
|
||||
if (presContext && !presContext->GetLinkHandler()) {
|
||||
*aIsFocusable = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Links that are in an editable region should never be focusable, even if
|
||||
// they are in a contenteditable="false" region.
|
||||
if (IsNodeInEditableRegion(this)) {
|
||||
if (aTabIndex) {
|
||||
*aTabIndex = -1;
|
||||
}
|
||||
|
||||
*aIsFocusable = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!HasAttr(kNameSpaceID_None, nsGkAtoms::tabindex)) {
|
||||
// check whether we're actually a link
|
||||
if (!Link::HasURI()) {
|
||||
// Not tabbable or focusable without href (bug 17605), unless
|
||||
// forced to be via presence of nonnegative tabindex attribute
|
||||
if (aTabIndex) {
|
||||
*aTabIndex = -1;
|
||||
}
|
||||
|
||||
*aIsFocusable = false;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (aTabIndex && (sTabFocusModel & eTabFocus_linksMask) == 0) {
|
||||
*aTabIndex = -1;
|
||||
}
|
||||
|
||||
*aIsFocusable = true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLAnchorElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
{
|
||||
return PreHandleEventForAnchors(aVisitor);
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLAnchorElement::PostHandleEvent(EventChainPostVisitor& aVisitor)
|
||||
{
|
||||
return PostHandleEventForAnchors(aVisitor);
|
||||
}
|
||||
|
||||
bool
|
||||
HTMLAnchorElement::IsLink(nsIURI** aURI) const
|
||||
{
|
||||
return IsHTMLLink(aURI);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLAnchorElement::GetLinkTarget(nsAString& aTarget)
|
||||
{
|
||||
GetAttr(kNameSpaceID_None, nsGkAtoms::target, aTarget);
|
||||
if (aTarget.IsEmpty()) {
|
||||
GetBaseTarget(aTarget);
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLAnchorElement::GetTarget(nsAString& aValue)
|
||||
{
|
||||
if (!GetAttr(kNameSpaceID_None, nsGkAtoms::target, aValue)) {
|
||||
GetBaseTarget(aValue);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLAnchorElement::SetTarget(const nsAString& aValue)
|
||||
{
|
||||
return SetAttr(kNameSpaceID_None, nsGkAtoms::target, aValue, true);
|
||||
}
|
||||
|
||||
nsDOMTokenList*
|
||||
HTMLAnchorElement::RelList()
|
||||
{
|
||||
if (!mRelList) {
|
||||
mRelList = new nsDOMTokenList(this, nsGkAtoms::rel, sSupportedRelValues);
|
||||
}
|
||||
return mRelList;
|
||||
}
|
||||
|
||||
#define IMPL_URI_PART(_part) \
|
||||
NS_IMETHODIMP \
|
||||
HTMLAnchorElement::Get##_part(nsAString& a##_part) \
|
||||
{ \
|
||||
Link::Get##_part(a##_part); \
|
||||
return NS_OK; \
|
||||
} \
|
||||
NS_IMETHODIMP \
|
||||
HTMLAnchorElement::Set##_part(const nsAString& a##_part) \
|
||||
{ \
|
||||
Link::Set##_part(a##_part); \
|
||||
return NS_OK; \
|
||||
}
|
||||
|
||||
IMPL_URI_PART(Protocol)
|
||||
IMPL_URI_PART(Host)
|
||||
IMPL_URI_PART(Hostname)
|
||||
IMPL_URI_PART(Pathname)
|
||||
IMPL_URI_PART(Search)
|
||||
IMPL_URI_PART(Port)
|
||||
IMPL_URI_PART(Hash)
|
||||
|
||||
#undef IMPL_URI_PART
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLAnchorElement::GetText(nsAString& aText)
|
||||
{
|
||||
if(!nsContentUtils::GetNodeTextContent(this, true, aText, fallible)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLAnchorElement::SetText(const nsAString& aText)
|
||||
{
|
||||
return nsContentUtils::SetNodeTextContent(this, aText, false);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLAnchorElement::ToString(nsAString& aSource)
|
||||
{
|
||||
return GetHref(aSource);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLAnchorElement::GetPing(nsAString& aValue)
|
||||
{
|
||||
GetAttr(kNameSpaceID_None, nsGkAtoms::ping, aValue);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLAnchorElement::SetPing(const nsAString& aValue)
|
||||
{
|
||||
return SetAttr(kNameSpaceID_None, nsGkAtoms::ping, aValue, true);
|
||||
}
|
||||
|
||||
already_AddRefed<nsIURI>
|
||||
HTMLAnchorElement::GetHrefURI() const
|
||||
{
|
||||
nsCOMPtr<nsIURI> uri = Link::GetCachedURI();
|
||||
if (uri) {
|
||||
return uri.forget();
|
||||
}
|
||||
|
||||
return GetHrefURIForAnchors();
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLAnchorElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
nsIAtom* aPrefix, const nsAString& aValue,
|
||||
bool aNotify)
|
||||
{
|
||||
bool reset = false;
|
||||
if (aName == nsGkAtoms::href && kNameSpaceID_None == aNameSpaceID) {
|
||||
// If we do not have a cached URI, we have some value here so we must reset
|
||||
// our link state after calling the parent.
|
||||
if (!Link::HasCachedURI()) {
|
||||
reset = true;
|
||||
}
|
||||
// However, if we have a cached URI, we'll want to see if the value changed.
|
||||
else {
|
||||
nsAutoString val;
|
||||
GetHref(val);
|
||||
if (!val.Equals(aValue)) {
|
||||
reset = true;
|
||||
}
|
||||
}
|
||||
if (reset) {
|
||||
CancelDNSPrefetch(HTML_ANCHOR_DNS_PREFETCH_DEFERRED,
|
||||
HTML_ANCHOR_DNS_PREFETCH_REQUESTED);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult rv = nsGenericHTMLElement::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 (reset) {
|
||||
Link::ResetLinkState(!!aNotify, true);
|
||||
if (IsInComposedDoc()) {
|
||||
TryDNSPrefetch();
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLAnchorElement::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
|
||||
bool aNotify)
|
||||
{
|
||||
bool href =
|
||||
(aAttribute == nsGkAtoms::href && kNameSpaceID_None == aNameSpaceID);
|
||||
|
||||
if (href) {
|
||||
CancelDNSPrefetch(HTML_ANCHOR_DNS_PREFETCH_DEFERRED,
|
||||
HTML_ANCHOR_DNS_PREFETCH_REQUESTED);
|
||||
}
|
||||
|
||||
nsresult rv = nsGenericHTMLElement::UnsetAttr(aNameSpaceID, aAttribute,
|
||||
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 (href) {
|
||||
Link::ResetLinkState(!!aNotify, false);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
bool
|
||||
HTMLAnchorElement::ParseAttribute(int32_t aNamespaceID,
|
||||
nsIAtom* aAttribute,
|
||||
const nsAString& aValue,
|
||||
nsAttrValue& aResult)
|
||||
{
|
||||
return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
|
||||
aResult);
|
||||
}
|
||||
|
||||
EventStates
|
||||
HTMLAnchorElement::IntrinsicState() const
|
||||
{
|
||||
return Link::LinkState() | nsGenericHTMLElement::IntrinsicState();
|
||||
}
|
||||
|
||||
size_t
|
||||
HTMLAnchorElement::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
|
||||
{
|
||||
return nsGenericHTMLElement::SizeOfExcludingThis(aMallocSizeOf) +
|
||||
Link::SizeOfExcludingThis(aMallocSizeOf);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
242
dom/html/HTMLAnchorElement.h
Normal file
242
dom/html/HTMLAnchorElement.h
Normal file
|
|
@ -0,0 +1,242 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_dom_HTMLAnchorElement_h
|
||||
#define mozilla_dom_HTMLAnchorElement_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/dom/Link.h"
|
||||
#include "nsGenericHTMLElement.h"
|
||||
#include "nsIDOMHTMLAnchorElement.h"
|
||||
#include "nsDOMTokenList.h"
|
||||
|
||||
namespace mozilla {
|
||||
class EventChainPostVisitor;
|
||||
class EventChainPreVisitor;
|
||||
namespace dom {
|
||||
|
||||
class HTMLAnchorElement final : public nsGenericHTMLElement,
|
||||
public nsIDOMHTMLAnchorElement,
|
||||
public Link
|
||||
{
|
||||
public:
|
||||
using Element::GetText;
|
||||
using Element::SetText;
|
||||
|
||||
explicit HTMLAnchorElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
|
||||
: nsGenericHTMLElement(aNodeInfo)
|
||||
, Link(this)
|
||||
{
|
||||
}
|
||||
|
||||
// nsISupports
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
// CC
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLAnchorElement,
|
||||
nsGenericHTMLElement)
|
||||
|
||||
virtual int32_t TabIndexDefault() override;
|
||||
virtual bool Draggable() const override;
|
||||
|
||||
// Element
|
||||
virtual bool IsInteractiveHTMLContent(bool aIgnoreTabindex) const override;
|
||||
|
||||
// nsIDOMHTMLAnchorElement
|
||||
NS_DECL_NSIDOMHTMLANCHORELEMENT
|
||||
|
||||
// DOM memory reporter participant
|
||||
NS_DECL_SIZEOF_EXCLUDING_THIS
|
||||
|
||||
virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
||||
nsIContent* aBindingParent,
|
||||
bool aCompileEventHandlers) override;
|
||||
virtual void UnbindFromTree(bool aDeep = true,
|
||||
bool aNullParent = true) override;
|
||||
virtual bool IsHTMLFocusable(bool aWithMouse, bool *aIsFocusable, int32_t *aTabIndex) override;
|
||||
|
||||
virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override;
|
||||
virtual nsresult PostHandleEvent(
|
||||
EventChainPostVisitor& aVisitor) override;
|
||||
virtual bool IsLink(nsIURI** aURI) const override;
|
||||
virtual void GetLinkTarget(nsAString& aTarget) override;
|
||||
virtual already_AddRefed<nsIURI> GetHrefURI() const override;
|
||||
|
||||
nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
const nsAString& aValue, bool aNotify)
|
||||
{
|
||||
return SetAttr(aNameSpaceID, aName, nullptr, aValue, aNotify);
|
||||
}
|
||||
virtual nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
nsIAtom* aPrefix, const nsAString& aValue,
|
||||
bool aNotify) override;
|
||||
virtual nsresult UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
|
||||
bool aNotify) override;
|
||||
virtual bool ParseAttribute(int32_t aNamespaceID,
|
||||
nsIAtom* aAttribute,
|
||||
const nsAString& aValue,
|
||||
nsAttrValue& aResult) override;
|
||||
|
||||
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
|
||||
|
||||
virtual EventStates IntrinsicState() const override;
|
||||
|
||||
virtual void OnDNSPrefetchDeferred() override;
|
||||
virtual void OnDNSPrefetchRequested() override;
|
||||
virtual bool HasDeferredDNSPrefetchRequest() override;
|
||||
|
||||
// WebIDL API
|
||||
|
||||
// The XPCOM GetHref is OK for us
|
||||
void SetHref(const nsAString& aValue, mozilla::ErrorResult& rv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::href, aValue, rv);
|
||||
}
|
||||
// The XPCOM GetTarget is OK for us
|
||||
void SetTarget(const nsAString& aValue, mozilla::ErrorResult& rv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::target, aValue, rv);
|
||||
}
|
||||
void GetDownload(DOMString& aValue)
|
||||
{
|
||||
GetHTMLAttr(nsGkAtoms::download, aValue);
|
||||
}
|
||||
void SetDownload(const nsAString& aValue, mozilla::ErrorResult& rv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::download, aValue, rv);
|
||||
}
|
||||
// The XPCOM GetPing is OK for us
|
||||
void SetPing(const nsAString& aValue, mozilla::ErrorResult& rv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::ping, aValue, rv);
|
||||
}
|
||||
void GetRel(DOMString& aValue)
|
||||
{
|
||||
GetHTMLAttr(nsGkAtoms::rel, aValue);
|
||||
}
|
||||
void SetRel(const nsAString& aValue, mozilla::ErrorResult& rv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::rel, aValue, rv);
|
||||
}
|
||||
void SetReferrerPolicy(const nsAString& aValue, mozilla::ErrorResult& rv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::referrerpolicy, aValue, rv);
|
||||
}
|
||||
void GetReferrerPolicy(nsAString& aReferrer)
|
||||
{
|
||||
GetEnumAttr(nsGkAtoms::referrerpolicy, EmptyCString().get(), aReferrer);
|
||||
}
|
||||
nsDOMTokenList* RelList();
|
||||
void GetHreflang(DOMString& aValue)
|
||||
{
|
||||
GetHTMLAttr(nsGkAtoms::hreflang, aValue);
|
||||
}
|
||||
void SetHreflang(const nsAString& aValue, mozilla::ErrorResult& rv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::hreflang, aValue, rv);
|
||||
}
|
||||
void GetType(DOMString& aValue)
|
||||
{
|
||||
GetHTMLAttr(nsGkAtoms::type, aValue);
|
||||
}
|
||||
void SetType(const nsAString& aValue, mozilla::ErrorResult& rv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::type, aValue, rv);
|
||||
}
|
||||
// The XPCOM GetText is OK for us
|
||||
void SetText(const nsAString& aValue, mozilla::ErrorResult& rv)
|
||||
{
|
||||
rv = SetText(aValue);
|
||||
}
|
||||
|
||||
// Link::GetOrigin is OK for us
|
||||
|
||||
// Link::GetProtocol is OK for us
|
||||
// Link::SetProtocol is OK for us
|
||||
|
||||
// Link::GetUsername is OK for us
|
||||
// Link::SetUsername is OK for us
|
||||
|
||||
// Link::GetPassword is OK for us
|
||||
// Link::SetPassword is OK for us
|
||||
|
||||
// Link::Link::GetHost is OK for us
|
||||
// Link::Link::SetHost is OK for us
|
||||
|
||||
// Link::Link::GetHostname is OK for us
|
||||
// Link::Link::SetHostname is OK for us
|
||||
|
||||
// Link::Link::GetPort is OK for us
|
||||
// Link::Link::SetPort is OK for us
|
||||
|
||||
// Link::Link::GetPathname is OK for us
|
||||
// Link::Link::SetPathname is OK for us
|
||||
|
||||
// Link::Link::GetSearch is OK for us
|
||||
// Link::Link::SetSearch is OK for us
|
||||
|
||||
// Link::Link::GetHash is OK for us
|
||||
// Link::Link::SetHash is OK for us
|
||||
|
||||
// The XPCOM URI decomposition attributes are fine for us
|
||||
void GetCoords(DOMString& aValue)
|
||||
{
|
||||
GetHTMLAttr(nsGkAtoms::coords, aValue);
|
||||
}
|
||||
void SetCoords(const nsAString& aValue, mozilla::ErrorResult& rv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::coords, aValue, rv);
|
||||
}
|
||||
void GetCharset(DOMString& aValue)
|
||||
{
|
||||
GetHTMLAttr(nsGkAtoms::charset, aValue);
|
||||
}
|
||||
void SetCharset(const nsAString& aValue, mozilla::ErrorResult& rv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::charset, aValue, rv);
|
||||
}
|
||||
void GetName(DOMString& aValue)
|
||||
{
|
||||
GetHTMLAttr(nsGkAtoms::name, aValue);
|
||||
}
|
||||
void SetName(const nsAString& aValue, mozilla::ErrorResult& rv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::name, aValue, rv);
|
||||
}
|
||||
void GetRev(DOMString& aValue)
|
||||
{
|
||||
GetHTMLAttr(nsGkAtoms::rev, aValue);
|
||||
}
|
||||
void SetRev(const nsAString& aValue, mozilla::ErrorResult& rv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::rev, aValue, rv);
|
||||
}
|
||||
void GetShape(DOMString& aValue)
|
||||
{
|
||||
GetHTMLAttr(nsGkAtoms::shape, aValue);
|
||||
}
|
||||
void SetShape(const nsAString& aValue, mozilla::ErrorResult& rv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::shape, aValue, rv);
|
||||
}
|
||||
void Stringify(nsAString& aResult)
|
||||
{
|
||||
GetHref(aResult);
|
||||
}
|
||||
|
||||
static DOMTokenListSupportedToken sSupportedRelValues[];
|
||||
|
||||
protected:
|
||||
virtual ~HTMLAnchorElement();
|
||||
|
||||
virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
RefPtr<nsDOMTokenList > mRelList;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_HTMLAnchorElement_h
|
||||
263
dom/html/HTMLAreaElement.cpp
Normal file
263
dom/html/HTMLAreaElement.cpp
Normal file
|
|
@ -0,0 +1,263 @@
|
|||
/* -*- 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/HTMLAreaElement.h"
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/dom/HTMLAnchorElement.h"
|
||||
#include "mozilla/dom/HTMLAreaElementBinding.h"
|
||||
#include "mozilla/EventDispatcher.h"
|
||||
#include "mozilla/EventStates.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
|
||||
NS_IMPL_NS_NEW_HTML_ELEMENT(Area)
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
HTMLAreaElement::HTMLAreaElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
|
||||
: nsGenericHTMLElement(aNodeInfo)
|
||||
, Link(this)
|
||||
{
|
||||
}
|
||||
|
||||
HTMLAreaElement::~HTMLAreaElement()
|
||||
{
|
||||
}
|
||||
|
||||
NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(HTMLAreaElement)
|
||||
NS_INTERFACE_TABLE_INHERITED(HTMLAreaElement,
|
||||
nsIDOMHTMLAreaElement,
|
||||
Link)
|
||||
NS_INTERFACE_TABLE_TAIL_INHERITING(nsGenericHTMLElement)
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(HTMLAreaElement, Element)
|
||||
NS_IMPL_RELEASE_INHERITED(HTMLAreaElement, Element)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(HTMLAreaElement)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLAreaElement,
|
||||
nsGenericHTMLElement)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRelList)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLAreaElement,
|
||||
nsGenericHTMLElement)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mRelList)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_IMPL_ELEMENT_CLONE(HTMLAreaElement)
|
||||
|
||||
|
||||
NS_IMPL_STRING_ATTR(HTMLAreaElement, Alt, alt)
|
||||
NS_IMPL_STRING_ATTR(HTMLAreaElement, Coords, coords)
|
||||
NS_IMPL_URI_ATTR(HTMLAreaElement, Href, href)
|
||||
NS_IMPL_BOOL_ATTR(HTMLAreaElement, NoHref, nohref)
|
||||
NS_IMPL_STRING_ATTR(HTMLAreaElement, Shape, shape)
|
||||
NS_IMPL_STRING_ATTR(HTMLAreaElement, Download, download)
|
||||
|
||||
int32_t
|
||||
HTMLAreaElement::TabIndexDefault()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLAreaElement::GetTarget(nsAString& aValue)
|
||||
{
|
||||
if (!GetAttr(kNameSpaceID_None, nsGkAtoms::target, aValue)) {
|
||||
GetBaseTarget(aValue);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLAreaElement::SetTarget(const nsAString& aValue)
|
||||
{
|
||||
return SetAttr(kNameSpaceID_None, nsGkAtoms::target, aValue, true);
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLAreaElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
{
|
||||
return PreHandleEventForAnchors(aVisitor);
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLAreaElement::PostHandleEvent(EventChainPostVisitor& aVisitor)
|
||||
{
|
||||
return PostHandleEventForAnchors(aVisitor);
|
||||
}
|
||||
|
||||
bool
|
||||
HTMLAreaElement::IsLink(nsIURI** aURI) const
|
||||
{
|
||||
return IsHTMLLink(aURI);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLAreaElement::GetLinkTarget(nsAString& aTarget)
|
||||
{
|
||||
GetAttr(kNameSpaceID_None, nsGkAtoms::target, aTarget);
|
||||
if (aTarget.IsEmpty()) {
|
||||
GetBaseTarget(aTarget);
|
||||
}
|
||||
}
|
||||
|
||||
nsDOMTokenList*
|
||||
HTMLAreaElement::RelList()
|
||||
{
|
||||
if (!mRelList) {
|
||||
mRelList = new nsDOMTokenList(this, nsGkAtoms::rel,
|
||||
HTMLAnchorElement::sSupportedRelValues);
|
||||
}
|
||||
return mRelList;
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLAreaElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
||||
nsIContent* aBindingParent,
|
||||
bool aCompileEventHandlers)
|
||||
{
|
||||
Link::ResetLinkState(false, Link::ElementHasHref());
|
||||
nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent,
|
||||
aBindingParent,
|
||||
aCompileEventHandlers);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsIDocument* doc = GetComposedDoc();
|
||||
if (doc) {
|
||||
doc->RegisterPendingLinkUpdate(this);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
void
|
||||
HTMLAreaElement::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() might
|
||||
// return null.
|
||||
nsIDocument* doc = OwnerDoc();
|
||||
if (doc) {
|
||||
doc->UnregisterPendingLinkUpdate(this);
|
||||
}
|
||||
|
||||
nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLAreaElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
nsIAtom* aPrefix, const nsAString& aValue,
|
||||
bool aNotify)
|
||||
{
|
||||
nsresult rv =
|
||||
nsGenericHTMLElement::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_None) {
|
||||
Link::ResetLinkState(!!aNotify, true);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLAreaElement::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
|
||||
bool aNotify)
|
||||
{
|
||||
nsresult rv = nsGenericHTMLElement::UnsetAttr(aNameSpaceID, aAttribute,
|
||||
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 (aAttribute == nsGkAtoms::href && kNameSpaceID_None == aNameSpaceID) {
|
||||
Link::ResetLinkState(!!aNotify, false);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
#define IMPL_URI_PART(_part) \
|
||||
NS_IMETHODIMP \
|
||||
HTMLAreaElement::Get##_part(nsAString& a##_part) \
|
||||
{ \
|
||||
Link::Get##_part(a##_part); \
|
||||
return NS_OK; \
|
||||
} \
|
||||
NS_IMETHODIMP \
|
||||
HTMLAreaElement::Set##_part(const nsAString& a##_part) \
|
||||
{ \
|
||||
Link::Set##_part(a##_part); \
|
||||
return NS_OK; \
|
||||
}
|
||||
|
||||
IMPL_URI_PART(Protocol)
|
||||
IMPL_URI_PART(Host)
|
||||
IMPL_URI_PART(Hostname)
|
||||
IMPL_URI_PART(Pathname)
|
||||
IMPL_URI_PART(Search)
|
||||
IMPL_URI_PART(Port)
|
||||
IMPL_URI_PART(Hash)
|
||||
|
||||
#undef IMPL_URI_PART
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLAreaElement::ToString(nsAString& aSource)
|
||||
{
|
||||
return GetHref(aSource);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLAreaElement::GetPing(nsAString& aValue)
|
||||
{
|
||||
GetAttr(kNameSpaceID_None, nsGkAtoms::ping, aValue);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLAreaElement::SetPing(const nsAString& aValue)
|
||||
{
|
||||
return SetAttr(kNameSpaceID_None, nsGkAtoms::ping, aValue, true);
|
||||
}
|
||||
|
||||
already_AddRefed<nsIURI>
|
||||
HTMLAreaElement::GetHrefURI() const
|
||||
{
|
||||
return GetHrefURIForAnchors();
|
||||
}
|
||||
|
||||
EventStates
|
||||
HTMLAreaElement::IntrinsicState() const
|
||||
{
|
||||
return Link::LinkState() | nsGenericHTMLElement::IntrinsicState();
|
||||
}
|
||||
|
||||
size_t
|
||||
HTMLAreaElement::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
|
||||
{
|
||||
return nsGenericHTMLElement::SizeOfExcludingThis(aMallocSizeOf) +
|
||||
Link::SizeOfExcludingThis(aMallocSizeOf);
|
||||
}
|
||||
|
||||
JSObject*
|
||||
HTMLAreaElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return HTMLAreaElementBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
194
dom/html/HTMLAreaElement.h
Normal file
194
dom/html/HTMLAreaElement.h
Normal file
|
|
@ -0,0 +1,194 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_dom_HTMLAreaElement_h
|
||||
#define mozilla_dom_HTMLAreaElement_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/dom/Link.h"
|
||||
#include "nsGenericHTMLElement.h"
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsDOMTokenList.h"
|
||||
#include "nsIDOMHTMLAreaElement.h"
|
||||
#include "nsIURL.h"
|
||||
|
||||
class nsIDocument;
|
||||
|
||||
namespace mozilla {
|
||||
class EventChainPostVisitor;
|
||||
class EventChainPreVisitor;
|
||||
namespace dom {
|
||||
|
||||
class HTMLAreaElement final : public nsGenericHTMLElement,
|
||||
public nsIDOMHTMLAreaElement,
|
||||
public Link
|
||||
{
|
||||
public:
|
||||
explicit HTMLAreaElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
|
||||
|
||||
// nsISupports
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
// CC
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLAreaElement,
|
||||
nsGenericHTMLElement)
|
||||
|
||||
// DOM memory reporter participant
|
||||
NS_DECL_SIZEOF_EXCLUDING_THIS
|
||||
|
||||
virtual int32_t TabIndexDefault() override;
|
||||
|
||||
// nsIDOMHTMLAreaElement
|
||||
NS_DECL_NSIDOMHTMLAREAELEMENT
|
||||
|
||||
virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override;
|
||||
virtual nsresult PostHandleEvent(EventChainPostVisitor& aVisitor) override;
|
||||
virtual bool IsLink(nsIURI** aURI) const override;
|
||||
virtual void GetLinkTarget(nsAString& aTarget) override;
|
||||
virtual already_AddRefed<nsIURI> GetHrefURI() const override;
|
||||
|
||||
virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
||||
nsIContent* aBindingParent,
|
||||
bool aCompileEventHandlers) override;
|
||||
virtual void UnbindFromTree(bool aDeep = true,
|
||||
bool aNullParent = true) override;
|
||||
nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
const nsAString& aValue, bool aNotify)
|
||||
{
|
||||
return SetAttr(aNameSpaceID, aName, nullptr, aValue, aNotify);
|
||||
}
|
||||
virtual nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
nsIAtom* aPrefix, const nsAString& aValue,
|
||||
bool aNotify) override;
|
||||
virtual nsresult UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
|
||||
bool aNotify) override;
|
||||
|
||||
virtual nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult) const override;
|
||||
|
||||
virtual EventStates IntrinsicState() const override;
|
||||
|
||||
// WebIDL
|
||||
|
||||
// The XPCOM GetAlt is OK for us
|
||||
void SetAlt(const nsAString& aAlt, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::alt, aAlt, aError);
|
||||
}
|
||||
|
||||
// The XPCOM GetCoords is OK for us
|
||||
void SetCoords(const nsAString& aCoords, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::coords, aCoords, aError);
|
||||
}
|
||||
|
||||
// The XPCOM GetShape is OK for us
|
||||
void SetShape(const nsAString& aShape, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::shape, aShape, aError);
|
||||
}
|
||||
|
||||
// The XPCOM GetHref is OK for us
|
||||
void SetHref(const nsAString& aHref, ErrorResult& aError)
|
||||
{
|
||||
aError = SetHref(aHref);
|
||||
}
|
||||
|
||||
// The XPCOM GetTarget is OK for us
|
||||
void SetTarget(const nsAString& aTarget, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::target, aTarget, aError);
|
||||
}
|
||||
|
||||
// The XPCOM GetDownload is OK for us
|
||||
void SetDownload(const nsAString& aDownload, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::download, aDownload, aError);
|
||||
}
|
||||
|
||||
// The XPCOM GetPing is OK for us
|
||||
void SetPing(const nsAString& aPing, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::ping, aPing, aError);
|
||||
}
|
||||
|
||||
void GetRel(DOMString& aValue)
|
||||
{
|
||||
GetHTMLAttr(nsGkAtoms::rel, aValue);
|
||||
}
|
||||
|
||||
void SetRel(const nsAString& aRel, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::rel, aRel, aError);
|
||||
}
|
||||
nsDOMTokenList* RelList();
|
||||
|
||||
void SetReferrerPolicy(const nsAString& aValue, mozilla::ErrorResult& rv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::referrerpolicy, aValue, rv);
|
||||
}
|
||||
void GetReferrerPolicy(nsAString& aReferrer)
|
||||
{
|
||||
GetEnumAttr(nsGkAtoms::referrerpolicy, EmptyCString().get(), aReferrer);
|
||||
}
|
||||
|
||||
// The Link::GetOrigin is OK for us
|
||||
|
||||
// Link::Link::GetProtocol is OK for us
|
||||
// Link::Link::SetProtocol is OK for us
|
||||
|
||||
// The Link::GetUsername is OK for us
|
||||
// The Link::SetUsername is OK for us
|
||||
|
||||
// The Link::GetPassword is OK for us
|
||||
// The Link::SetPassword is OK for us
|
||||
|
||||
// Link::Link::GetHost is OK for us
|
||||
// Link::Link::SetHost is OK for us
|
||||
|
||||
// Link::Link::GetHostname is OK for us
|
||||
// Link::Link::SetHostname is OK for us
|
||||
|
||||
// Link::Link::GetPort is OK for us
|
||||
// Link::Link::SetPort is OK for us
|
||||
|
||||
// Link::Link::GetPathname is OK for us
|
||||
// Link::Link::SetPathname is OK for us
|
||||
|
||||
// Link::Link::GetSearch is OK for us
|
||||
// Link::Link::SetSearch is OK for us
|
||||
|
||||
// Link::Link::GetHash is OK for us
|
||||
// Link::Link::SetHash is OK for us
|
||||
|
||||
// The Link::GetSearchParams is OK for us
|
||||
|
||||
bool NoHref() const
|
||||
{
|
||||
return GetBoolAttr(nsGkAtoms::nohref);
|
||||
}
|
||||
|
||||
void SetNoHref(bool aValue, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLBoolAttr(nsGkAtoms::nohref, aValue, aError);
|
||||
}
|
||||
|
||||
void Stringify(nsAString& aResult)
|
||||
{
|
||||
GetHref(aResult);
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual ~HTMLAreaElement();
|
||||
|
||||
virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
RefPtr<nsDOMTokenList > mRelList;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* mozilla_dom_HTMLAreaElement_h */
|
||||
98
dom/html/HTMLAudioElement.cpp
Normal file
98
dom/html/HTMLAudioElement.cpp
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
/* -*- 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/HTMLAudioElement.h"
|
||||
#include "mozilla/dom/HTMLAudioElementBinding.h"
|
||||
#include "nsError.h"
|
||||
#include "nsGenericHTMLElement.h"
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "jsfriendapi.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsJSUtils.h"
|
||||
#include "AudioSampleFormat.h"
|
||||
#include <algorithm>
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsIHttpChannel.h"
|
||||
#include "mozilla/dom/TimeRanges.h"
|
||||
#include "AudioStream.h"
|
||||
|
||||
NS_IMPL_NS_NEW_HTML_ELEMENT(Audio)
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
NS_IMPL_ELEMENT_CLONE(HTMLAudioElement)
|
||||
|
||||
HTMLAudioElement::HTMLAudioElement(already_AddRefed<NodeInfo>& aNodeInfo)
|
||||
: HTMLMediaElement(aNodeInfo)
|
||||
{
|
||||
}
|
||||
|
||||
HTMLAudioElement::~HTMLAudioElement()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
HTMLAudioElement::IsInteractiveHTMLContent(bool aIgnoreTabindex) const
|
||||
{
|
||||
return HasAttr(kNameSpaceID_None, nsGkAtoms::controls) ||
|
||||
HTMLMediaElement::IsInteractiveHTMLContent(aIgnoreTabindex);
|
||||
}
|
||||
|
||||
already_AddRefed<HTMLAudioElement>
|
||||
HTMLAudioElement::Audio(const GlobalObject& aGlobal,
|
||||
const Optional<nsAString>& aSrc,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindowInner> win = do_QueryInterface(aGlobal.GetAsSupports());
|
||||
nsIDocument* doc;
|
||||
if (!win || !(doc = win->GetExtantDoc())) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
already_AddRefed<mozilla::dom::NodeInfo> nodeInfo =
|
||||
doc->NodeInfoManager()->GetNodeInfo(nsGkAtoms::audio, nullptr,
|
||||
kNameSpaceID_XHTML,
|
||||
nsIDOMNode::ELEMENT_NODE);
|
||||
|
||||
RefPtr<HTMLAudioElement> audio = new HTMLAudioElement(nodeInfo);
|
||||
audio->SetHTMLAttr(nsGkAtoms::preload, NS_LITERAL_STRING("auto"), aRv);
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (aSrc.WasPassed()) {
|
||||
aRv = audio->SetSrc(aSrc.Value());
|
||||
}
|
||||
|
||||
return audio.forget();
|
||||
}
|
||||
|
||||
nsresult HTMLAudioElement::SetAcceptHeader(nsIHttpChannel* aChannel)
|
||||
{
|
||||
nsAutoCString value(
|
||||
"audio/webm,"
|
||||
"audio/ogg,"
|
||||
"audio/wav,"
|
||||
"audio/*;q=0.9,"
|
||||
"application/ogg;q=0.7,"
|
||||
"video/*;q=0.6,*/*;q=0.5");
|
||||
|
||||
return aChannel->SetRequestHeader(NS_LITERAL_CSTRING("Accept"),
|
||||
value,
|
||||
false);
|
||||
}
|
||||
|
||||
JSObject*
|
||||
HTMLAudioElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return HTMLAudioElementBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
52
dom/html/HTMLAudioElement.h
Normal file
52
dom/html/HTMLAudioElement.h
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/* -*- 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/. */
|
||||
#ifndef mozilla_dom_HTMLAudioElement_h
|
||||
#define mozilla_dom_HTMLAudioElement_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/dom/HTMLMediaElement.h"
|
||||
#include "mozilla/dom/TypedArray.h"
|
||||
|
||||
typedef uint16_t nsMediaNetworkState;
|
||||
typedef uint16_t nsMediaReadyState;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class HTMLAudioElement final : public HTMLMediaElement
|
||||
{
|
||||
public:
|
||||
typedef mozilla::dom::NodeInfo NodeInfo;
|
||||
|
||||
explicit HTMLAudioElement(already_AddRefed<NodeInfo>& aNodeInfo);
|
||||
|
||||
// Element
|
||||
virtual bool IsInteractiveHTMLContent(bool aIgnoreTabindex) const override;
|
||||
|
||||
// nsIDOMHTMLMediaElement
|
||||
using HTMLMediaElement::GetPaused;
|
||||
|
||||
virtual nsresult Clone(NodeInfo *aNodeInfo, nsINode **aResult) const override;
|
||||
virtual nsresult SetAcceptHeader(nsIHttpChannel* aChannel) override;
|
||||
|
||||
virtual nsIDOMNode* AsDOMNode() override { return this; }
|
||||
|
||||
// WebIDL
|
||||
|
||||
static already_AddRefed<HTMLAudioElement>
|
||||
Audio(const GlobalObject& aGlobal,
|
||||
const Optional<nsAString>& aSrc, ErrorResult& aRv);
|
||||
|
||||
protected:
|
||||
virtual ~HTMLAudioElement();
|
||||
|
||||
virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_HTMLAudioElement_h
|
||||
99
dom/html/HTMLBRElement.cpp
Normal file
99
dom/html/HTMLBRElement.cpp
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
/* -*- 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/HTMLBRElement.h"
|
||||
#include "mozilla/dom/HTMLBRElementBinding.h"
|
||||
|
||||
#include "nsAttrValueInlines.h"
|
||||
#include "nsStyleConsts.h"
|
||||
#include "nsMappedAttributes.h"
|
||||
#include "nsRuleData.h"
|
||||
|
||||
|
||||
NS_IMPL_NS_NEW_HTML_ELEMENT(BR)
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
HTMLBRElement::HTMLBRElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
|
||||
: nsGenericHTMLElement(aNodeInfo)
|
||||
{
|
||||
}
|
||||
|
||||
HTMLBRElement::~HTMLBRElement()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMPL_ELEMENT_CLONE(HTMLBRElement)
|
||||
|
||||
static const nsAttrValue::EnumTable kClearTable[] = {
|
||||
{ "left", StyleClear::Left },
|
||||
{ "right", StyleClear::Right },
|
||||
{ "all", StyleClear::Both },
|
||||
{ "both", StyleClear::Both },
|
||||
{ nullptr, 0 }
|
||||
};
|
||||
|
||||
bool
|
||||
HTMLBRElement::ParseAttribute(int32_t aNamespaceID,
|
||||
nsIAtom* aAttribute,
|
||||
const nsAString& aValue,
|
||||
nsAttrValue& aResult)
|
||||
{
|
||||
if (aAttribute == nsGkAtoms::clear && aNamespaceID == kNameSpaceID_None) {
|
||||
return aResult.ParseEnumValue(aValue, kClearTable, false);
|
||||
}
|
||||
|
||||
return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
|
||||
aResult);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLBRElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
|
||||
nsRuleData* aData)
|
||||
{
|
||||
if (aData->mSIDs & NS_STYLE_INHERIT_BIT(Display)) {
|
||||
nsCSSValue* clear = aData->ValueForClear();
|
||||
if (clear->GetUnit() == eCSSUnit_Null) {
|
||||
const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::clear);
|
||||
if (value && value->Type() == nsAttrValue::eEnum)
|
||||
clear->SetIntValue(value->GetEnumValue(), eCSSUnit_Enumerated);
|
||||
}
|
||||
}
|
||||
|
||||
nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aData);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(bool)
|
||||
HTMLBRElement::IsAttributeMapped(const nsIAtom* aAttribute) const
|
||||
{
|
||||
static const MappedAttributeEntry attributes[] = {
|
||||
{ &nsGkAtoms::clear },
|
||||
{ nullptr }
|
||||
};
|
||||
|
||||
static const MappedAttributeEntry* const map[] = {
|
||||
attributes,
|
||||
sCommonAttributeMap,
|
||||
};
|
||||
|
||||
return FindAttributeDependence(aAttribute, map);
|
||||
}
|
||||
|
||||
nsMapRuleToAttributesFunc
|
||||
HTMLBRElement::GetAttributeMappingFunction() const
|
||||
{
|
||||
return &MapAttributesIntoRule;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
HTMLBRElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return HTMLBRElementBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
56
dom/html/HTMLBRElement.h
Normal file
56
dom/html/HTMLBRElement.h
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_dom_HTMLBRElement_h
|
||||
#define mozilla_dom_HTMLBRElement_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsGenericHTMLElement.h"
|
||||
#include "nsGkAtoms.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class HTMLBRElement final : public nsGenericHTMLElement
|
||||
{
|
||||
public:
|
||||
explicit HTMLBRElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
|
||||
|
||||
virtual bool ParseAttribute(int32_t aNamespaceID,
|
||||
nsIAtom* aAttribute,
|
||||
const nsAString& aValue,
|
||||
nsAttrValue& aResult) override;
|
||||
NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
|
||||
virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const override;
|
||||
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
|
||||
|
||||
bool Clear()
|
||||
{
|
||||
return GetBoolAttr(nsGkAtoms::clear);
|
||||
}
|
||||
void SetClear(const nsAString& aClear, ErrorResult& aError)
|
||||
{
|
||||
return SetHTMLAttr(nsGkAtoms::clear, aClear, aError);
|
||||
}
|
||||
void GetClear(DOMString& aClear) const
|
||||
{
|
||||
return GetHTMLAttr(nsGkAtoms::clear, aClear);
|
||||
}
|
||||
|
||||
virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
private:
|
||||
virtual ~HTMLBRElement();
|
||||
|
||||
static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
|
||||
nsRuleData* aData);
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
|
||||
530
dom/html/HTMLBodyElement.cpp
Normal file
530
dom/html/HTMLBodyElement.cpp
Normal file
|
|
@ -0,0 +1,530 @@
|
|||
/* -*- 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 "HTMLBodyElement.h"
|
||||
#include "mozilla/dom/HTMLBodyElementBinding.h"
|
||||
#include "nsAttrValueInlines.h"
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsStyleConsts.h"
|
||||
#include "nsPresContext.h"
|
||||
#include "nsIPresShell.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsHTMLStyleSheet.h"
|
||||
#include "nsIEditor.h"
|
||||
#include "nsMappedAttributes.h"
|
||||
#include "nsRuleData.h"
|
||||
#include "nsIDocShell.h"
|
||||
#include "nsRuleWalker.h"
|
||||
#include "nsGlobalWindow.h"
|
||||
|
||||
NS_IMPL_NS_NEW_HTML_ELEMENT(Body)
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
BodyRule::BodyRule(HTMLBodyElement* aPart)
|
||||
: mPart(aPart)
|
||||
{
|
||||
}
|
||||
|
||||
BodyRule::~BodyRule()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(BodyRule, nsIStyleRule)
|
||||
|
||||
/* virtual */ void
|
||||
BodyRule::MapRuleInfoInto(nsRuleData* aData)
|
||||
{
|
||||
if (!(aData->mSIDs & NS_STYLE_INHERIT_BIT(Margin)) || !mPart)
|
||||
return; // We only care about margins.
|
||||
|
||||
int32_t bodyMarginWidth = -1;
|
||||
int32_t bodyMarginHeight = -1;
|
||||
int32_t bodyTopMargin = -1;
|
||||
int32_t bodyBottomMargin = -1;
|
||||
int32_t bodyLeftMargin = -1;
|
||||
int32_t bodyRightMargin = -1;
|
||||
|
||||
// check the mode (fortunately, the ruleData has a presContext for us to use!)
|
||||
NS_ASSERTION(aData->mPresContext, "null presContext in ruleNode was unexpected");
|
||||
nsCompatibility mode = aData->mPresContext->CompatibilityMode();
|
||||
|
||||
|
||||
const nsAttrValue* value;
|
||||
if (mPart->GetAttrCount() > 0) {
|
||||
// if marginwidth/marginheight are set, reflect them as 'margin'
|
||||
value = mPart->GetParsedAttr(nsGkAtoms::marginwidth);
|
||||
if (value && value->Type() == nsAttrValue::eInteger) {
|
||||
bodyMarginWidth = value->GetIntegerValue();
|
||||
if (bodyMarginWidth < 0) bodyMarginWidth = 0;
|
||||
nsCSSValue* marginLeft = aData->ValueForMarginLeft();
|
||||
if (marginLeft->GetUnit() == eCSSUnit_Null)
|
||||
marginLeft->SetFloatValue((float)bodyMarginWidth, eCSSUnit_Pixel);
|
||||
nsCSSValue* marginRight = aData->ValueForMarginRight();
|
||||
if (marginRight->GetUnit() == eCSSUnit_Null)
|
||||
marginRight->SetFloatValue((float)bodyMarginWidth, eCSSUnit_Pixel);
|
||||
}
|
||||
|
||||
value = mPart->GetParsedAttr(nsGkAtoms::marginheight);
|
||||
if (value && value->Type() == nsAttrValue::eInteger) {
|
||||
bodyMarginHeight = value->GetIntegerValue();
|
||||
if (bodyMarginHeight < 0) bodyMarginHeight = 0;
|
||||
nsCSSValue* marginTop = aData->ValueForMarginTop();
|
||||
if (marginTop->GetUnit() == eCSSUnit_Null)
|
||||
marginTop->SetFloatValue((float)bodyMarginHeight, eCSSUnit_Pixel);
|
||||
nsCSSValue* marginBottom = aData->ValueForMarginBottom();
|
||||
if (marginBottom->GetUnit() == eCSSUnit_Null)
|
||||
marginBottom->SetFloatValue((float)bodyMarginHeight, eCSSUnit_Pixel);
|
||||
}
|
||||
|
||||
// topmargin (IE-attribute)
|
||||
value = mPart->GetParsedAttr(nsGkAtoms::topmargin);
|
||||
if (value && value->Type() == nsAttrValue::eInteger) {
|
||||
bodyTopMargin = value->GetIntegerValue();
|
||||
if (bodyTopMargin < 0) bodyTopMargin = 0;
|
||||
nsCSSValue* marginTop = aData->ValueForMarginTop();
|
||||
if (marginTop->GetUnit() == eCSSUnit_Null)
|
||||
marginTop->SetFloatValue((float)bodyTopMargin, eCSSUnit_Pixel);
|
||||
}
|
||||
|
||||
// bottommargin (IE-attribute)
|
||||
value = mPart->GetParsedAttr(nsGkAtoms::bottommargin);
|
||||
if (value && value->Type() == nsAttrValue::eInteger) {
|
||||
bodyBottomMargin = value->GetIntegerValue();
|
||||
if (bodyBottomMargin < 0) bodyBottomMargin = 0;
|
||||
nsCSSValue* marginBottom = aData->ValueForMarginBottom();
|
||||
if (marginBottom->GetUnit() == eCSSUnit_Null)
|
||||
marginBottom->SetFloatValue((float)bodyBottomMargin, eCSSUnit_Pixel);
|
||||
}
|
||||
|
||||
// leftmargin (IE-attribute)
|
||||
value = mPart->GetParsedAttr(nsGkAtoms::leftmargin);
|
||||
if (value && value->Type() == nsAttrValue::eInteger) {
|
||||
bodyLeftMargin = value->GetIntegerValue();
|
||||
if (bodyLeftMargin < 0) bodyLeftMargin = 0;
|
||||
nsCSSValue* marginLeft = aData->ValueForMarginLeft();
|
||||
if (marginLeft->GetUnit() == eCSSUnit_Null)
|
||||
marginLeft->SetFloatValue((float)bodyLeftMargin, eCSSUnit_Pixel);
|
||||
}
|
||||
|
||||
// rightmargin (IE-attribute)
|
||||
value = mPart->GetParsedAttr(nsGkAtoms::rightmargin);
|
||||
if (value && value->Type() == nsAttrValue::eInteger) {
|
||||
bodyRightMargin = value->GetIntegerValue();
|
||||
if (bodyRightMargin < 0) bodyRightMargin = 0;
|
||||
nsCSSValue* marginRight = aData->ValueForMarginRight();
|
||||
if (marginRight->GetUnit() == eCSSUnit_Null)
|
||||
marginRight->SetFloatValue((float)bodyRightMargin, eCSSUnit_Pixel);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// if marginwidth or marginheight is set in the <frame> and not set in the <body>
|
||||
// reflect them as margin in the <body>
|
||||
if (bodyMarginWidth == -1 || bodyMarginHeight == -1) {
|
||||
nsCOMPtr<nsIDocShell> docShell(aData->mPresContext->GetDocShell());
|
||||
if (docShell) {
|
||||
nscoord frameMarginWidth=-1; // default value
|
||||
nscoord frameMarginHeight=-1; // default value
|
||||
docShell->GetMarginWidth(&frameMarginWidth); // -1 indicates not set
|
||||
docShell->GetMarginHeight(&frameMarginHeight);
|
||||
if ((frameMarginWidth >= 0) && (bodyMarginWidth == -1)) { // set in <frame> & not in <body>
|
||||
if (eCompatibility_NavQuirks == mode) {
|
||||
if ((bodyMarginHeight == -1) && (0 > frameMarginHeight)) // nav quirk
|
||||
frameMarginHeight = 0;
|
||||
}
|
||||
}
|
||||
if ((frameMarginHeight >= 0) && (bodyMarginHeight == -1)) { // set in <frame> & not in <body>
|
||||
if (eCompatibility_NavQuirks == mode) {
|
||||
if ((bodyMarginWidth == -1) && (0 > frameMarginWidth)) // nav quirk
|
||||
frameMarginWidth = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ((bodyMarginWidth == -1) && (frameMarginWidth >= 0)) {
|
||||
nsCSSValue* marginLeft = aData->ValueForMarginLeft();
|
||||
if (marginLeft->GetUnit() == eCSSUnit_Null)
|
||||
marginLeft->SetFloatValue((float)frameMarginWidth, eCSSUnit_Pixel);
|
||||
nsCSSValue* marginRight = aData->ValueForMarginRight();
|
||||
if (marginRight->GetUnit() == eCSSUnit_Null)
|
||||
marginRight->SetFloatValue((float)frameMarginWidth, eCSSUnit_Pixel);
|
||||
}
|
||||
|
||||
if ((bodyMarginHeight == -1) && (frameMarginHeight >= 0)) {
|
||||
nsCSSValue* marginTop = aData->ValueForMarginTop();
|
||||
if (marginTop->GetUnit() == eCSSUnit_Null)
|
||||
marginTop->SetFloatValue((float)frameMarginHeight, eCSSUnit_Pixel);
|
||||
nsCSSValue* marginBottom = aData->ValueForMarginBottom();
|
||||
if (marginBottom->GetUnit() == eCSSUnit_Null)
|
||||
marginBottom->SetFloatValue((float)frameMarginHeight, eCSSUnit_Pixel);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* virtual */ bool
|
||||
BodyRule::MightMapInheritedStyleData()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/* virtual */ bool
|
||||
BodyRule::GetDiscretelyAnimatedCSSValue(nsCSSPropertyID aProperty,
|
||||
nsCSSValue* aValue)
|
||||
{
|
||||
MOZ_ASSERT(false, "GetDiscretelyAnimatedCSSValue is not implemented yet");
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
/* virtual */ void
|
||||
BodyRule::List(FILE* out, int32_t aIndent) const
|
||||
{
|
||||
nsAutoCString indent;
|
||||
for (int32_t index = aIndent; --index >= 0; ) {
|
||||
indent.AppendLiteral(" ");
|
||||
}
|
||||
fprintf_stderr(out, "%s[body rule] {}\n", indent.get());
|
||||
}
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
HTMLBodyElement::~HTMLBodyElement()
|
||||
{
|
||||
if (mContentStyleRule) {
|
||||
mContentStyleRule->mPart = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
JSObject*
|
||||
HTMLBodyElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return HTMLBodyElementBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED(HTMLBodyElement, nsGenericHTMLElement,
|
||||
nsIDOMHTMLBodyElement)
|
||||
|
||||
NS_IMPL_ELEMENT_CLONE(HTMLBodyElement)
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLBodyElement::SetBackground(const nsAString& aBackground)
|
||||
{
|
||||
ErrorResult rv;
|
||||
SetBackground(aBackground, rv);
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLBodyElement::GetBackground(nsAString& aBackground)
|
||||
{
|
||||
DOMString background;
|
||||
GetBackground(background);
|
||||
background.ToString(aBackground);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLBodyElement::SetVLink(const nsAString& aVLink)
|
||||
{
|
||||
ErrorResult rv;
|
||||
SetVLink(aVLink, rv);
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLBodyElement::GetVLink(nsAString& aVLink)
|
||||
{
|
||||
DOMString vLink;
|
||||
GetVLink(vLink);
|
||||
vLink.ToString(aVLink);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLBodyElement::SetALink(const nsAString& aALink)
|
||||
{
|
||||
ErrorResult rv;
|
||||
SetALink(aALink, rv);
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLBodyElement::GetALink(nsAString& aALink)
|
||||
{
|
||||
DOMString aLink;
|
||||
GetALink(aLink);
|
||||
aLink.ToString(aALink);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLBodyElement::SetLink(const nsAString& aLink)
|
||||
{
|
||||
ErrorResult rv;
|
||||
SetLink(aLink, rv);
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLBodyElement::GetLink(nsAString& aLink)
|
||||
{
|
||||
DOMString link;
|
||||
GetLink(link);
|
||||
link.ToString(aLink);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLBodyElement::SetText(const nsAString& aText)
|
||||
{
|
||||
ErrorResult rv;
|
||||
SetText(aText, rv);
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLBodyElement::GetText(nsAString& aText)
|
||||
{
|
||||
DOMString text;
|
||||
GetText(text);
|
||||
text.ToString(aText);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLBodyElement::SetBgColor(const nsAString& aBgColor)
|
||||
{
|
||||
ErrorResult rv;
|
||||
SetBgColor(aBgColor, rv);
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLBodyElement::GetBgColor(nsAString& aBgColor)
|
||||
{
|
||||
DOMString bgColor;
|
||||
GetBgColor(bgColor);
|
||||
bgColor.ToString(aBgColor);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
HTMLBodyElement::ParseAttribute(int32_t aNamespaceID,
|
||||
nsIAtom* aAttribute,
|
||||
const nsAString& aValue,
|
||||
nsAttrValue& aResult)
|
||||
{
|
||||
if (aNamespaceID == kNameSpaceID_None) {
|
||||
if (aAttribute == nsGkAtoms::bgcolor ||
|
||||
aAttribute == nsGkAtoms::text ||
|
||||
aAttribute == nsGkAtoms::link ||
|
||||
aAttribute == nsGkAtoms::alink ||
|
||||
aAttribute == nsGkAtoms::vlink) {
|
||||
return aResult.ParseColor(aValue);
|
||||
}
|
||||
if (aAttribute == nsGkAtoms::marginwidth ||
|
||||
aAttribute == nsGkAtoms::marginheight ||
|
||||
aAttribute == nsGkAtoms::topmargin ||
|
||||
aAttribute == nsGkAtoms::bottommargin ||
|
||||
aAttribute == nsGkAtoms::leftmargin ||
|
||||
aAttribute == nsGkAtoms::rightmargin) {
|
||||
return aResult.ParseIntWithBounds(aValue, 0);
|
||||
}
|
||||
}
|
||||
|
||||
return nsGenericHTMLElement::ParseBackgroundAttribute(aNamespaceID,
|
||||
aAttribute, aValue,
|
||||
aResult) ||
|
||||
nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
|
||||
aResult);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLBodyElement::UnbindFromTree(bool aDeep, bool aNullParent)
|
||||
{
|
||||
if (mContentStyleRule) {
|
||||
mContentStyleRule->mPart = nullptr;
|
||||
mContentStyleRule = nullptr;
|
||||
}
|
||||
|
||||
nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLBodyElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
|
||||
nsRuleData* aData)
|
||||
{
|
||||
if (aData->mSIDs & NS_STYLE_INHERIT_BIT(Display)) {
|
||||
// When display if first asked for, go ahead and get our colors set up.
|
||||
nsIPresShell *presShell = aData->mPresContext->GetPresShell();
|
||||
if (presShell) {
|
||||
nsIDocument *doc = presShell->GetDocument();
|
||||
if (doc) {
|
||||
nsHTMLStyleSheet* styleSheet = doc->GetAttributeStyleSheet();
|
||||
if (styleSheet) {
|
||||
const nsAttrValue* value;
|
||||
nscolor color;
|
||||
value = aAttributes->GetAttr(nsGkAtoms::link);
|
||||
if (value && value->GetColorValue(color)) {
|
||||
styleSheet->SetLinkColor(color);
|
||||
}
|
||||
|
||||
value = aAttributes->GetAttr(nsGkAtoms::alink);
|
||||
if (value && value->GetColorValue(color)) {
|
||||
styleSheet->SetActiveLinkColor(color);
|
||||
}
|
||||
|
||||
value = aAttributes->GetAttr(nsGkAtoms::vlink);
|
||||
if (value && value->GetColorValue(color)) {
|
||||
styleSheet->SetVisitedLinkColor(color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (aData->mSIDs & NS_STYLE_INHERIT_BIT(Color)) {
|
||||
nsCSSValue *colorValue = aData->ValueForColor();
|
||||
if (colorValue->GetUnit() == eCSSUnit_Null &&
|
||||
aData->mPresContext->UseDocumentColors()) {
|
||||
// color: color
|
||||
nscolor color;
|
||||
const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::text);
|
||||
if (value && value->GetColorValue(color))
|
||||
colorValue->SetColorValue(color);
|
||||
}
|
||||
}
|
||||
|
||||
nsGenericHTMLElement::MapBackgroundAttributesInto(aAttributes, aData);
|
||||
nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aData);
|
||||
}
|
||||
|
||||
nsMapRuleToAttributesFunc
|
||||
HTMLBodyElement::GetAttributeMappingFunction() const
|
||||
{
|
||||
return &MapAttributesIntoRule;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLBodyElement::WalkContentStyleRules(nsRuleWalker* aRuleWalker)
|
||||
{
|
||||
nsGenericHTMLElement::WalkContentStyleRules(aRuleWalker);
|
||||
|
||||
if (!mContentStyleRule && IsInUncomposedDoc()) {
|
||||
// XXXbz should this use OwnerDoc() or GetComposedDoc()?
|
||||
// sXBL/XBL2 issue!
|
||||
mContentStyleRule = new BodyRule(this);
|
||||
}
|
||||
if (aRuleWalker && mContentStyleRule) {
|
||||
aRuleWalker->Forward(mContentStyleRule);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(bool)
|
||||
HTMLBodyElement::IsAttributeMapped(const nsIAtom* aAttribute) const
|
||||
{
|
||||
static const MappedAttributeEntry attributes[] = {
|
||||
{ &nsGkAtoms::link },
|
||||
{ &nsGkAtoms::vlink },
|
||||
{ &nsGkAtoms::alink },
|
||||
{ &nsGkAtoms::text },
|
||||
// These aren't mapped through attribute mapping, but they are
|
||||
// mapped through a style rule, so it is attribute dependent style.
|
||||
// XXXldb But we don't actually replace the body rule when we have
|
||||
// dynamic changes...
|
||||
{ &nsGkAtoms::marginwidth },
|
||||
{ &nsGkAtoms::marginheight },
|
||||
{ nullptr },
|
||||
};
|
||||
|
||||
static const MappedAttributeEntry* const map[] = {
|
||||
attributes,
|
||||
sCommonAttributeMap,
|
||||
sBackgroundAttributeMap,
|
||||
};
|
||||
|
||||
return FindAttributeDependence(aAttribute, map);
|
||||
}
|
||||
|
||||
already_AddRefed<nsIEditor>
|
||||
HTMLBodyElement::GetAssociatedEditor()
|
||||
{
|
||||
nsCOMPtr<nsIEditor> editor = GetEditorInternal();
|
||||
if (editor) {
|
||||
return editor.forget();
|
||||
}
|
||||
|
||||
// Make sure this is the actual body of the document
|
||||
if (!IsCurrentBodyElement()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// For designmode, try to get document's editor
|
||||
nsPresContext* presContext = GetPresContext(eForComposedDoc);
|
||||
if (!presContext) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDocShell> docShell = presContext->GetDocShell();
|
||||
if (!docShell) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
docShell->GetEditor(getter_AddRefs(editor));
|
||||
return editor.forget();
|
||||
}
|
||||
|
||||
bool
|
||||
HTMLBodyElement::IsEventAttributeName(nsIAtom *aName)
|
||||
{
|
||||
return nsContentUtils::IsEventAttributeName(aName,
|
||||
EventNameType_HTML |
|
||||
EventNameType_HTMLBodyOrFramesetOnly);
|
||||
}
|
||||
|
||||
#define EVENT(name_, id_, type_, struct_) /* nothing; handled by the superclass */
|
||||
// nsGenericHTMLElement::GetOnError returns
|
||||
// already_AddRefed<EventHandlerNonNull> while other getters return
|
||||
// EventHandlerNonNull*, so allow passing in the type to use here.
|
||||
#define WINDOW_EVENT_HELPER(name_, type_) \
|
||||
type_* \
|
||||
HTMLBodyElement::GetOn##name_() \
|
||||
{ \
|
||||
if (nsPIDOMWindowInner* win = OwnerDoc()->GetInnerWindow()) { \
|
||||
nsGlobalWindow* globalWin = nsGlobalWindow::Cast(win); \
|
||||
return globalWin->GetOn##name_(); \
|
||||
} \
|
||||
return nullptr; \
|
||||
} \
|
||||
void \
|
||||
HTMLBodyElement::SetOn##name_(type_* handler) \
|
||||
{ \
|
||||
nsPIDOMWindowInner* win = OwnerDoc()->GetInnerWindow(); \
|
||||
if (!win) { \
|
||||
return; \
|
||||
} \
|
||||
\
|
||||
nsGlobalWindow* globalWin = nsGlobalWindow::Cast(win); \
|
||||
return globalWin->SetOn##name_(handler); \
|
||||
}
|
||||
#define WINDOW_EVENT(name_, id_, type_, struct_) \
|
||||
WINDOW_EVENT_HELPER(name_, EventHandlerNonNull)
|
||||
#define BEFOREUNLOAD_EVENT(name_, id_, type_, struct_) \
|
||||
WINDOW_EVENT_HELPER(name_, OnBeforeUnloadEventHandlerNonNull)
|
||||
#include "mozilla/EventNameList.h" // IWYU pragma: keep
|
||||
#undef BEFOREUNLOAD_EVENT
|
||||
#undef WINDOW_EVENT
|
||||
#undef WINDOW_EVENT_HELPER
|
||||
#undef EVENT
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
153
dom/html/HTMLBodyElement.h
Normal file
153
dom/html/HTMLBodyElement.h
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
/* -*- 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/. */
|
||||
#ifndef HTMLBodyElement_h___
|
||||
#define HTMLBodyElement_h___
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsGenericHTMLElement.h"
|
||||
#include "nsIDOMHTMLBodyElement.h"
|
||||
#include "nsIStyleRule.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class OnBeforeUnloadEventHandlerNonNull;
|
||||
class HTMLBodyElement;
|
||||
|
||||
class BodyRule: public nsIStyleRule
|
||||
{
|
||||
virtual ~BodyRule();
|
||||
|
||||
public:
|
||||
explicit BodyRule(HTMLBodyElement* aPart);
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// nsIStyleRule interface
|
||||
virtual void MapRuleInfoInto(nsRuleData* aRuleData) override;
|
||||
virtual bool MightMapInheritedStyleData() override;
|
||||
virtual bool GetDiscretelyAnimatedCSSValue(nsCSSPropertyID aProperty,
|
||||
nsCSSValue* aValue) override;
|
||||
#ifdef DEBUG
|
||||
virtual void List(FILE* out = stdout, int32_t aIndent = 0) const override;
|
||||
#endif
|
||||
|
||||
HTMLBodyElement* mPart; // not ref-counted, cleared by content
|
||||
};
|
||||
|
||||
class HTMLBodyElement final : public nsGenericHTMLElement,
|
||||
public nsIDOMHTMLBodyElement
|
||||
{
|
||||
public:
|
||||
using Element::GetText;
|
||||
using Element::SetText;
|
||||
|
||||
explicit HTMLBodyElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
|
||||
: nsGenericHTMLElement(aNodeInfo)
|
||||
{
|
||||
}
|
||||
|
||||
// nsISupports
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
// nsIDOMHTMLBodyElement
|
||||
NS_DECL_NSIDOMHTMLBODYELEMENT
|
||||
|
||||
// Event listener stuff; we need to declare only the ones we need to
|
||||
// forward to window that don't come from nsIDOMHTMLBodyElement.
|
||||
#define EVENT(name_, id_, type_, struct_) /* nothing; handled by the shim */
|
||||
#define WINDOW_EVENT_HELPER(name_, type_) \
|
||||
type_* GetOn##name_(); \
|
||||
void SetOn##name_(type_* handler);
|
||||
#define WINDOW_EVENT(name_, id_, type_, struct_) \
|
||||
WINDOW_EVENT_HELPER(name_, EventHandlerNonNull)
|
||||
#define BEFOREUNLOAD_EVENT(name_, id_, type_, struct_) \
|
||||
WINDOW_EVENT_HELPER(name_, OnBeforeUnloadEventHandlerNonNull)
|
||||
#include "mozilla/EventNameList.h" // IWYU pragma: keep
|
||||
#undef BEFOREUNLOAD_EVENT
|
||||
#undef WINDOW_EVENT
|
||||
#undef WINDOW_EVENT_HELPER
|
||||
#undef EVENT
|
||||
|
||||
void GetText(DOMString& aText)
|
||||
{
|
||||
GetHTMLAttr(nsGkAtoms::text, aText);
|
||||
}
|
||||
void SetText(const nsAString& aText, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::text, aText, aError);
|
||||
}
|
||||
void GetLink(DOMString& aLink)
|
||||
{
|
||||
GetHTMLAttr(nsGkAtoms::link, aLink);
|
||||
}
|
||||
void SetLink(const nsAString& aLink, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::link, aLink, aError);
|
||||
}
|
||||
void GetVLink(DOMString& aVLink)
|
||||
{
|
||||
GetHTMLAttr(nsGkAtoms::vlink, aVLink);
|
||||
}
|
||||
void SetVLink(const nsAString& aVLink, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::vlink, aVLink, aError);
|
||||
}
|
||||
void GetALink(DOMString& aALink)
|
||||
{
|
||||
GetHTMLAttr(nsGkAtoms::alink, aALink);
|
||||
}
|
||||
void SetALink(const nsAString& aALink, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::alink, aALink, aError);
|
||||
}
|
||||
void GetBgColor(DOMString& aBgColor)
|
||||
{
|
||||
GetHTMLAttr(nsGkAtoms::bgcolor, aBgColor);
|
||||
}
|
||||
void SetBgColor(const nsAString& aBgColor, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::bgcolor, aBgColor, aError);
|
||||
}
|
||||
void GetBackground(DOMString& aBackground)
|
||||
{
|
||||
GetHTMLAttr(nsGkAtoms::background, aBackground);
|
||||
}
|
||||
void SetBackground(const nsAString& aBackground, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::background, aBackground, aError);
|
||||
}
|
||||
|
||||
virtual bool ParseAttribute(int32_t aNamespaceID,
|
||||
nsIAtom* aAttribute,
|
||||
const nsAString& aValue,
|
||||
nsAttrValue& aResult) override;
|
||||
virtual void UnbindFromTree(bool aDeep = true,
|
||||
bool aNullParent = true) override;
|
||||
virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const override;
|
||||
NS_IMETHOD WalkContentStyleRules(nsRuleWalker* aRuleWalker) override;
|
||||
NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
|
||||
virtual already_AddRefed<nsIEditor> GetAssociatedEditor() override;
|
||||
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
|
||||
|
||||
virtual bool IsEventAttributeName(nsIAtom* aName) override;
|
||||
|
||||
protected:
|
||||
virtual ~HTMLBodyElement();
|
||||
|
||||
virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
RefPtr<BodyRule> mContentStyleRule;
|
||||
|
||||
private:
|
||||
static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
|
||||
nsRuleData* aData);
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* HTMLBodyElement_h___ */
|
||||
519
dom/html/HTMLButtonElement.cpp
Normal file
519
dom/html/HTMLButtonElement.cpp
Normal file
|
|
@ -0,0 +1,519 @@
|
|||
/* -*- 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/HTMLButtonElement.h"
|
||||
|
||||
#include "HTMLFormSubmissionConstants.h"
|
||||
#include "mozilla/dom/HTMLButtonElementBinding.h"
|
||||
#include "mozilla/dom/HTMLFormSubmission.h"
|
||||
#include "nsIDOMHTMLFormElement.h"
|
||||
#include "nsAttrValueInlines.h"
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsIPresShell.h"
|
||||
#include "nsStyleConsts.h"
|
||||
#include "nsPresContext.h"
|
||||
#include "nsIFormControl.h"
|
||||
#include "nsIURL.h"
|
||||
#include "nsIFrame.h"
|
||||
#include "nsIFormControlFrame.h"
|
||||
#include "nsIDOMEvent.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "mozilla/ContentEvents.h"
|
||||
#include "mozilla/EventDispatcher.h"
|
||||
#include "mozilla/EventStateManager.h"
|
||||
#include "mozilla/EventStates.h"
|
||||
#include "mozilla/MouseEvents.h"
|
||||
#include "mozilla/TextEvents.h"
|
||||
#include "nsUnicharUtils.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
#include "nsPresState.h"
|
||||
#include "nsError.h"
|
||||
#include "nsFocusManager.h"
|
||||
#include "mozilla/dom/HTMLFormElement.h"
|
||||
#include "mozAutoDocUpdate.h"
|
||||
|
||||
#define NS_IN_SUBMIT_CLICK (1 << 0)
|
||||
#define NS_OUTER_ACTIVATE_EVENT (1 << 1)
|
||||
|
||||
NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER(Button)
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
static const nsAttrValue::EnumTable kButtonTypeTable[] = {
|
||||
{ "button", NS_FORM_BUTTON_BUTTON },
|
||||
{ "reset", NS_FORM_BUTTON_RESET },
|
||||
{ "submit", NS_FORM_BUTTON_SUBMIT },
|
||||
{ nullptr, 0 }
|
||||
};
|
||||
|
||||
// Default type is 'submit'.
|
||||
static const nsAttrValue::EnumTable* kButtonDefaultType = &kButtonTypeTable[2];
|
||||
|
||||
|
||||
// Construction, destruction
|
||||
HTMLButtonElement::HTMLButtonElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo,
|
||||
FromParser aFromParser)
|
||||
: nsGenericHTMLFormElementWithState(aNodeInfo),
|
||||
mType(kButtonDefaultType->value),
|
||||
mDisabledChanged(false),
|
||||
mInInternalActivate(false),
|
||||
mInhibitStateRestoration(!!(aFromParser & FROM_PARSER_FRAGMENT))
|
||||
{
|
||||
// Set up our default state: enabled
|
||||
AddStatesSilently(NS_EVENT_STATE_ENABLED);
|
||||
}
|
||||
|
||||
HTMLButtonElement::~HTMLButtonElement()
|
||||
{
|
||||
}
|
||||
|
||||
// nsISupports
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_INHERITED(HTMLButtonElement,
|
||||
nsGenericHTMLFormElementWithState,
|
||||
mValidity)
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(HTMLButtonElement, Element)
|
||||
NS_IMPL_RELEASE_INHERITED(HTMLButtonElement, Element)
|
||||
|
||||
|
||||
// QueryInterface implementation for HTMLButtonElement
|
||||
NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(HTMLButtonElement)
|
||||
NS_INTERFACE_TABLE_INHERITED(HTMLButtonElement,
|
||||
nsIDOMHTMLButtonElement,
|
||||
nsIConstraintValidation)
|
||||
NS_INTERFACE_TABLE_TAIL_INHERITING(nsGenericHTMLFormElementWithState)
|
||||
|
||||
// nsIConstraintValidation
|
||||
NS_IMPL_NSICONSTRAINTVALIDATION_EXCEPT_SETCUSTOMVALIDITY(HTMLButtonElement)
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLButtonElement::SetCustomValidity(const nsAString& aError)
|
||||
{
|
||||
nsIConstraintValidation::SetCustomValidity(aError);
|
||||
|
||||
UpdateState(true);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
HTMLButtonElement::UpdateBarredFromConstraintValidation()
|
||||
{
|
||||
SetBarredFromConstraintValidation(mType == NS_FORM_BUTTON_BUTTON ||
|
||||
mType == NS_FORM_BUTTON_RESET ||
|
||||
IsDisabled());
|
||||
}
|
||||
|
||||
void
|
||||
HTMLButtonElement::FieldSetDisabledChanged(bool aNotify)
|
||||
{
|
||||
UpdateBarredFromConstraintValidation();
|
||||
|
||||
nsGenericHTMLFormElementWithState::FieldSetDisabledChanged(aNotify);
|
||||
}
|
||||
|
||||
// nsIDOMHTMLButtonElement
|
||||
|
||||
NS_IMPL_ELEMENT_CLONE(HTMLButtonElement)
|
||||
|
||||
|
||||
// nsIDOMHTMLButtonElement
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLButtonElement::GetForm(nsIDOMHTMLFormElement** aForm)
|
||||
{
|
||||
return nsGenericHTMLFormElementWithState::GetForm(aForm);
|
||||
}
|
||||
|
||||
NS_IMPL_BOOL_ATTR(HTMLButtonElement, Autofocus, autofocus)
|
||||
NS_IMPL_BOOL_ATTR(HTMLButtonElement, Disabled, disabled)
|
||||
NS_IMPL_ACTION_ATTR(HTMLButtonElement, FormAction, formaction)
|
||||
NS_IMPL_ENUM_ATTR_DEFAULT_MISSING_INVALID_VALUES(HTMLButtonElement, FormEnctype, formenctype,
|
||||
"", kFormDefaultEnctype->tag)
|
||||
NS_IMPL_ENUM_ATTR_DEFAULT_MISSING_INVALID_VALUES(HTMLButtonElement, FormMethod, formmethod,
|
||||
"", kFormDefaultMethod->tag)
|
||||
NS_IMPL_BOOL_ATTR(HTMLButtonElement, FormNoValidate, formnovalidate)
|
||||
NS_IMPL_STRING_ATTR(HTMLButtonElement, FormTarget, formtarget)
|
||||
NS_IMPL_STRING_ATTR(HTMLButtonElement, Name, name)
|
||||
NS_IMPL_STRING_ATTR(HTMLButtonElement, Value, value)
|
||||
NS_IMPL_ENUM_ATTR_DEFAULT_VALUE(HTMLButtonElement, Type, type,
|
||||
kButtonDefaultType->tag)
|
||||
|
||||
int32_t
|
||||
HTMLButtonElement::TabIndexDefault()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool
|
||||
HTMLButtonElement::IsHTMLFocusable(bool aWithMouse, bool *aIsFocusable, int32_t *aTabIndex)
|
||||
{
|
||||
if (nsGenericHTMLFormElementWithState::IsHTMLFocusable(aWithMouse, aIsFocusable, aTabIndex)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
*aIsFocusable =
|
||||
#ifdef XP_MACOSX
|
||||
(!aWithMouse || nsFocusManager::sMouseFocusesFormControl) &&
|
||||
#endif
|
||||
!IsDisabled();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
HTMLButtonElement::ParseAttribute(int32_t aNamespaceID,
|
||||
nsIAtom* aAttribute,
|
||||
const nsAString& aValue,
|
||||
nsAttrValue& aResult)
|
||||
{
|
||||
if (aNamespaceID == kNameSpaceID_None) {
|
||||
if (aAttribute == nsGkAtoms::type) {
|
||||
// XXX ARG!! This is major evilness. ParseAttribute
|
||||
// shouldn't set members. Override SetAttr instead
|
||||
bool success = aResult.ParseEnumValue(aValue, kButtonTypeTable, false);
|
||||
if (success) {
|
||||
mType = aResult.GetEnumValue();
|
||||
} else {
|
||||
mType = kButtonDefaultType->value;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
if (aAttribute == nsGkAtoms::formmethod) {
|
||||
return aResult.ParseEnumValue(aValue, kFormMethodTable, false);
|
||||
}
|
||||
if (aAttribute == nsGkAtoms::formenctype) {
|
||||
return aResult.ParseEnumValue(aValue, kFormEnctypeTable, false);
|
||||
}
|
||||
}
|
||||
|
||||
return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
|
||||
aResult);
|
||||
}
|
||||
|
||||
bool
|
||||
HTMLButtonElement::IsDisabledForEvents(EventMessage aMessage)
|
||||
{
|
||||
nsIFormControlFrame* formControlFrame = GetFormControlFrame(false);
|
||||
nsIFrame* formFrame = do_QueryFrame(formControlFrame);
|
||||
return IsElementDisabledForEvents(aMessage, formFrame);
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLButtonElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
{
|
||||
aVisitor.mCanHandle = false;
|
||||
if (IsDisabledForEvents(aVisitor.mEvent->mMessage)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Track whether we're in the outermost Dispatch invocation that will
|
||||
// cause activation of the input. That is, if we're a click event, or a
|
||||
// DOMActivate that was dispatched directly, this will be set, but if we're
|
||||
// a DOMActivate dispatched from click handling, it will not be set.
|
||||
WidgetMouseEvent* mouseEvent = aVisitor.mEvent->AsMouseEvent();
|
||||
bool outerActivateEvent =
|
||||
((mouseEvent && mouseEvent->IsLeftClickEvent()) ||
|
||||
(aVisitor.mEvent->mMessage == eLegacyDOMActivate &&
|
||||
!mInInternalActivate));
|
||||
|
||||
if (outerActivateEvent) {
|
||||
aVisitor.mItemFlags |= NS_OUTER_ACTIVATE_EVENT;
|
||||
if (mType == NS_FORM_BUTTON_SUBMIT && mForm) {
|
||||
aVisitor.mItemFlags |= NS_IN_SUBMIT_CLICK;
|
||||
// tell the form that we are about to enter a click handler.
|
||||
// that means that if there are scripted submissions, the
|
||||
// latest one will be deferred until after the exit point of the handler.
|
||||
mForm->OnSubmitClickBegin(this);
|
||||
}
|
||||
}
|
||||
|
||||
return nsGenericHTMLElement::PreHandleEvent(aVisitor);
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLButtonElement::PostHandleEvent(EventChainPostVisitor& aVisitor)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
if (!aVisitor.mPresContext) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (aVisitor.mEventStatus != nsEventStatus_eConsumeNoDefault) {
|
||||
WidgetMouseEvent* mouseEvent = aVisitor.mEvent->AsMouseEvent();
|
||||
if (mouseEvent && mouseEvent->IsLeftClickEvent()) {
|
||||
// DOMActive event should be trusted since the activation is actually
|
||||
// occurred even if the cause is an untrusted click event.
|
||||
InternalUIEvent actEvent(true, eLegacyDOMActivate, mouseEvent);
|
||||
actEvent.mDetail = 1;
|
||||
|
||||
nsCOMPtr<nsIPresShell> shell = aVisitor.mPresContext->GetPresShell();
|
||||
if (shell) {
|
||||
nsEventStatus status = nsEventStatus_eIgnore;
|
||||
mInInternalActivate = true;
|
||||
shell->HandleDOMEventWithTarget(this, &actEvent, &status);
|
||||
mInInternalActivate = false;
|
||||
|
||||
// If activate is cancelled, we must do the same as when click is
|
||||
// cancelled (revert the checkbox to its original value).
|
||||
if (status == nsEventStatus_eConsumeNoDefault) {
|
||||
aVisitor.mEventStatus = status;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// mForm is null if the event handler removed us from the document (bug 194582).
|
||||
if ((aVisitor.mItemFlags & NS_IN_SUBMIT_CLICK) && mForm) {
|
||||
// tell the form that we are about to exit a click handler
|
||||
// so the form knows not to defer subsequent submissions
|
||||
// the pending ones that were created during the handler
|
||||
// will be flushed or forgoten.
|
||||
mForm->OnSubmitClickEnd();
|
||||
}
|
||||
|
||||
if (nsEventStatus_eIgnore == aVisitor.mEventStatus) {
|
||||
switch (aVisitor.mEvent->mMessage) {
|
||||
case eKeyPress:
|
||||
case eKeyUp:
|
||||
{
|
||||
// For backwards compat, trigger buttons with space or enter
|
||||
// (bug 25300)
|
||||
WidgetKeyboardEvent* keyEvent = aVisitor.mEvent->AsKeyboardEvent();
|
||||
if ((keyEvent->mKeyCode == NS_VK_RETURN &&
|
||||
eKeyPress == aVisitor.mEvent->mMessage) ||
|
||||
(keyEvent->mKeyCode == NS_VK_SPACE &&
|
||||
eKeyUp == aVisitor.mEvent->mMessage)) {
|
||||
DispatchSimulatedClick(this, aVisitor.mEvent->IsTrusted(),
|
||||
aVisitor.mPresContext);
|
||||
aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (aVisitor.mItemFlags & NS_OUTER_ACTIVATE_EVENT) {
|
||||
if (mForm && (mType == NS_FORM_BUTTON_SUBMIT ||
|
||||
mType == NS_FORM_BUTTON_RESET)) {
|
||||
InternalFormEvent event(true,
|
||||
(mType == NS_FORM_BUTTON_RESET) ? eFormReset : eFormSubmit);
|
||||
event.mOriginator = this;
|
||||
nsEventStatus status = nsEventStatus_eIgnore;
|
||||
|
||||
nsCOMPtr<nsIPresShell> presShell =
|
||||
aVisitor.mPresContext->GetPresShell();
|
||||
// If |nsIPresShell::Destroy| has been called due to
|
||||
// handling the event, the pres context will return
|
||||
// a null pres shell. See bug 125624.
|
||||
//
|
||||
// Using presShell to dispatch the event. It makes sure that
|
||||
// event is not handled if the window is being destroyed.
|
||||
if (presShell && (event.mMessage != eFormSubmit ||
|
||||
mForm->SubmissionCanProceed(this))) {
|
||||
// TODO: removing this code and have the submit event sent by the form
|
||||
// see bug 592124.
|
||||
// Hold a strong ref while dispatching
|
||||
RefPtr<HTMLFormElement> form(mForm);
|
||||
presShell->HandleDOMEventWithTarget(form, &event, &status);
|
||||
aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if ((aVisitor.mItemFlags & NS_IN_SUBMIT_CLICK) && mForm) {
|
||||
// Tell the form to flush a possible pending submission.
|
||||
// the reason is that the script returned false (the event was
|
||||
// not ignored) so if there is a stored submission, it needs to
|
||||
// be submitted immediatelly.
|
||||
// Note, NS_IN_SUBMIT_CLICK is set only when we're in outer activate event.
|
||||
mForm->FlushPendingSubmission();
|
||||
} //if
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLButtonElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
||||
nsIContent* aBindingParent,
|
||||
bool aCompileEventHandlers)
|
||||
{
|
||||
nsresult rv =
|
||||
nsGenericHTMLFormElementWithState::BindToTree(aDocument, aParent, aBindingParent,
|
||||
aCompileEventHandlers);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Update our state; we may now be the default submit element
|
||||
UpdateState(false);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
HTMLButtonElement::UnbindFromTree(bool aDeep, bool aNullParent)
|
||||
{
|
||||
nsGenericHTMLFormElementWithState::UnbindFromTree(aDeep, aNullParent);
|
||||
|
||||
// Update our state; we may no longer be the default submit element
|
||||
UpdateState(false);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLButtonElement::Reset()
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLButtonElement::SubmitNamesValues(HTMLFormSubmission* aFormSubmission)
|
||||
{
|
||||
//
|
||||
// We only submit if we were the button pressed
|
||||
//
|
||||
if (aFormSubmission->GetOriginatingElement() != this) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Disabled elements don't submit
|
||||
if (IsDisabled()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//
|
||||
// Get the name (if no name, no submit)
|
||||
//
|
||||
nsAutoString name;
|
||||
GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
|
||||
if (name.IsEmpty()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//
|
||||
// Get the value
|
||||
//
|
||||
nsAutoString value;
|
||||
nsresult rv = GetValue(value);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
//
|
||||
// Submit
|
||||
//
|
||||
return aFormSubmission->AddNameValuePair(name, value);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLButtonElement::DoneCreatingElement()
|
||||
{
|
||||
if (!mInhibitStateRestoration) {
|
||||
nsresult rv = GenerateStateKey();
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
RestoreFormControlState();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLButtonElement::BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
nsAttrValueOrString* aValue,
|
||||
bool aNotify)
|
||||
{
|
||||
if (aNotify && aName == nsGkAtoms::disabled &&
|
||||
aNameSpaceID == kNameSpaceID_None) {
|
||||
mDisabledChanged = true;
|
||||
}
|
||||
|
||||
return nsGenericHTMLFormElementWithState::BeforeSetAttr(aNameSpaceID, aName,
|
||||
aValue, aNotify);
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLButtonElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
const nsAttrValue* aValue, bool aNotify)
|
||||
{
|
||||
if (aNameSpaceID == kNameSpaceID_None) {
|
||||
if (aName == nsGkAtoms::type) {
|
||||
if (!aValue) {
|
||||
mType = kButtonDefaultType->value;
|
||||
}
|
||||
}
|
||||
|
||||
if (aName == nsGkAtoms::type || aName == nsGkAtoms::disabled) {
|
||||
UpdateBarredFromConstraintValidation();
|
||||
UpdateState(aNotify);
|
||||
}
|
||||
}
|
||||
|
||||
return nsGenericHTMLFormElementWithState::AfterSetAttr(aNameSpaceID, aName,
|
||||
aValue, aNotify);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLButtonElement::SaveState()
|
||||
{
|
||||
if (!mDisabledChanged) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsPresState* state = GetPrimaryPresState();
|
||||
if (state) {
|
||||
// We do not want to save the real disabled state but the disabled
|
||||
// attribute.
|
||||
state->SetDisabled(HasAttr(kNameSpaceID_None, nsGkAtoms::disabled));
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
HTMLButtonElement::RestoreState(nsPresState* aState)
|
||||
{
|
||||
if (aState && aState->IsDisabledSet()) {
|
||||
SetDisabled(aState->GetDisabled());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
EventStates
|
||||
HTMLButtonElement::IntrinsicState() const
|
||||
{
|
||||
EventStates state = nsGenericHTMLFormElementWithState::IntrinsicState();
|
||||
|
||||
if (IsCandidateForConstraintValidation()) {
|
||||
if (IsValid()) {
|
||||
state |= NS_EVENT_STATE_VALID;
|
||||
if (!mForm || !mForm->HasAttr(kNameSpaceID_None, nsGkAtoms::novalidate)) {
|
||||
state |= NS_EVENT_STATE_MOZ_UI_VALID;
|
||||
}
|
||||
} else {
|
||||
state |= NS_EVENT_STATE_INVALID;
|
||||
if (!mForm || !mForm->HasAttr(kNameSpaceID_None, nsGkAtoms::novalidate)) {
|
||||
state |= NS_EVENT_STATE_MOZ_UI_INVALID;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mForm && !mForm->GetValidity() && IsSubmitControl()) {
|
||||
state |= NS_EVENT_STATE_MOZ_SUBMITINVALID;
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
HTMLButtonElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return HTMLButtonElementBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
183
dom/html/HTMLButtonElement.h
Normal file
183
dom/html/HTMLButtonElement.h
Normal file
|
|
@ -0,0 +1,183 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_dom_HTMLButtonElement_h
|
||||
#define mozilla_dom_HTMLButtonElement_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsGenericHTMLElement.h"
|
||||
#include "nsIDOMHTMLButtonElement.h"
|
||||
#include "nsIConstraintValidation.h"
|
||||
|
||||
namespace mozilla {
|
||||
class EventChainPostVisitor;
|
||||
class EventChainPreVisitor;
|
||||
namespace dom {
|
||||
|
||||
class HTMLButtonElement final : public nsGenericHTMLFormElementWithState,
|
||||
public nsIDOMHTMLButtonElement,
|
||||
public nsIConstraintValidation
|
||||
{
|
||||
public:
|
||||
using nsIConstraintValidation::GetValidationMessage;
|
||||
|
||||
explicit HTMLButtonElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo,
|
||||
FromParser aFromParser = NOT_FROM_PARSER);
|
||||
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLButtonElement,
|
||||
nsGenericHTMLFormElementWithState)
|
||||
|
||||
// nsISupports
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
virtual int32_t TabIndexDefault() override;
|
||||
|
||||
NS_IMPL_FROMCONTENT_HTML_WITH_TAG(HTMLButtonElement, button)
|
||||
|
||||
// Element
|
||||
virtual bool IsInteractiveHTMLContent(bool aIgnoreTabindex) const override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// nsIDOMHTMLButtonElement
|
||||
NS_DECL_NSIDOMHTMLBUTTONELEMENT
|
||||
|
||||
// overriden nsIFormControl methods
|
||||
NS_IMETHOD_(uint32_t) GetType() const override { return mType; }
|
||||
NS_IMETHOD Reset() override;
|
||||
NS_IMETHOD SubmitNamesValues(HTMLFormSubmission* aFormSubmission) override;
|
||||
NS_IMETHOD SaveState() override;
|
||||
bool RestoreState(nsPresState* aState) override;
|
||||
virtual bool IsDisabledForEvents(EventMessage aMessage) override;
|
||||
|
||||
virtual void FieldSetDisabledChanged(bool aNotify) override;
|
||||
|
||||
// nsIDOMEventTarget
|
||||
virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override;
|
||||
virtual nsresult PostHandleEvent(
|
||||
EventChainPostVisitor& aVisitor) override;
|
||||
|
||||
// nsINode
|
||||
virtual nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult) const override;
|
||||
virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
// nsIContent
|
||||
virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
||||
nsIContent* aBindingParent,
|
||||
bool aCompileEventHandlers) override;
|
||||
virtual void UnbindFromTree(bool aDeep = true,
|
||||
bool aNullParent = true) override;
|
||||
virtual void DoneCreatingElement() override;
|
||||
|
||||
void UpdateBarredFromConstraintValidation();
|
||||
// Element
|
||||
EventStates IntrinsicState() const override;
|
||||
/**
|
||||
* Called when an attribute is about to be changed
|
||||
*/
|
||||
virtual nsresult BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
nsAttrValueOrString* aValue,
|
||||
bool aNotify) override;
|
||||
/**
|
||||
* Called when an attribute has just been changed
|
||||
*/
|
||||
nsresult AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
|
||||
const nsAttrValue* aValue, bool aNotify) override;
|
||||
virtual bool ParseAttribute(int32_t aNamespaceID,
|
||||
nsIAtom* aAttribute,
|
||||
const nsAString& aValue,
|
||||
nsAttrValue& aResult) override;
|
||||
|
||||
// nsGenericHTMLElement
|
||||
virtual bool IsHTMLFocusable(bool aWithMouse,
|
||||
bool* aIsFocusable,
|
||||
int32_t* aTabIndex) override;
|
||||
|
||||
// WebIDL
|
||||
bool Autofocus() const
|
||||
{
|
||||
return GetBoolAttr(nsGkAtoms::autofocus);
|
||||
}
|
||||
void SetAutofocus(bool aAutofocus, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLBoolAttr(nsGkAtoms::autofocus, aAutofocus, aError);
|
||||
}
|
||||
bool Disabled() const
|
||||
{
|
||||
return GetBoolAttr(nsGkAtoms::disabled);
|
||||
}
|
||||
void SetDisabled(bool aDisabled, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLBoolAttr(nsGkAtoms::disabled, aDisabled, aError);
|
||||
}
|
||||
// nsGenericHTMLFormElement::GetForm is fine.
|
||||
using nsGenericHTMLFormElement::GetForm;
|
||||
// XPCOM GetFormAction is fine.
|
||||
void SetFormAction(const nsAString& aFormAction, ErrorResult& aRv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::formaction, aFormAction, aRv);
|
||||
}
|
||||
// XPCOM GetFormEnctype is fine.
|
||||
void SetFormEnctype(const nsAString& aFormEnctype, ErrorResult& aRv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::formenctype, aFormEnctype, aRv);
|
||||
}
|
||||
// XPCOM GetFormMethod is fine.
|
||||
void SetFormMethod(const nsAString& aFormMethod, ErrorResult& aRv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::formmethod, aFormMethod, aRv);
|
||||
}
|
||||
bool FormNoValidate() const
|
||||
{
|
||||
return GetBoolAttr(nsGkAtoms::formnovalidate);
|
||||
}
|
||||
void SetFormNoValidate(bool aFormNoValidate, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLBoolAttr(nsGkAtoms::formnovalidate, aFormNoValidate, aError);
|
||||
}
|
||||
// XPCOM GetFormTarget is fine.
|
||||
void SetFormTarget(const nsAString& aFormTarget, ErrorResult& aRv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::formtarget, aFormTarget, aRv);
|
||||
}
|
||||
// XPCOM GetName is fine.
|
||||
void SetName(const nsAString& aName, ErrorResult& aRv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::name, aName, aRv);
|
||||
}
|
||||
// XPCOM GetType is fine.
|
||||
void SetType(const nsAString& aType, ErrorResult& aRv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::type, aType, aRv);
|
||||
}
|
||||
// XPCOM GetValue is fine.
|
||||
void SetValue(const nsAString& aValue, ErrorResult& aRv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::value, aValue, aRv);
|
||||
}
|
||||
|
||||
// nsIConstraintValidation::WillValidate is fine.
|
||||
// nsIConstraintValidation::Validity() is fine.
|
||||
// nsIConstraintValidation::GetValidationMessage() is fine.
|
||||
// nsIConstraintValidation::CheckValidity() is fine.
|
||||
using nsIConstraintValidation::CheckValidity;
|
||||
using nsIConstraintValidation::ReportValidity;
|
||||
// nsIConstraintValidation::SetCustomValidity() is fine.
|
||||
|
||||
protected:
|
||||
virtual ~HTMLButtonElement();
|
||||
|
||||
uint8_t mType;
|
||||
bool mDisabledChanged;
|
||||
bool mInInternalActivate;
|
||||
bool mInhibitStateRestoration;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_HTMLButtonElement_h
|
||||
1482
dom/html/HTMLCanvasElement.cpp
Normal file
1482
dom/html/HTMLCanvasElement.cpp
Normal file
File diff suppressed because it is too large
Load diff
452
dom/html/HTMLCanvasElement.h
Normal file
452
dom/html/HTMLCanvasElement.h
Normal file
|
|
@ -0,0 +1,452 @@
|
|||
/* -*- 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/. */
|
||||
#if !defined(mozilla_dom_HTMLCanvasElement_h)
|
||||
#define mozilla_dom_HTMLCanvasElement_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/WeakPtr.h"
|
||||
#include "nsIDOMEventListener.h"
|
||||
#include "nsIDOMHTMLCanvasElement.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsGenericHTMLElement.h"
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsSize.h"
|
||||
#include "nsError.h"
|
||||
|
||||
#include "mozilla/dom/CanvasRenderingContextHelper.h"
|
||||
#include "mozilla/gfx/Rect.h"
|
||||
#include "mozilla/layers/LayersTypes.h"
|
||||
|
||||
class nsICanvasRenderingContextInternal;
|
||||
class nsITimerCallback;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class WebGLContext;
|
||||
|
||||
namespace layers {
|
||||
class AsyncCanvasRenderer;
|
||||
class CanvasLayer;
|
||||
class Image;
|
||||
class Layer;
|
||||
class LayerManager;
|
||||
class SharedSurfaceTextureClient;
|
||||
} // namespace layers
|
||||
namespace gfx {
|
||||
class SourceSurface;
|
||||
class VRLayerChild;
|
||||
} // namespace gfx
|
||||
|
||||
namespace dom {
|
||||
class BlobCallback;
|
||||
class CanvasCaptureMediaStream;
|
||||
class File;
|
||||
class HTMLCanvasPrintState;
|
||||
class OffscreenCanvas;
|
||||
class PrintCallback;
|
||||
class RequestedFrameRefreshObserver;
|
||||
|
||||
// Listen visibilitychange and memory-pressure event and inform
|
||||
// context when event is fired.
|
||||
class HTMLCanvasElementObserver final : public nsIObserver
|
||||
, public nsIDOMEventListener
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIOBSERVER
|
||||
NS_DECL_NSIDOMEVENTLISTENER
|
||||
|
||||
explicit HTMLCanvasElementObserver(HTMLCanvasElement* aElement);
|
||||
void Destroy();
|
||||
|
||||
void RegisterVisibilityChangeEvent();
|
||||
void UnregisterVisibilityChangeEvent();
|
||||
|
||||
void RegisterMemoryPressureEvent();
|
||||
void UnregisterMemoryPressureEvent();
|
||||
|
||||
private:
|
||||
~HTMLCanvasElementObserver();
|
||||
|
||||
HTMLCanvasElement* mElement;
|
||||
};
|
||||
|
||||
/*
|
||||
* FrameCaptureListener is used by captureStream() as a way of getting video
|
||||
* frames from the canvas. On a refresh driver tick after something has been
|
||||
* drawn to the canvas since the last such tick, all registered
|
||||
* FrameCaptureListeners whose `mFrameCaptureRequested` equals `true`,
|
||||
* will be given a copy of the just-painted canvas.
|
||||
* All FrameCaptureListeners get the same copy.
|
||||
*/
|
||||
class FrameCaptureListener : public SupportsWeakPtr<FrameCaptureListener>
|
||||
{
|
||||
public:
|
||||
MOZ_DECLARE_WEAKREFERENCE_TYPENAME(FrameCaptureListener)
|
||||
|
||||
FrameCaptureListener()
|
||||
: mFrameCaptureRequested(false) {}
|
||||
|
||||
/*
|
||||
* Called when a frame capture is desired on next paint.
|
||||
*/
|
||||
void RequestFrameCapture() { mFrameCaptureRequested = true; }
|
||||
|
||||
/*
|
||||
* Indicates to the canvas whether or not this listener has requested a frame.
|
||||
*/
|
||||
bool FrameCaptureRequested() const { return mFrameCaptureRequested; }
|
||||
|
||||
/*
|
||||
* Interface through which new video frames will be provided while
|
||||
* `mFrameCaptureRequested` is `true`.
|
||||
*/
|
||||
virtual void NewFrame(already_AddRefed<layers::Image> aImage) = 0;
|
||||
|
||||
protected:
|
||||
virtual ~FrameCaptureListener() {}
|
||||
|
||||
bool mFrameCaptureRequested;
|
||||
};
|
||||
|
||||
class HTMLCanvasElement final : public nsGenericHTMLElement,
|
||||
public nsIDOMHTMLCanvasElement,
|
||||
public CanvasRenderingContextHelper
|
||||
{
|
||||
enum {
|
||||
DEFAULT_CANVAS_WIDTH = 300,
|
||||
DEFAULT_CANVAS_HEIGHT = 150
|
||||
};
|
||||
|
||||
typedef layers::AsyncCanvasRenderer AsyncCanvasRenderer;
|
||||
typedef layers::CanvasLayer CanvasLayer;
|
||||
typedef layers::Layer Layer;
|
||||
typedef layers::LayerManager LayerManager;
|
||||
|
||||
public:
|
||||
explicit HTMLCanvasElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
|
||||
|
||||
NS_IMPL_FROMCONTENT_HTML_WITH_TAG(HTMLCanvasElement, canvas)
|
||||
|
||||
// nsISupports
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
// nsIDOMHTMLCanvasElement
|
||||
NS_DECL_NSIDOMHTMLCANVASELEMENT
|
||||
|
||||
// CC
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLCanvasElement,
|
||||
nsGenericHTMLElement)
|
||||
|
||||
// WebIDL
|
||||
uint32_t Height()
|
||||
{
|
||||
return GetUnsignedIntAttr(nsGkAtoms::height, DEFAULT_CANVAS_HEIGHT);
|
||||
}
|
||||
void SetHeight(uint32_t aHeight, ErrorResult& aRv)
|
||||
{
|
||||
if (mOffscreenCanvas) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return;
|
||||
}
|
||||
|
||||
SetUnsignedIntAttr(nsGkAtoms::height, aHeight, DEFAULT_CANVAS_HEIGHT, aRv);
|
||||
}
|
||||
uint32_t Width()
|
||||
{
|
||||
return GetUnsignedIntAttr(nsGkAtoms::width, DEFAULT_CANVAS_WIDTH);
|
||||
}
|
||||
void SetWidth(uint32_t aWidth, ErrorResult& aRv)
|
||||
{
|
||||
if (mOffscreenCanvas) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return;
|
||||
}
|
||||
|
||||
SetUnsignedIntAttr(nsGkAtoms::width, aWidth, DEFAULT_CANVAS_WIDTH, aRv);
|
||||
}
|
||||
|
||||
virtual already_AddRefed<nsISupports>
|
||||
GetContext(JSContext* aCx, const nsAString& aContextId,
|
||||
JS::Handle<JS::Value> aContextOptions,
|
||||
ErrorResult& aRv) override;
|
||||
|
||||
void ToDataURL(JSContext* aCx, const nsAString& aType,
|
||||
JS::Handle<JS::Value> aParams,
|
||||
nsAString& aDataURL, ErrorResult& aRv)
|
||||
{
|
||||
aRv = ToDataURL(aType, aParams, aCx, aDataURL);
|
||||
}
|
||||
|
||||
void ToBlob(JSContext* aCx,
|
||||
BlobCallback& aCallback,
|
||||
const nsAString& aType,
|
||||
JS::Handle<JS::Value> aParams,
|
||||
ErrorResult& aRv);
|
||||
|
||||
OffscreenCanvas* TransferControlToOffscreen(ErrorResult& aRv);
|
||||
|
||||
bool MozOpaque() const
|
||||
{
|
||||
return GetBoolAttr(nsGkAtoms::moz_opaque);
|
||||
}
|
||||
void SetMozOpaque(bool aValue, ErrorResult& aRv)
|
||||
{
|
||||
if (mOffscreenCanvas) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return;
|
||||
}
|
||||
|
||||
SetHTMLBoolAttr(nsGkAtoms::moz_opaque, aValue, aRv);
|
||||
}
|
||||
already_AddRefed<File> MozGetAsFile(const nsAString& aName,
|
||||
const nsAString& aType,
|
||||
ErrorResult& aRv);
|
||||
already_AddRefed<nsISupports> MozGetIPCContext(const nsAString& aContextId,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
nsCOMPtr<nsISupports> context;
|
||||
aRv = MozGetIPCContext(aContextId, getter_AddRefs(context));
|
||||
return context.forget();
|
||||
}
|
||||
PrintCallback* GetMozPrintCallback() const;
|
||||
void SetMozPrintCallback(PrintCallback* aCallback);
|
||||
|
||||
already_AddRefed<CanvasCaptureMediaStream>
|
||||
CaptureStream(const Optional<double>& aFrameRate, ErrorResult& aRv);
|
||||
|
||||
/**
|
||||
* Get the size in pixels of this canvas element
|
||||
*/
|
||||
nsIntSize GetSize();
|
||||
|
||||
/**
|
||||
* Determine whether the canvas is write-only.
|
||||
*/
|
||||
bool IsWriteOnly();
|
||||
|
||||
/**
|
||||
* Force the canvas to be write-only.
|
||||
*/
|
||||
void SetWriteOnly();
|
||||
|
||||
/**
|
||||
* Notify that some canvas content has changed and the window may
|
||||
* need to be updated. aDamageRect is in canvas coordinates.
|
||||
*/
|
||||
void InvalidateCanvasContent(const mozilla::gfx::Rect* aDamageRect);
|
||||
/*
|
||||
* Notify that we need to repaint the entire canvas, including updating of
|
||||
* the layer tree.
|
||||
*/
|
||||
void InvalidateCanvas();
|
||||
|
||||
/*
|
||||
* Get the number of contexts in this canvas, and request a context at
|
||||
* an index.
|
||||
*/
|
||||
int32_t CountContexts ();
|
||||
nsICanvasRenderingContextInternal *GetContextAtIndex (int32_t index);
|
||||
|
||||
/*
|
||||
* Returns true if the canvas context content is guaranteed to be opaque
|
||||
* across its entire area.
|
||||
*/
|
||||
bool GetIsOpaque();
|
||||
virtual bool GetOpaqueAttr() override;
|
||||
|
||||
virtual already_AddRefed<gfx::SourceSurface> GetSurfaceSnapshot(bool* aPremultAlpha = nullptr);
|
||||
|
||||
/*
|
||||
* Register a FrameCaptureListener with this canvas.
|
||||
* The canvas hooks into the RefreshDriver while there are
|
||||
* FrameCaptureListeners registered.
|
||||
* The registered FrameCaptureListeners are stored as WeakPtrs, thus it's the
|
||||
* caller's responsibility to keep them alive. Once a registered
|
||||
* FrameCaptureListener is destroyed it will be automatically deregistered.
|
||||
*/
|
||||
nsresult RegisterFrameCaptureListener(FrameCaptureListener* aListener);
|
||||
|
||||
/*
|
||||
* Returns true when there is at least one registered FrameCaptureListener
|
||||
* that has requested a frame capture.
|
||||
*/
|
||||
bool IsFrameCaptureRequested() const;
|
||||
|
||||
/*
|
||||
* Processes destroyed FrameCaptureListeners and removes them if necessary.
|
||||
* Should there be none left, the FrameRefreshObserver will be unregistered.
|
||||
*/
|
||||
void ProcessDestroyedFrameListeners();
|
||||
|
||||
/*
|
||||
* Called by the RefreshDriver hook when a frame has been captured.
|
||||
* Makes a copy of the provided surface and hands it to all
|
||||
* FrameCaptureListeners having requested frame capture.
|
||||
*/
|
||||
void SetFrameCapture(already_AddRefed<gfx::SourceSurface> aSurface);
|
||||
|
||||
virtual bool ParseAttribute(int32_t aNamespaceID,
|
||||
nsIAtom* aAttribute,
|
||||
const nsAString& aValue,
|
||||
nsAttrValue& aResult) override;
|
||||
nsChangeHint GetAttributeChangeHint(const nsIAtom* aAttribute, int32_t aModType) const override;
|
||||
|
||||
// SetAttr override. C++ is stupid, so have to override both
|
||||
// overloaded methods.
|
||||
nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
const nsAString& aValue, bool aNotify)
|
||||
{
|
||||
return SetAttr(aNameSpaceID, aName, nullptr, aValue, aNotify);
|
||||
}
|
||||
virtual nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
nsIAtom* aPrefix, const nsAString& aValue,
|
||||
bool aNotify) override;
|
||||
|
||||
virtual nsresult UnsetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
bool aNotify) override;
|
||||
|
||||
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
|
||||
nsresult CopyInnerTo(mozilla::dom::Element* aDest);
|
||||
|
||||
virtual nsresult PreHandleEvent(mozilla::EventChainPreVisitor& aVisitor) override;
|
||||
|
||||
/*
|
||||
* Helpers called by various users of Canvas
|
||||
*/
|
||||
|
||||
already_AddRefed<Layer> GetCanvasLayer(nsDisplayListBuilder* aBuilder,
|
||||
Layer *aOldLayer,
|
||||
LayerManager *aManager);
|
||||
// Should return true if the canvas layer should always be marked inactive.
|
||||
// We should return true here if we can't do accelerated compositing with
|
||||
// a non-BasicCanvasLayer.
|
||||
bool ShouldForceInactiveLayer(LayerManager *aManager);
|
||||
|
||||
// Call this whenever we need future changes to the canvas
|
||||
// to trigger fresh invalidation requests. This needs to be called
|
||||
// whenever we render the canvas contents to the screen, or whenever we
|
||||
// take a snapshot of the canvas that needs to be "live" (e.g. -moz-element).
|
||||
void MarkContextClean();
|
||||
|
||||
// Call this after capturing a frame, so we can avoid unnecessary surface
|
||||
// copies for future frames when no drawing has occurred.
|
||||
void MarkContextCleanForFrameCapture();
|
||||
|
||||
// Starts returning false when something is drawn.
|
||||
bool IsContextCleanForFrameCapture();
|
||||
|
||||
nsresult GetContext(const nsAString& aContextId, nsISupports** aContext);
|
||||
|
||||
layers::LayersBackend GetCompositorBackendType() const;
|
||||
|
||||
void OnVisibilityChange();
|
||||
|
||||
void OnMemoryPressure();
|
||||
|
||||
static void SetAttrFromAsyncCanvasRenderer(AsyncCanvasRenderer *aRenderer);
|
||||
static void InvalidateFromAsyncCanvasRenderer(AsyncCanvasRenderer *aRenderer);
|
||||
|
||||
void StartVRPresentation();
|
||||
void StopVRPresentation();
|
||||
already_AddRefed<layers::SharedSurfaceTextureClient> GetVRFrame();
|
||||
|
||||
protected:
|
||||
virtual ~HTMLCanvasElement();
|
||||
|
||||
virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
virtual nsIntSize GetWidthHeight() override;
|
||||
|
||||
virtual already_AddRefed<nsICanvasRenderingContextInternal>
|
||||
CreateContext(CanvasContextType aContextType) override;
|
||||
|
||||
nsresult ExtractData(nsAString& aType,
|
||||
const nsAString& aOptions,
|
||||
nsIInputStream** aStream);
|
||||
nsresult ToDataURLImpl(JSContext* aCx,
|
||||
const nsAString& aMimeType,
|
||||
const JS::Value& aEncoderOptions,
|
||||
nsAString& aDataURL);
|
||||
nsresult MozGetAsBlobImpl(const nsAString& aName,
|
||||
const nsAString& aType,
|
||||
nsISupports** aResult);
|
||||
void CallPrintCallback();
|
||||
|
||||
AsyncCanvasRenderer* GetAsyncCanvasRenderer();
|
||||
|
||||
bool mResetLayer;
|
||||
RefPtr<HTMLCanvasElement> mOriginalCanvas;
|
||||
RefPtr<PrintCallback> mPrintCallback;
|
||||
RefPtr<HTMLCanvasPrintState> mPrintState;
|
||||
nsTArray<WeakPtr<FrameCaptureListener>> mRequestedFrameListeners;
|
||||
RefPtr<RequestedFrameRefreshObserver> mRequestedFrameRefreshObserver;
|
||||
RefPtr<AsyncCanvasRenderer> mAsyncCanvasRenderer;
|
||||
RefPtr<OffscreenCanvas> mOffscreenCanvas;
|
||||
RefPtr<HTMLCanvasElementObserver> mContextObserver;
|
||||
bool mVRPresentationActive;
|
||||
|
||||
public:
|
||||
// Record whether this canvas should be write-only or not.
|
||||
// We set this when script paints an image from a different origin.
|
||||
// We also transitively set it when script paints a canvas which
|
||||
// is itself write-only.
|
||||
bool mWriteOnly;
|
||||
|
||||
bool IsPrintCallbackDone();
|
||||
|
||||
void HandlePrintCallback(nsPresContext::nsPresContextType aType);
|
||||
|
||||
nsresult DispatchPrintCallback(nsITimerCallback* aCallback);
|
||||
|
||||
void ResetPrintCallback();
|
||||
|
||||
HTMLCanvasElement* GetOriginalCanvas();
|
||||
|
||||
CanvasContextType GetCurrentContextType() {
|
||||
return mCurrentContextType;
|
||||
}
|
||||
};
|
||||
|
||||
class HTMLCanvasPrintState final : public nsWrapperCache
|
||||
{
|
||||
public:
|
||||
HTMLCanvasPrintState(HTMLCanvasElement* aCanvas,
|
||||
nsICanvasRenderingContextInternal* aContext,
|
||||
nsITimerCallback* aCallback);
|
||||
|
||||
nsISupports* Context() const;
|
||||
|
||||
void Done();
|
||||
|
||||
void NotifyDone();
|
||||
|
||||
bool mIsDone;
|
||||
|
||||
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(HTMLCanvasPrintState)
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(HTMLCanvasPrintState)
|
||||
|
||||
virtual JSObject* WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
HTMLCanvasElement* GetParentObject()
|
||||
{
|
||||
return mCanvas;
|
||||
}
|
||||
|
||||
private:
|
||||
~HTMLCanvasPrintState();
|
||||
bool mPendingNotify;
|
||||
|
||||
protected:
|
||||
RefPtr<HTMLCanvasElement> mCanvas;
|
||||
nsCOMPtr<nsICanvasRenderingContextInternal> mContext;
|
||||
nsCOMPtr<nsITimerCallback> mCallback;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* mozilla_dom_HTMLCanvasElement_h */
|
||||
393
dom/html/HTMLContentElement.cpp
Normal file
393
dom/html/HTMLContentElement.cpp
Normal file
|
|
@ -0,0 +1,393 @@
|
|||
/* -*- 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/HTMLContentElement.h"
|
||||
#include "mozilla/dom/HTMLContentElementBinding.h"
|
||||
#include "mozilla/dom/HTMLUnknownElement.h"
|
||||
#include "mozilla/dom/NodeListBinding.h"
|
||||
#include "mozilla/dom/ShadowRoot.h"
|
||||
#include "mozilla/css/StyleRule.h"
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsStyleConsts.h"
|
||||
#include "nsIAtom.h"
|
||||
#include "nsCSSRuleProcessor.h"
|
||||
#include "nsRuleData.h"
|
||||
#include "nsRuleProcessorData.h"
|
||||
#include "nsRuleWalker.h"
|
||||
#include "nsCSSParser.h"
|
||||
#include "nsDocument.h"
|
||||
|
||||
// Expand NS_IMPL_NS_NEW_HTML_ELEMENT(Content) to add check for web components
|
||||
// being enabled.
|
||||
nsGenericHTMLElement*
|
||||
NS_NewHTMLContentElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
|
||||
mozilla::dom::FromParser aFromParser)
|
||||
{
|
||||
// When this check is removed, remove the nsDocument.h and
|
||||
// HTMLUnknownElement.h includes. Also remove nsINode::IsHTMLContentElement.
|
||||
//
|
||||
// We have to jump through some hoops to be able to produce both NodeInfo* and
|
||||
// already_AddRefed<NodeInfo>& for our callees.
|
||||
RefPtr<mozilla::dom::NodeInfo> nodeInfo(aNodeInfo);
|
||||
if (!nsDocument::IsWebComponentsEnabled(nodeInfo)) {
|
||||
already_AddRefed<mozilla::dom::NodeInfo> nodeInfoArg(nodeInfo.forget());
|
||||
return new mozilla::dom::HTMLUnknownElement(nodeInfoArg);
|
||||
}
|
||||
|
||||
already_AddRefed<mozilla::dom::NodeInfo> nodeInfoArg(nodeInfo.forget());
|
||||
return new mozilla::dom::HTMLContentElement(nodeInfoArg);
|
||||
}
|
||||
|
||||
using namespace mozilla::dom;
|
||||
|
||||
HTMLContentElement::HTMLContentElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
|
||||
: nsGenericHTMLElement(aNodeInfo), mValidSelector(true), mIsInsertionPoint(false)
|
||||
{
|
||||
}
|
||||
|
||||
HTMLContentElement::~HTMLContentElement()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_INHERITED(HTMLContentElement,
|
||||
nsGenericHTMLElement,
|
||||
mMatchedNodes)
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(HTMLContentElement, Element)
|
||||
NS_IMPL_RELEASE_INHERITED(HTMLContentElement, Element)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(HTMLContentElement)
|
||||
NS_INTERFACE_MAP_END_INHERITING(nsGenericHTMLElement)
|
||||
|
||||
NS_IMPL_ELEMENT_CLONE(HTMLContentElement)
|
||||
|
||||
JSObject*
|
||||
HTMLContentElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return HTMLContentElementBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLContentElement::BindToTree(nsIDocument* aDocument,
|
||||
nsIContent* aParent,
|
||||
nsIContent* aBindingParent,
|
||||
bool aCompileEventHandlers)
|
||||
{
|
||||
RefPtr<ShadowRoot> oldContainingShadow = GetContainingShadow();
|
||||
|
||||
nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent,
|
||||
aBindingParent,
|
||||
aCompileEventHandlers);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
ShadowRoot* containingShadow = GetContainingShadow();
|
||||
if (containingShadow && !oldContainingShadow) {
|
||||
nsINode* parentNode = nsINode::GetParentNode();
|
||||
while (parentNode && parentNode != containingShadow) {
|
||||
if (parentNode->IsHTMLContentElement()) {
|
||||
// Content element in fallback content is not an insertion point.
|
||||
return NS_OK;
|
||||
}
|
||||
parentNode = parentNode->GetParentNode();
|
||||
}
|
||||
|
||||
// If the content element is being inserted into a ShadowRoot,
|
||||
// add this element to the list of insertion points.
|
||||
mIsInsertionPoint = true;
|
||||
containingShadow->AddInsertionPoint(this);
|
||||
containingShadow->SetInsertionPointChanged();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
HTMLContentElement::UnbindFromTree(bool aDeep, bool aNullParent)
|
||||
{
|
||||
RefPtr<ShadowRoot> oldContainingShadow = GetContainingShadow();
|
||||
|
||||
nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
|
||||
|
||||
if (oldContainingShadow && !GetContainingShadow() && mIsInsertionPoint) {
|
||||
oldContainingShadow->RemoveInsertionPoint(this);
|
||||
|
||||
// Remove all the matched nodes now that the
|
||||
// insertion point is no longer an insertion point.
|
||||
ClearMatchedNodes();
|
||||
oldContainingShadow->SetInsertionPointChanged();
|
||||
|
||||
mIsInsertionPoint = false;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
HTMLContentElement::AppendMatchedNode(nsIContent* aContent)
|
||||
{
|
||||
mMatchedNodes.AppendElement(aContent);
|
||||
nsTArray<nsIContent*>& destInsertionPoint = aContent->DestInsertionPoints();
|
||||
destInsertionPoint.AppendElement(this);
|
||||
|
||||
if (mMatchedNodes.Length() == 1) {
|
||||
// Fallback content gets dropped so we need to updated fallback
|
||||
// content distribution.
|
||||
UpdateFallbackDistribution();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
HTMLContentElement::UpdateFallbackDistribution()
|
||||
{
|
||||
for (nsIContent* child = nsINode::GetFirstChild();
|
||||
child;
|
||||
child = child->GetNextSibling()) {
|
||||
nsTArray<nsIContent*>& destInsertionPoint = child->DestInsertionPoints();
|
||||
destInsertionPoint.Clear();
|
||||
if (mMatchedNodes.IsEmpty()) {
|
||||
destInsertionPoint.AppendElement(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
HTMLContentElement::RemoveMatchedNode(nsIContent* aContent)
|
||||
{
|
||||
mMatchedNodes.RemoveElement(aContent);
|
||||
ShadowRoot::RemoveDestInsertionPoint(this, aContent->DestInsertionPoints());
|
||||
|
||||
if (mMatchedNodes.IsEmpty()) {
|
||||
// Fallback content is activated so we need to update fallback
|
||||
// content distribution.
|
||||
UpdateFallbackDistribution();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
HTMLContentElement::InsertMatchedNode(uint32_t aIndex, nsIContent* aContent)
|
||||
{
|
||||
mMatchedNodes.InsertElementAt(aIndex, aContent);
|
||||
nsTArray<nsIContent*>& destInsertionPoint = aContent->DestInsertionPoints();
|
||||
destInsertionPoint.AppendElement(this);
|
||||
|
||||
if (mMatchedNodes.Length() == 1) {
|
||||
// Fallback content gets dropped so we need to updated fallback
|
||||
// content distribution.
|
||||
UpdateFallbackDistribution();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
HTMLContentElement::ClearMatchedNodes()
|
||||
{
|
||||
for (uint32_t i = 0; i < mMatchedNodes.Length(); i++) {
|
||||
ShadowRoot::RemoveDestInsertionPoint(this, mMatchedNodes[i]->DestInsertionPoints());
|
||||
}
|
||||
|
||||
mMatchedNodes.Clear();
|
||||
|
||||
UpdateFallbackDistribution();
|
||||
}
|
||||
|
||||
static bool
|
||||
IsValidContentSelectors(nsCSSSelector* aSelector)
|
||||
{
|
||||
nsCSSSelector* currentSelector = aSelector;
|
||||
while (currentSelector) {
|
||||
// Blacklist invalid selector fragments.
|
||||
if (currentSelector->IsPseudoElement() ||
|
||||
currentSelector->mPseudoClassList ||
|
||||
currentSelector->mNegations ||
|
||||
currentSelector->mOperator) {
|
||||
return false;
|
||||
}
|
||||
|
||||
currentSelector = currentSelector->mNext;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLContentElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
nsIAtom* aPrefix, const nsAString& aValue,
|
||||
bool aNotify)
|
||||
{
|
||||
nsresult rv = nsGenericHTMLElement::SetAttr(aNameSpaceID, aName, aPrefix,
|
||||
aValue, aNotify);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::select) {
|
||||
// Select attribute was updated, the insertion point may match different
|
||||
// elements.
|
||||
nsIDocument* doc = OwnerDoc();
|
||||
nsCSSParser parser(doc->CSSLoader());
|
||||
|
||||
mValidSelector = true;
|
||||
mSelectorList = nullptr;
|
||||
|
||||
nsresult rv = parser.ParseSelectorString(aValue,
|
||||
doc->GetDocumentURI(),
|
||||
// Bug 11240
|
||||
0, // XXX get the line number!
|
||||
getter_Transfers(mSelectorList));
|
||||
|
||||
// We don't want to return an exception if parsing failed because
|
||||
// the spec does not define it as an exception case.
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// Ensure that all the selectors are valid
|
||||
nsCSSSelectorList* selectors = mSelectorList;
|
||||
while (selectors) {
|
||||
if (!IsValidContentSelectors(selectors->mSelectors)) {
|
||||
// If we have an invalid selector, we can not match anything.
|
||||
mValidSelector = false;
|
||||
mSelectorList = nullptr;
|
||||
break;
|
||||
}
|
||||
selectors = selectors->mNext;
|
||||
}
|
||||
}
|
||||
|
||||
ShadowRoot* containingShadow = GetContainingShadow();
|
||||
if (containingShadow) {
|
||||
containingShadow->DistributeAllNodes();
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLContentElement::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
|
||||
bool aNotify)
|
||||
{
|
||||
nsresult rv = nsGenericHTMLElement::UnsetAttr(aNameSpaceID,
|
||||
aAttribute, aNotify);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (aNameSpaceID == kNameSpaceID_None && aAttribute == nsGkAtoms::select) {
|
||||
// The select attribute was removed. This insertion point becomes
|
||||
// a universal selector.
|
||||
mValidSelector = true;
|
||||
mSelectorList = nullptr;
|
||||
|
||||
ShadowRoot* containingShadow = GetContainingShadow();
|
||||
if (containingShadow) {
|
||||
containingShadow->DistributeAllNodes();
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
HTMLContentElement::Match(nsIContent* aContent)
|
||||
{
|
||||
if (!mValidSelector) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mSelectorList) {
|
||||
nsIDocument* doc = OwnerDoc();
|
||||
ShadowRoot* containingShadow = GetContainingShadow();
|
||||
nsIContent* host = containingShadow->GetHost();
|
||||
|
||||
TreeMatchContext matchingContext(false, nsRuleWalker::eRelevantLinkUnvisited,
|
||||
doc, TreeMatchContext::eNeverMatchVisited);
|
||||
doc->FlushPendingLinkUpdates();
|
||||
matchingContext.SetHasSpecifiedScope();
|
||||
matchingContext.AddScopeElement(host->AsElement());
|
||||
|
||||
if (!aContent->IsElement()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return nsCSSRuleProcessor::SelectorListMatches(aContent->AsElement(),
|
||||
matchingContext,
|
||||
mSelectorList);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
already_AddRefed<DistributedContentList>
|
||||
HTMLContentElement::GetDistributedNodes()
|
||||
{
|
||||
RefPtr<DistributedContentList> list = new DistributedContentList(this);
|
||||
return list.forget();
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DistributedContentList, mParent,
|
||||
mDistributedNodes)
|
||||
|
||||
NS_INTERFACE_TABLE_HEAD(DistributedContentList)
|
||||
NS_WRAPPERCACHE_INTERFACE_TABLE_ENTRY
|
||||
NS_INTERFACE_TABLE(DistributedContentList, nsINodeList, nsIDOMNodeList)
|
||||
NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(DistributedContentList)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(DistributedContentList)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(DistributedContentList)
|
||||
|
||||
DistributedContentList::DistributedContentList(HTMLContentElement* aHostElement)
|
||||
: mParent(aHostElement)
|
||||
{
|
||||
MOZ_COUNT_CTOR(DistributedContentList);
|
||||
|
||||
if (aHostElement->IsInsertionPoint()) {
|
||||
if (aHostElement->MatchedNodes().IsEmpty()) {
|
||||
// Fallback content.
|
||||
nsINode* contentNode = aHostElement;
|
||||
for (nsIContent* content = contentNode->GetFirstChild();
|
||||
content;
|
||||
content = content->GetNextSibling()) {
|
||||
mDistributedNodes.AppendElement(content);
|
||||
}
|
||||
} else {
|
||||
mDistributedNodes.AppendElements(aHostElement->MatchedNodes());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DistributedContentList::~DistributedContentList()
|
||||
{
|
||||
MOZ_COUNT_DTOR(DistributedContentList);
|
||||
}
|
||||
|
||||
nsIContent*
|
||||
DistributedContentList::Item(uint32_t aIndex)
|
||||
{
|
||||
return mDistributedNodes.SafeElementAt(aIndex);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DistributedContentList::Item(uint32_t aIndex, nsIDOMNode** aReturn)
|
||||
{
|
||||
nsIContent* item = Item(aIndex);
|
||||
if (!item) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return CallQueryInterface(item, aReturn);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DistributedContentList::GetLength(uint32_t* aLength)
|
||||
{
|
||||
*aLength = mDistributedNodes.Length();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
int32_t
|
||||
DistributedContentList::IndexOf(nsIContent* aContent)
|
||||
{
|
||||
return mDistributedNodes.IndexOf(aContent);
|
||||
}
|
||||
|
||||
JSObject*
|
||||
DistributedContentList::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return NodeListBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
135
dom/html/HTMLContentElement.h
Normal file
135
dom/html/HTMLContentElement.h
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_dom_HTMLContentElement_h__
|
||||
#define mozilla_dom_HTMLContentElement_h__
|
||||
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsINodeList.h"
|
||||
#include "nsGenericHTMLElement.h"
|
||||
|
||||
struct nsCSSSelectorList;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class DistributedContentList;
|
||||
|
||||
class HTMLContentElement final : public nsGenericHTMLElement
|
||||
{
|
||||
public:
|
||||
explicit HTMLContentElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
|
||||
|
||||
// nsISupports
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLContentElement,
|
||||
nsGenericHTMLElement)
|
||||
|
||||
static HTMLContentElement* FromContent(nsIContent* aContent)
|
||||
{
|
||||
if (aContent->IsHTMLContentElement()) {
|
||||
return static_cast<HTMLContentElement*>(aContent);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
virtual bool IsHTMLContentElement() const override { return true; }
|
||||
|
||||
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
|
||||
|
||||
virtual nsIDOMNode* AsDOMNode() override { return this; }
|
||||
|
||||
virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
||||
nsIContent* aBindingParent,
|
||||
bool aCompileEventHandlers) override;
|
||||
|
||||
virtual void UnbindFromTree(bool aDeep = true,
|
||||
bool aNullParent = true) override;
|
||||
|
||||
/**
|
||||
* Returns whether if the selector of this insertion point
|
||||
* matches the provided content.
|
||||
*/
|
||||
bool Match(nsIContent* aContent);
|
||||
bool IsInsertionPoint() const { return mIsInsertionPoint; }
|
||||
nsCOMArray<nsIContent>& MatchedNodes() { return mMatchedNodes; }
|
||||
void AppendMatchedNode(nsIContent* aContent);
|
||||
void RemoveMatchedNode(nsIContent* aContent);
|
||||
void InsertMatchedNode(uint32_t aIndex, nsIContent* aContent);
|
||||
void ClearMatchedNodes();
|
||||
|
||||
virtual nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
nsIAtom* aPrefix, const nsAString& aValue,
|
||||
bool aNotify) override;
|
||||
|
||||
virtual nsresult UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
|
||||
bool aNotify) override;
|
||||
|
||||
// WebIDL methods.
|
||||
already_AddRefed<DistributedContentList> GetDistributedNodes();
|
||||
void GetSelect(nsAString& aSelect)
|
||||
{
|
||||
Element::GetAttr(kNameSpaceID_None, nsGkAtoms::select, aSelect);
|
||||
}
|
||||
void SetSelect(const nsAString& aSelect)
|
||||
{
|
||||
Element::SetAttr(kNameSpaceID_None, nsGkAtoms::select, aSelect, true);
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual ~HTMLContentElement();
|
||||
|
||||
virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
/**
|
||||
* Updates the destination insertion points of the fallback
|
||||
* content of this insertion point. If there are nodes matched
|
||||
* to this insertion point, then destination insertion points
|
||||
* of fallback are cleared, otherwise, this insertion point
|
||||
* is a destination insertion point.
|
||||
*/
|
||||
void UpdateFallbackDistribution();
|
||||
|
||||
/**
|
||||
* An array of nodes from the ShadowRoot host that match the
|
||||
* content insertion selector.
|
||||
*/
|
||||
nsCOMArray<nsIContent> mMatchedNodes;
|
||||
|
||||
nsAutoPtr<nsCSSSelectorList> mSelectorList;
|
||||
bool mValidSelector;
|
||||
bool mIsInsertionPoint;
|
||||
};
|
||||
|
||||
class DistributedContentList : public nsINodeList
|
||||
{
|
||||
public:
|
||||
explicit DistributedContentList(HTMLContentElement* aHostElement);
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(DistributedContentList)
|
||||
|
||||
// nsIDOMNodeList
|
||||
NS_DECL_NSIDOMNODELIST
|
||||
|
||||
// nsINodeList
|
||||
virtual nsIContent* Item(uint32_t aIndex) override;
|
||||
virtual int32_t IndexOf(nsIContent* aContent) override;
|
||||
virtual nsINode* GetParentObject() override { return mParent; }
|
||||
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
protected:
|
||||
virtual ~DistributedContentList();
|
||||
RefPtr<HTMLContentElement> mParent;
|
||||
nsCOMArray<nsIContent> mDistributedNodes;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_HTMLContentElement_h__
|
||||
|
||||
34
dom/html/HTMLDataElement.cpp
Normal file
34
dom/html/HTMLDataElement.cpp
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/* -*- 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 "HTMLDataElement.h"
|
||||
#include "mozilla/dom/HTMLDataElementBinding.h"
|
||||
#include "nsGenericHTMLElement.h"
|
||||
|
||||
NS_IMPL_NS_NEW_HTML_ELEMENT(Data)
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
HTMLDataElement::HTMLDataElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
|
||||
: nsGenericHTMLElement(aNodeInfo)
|
||||
{
|
||||
}
|
||||
|
||||
HTMLDataElement::~HTMLDataElement()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMPL_ELEMENT_CLONE(HTMLDataElement)
|
||||
|
||||
JSObject*
|
||||
HTMLDataElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return HTMLDataElementBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
45
dom/html/HTMLDataElement.h
Normal file
45
dom/html/HTMLDataElement.h
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_dom_HTMLDataElement_h
|
||||
#define mozilla_dom_HTMLDataElement_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsIDOMHTMLElement.h"
|
||||
#include "nsGenericHTMLElement.h"
|
||||
#include "nsGkAtoms.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class HTMLDataElement final : public nsGenericHTMLElement
|
||||
{
|
||||
public:
|
||||
explicit HTMLDataElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
|
||||
|
||||
// HTMLDataElement WebIDL
|
||||
void GetValue(DOMString& aValue)
|
||||
{
|
||||
GetHTMLAttr(nsGkAtoms::value, aValue);
|
||||
}
|
||||
|
||||
void SetValue(const nsAString& aValue, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::value, aValue, aError);
|
||||
}
|
||||
|
||||
virtual nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult) const override;
|
||||
|
||||
protected:
|
||||
virtual ~HTMLDataElement();
|
||||
|
||||
virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_HTMLDataElement_h
|
||||
46
dom/html/HTMLDataListElement.cpp
Normal file
46
dom/html/HTMLDataListElement.cpp
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
/* -*- 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 "HTMLDataListElement.h"
|
||||
#include "mozilla/dom/HTMLDataListElementBinding.h"
|
||||
|
||||
NS_IMPL_NS_NEW_HTML_ELEMENT(DataList)
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
HTMLDataListElement::~HTMLDataListElement()
|
||||
{
|
||||
}
|
||||
|
||||
JSObject*
|
||||
HTMLDataListElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return HTMLDataListElementBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_INHERITED(HTMLDataListElement, nsGenericHTMLElement,
|
||||
mOptions)
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(HTMLDataListElement, Element)
|
||||
NS_IMPL_RELEASE_INHERITED(HTMLDataListElement, Element)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(HTMLDataListElement)
|
||||
NS_INTERFACE_MAP_END_INHERITING(nsGenericHTMLElement)
|
||||
|
||||
|
||||
NS_IMPL_ELEMENT_CLONE(HTMLDataListElement)
|
||||
|
||||
bool
|
||||
HTMLDataListElement::MatchOptions(nsIContent* aContent, int32_t aNamespaceID,
|
||||
nsIAtom* aAtom, void* aData)
|
||||
{
|
||||
return aContent->NodeInfo()->Equals(nsGkAtoms::option, kNameSpaceID_XHTML) &&
|
||||
!aContent->HasAttr(kNameSpaceID_None, nsGkAtoms::disabled);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
57
dom/html/HTMLDataListElement.h
Normal file
57
dom/html/HTMLDataListElement.h
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
/* -*- 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/. */
|
||||
#ifndef HTMLDataListElement_h___
|
||||
#define HTMLDataListElement_h___
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsGenericHTMLElement.h"
|
||||
#include "nsContentList.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class HTMLDataListElement final : public nsGenericHTMLElement
|
||||
{
|
||||
public:
|
||||
explicit HTMLDataListElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
|
||||
: nsGenericHTMLElement(aNodeInfo)
|
||||
{
|
||||
}
|
||||
|
||||
// nsISupports
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
nsContentList* Options()
|
||||
{
|
||||
if (!mOptions) {
|
||||
mOptions = new nsContentList(this, MatchOptions, nullptr, nullptr, true);
|
||||
}
|
||||
|
||||
return mOptions;
|
||||
}
|
||||
|
||||
|
||||
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
|
||||
|
||||
// This function is used to generate the nsContentList (option elements).
|
||||
static bool MatchOptions(nsIContent* aContent, int32_t aNamespaceID,
|
||||
nsIAtom* aAtom, void* aData);
|
||||
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLDataListElement,
|
||||
nsGenericHTMLElement)
|
||||
protected:
|
||||
virtual ~HTMLDataListElement();
|
||||
|
||||
virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
// <option>'s list inside the datalist element.
|
||||
RefPtr<nsContentList> mOptions;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* HTMLDataListElement_h___ */
|
||||
111
dom/html/HTMLDetailsElement.cpp
Normal file
111
dom/html/HTMLDetailsElement.cpp
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
/* -*- Mode: C++; tab-width: 2; 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/HTMLDetailsElement.h"
|
||||
|
||||
#include "mozilla/dom/HTMLDetailsElementBinding.h"
|
||||
#include "mozilla/dom/HTMLUnknownElement.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
// Expand NS_IMPL_NS_NEW_HTML_ELEMENT(Details) to add pref check.
|
||||
nsGenericHTMLElement*
|
||||
NS_NewHTMLDetailsElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
|
||||
mozilla::dom::FromParser aFromParser)
|
||||
{
|
||||
if (!mozilla::dom::HTMLDetailsElement::IsDetailsEnabled()) {
|
||||
return new mozilla::dom::HTMLUnknownElement(aNodeInfo);
|
||||
}
|
||||
|
||||
return new mozilla::dom::HTMLDetailsElement(aNodeInfo);
|
||||
}
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
/* static */ bool
|
||||
HTMLDetailsElement::IsDetailsEnabled()
|
||||
{
|
||||
static bool isDetailsEnabled = false;
|
||||
static bool added = false;
|
||||
|
||||
if (!added) {
|
||||
Preferences::AddBoolVarCache(&isDetailsEnabled,
|
||||
"dom.details_element.enabled");
|
||||
added = true;
|
||||
}
|
||||
|
||||
return isDetailsEnabled;
|
||||
}
|
||||
|
||||
HTMLDetailsElement::~HTMLDetailsElement()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMPL_ELEMENT_CLONE(HTMLDetailsElement)
|
||||
|
||||
nsIContent*
|
||||
HTMLDetailsElement::GetFirstSummary() const
|
||||
{
|
||||
// XXX: Bug 1245032: Might want to cache the first summary element.
|
||||
for (nsIContent* child = nsINode::GetFirstChild();
|
||||
child;
|
||||
child = child->GetNextSibling()) {
|
||||
if (child->IsHTMLElement(nsGkAtoms::summary)) {
|
||||
return child;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsChangeHint
|
||||
HTMLDetailsElement::GetAttributeChangeHint(const nsIAtom* aAttribute,
|
||||
int32_t aModType) const
|
||||
{
|
||||
nsChangeHint hint =
|
||||
nsGenericHTMLElement::GetAttributeChangeHint(aAttribute, aModType);
|
||||
if (aAttribute == nsGkAtoms::open) {
|
||||
hint |= nsChangeHint_ReconstructFrame;
|
||||
}
|
||||
return hint;
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLDetailsElement::BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
nsAttrValueOrString* aValue, bool aNotify)
|
||||
{
|
||||
if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::open) {
|
||||
bool setOpen = aValue != nullptr;
|
||||
if (Open() != setOpen) {
|
||||
if (mToggleEventDispatcher) {
|
||||
mToggleEventDispatcher->Cancel();
|
||||
}
|
||||
// According to the html spec, a 'toggle' event is a simple event which
|
||||
// does not bubble.
|
||||
mToggleEventDispatcher =
|
||||
new AsyncEventDispatcher(this, NS_LITERAL_STRING("toggle"), false);
|
||||
mToggleEventDispatcher->PostDOMEvent();
|
||||
}
|
||||
}
|
||||
|
||||
return nsGenericHTMLElement::BeforeSetAttr(aNameSpaceID, aName, aValue,
|
||||
aNotify);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLDetailsElement::AsyncEventRunning(AsyncEventDispatcher* aEvent)
|
||||
{
|
||||
if (mToggleEventDispatcher == aEvent) {
|
||||
mToggleEventDispatcher = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
JSObject*
|
||||
HTMLDetailsElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return HTMLDetailsElementBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
74
dom/html/HTMLDetailsElement.h
Normal file
74
dom/html/HTMLDetailsElement.h
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
/* -*- Mode: C++; tab-width: 2; 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/. */
|
||||
|
||||
#ifndef mozilla_dom_HTMLDetailsElement_h
|
||||
#define mozilla_dom_HTMLDetailsElement_h
|
||||
|
||||
#include "mozilla/AsyncEventDispatcher.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsGenericHTMLElement.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
// HTMLDetailsElement implements the <details> tag, which is used as a
|
||||
// disclosure widget from which the user can obtain additional information or
|
||||
// controls. Please see the spec for more information.
|
||||
// https://html.spec.whatwg.org/multipage/forms.html#the-details-element
|
||||
//
|
||||
class HTMLDetailsElement final : public nsGenericHTMLElement
|
||||
{
|
||||
public:
|
||||
using NodeInfo = mozilla::dom::NodeInfo;
|
||||
|
||||
static bool IsDetailsEnabled();
|
||||
|
||||
explicit HTMLDetailsElement(already_AddRefed<NodeInfo>& aNodeInfo)
|
||||
: nsGenericHTMLElement(aNodeInfo)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMPL_FROMCONTENT_HTML_WITH_TAG(HTMLDetailsElement, details)
|
||||
|
||||
nsIContent* GetFirstSummary() const;
|
||||
|
||||
nsresult Clone(NodeInfo* aNodeInfo, nsINode** aResult) const override;
|
||||
|
||||
nsChangeHint GetAttributeChangeHint(const nsIAtom* aAttribute,
|
||||
int32_t aModType) const override;
|
||||
|
||||
nsresult BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
nsAttrValueOrString* aValue, bool aNotify) override;
|
||||
|
||||
// HTMLDetailsElement WebIDL
|
||||
bool Open() const { return GetBoolAttr(nsGkAtoms::open); }
|
||||
|
||||
void SetOpen(bool aOpen, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLBoolAttr(nsGkAtoms::open, aOpen, aError);
|
||||
}
|
||||
|
||||
void ToggleOpen()
|
||||
{
|
||||
ErrorResult rv;
|
||||
SetOpen(!Open(), rv);
|
||||
rv.SuppressException();
|
||||
}
|
||||
|
||||
virtual void AsyncEventRunning(AsyncEventDispatcher* aEvent) override;
|
||||
|
||||
protected:
|
||||
virtual ~HTMLDetailsElement();
|
||||
|
||||
JSObject* WrapNode(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
RefPtr<AsyncEventDispatcher> mToggleEventDispatcher;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* mozilla_dom_HTMLDetailsElement_h */
|
||||
113
dom/html/HTMLDivElement.cpp
Normal file
113
dom/html/HTMLDivElement.cpp
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
/* -*- 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 "HTMLDivElement.h"
|
||||
#include "nsGenericHTMLElement.h"
|
||||
#include "nsStyleConsts.h"
|
||||
#include "nsMappedAttributes.h"
|
||||
#include "mozilla/dom/HTMLDivElementBinding.h"
|
||||
|
||||
NS_IMPL_NS_NEW_HTML_ELEMENT(Div)
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
HTMLDivElement::~HTMLDivElement()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMPL_ELEMENT_CLONE(HTMLDivElement)
|
||||
|
||||
JSObject*
|
||||
HTMLDivElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return dom::HTMLDivElementBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
bool
|
||||
HTMLDivElement::ParseAttribute(int32_t aNamespaceID,
|
||||
nsIAtom* aAttribute,
|
||||
const nsAString& aValue,
|
||||
nsAttrValue& aResult)
|
||||
{
|
||||
if (aNamespaceID == kNameSpaceID_None) {
|
||||
if (mNodeInfo->Equals(nsGkAtoms::marquee)) {
|
||||
if ((aAttribute == nsGkAtoms::width) ||
|
||||
(aAttribute == nsGkAtoms::height)) {
|
||||
return aResult.ParseSpecialIntValue(aValue);
|
||||
}
|
||||
if (aAttribute == nsGkAtoms::bgcolor) {
|
||||
return aResult.ParseColor(aValue);
|
||||
}
|
||||
if ((aAttribute == nsGkAtoms::hspace) ||
|
||||
(aAttribute == nsGkAtoms::vspace)) {
|
||||
return aResult.ParseIntWithBounds(aValue, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (mNodeInfo->Equals(nsGkAtoms::div) &&
|
||||
aAttribute == nsGkAtoms::align) {
|
||||
return ParseDivAlignValue(aValue, aResult);
|
||||
}
|
||||
}
|
||||
|
||||
return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
|
||||
aResult);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLDivElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
|
||||
nsRuleData* aData)
|
||||
{
|
||||
nsGenericHTMLElement::MapDivAlignAttributeInto(aAttributes, aData);
|
||||
nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aData);
|
||||
}
|
||||
|
||||
static void
|
||||
MapMarqueeAttributesIntoRule(const nsMappedAttributes* aAttributes, nsRuleData* aData)
|
||||
{
|
||||
nsGenericHTMLElement::MapImageMarginAttributeInto(aAttributes, aData);
|
||||
nsGenericHTMLElement::MapImageSizeAttributesInto(aAttributes, aData);
|
||||
nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aData);
|
||||
nsGenericHTMLElement::MapBGColorInto(aAttributes, aData);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(bool)
|
||||
HTMLDivElement::IsAttributeMapped(const nsIAtom* aAttribute) const
|
||||
{
|
||||
if (mNodeInfo->Equals(nsGkAtoms::div)) {
|
||||
static const MappedAttributeEntry* const map[] = {
|
||||
sDivAlignAttributeMap,
|
||||
sCommonAttributeMap
|
||||
};
|
||||
return FindAttributeDependence(aAttribute, map);
|
||||
}
|
||||
if (mNodeInfo->Equals(nsGkAtoms::marquee)) {
|
||||
static const MappedAttributeEntry* const map[] = {
|
||||
sImageMarginSizeAttributeMap,
|
||||
sBackgroundColorAttributeMap,
|
||||
sCommonAttributeMap
|
||||
};
|
||||
return FindAttributeDependence(aAttribute, map);
|
||||
}
|
||||
|
||||
return nsGenericHTMLElement::IsAttributeMapped(aAttribute);
|
||||
}
|
||||
|
||||
nsMapRuleToAttributesFunc
|
||||
HTMLDivElement::GetAttributeMappingFunction() const
|
||||
{
|
||||
if (mNodeInfo->Equals(nsGkAtoms::div)) {
|
||||
return &MapAttributesIntoRule;
|
||||
}
|
||||
if (mNodeInfo->Equals(nsGkAtoms::marquee)) {
|
||||
return &MapMarqueeAttributesIntoRule;
|
||||
}
|
||||
return nsGenericHTMLElement::GetAttributeMappingFunction();
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
53
dom/html/HTMLDivElement.h
Normal file
53
dom/html/HTMLDivElement.h
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/* -*- 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/. */
|
||||
#ifndef HTMLDivElement_h___
|
||||
#define HTMLDivElement_h___
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsGenericHTMLElement.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class HTMLDivElement final : public nsGenericHTMLElement
|
||||
{
|
||||
public:
|
||||
explicit HTMLDivElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
|
||||
: nsGenericHTMLElement(aNodeInfo)
|
||||
{
|
||||
}
|
||||
|
||||
void GetAlign(DOMString& aAlign)
|
||||
{
|
||||
GetHTMLAttr(nsGkAtoms::align, aAlign);
|
||||
}
|
||||
void SetAlign(const nsAString& aAlign, mozilla::ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::align, aAlign, aError);
|
||||
}
|
||||
|
||||
virtual bool ParseAttribute(int32_t aNamespaceID,
|
||||
nsIAtom* aAttribute,
|
||||
const nsAString& aValue,
|
||||
nsAttrValue& aResult) override;
|
||||
NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
|
||||
virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const override;
|
||||
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
|
||||
|
||||
protected:
|
||||
virtual ~HTMLDivElement();
|
||||
|
||||
virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
private:
|
||||
static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
|
||||
nsRuleData* aData);
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* HTMLDivElement_h___ */
|
||||
54
dom/html/HTMLElement.cpp
Normal file
54
dom/html/HTMLElement.cpp
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
/* -*- 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 "nsGenericHTMLElement.h"
|
||||
#include "mozilla/dom/HTMLElementBinding.h"
|
||||
#include "nsContentUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class HTMLElement final : public nsGenericHTMLElement
|
||||
{
|
||||
public:
|
||||
explicit HTMLElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
|
||||
virtual ~HTMLElement();
|
||||
|
||||
virtual nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo,
|
||||
nsINode** aResult) const override;
|
||||
|
||||
protected:
|
||||
virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
};
|
||||
|
||||
HTMLElement::HTMLElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
|
||||
: nsGenericHTMLElement(aNodeInfo)
|
||||
{
|
||||
}
|
||||
|
||||
HTMLElement::~HTMLElement()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMPL_ELEMENT_CLONE(HTMLElement)
|
||||
|
||||
JSObject*
|
||||
HTMLElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return dom::HTMLElementBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
// Here, we expand 'NS_IMPL_NS_NEW_HTML_ELEMENT()' by hand.
|
||||
// (Calling the macro directly (with no args) produces compiler warnings.)
|
||||
nsGenericHTMLElement*
|
||||
NS_NewHTMLElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
|
||||
mozilla::dom::FromParser aFromParser)
|
||||
{
|
||||
return new mozilla::dom::HTMLElement(aNodeInfo);
|
||||
}
|
||||
370
dom/html/HTMLFieldSetElement.cpp
Normal file
370
dom/html/HTMLFieldSetElement.cpp
Normal file
|
|
@ -0,0 +1,370 @@
|
|||
/* -*- 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/BasicEvents.h"
|
||||
#include "mozilla/EventDispatcher.h"
|
||||
#include "mozilla/EventStates.h"
|
||||
#include "mozilla/dom/HTMLFieldSetElement.h"
|
||||
#include "mozilla/dom/HTMLFieldSetElementBinding.h"
|
||||
#include "nsContentList.h"
|
||||
#include "nsQueryObject.h"
|
||||
|
||||
NS_IMPL_NS_NEW_HTML_ELEMENT(FieldSet)
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
HTMLFieldSetElement::HTMLFieldSetElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
|
||||
: nsGenericHTMLFormElement(aNodeInfo)
|
||||
, mElements(nullptr)
|
||||
, mFirstLegend(nullptr)
|
||||
, mInvalidElementsCount(0)
|
||||
{
|
||||
// <fieldset> is always barred from constraint validation.
|
||||
SetBarredFromConstraintValidation(true);
|
||||
|
||||
// We start out enabled and valid.
|
||||
AddStatesSilently(NS_EVENT_STATE_ENABLED | NS_EVENT_STATE_VALID);
|
||||
}
|
||||
|
||||
HTMLFieldSetElement::~HTMLFieldSetElement()
|
||||
{
|
||||
uint32_t length = mDependentElements.Length();
|
||||
for (uint32_t i = 0; i < length; ++i) {
|
||||
mDependentElements[i]->ForgetFieldSet(this);
|
||||
}
|
||||
}
|
||||
|
||||
// nsISupports
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_INHERITED(HTMLFieldSetElement, nsGenericHTMLFormElement,
|
||||
mValidity, mElements)
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(HTMLFieldSetElement, Element)
|
||||
NS_IMPL_RELEASE_INHERITED(HTMLFieldSetElement, Element)
|
||||
|
||||
// QueryInterface implementation for HTMLFieldSetElement
|
||||
NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(HTMLFieldSetElement)
|
||||
NS_INTERFACE_TABLE_INHERITED(HTMLFieldSetElement,
|
||||
nsIDOMHTMLFieldSetElement,
|
||||
nsIConstraintValidation)
|
||||
NS_INTERFACE_TABLE_TAIL_INHERITING(nsGenericHTMLFormElement)
|
||||
|
||||
NS_IMPL_ELEMENT_CLONE(HTMLFieldSetElement)
|
||||
|
||||
|
||||
NS_IMPL_BOOL_ATTR(HTMLFieldSetElement, Disabled, disabled)
|
||||
NS_IMPL_STRING_ATTR(HTMLFieldSetElement, Name, name)
|
||||
|
||||
// nsIConstraintValidation
|
||||
NS_IMPL_NSICONSTRAINTVALIDATION(HTMLFieldSetElement)
|
||||
|
||||
bool
|
||||
HTMLFieldSetElement::IsDisabledForEvents(EventMessage aMessage)
|
||||
{
|
||||
return IsElementDisabledForEvents(aMessage, nullptr);
|
||||
}
|
||||
|
||||
// nsIContent
|
||||
nsresult
|
||||
HTMLFieldSetElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
{
|
||||
// Do not process any DOM events if the element is disabled.
|
||||
aVisitor.mCanHandle = false;
|
||||
if (IsDisabledForEvents(aVisitor.mEvent->mMessage)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return nsGenericHTMLFormElement::PreHandleEvent(aVisitor);
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLFieldSetElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
const nsAttrValue* aValue, bool aNotify)
|
||||
{
|
||||
if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::disabled &&
|
||||
nsINode::GetFirstChild()) {
|
||||
if (!mElements) {
|
||||
mElements = new nsContentList(this, MatchListedElements, nullptr, nullptr,
|
||||
true);
|
||||
}
|
||||
|
||||
uint32_t length = mElements->Length(true);
|
||||
for (uint32_t i=0; i<length; ++i) {
|
||||
static_cast<nsGenericHTMLFormElement*>(mElements->Item(i))
|
||||
->FieldSetDisabledChanged(aNotify);
|
||||
}
|
||||
}
|
||||
|
||||
return nsGenericHTMLFormElement::AfterSetAttr(aNameSpaceID, aName,
|
||||
aValue, aNotify);
|
||||
}
|
||||
|
||||
// nsIDOMHTMLFieldSetElement
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLFieldSetElement::GetForm(nsIDOMHTMLFormElement** aForm)
|
||||
{
|
||||
return nsGenericHTMLFormElement::GetForm(aForm);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLFieldSetElement::GetType(nsAString& aType)
|
||||
{
|
||||
aType.AssignLiteral("fieldset");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool
|
||||
HTMLFieldSetElement::MatchListedElements(nsIContent* aContent, int32_t aNamespaceID,
|
||||
nsIAtom* aAtom, void* aData)
|
||||
{
|
||||
nsCOMPtr<nsIFormControl> formControl = do_QueryInterface(aContent);
|
||||
return formControl;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLFieldSetElement::GetElements(nsIDOMHTMLCollection** aElements)
|
||||
{
|
||||
NS_ADDREF(*aElements = Elements());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsIHTMLCollection*
|
||||
HTMLFieldSetElement::Elements()
|
||||
{
|
||||
if (!mElements) {
|
||||
mElements = new nsContentList(this, MatchListedElements, nullptr, nullptr,
|
||||
true);
|
||||
}
|
||||
|
||||
return mElements;
|
||||
}
|
||||
|
||||
// nsIFormControl
|
||||
|
||||
nsresult
|
||||
HTMLFieldSetElement::Reset()
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLFieldSetElement::SubmitNamesValues(HTMLFormSubmission* aFormSubmission)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLFieldSetElement::InsertChildAt(nsIContent* aChild, uint32_t aIndex,
|
||||
bool aNotify)
|
||||
{
|
||||
bool firstLegendHasChanged = false;
|
||||
|
||||
if (aChild->IsHTMLElement(nsGkAtoms::legend)) {
|
||||
if (!mFirstLegend) {
|
||||
mFirstLegend = aChild;
|
||||
// We do not want to notify the first time mFirstElement is set.
|
||||
} else {
|
||||
// If mFirstLegend is before aIndex, we do not change it.
|
||||
// Otherwise, mFirstLegend is now aChild.
|
||||
if (int32_t(aIndex) <= IndexOf(mFirstLegend)) {
|
||||
mFirstLegend = aChild;
|
||||
firstLegendHasChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsresult rv = nsGenericHTMLFormElement::InsertChildAt(aChild, aIndex, aNotify);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (firstLegendHasChanged) {
|
||||
NotifyElementsForFirstLegendChange(aNotify);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
void
|
||||
HTMLFieldSetElement::RemoveChildAt(uint32_t aIndex, bool aNotify)
|
||||
{
|
||||
bool firstLegendHasChanged = false;
|
||||
|
||||
if (mFirstLegend && (GetChildAt(aIndex) == mFirstLegend)) {
|
||||
// If we are removing the first legend we have to found another one.
|
||||
nsIContent* child = mFirstLegend->GetNextSibling();
|
||||
mFirstLegend = nullptr;
|
||||
firstLegendHasChanged = true;
|
||||
|
||||
for (; child; child = child->GetNextSibling()) {
|
||||
if (child->IsHTMLElement(nsGkAtoms::legend)) {
|
||||
mFirstLegend = child;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsGenericHTMLFormElement::RemoveChildAt(aIndex, aNotify);
|
||||
|
||||
if (firstLegendHasChanged) {
|
||||
NotifyElementsForFirstLegendChange(aNotify);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
HTMLFieldSetElement::AddElement(nsGenericHTMLFormElement* aElement)
|
||||
{
|
||||
mDependentElements.AppendElement(aElement);
|
||||
|
||||
// If the element that we are adding aElement is a fieldset, then all the
|
||||
// invalid elements in aElement are also invalid elements of this.
|
||||
HTMLFieldSetElement* fieldSet = FromContent(aElement);
|
||||
if (fieldSet) {
|
||||
for (int32_t i = 0; i < fieldSet->mInvalidElementsCount; i++) {
|
||||
UpdateValidity(false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// We need to update the validity of the fieldset.
|
||||
nsCOMPtr<nsIConstraintValidation> cvElmt = do_QueryObject(aElement);
|
||||
if (cvElmt &&
|
||||
cvElmt->IsCandidateForConstraintValidation() && !cvElmt->IsValid()) {
|
||||
UpdateValidity(false);
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
int32_t debugInvalidElementsCount = 0;
|
||||
for (uint32_t i = 0; i < mDependentElements.Length(); i++) {
|
||||
HTMLFieldSetElement* fieldSet = FromContent(mDependentElements[i]);
|
||||
if (fieldSet) {
|
||||
debugInvalidElementsCount += fieldSet->mInvalidElementsCount;
|
||||
continue;
|
||||
}
|
||||
nsCOMPtr<nsIConstraintValidation>
|
||||
cvElmt = do_QueryObject(mDependentElements[i]);
|
||||
if (cvElmt &&
|
||||
cvElmt->IsCandidateForConstraintValidation() &&
|
||||
!(cvElmt->IsValid())) {
|
||||
debugInvalidElementsCount += 1;
|
||||
}
|
||||
}
|
||||
MOZ_ASSERT(debugInvalidElementsCount == mInvalidElementsCount);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
HTMLFieldSetElement::RemoveElement(nsGenericHTMLFormElement* aElement)
|
||||
{
|
||||
mDependentElements.RemoveElement(aElement);
|
||||
|
||||
// If the element that we are removing aElement is a fieldset, then all the
|
||||
// invalid elements in aElement are also removed from this.
|
||||
HTMLFieldSetElement* fieldSet = FromContent(aElement);
|
||||
if (fieldSet) {
|
||||
for (int32_t i = 0; i < fieldSet->mInvalidElementsCount; i++) {
|
||||
UpdateValidity(true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// We need to update the validity of the fieldset.
|
||||
nsCOMPtr<nsIConstraintValidation> cvElmt = do_QueryObject(aElement);
|
||||
if (cvElmt &&
|
||||
cvElmt->IsCandidateForConstraintValidation() && !cvElmt->IsValid()) {
|
||||
UpdateValidity(true);
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
int32_t debugInvalidElementsCount = 0;
|
||||
for (uint32_t i = 0; i < mDependentElements.Length(); i++) {
|
||||
HTMLFieldSetElement* fieldSet = FromContent(mDependentElements[i]);
|
||||
if (fieldSet) {
|
||||
debugInvalidElementsCount += fieldSet->mInvalidElementsCount;
|
||||
continue;
|
||||
}
|
||||
nsCOMPtr<nsIConstraintValidation>
|
||||
cvElmt = do_QueryObject(mDependentElements[i]);
|
||||
if (cvElmt &&
|
||||
cvElmt->IsCandidateForConstraintValidation() &&
|
||||
!(cvElmt->IsValid())) {
|
||||
debugInvalidElementsCount += 1;
|
||||
}
|
||||
}
|
||||
MOZ_ASSERT(debugInvalidElementsCount == mInvalidElementsCount);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
HTMLFieldSetElement::NotifyElementsForFirstLegendChange(bool aNotify)
|
||||
{
|
||||
/**
|
||||
* NOTE: this could be optimized if only call when the fieldset is currently
|
||||
* disabled.
|
||||
* This should also make sure that mElements is set when we happen to be here.
|
||||
* However, this method shouldn't be called very often in normal use cases.
|
||||
*/
|
||||
if (!mElements) {
|
||||
mElements = new nsContentList(this, MatchListedElements, nullptr, nullptr,
|
||||
true);
|
||||
}
|
||||
|
||||
uint32_t length = mElements->Length(true);
|
||||
for (uint32_t i = 0; i < length; ++i) {
|
||||
static_cast<nsGenericHTMLFormElement*>(mElements->Item(i))
|
||||
->FieldSetFirstLegendChanged(aNotify);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
HTMLFieldSetElement::UpdateValidity(bool aElementValidity)
|
||||
{
|
||||
if (aElementValidity) {
|
||||
--mInvalidElementsCount;
|
||||
} else {
|
||||
++mInvalidElementsCount;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mInvalidElementsCount >= 0);
|
||||
|
||||
// The fieldset validity has just changed if:
|
||||
// - there are no more invalid elements ;
|
||||
// - or there is one invalid elmement and an element just became invalid.
|
||||
if (!mInvalidElementsCount || (mInvalidElementsCount == 1 && !aElementValidity)) {
|
||||
UpdateState(true);
|
||||
}
|
||||
|
||||
// We should propagate the change to the fieldset parent chain.
|
||||
if (mFieldSet) {
|
||||
mFieldSet->UpdateValidity(aElementValidity);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
EventStates
|
||||
HTMLFieldSetElement::IntrinsicState() const
|
||||
{
|
||||
EventStates state = nsGenericHTMLFormElement::IntrinsicState();
|
||||
|
||||
if (mInvalidElementsCount) {
|
||||
state |= NS_EVENT_STATE_INVALID;
|
||||
} else {
|
||||
state |= NS_EVENT_STATE_VALID;
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
HTMLFieldSetElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return HTMLFieldSetElementBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
150
dom/html/HTMLFieldSetElement.h
Normal file
150
dom/html/HTMLFieldSetElement.h
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_dom_HTMLFieldSetElement_h
|
||||
#define mozilla_dom_HTMLFieldSetElement_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsGenericHTMLElement.h"
|
||||
#include "nsIDOMHTMLFieldSetElement.h"
|
||||
#include "nsIConstraintValidation.h"
|
||||
#include "mozilla/dom/HTMLFormElement.h"
|
||||
#include "mozilla/dom/ValidityState.h"
|
||||
|
||||
namespace mozilla {
|
||||
class EventChainPreVisitor;
|
||||
namespace dom {
|
||||
|
||||
class HTMLFieldSetElement final : public nsGenericHTMLFormElement,
|
||||
public nsIDOMHTMLFieldSetElement,
|
||||
public nsIConstraintValidation
|
||||
{
|
||||
public:
|
||||
using nsGenericHTMLFormElement::GetForm;
|
||||
using nsIConstraintValidation::Validity;
|
||||
using nsIConstraintValidation::CheckValidity;
|
||||
using nsIConstraintValidation::ReportValidity;
|
||||
using nsIConstraintValidation::GetValidationMessage;
|
||||
|
||||
explicit HTMLFieldSetElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
|
||||
|
||||
NS_IMPL_FROMCONTENT_HTML_WITH_TAG(HTMLFieldSetElement, fieldset)
|
||||
|
||||
// nsISupports
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
// nsIDOMHTMLFieldSetElement
|
||||
NS_DECL_NSIDOMHTMLFIELDSETELEMENT
|
||||
|
||||
// nsIContent
|
||||
virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override;
|
||||
virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
const nsAttrValue* aValue, bool aNotify) override;
|
||||
|
||||
virtual nsresult InsertChildAt(nsIContent* aChild, uint32_t aIndex,
|
||||
bool aNotify) override;
|
||||
virtual void RemoveChildAt(uint32_t aIndex, bool aNotify) override;
|
||||
|
||||
// nsIFormControl
|
||||
NS_IMETHOD_(uint32_t) GetType() const override { return NS_FORM_FIELDSET; }
|
||||
NS_IMETHOD Reset() override;
|
||||
NS_IMETHOD SubmitNamesValues(HTMLFormSubmission* aFormSubmission) override;
|
||||
virtual bool IsDisabledForEvents(EventMessage aMessage) override;
|
||||
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
|
||||
|
||||
const nsIContent* GetFirstLegend() const { return mFirstLegend; }
|
||||
|
||||
void AddElement(nsGenericHTMLFormElement* aElement);
|
||||
|
||||
void RemoveElement(nsGenericHTMLFormElement* aElement);
|
||||
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLFieldSetElement,
|
||||
nsGenericHTMLFormElement)
|
||||
|
||||
// WebIDL
|
||||
bool Disabled() const
|
||||
{
|
||||
return GetBoolAttr(nsGkAtoms::disabled);
|
||||
}
|
||||
void SetDisabled(bool aValue, ErrorResult& aRv)
|
||||
{
|
||||
SetHTMLBoolAttr(nsGkAtoms::disabled, aValue, aRv);
|
||||
}
|
||||
|
||||
// XPCOM GetName is OK for us
|
||||
|
||||
void SetName(const nsAString& aValue, ErrorResult& aRv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::name, aValue, aRv);
|
||||
}
|
||||
|
||||
// XPCOM GetType is OK for us
|
||||
|
||||
nsIHTMLCollection* Elements();
|
||||
|
||||
// XPCOM WillValidate is OK for us
|
||||
|
||||
// XPCOM Validity is OK for us
|
||||
|
||||
// XPCOM GetValidationMessage is OK for us
|
||||
|
||||
// XPCOM CheckValidity is OK for us
|
||||
|
||||
// XPCOM SetCustomValidity is OK for us
|
||||
|
||||
virtual EventStates IntrinsicState() const override;
|
||||
|
||||
|
||||
/*
|
||||
* This method will update the fieldset's validity. This method has to be
|
||||
* called by fieldset elements whenever their validity state or status regarding
|
||||
* constraint validation changes.
|
||||
*
|
||||
* @note If an element becomes barred from constraint validation, it has to
|
||||
* be considered as valid.
|
||||
*
|
||||
* @param aElementValidityState the new validity state of the element
|
||||
*/
|
||||
void UpdateValidity(bool aElementValidityState);
|
||||
|
||||
protected:
|
||||
virtual ~HTMLFieldSetElement();
|
||||
|
||||
virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* Notify all elements (in mElements) that the first legend of the fieldset
|
||||
* has now changed.
|
||||
*/
|
||||
void NotifyElementsForFirstLegendChange(bool aNotify);
|
||||
|
||||
// This function is used to generate the nsContentList (listed form elements).
|
||||
static bool MatchListedElements(nsIContent* aContent, int32_t aNamespaceID,
|
||||
nsIAtom* aAtom, void* aData);
|
||||
|
||||
// listed form controls elements.
|
||||
RefPtr<nsContentList> mElements;
|
||||
|
||||
// List of elements which have this fieldset as first fieldset ancestor.
|
||||
nsTArray<nsGenericHTMLFormElement*> mDependentElements;
|
||||
|
||||
nsIContent* mFirstLegend;
|
||||
|
||||
/**
|
||||
* Number of invalid and candidate for constraint validation
|
||||
* elements in the fieldSet the last time UpdateValidity has been called.
|
||||
*
|
||||
* @note Should only be used by UpdateValidity() and IntrinsicState()!
|
||||
*/
|
||||
int32_t mInvalidElementsCount;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* mozilla_dom_HTMLFieldSetElement_h */
|
||||
140
dom/html/HTMLFontElement.cpp
Normal file
140
dom/html/HTMLFontElement.cpp
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
/* -*- 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 "HTMLFontElement.h"
|
||||
#include "mozilla/dom/HTMLFontElementBinding.h"
|
||||
#include "nsAttrValueInlines.h"
|
||||
#include "nsMappedAttributes.h"
|
||||
#include "nsRuleData.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsCSSParser.h"
|
||||
|
||||
NS_IMPL_NS_NEW_HTML_ELEMENT(Font)
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
HTMLFontElement::~HTMLFontElement()
|
||||
{
|
||||
}
|
||||
|
||||
JSObject*
|
||||
HTMLFontElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return HTMLFontElementBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
NS_IMPL_ELEMENT_CLONE(HTMLFontElement)
|
||||
|
||||
bool
|
||||
HTMLFontElement::ParseAttribute(int32_t aNamespaceID,
|
||||
nsIAtom* aAttribute,
|
||||
const nsAString& aValue,
|
||||
nsAttrValue& aResult)
|
||||
{
|
||||
if (aNamespaceID == kNameSpaceID_None) {
|
||||
if (aAttribute == nsGkAtoms::size) {
|
||||
int32_t size = nsContentUtils::ParseLegacyFontSize(aValue);
|
||||
if (size) {
|
||||
aResult.SetTo(size, &aValue);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (aAttribute == nsGkAtoms::color) {
|
||||
return aResult.ParseColor(aValue);
|
||||
}
|
||||
}
|
||||
|
||||
return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
|
||||
aResult);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLFontElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
|
||||
nsRuleData* aData)
|
||||
{
|
||||
if (aData->mSIDs & NS_STYLE_INHERIT_BIT(Font)) {
|
||||
// face: string list
|
||||
nsCSSValue* family = aData->ValueForFontFamily();
|
||||
if (family->GetUnit() == eCSSUnit_Null) {
|
||||
const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::face);
|
||||
if (value && value->Type() == nsAttrValue::eString &&
|
||||
!value->IsEmptyString()) {
|
||||
nsCSSParser parser;
|
||||
parser.ParseFontFamilyListString(value->GetStringValue(),
|
||||
nullptr, 0, *family);
|
||||
}
|
||||
}
|
||||
|
||||
// size: int
|
||||
nsCSSValue* fontSize = aData->ValueForFontSize();
|
||||
if (fontSize->GetUnit() == eCSSUnit_Null) {
|
||||
const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::size);
|
||||
if (value && value->Type() == nsAttrValue::eInteger) {
|
||||
fontSize->SetIntValue(value->GetIntegerValue(), eCSSUnit_Enumerated);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (aData->mSIDs & NS_STYLE_INHERIT_BIT(Color)) {
|
||||
nsCSSValue* colorValue = aData->ValueForColor();
|
||||
if (colorValue->GetUnit() == eCSSUnit_Null &&
|
||||
aData->mPresContext->UseDocumentColors()) {
|
||||
// color: color
|
||||
const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::color);
|
||||
nscolor color;
|
||||
if (value && value->GetColorValue(color)) {
|
||||
colorValue->SetColorValue(color);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (aData->mSIDs & NS_STYLE_INHERIT_BIT(TextReset) &&
|
||||
aData->mPresContext->CompatibilityMode() == eCompatibility_NavQuirks) {
|
||||
// Make <a><font color="red">text</font></a> give the text a red underline
|
||||
// in quirks mode. The NS_STYLE_TEXT_DECORATION_LINE_OVERRIDE_ALL flag only
|
||||
// affects quirks mode rendering.
|
||||
const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::color);
|
||||
nscolor color;
|
||||
if (value && value->GetColorValue(color)) {
|
||||
nsCSSValue* decoration = aData->ValueForTextDecorationLine();
|
||||
int32_t newValue = NS_STYLE_TEXT_DECORATION_LINE_OVERRIDE_ALL;
|
||||
if (decoration->GetUnit() == eCSSUnit_Enumerated) {
|
||||
newValue |= decoration->GetIntValue();
|
||||
}
|
||||
decoration->SetIntValue(newValue, eCSSUnit_Enumerated);
|
||||
}
|
||||
}
|
||||
|
||||
nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aData);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(bool)
|
||||
HTMLFontElement::IsAttributeMapped(const nsIAtom* aAttribute) const
|
||||
{
|
||||
static const MappedAttributeEntry attributes[] = {
|
||||
{ &nsGkAtoms::face },
|
||||
{ &nsGkAtoms::size },
|
||||
{ &nsGkAtoms::color },
|
||||
{ nullptr }
|
||||
};
|
||||
|
||||
static const MappedAttributeEntry* const map[] = {
|
||||
attributes,
|
||||
sCommonAttributeMap,
|
||||
};
|
||||
|
||||
return FindAttributeDependence(aAttribute, map);
|
||||
}
|
||||
|
||||
|
||||
nsMapRuleToAttributesFunc
|
||||
HTMLFontElement::GetAttributeMappingFunction() const
|
||||
{
|
||||
return &MapAttributesIntoRule;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
69
dom/html/HTMLFontElement.h
Normal file
69
dom/html/HTMLFontElement.h
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
/* -*- 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/. */
|
||||
#ifndef HTMLFontElement_h___
|
||||
#define HTMLFontElement_h___
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsGenericHTMLElement.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class HTMLFontElement final : public nsGenericHTMLElement
|
||||
{
|
||||
public:
|
||||
explicit HTMLFontElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
|
||||
: nsGenericHTMLElement(aNodeInfo)
|
||||
{
|
||||
}
|
||||
|
||||
void GetColor(DOMString& aColor)
|
||||
{
|
||||
GetHTMLAttr(nsGkAtoms::color, aColor);
|
||||
}
|
||||
void SetColor(const nsAString& aColor, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::color, aColor, aError);
|
||||
}
|
||||
void GetFace(DOMString& aFace)
|
||||
{
|
||||
GetHTMLAttr(nsGkAtoms::face, aFace);
|
||||
}
|
||||
void SetFace(const nsAString& aFace, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::face, aFace, aError);
|
||||
}
|
||||
void GetSize(DOMString& aSize)
|
||||
{
|
||||
GetHTMLAttr(nsGkAtoms::size, aSize);
|
||||
}
|
||||
void SetSize(const nsAString& aSize, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::size, aSize, aError);
|
||||
}
|
||||
|
||||
virtual bool ParseAttribute(int32_t aNamespaceID,
|
||||
nsIAtom* aAttribute,
|
||||
const nsAString& aValue,
|
||||
nsAttrValue& aResult) override;
|
||||
NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
|
||||
virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const override;
|
||||
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
|
||||
|
||||
protected:
|
||||
virtual ~HTMLFontElement();
|
||||
|
||||
virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
private:
|
||||
static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
|
||||
nsRuleData* aData);
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* HTMLFontElement_h___ */
|
||||
416
dom/html/HTMLFormControlsCollection.cpp
Normal file
416
dom/html/HTMLFormControlsCollection.cpp
Normal file
|
|
@ -0,0 +1,416 @@
|
|||
/* -*- 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/HTMLFormControlsCollection.h"
|
||||
|
||||
#include "mozFlushType.h"
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/HTMLFormControlsCollectionBinding.h"
|
||||
#include "mozilla/dom/HTMLFormElement.h"
|
||||
#include "nsGenericHTMLElement.h" // nsGenericHTMLFormElement
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIDOMNode.h"
|
||||
#include "nsIDOMNodeList.h"
|
||||
#include "nsIFormControl.h"
|
||||
#include "RadioNodeList.h"
|
||||
#include "jsfriendapi.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
/* static */ bool
|
||||
HTMLFormControlsCollection::ShouldBeInElements(nsIFormControl* aFormControl)
|
||||
{
|
||||
// For backwards compatibility (with 4.x and IE) we must not add
|
||||
// <input type=image> elements to the list of form controls in a
|
||||
// form.
|
||||
|
||||
switch (aFormControl->GetType()) {
|
||||
case NS_FORM_BUTTON_BUTTON :
|
||||
case NS_FORM_BUTTON_RESET :
|
||||
case NS_FORM_BUTTON_SUBMIT :
|
||||
case NS_FORM_INPUT_BUTTON :
|
||||
case NS_FORM_INPUT_CHECKBOX :
|
||||
case NS_FORM_INPUT_COLOR :
|
||||
case NS_FORM_INPUT_EMAIL :
|
||||
case NS_FORM_INPUT_FILE :
|
||||
case NS_FORM_INPUT_HIDDEN :
|
||||
case NS_FORM_INPUT_RESET :
|
||||
case NS_FORM_INPUT_PASSWORD :
|
||||
case NS_FORM_INPUT_RADIO :
|
||||
case NS_FORM_INPUT_SEARCH :
|
||||
case NS_FORM_INPUT_SUBMIT :
|
||||
case NS_FORM_INPUT_TEXT :
|
||||
case NS_FORM_INPUT_TEL :
|
||||
case NS_FORM_INPUT_URL :
|
||||
case NS_FORM_INPUT_NUMBER :
|
||||
case NS_FORM_INPUT_RANGE :
|
||||
case NS_FORM_INPUT_DATE :
|
||||
case NS_FORM_INPUT_TIME :
|
||||
case NS_FORM_INPUT_MONTH :
|
||||
case NS_FORM_INPUT_WEEK :
|
||||
case NS_FORM_INPUT_DATETIME_LOCAL :
|
||||
case NS_FORM_SELECT :
|
||||
case NS_FORM_TEXTAREA :
|
||||
case NS_FORM_FIELDSET :
|
||||
case NS_FORM_OBJECT :
|
||||
case NS_FORM_OUTPUT :
|
||||
return true;
|
||||
}
|
||||
|
||||
// These form control types are not supposed to end up in the
|
||||
// form.elements array
|
||||
//
|
||||
// NS_FORM_INPUT_IMAGE
|
||||
//
|
||||
// XXXbz maybe we should just check for that type here instead of the big
|
||||
// switch?
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
HTMLFormControlsCollection::HTMLFormControlsCollection(HTMLFormElement* aForm)
|
||||
: mForm(aForm)
|
||||
// Initialize the elements list to have an initial capacity
|
||||
// of 8 to reduce allocations on small forms.
|
||||
, mElements(8)
|
||||
, mNameLookupTable(HTMLFormElement::FORM_CONTROL_LIST_HASHTABLE_LENGTH)
|
||||
{
|
||||
}
|
||||
|
||||
HTMLFormControlsCollection::~HTMLFormControlsCollection()
|
||||
{
|
||||
mForm = nullptr;
|
||||
Clear();
|
||||
}
|
||||
|
||||
void
|
||||
HTMLFormControlsCollection::DropFormReference()
|
||||
{
|
||||
mForm = nullptr;
|
||||
Clear();
|
||||
}
|
||||
|
||||
void
|
||||
HTMLFormControlsCollection::Clear()
|
||||
{
|
||||
// Null out childrens' pointer to me. No refcounting here
|
||||
for (int32_t i = mElements.Length() - 1; i >= 0; i--) {
|
||||
mElements[i]->ClearForm(false);
|
||||
}
|
||||
mElements.Clear();
|
||||
|
||||
for (int32_t i = mNotInElements.Length() - 1; i >= 0; i--) {
|
||||
mNotInElements[i]->ClearForm(false);
|
||||
}
|
||||
mNotInElements.Clear();
|
||||
|
||||
mNameLookupTable.Clear();
|
||||
}
|
||||
|
||||
void
|
||||
HTMLFormControlsCollection::FlushPendingNotifications()
|
||||
{
|
||||
if (mForm) {
|
||||
nsIDocument* doc = mForm->GetUncomposedDoc();
|
||||
if (doc) {
|
||||
doc->FlushPendingNotifications(Flush_Content);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(HTMLFormControlsCollection)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(HTMLFormControlsCollection)
|
||||
// Note: We intentionally don't set tmp->mForm to nullptr here, since doing
|
||||
// so may result in crashes because of inconsistent null-checking after the
|
||||
// object gets unlinked.
|
||||
tmp->Clear();
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(HTMLFormControlsCollection)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNameLookupTable)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(HTMLFormControlsCollection)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
||||
|
||||
// XPConnect interface list for HTMLFormControlsCollection
|
||||
NS_INTERFACE_TABLE_HEAD(HTMLFormControlsCollection)
|
||||
NS_WRAPPERCACHE_INTERFACE_TABLE_ENTRY
|
||||
NS_INTERFACE_TABLE(HTMLFormControlsCollection,
|
||||
nsIHTMLCollection,
|
||||
nsIDOMHTMLCollection)
|
||||
NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(HTMLFormControlsCollection)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(HTMLFormControlsCollection)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(HTMLFormControlsCollection)
|
||||
|
||||
|
||||
// nsIDOMHTMLCollection interface
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLFormControlsCollection::GetLength(uint32_t* aLength)
|
||||
{
|
||||
FlushPendingNotifications();
|
||||
*aLength = mElements.Length();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLFormControlsCollection::Item(uint32_t aIndex, nsIDOMNode** aReturn)
|
||||
{
|
||||
nsISupports* item = GetElementAt(aIndex);
|
||||
if (!item) {
|
||||
*aReturn = nullptr;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return CallQueryInterface(item, aReturn);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLFormControlsCollection::NamedItem(const nsAString& aName,
|
||||
nsIDOMNode** aReturn)
|
||||
{
|
||||
FlushPendingNotifications();
|
||||
|
||||
*aReturn = nullptr;
|
||||
|
||||
nsCOMPtr<nsISupports> supports;
|
||||
|
||||
if (!mNameLookupTable.Get(aName, getter_AddRefs(supports))) {
|
||||
// key not found
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!supports) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// We found something, check if it's a node
|
||||
CallQueryInterface(supports, aReturn);
|
||||
if (*aReturn) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// If not, we check if it's a node list.
|
||||
nsCOMPtr<nsIDOMNodeList> nodeList = do_QueryInterface(supports);
|
||||
NS_ASSERTION(nodeList, "Huh, what's going one here?");
|
||||
if (!nodeList) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// And since we're only asking for one node here, we return the first
|
||||
// one from the list.
|
||||
return nodeList->Item(0, aReturn);
|
||||
}
|
||||
|
||||
nsISupports*
|
||||
HTMLFormControlsCollection::NamedItemInternal(const nsAString& aName,
|
||||
bool aFlushContent)
|
||||
{
|
||||
if (aFlushContent) {
|
||||
FlushPendingNotifications();
|
||||
}
|
||||
|
||||
return mNameLookupTable.GetWeak(aName);
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLFormControlsCollection::AddElementToTable(nsGenericHTMLFormElement* aChild,
|
||||
const nsAString& aName)
|
||||
{
|
||||
if (!ShouldBeInElements(aChild)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return mForm->AddElementToTableInternal(mNameLookupTable, aChild, aName);
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLFormControlsCollection::IndexOfControl(nsIFormControl* aControl,
|
||||
int32_t* aIndex)
|
||||
{
|
||||
// Note -- not a DOM method; callers should handle flushing themselves
|
||||
|
||||
NS_ENSURE_ARG_POINTER(aIndex);
|
||||
|
||||
*aIndex = mElements.IndexOf(aControl);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLFormControlsCollection::RemoveElementFromTable(
|
||||
nsGenericHTMLFormElement* aChild, const nsAString& aName)
|
||||
{
|
||||
if (!ShouldBeInElements(aChild)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return mForm->RemoveElementFromTableInternal(mNameLookupTable, aChild, aName);
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLFormControlsCollection::GetSortedControls(
|
||||
nsTArray<nsGenericHTMLFormElement*>& aControls) const
|
||||
{
|
||||
#ifdef DEBUG
|
||||
HTMLFormElement::AssertDocumentOrder(mElements, mForm);
|
||||
HTMLFormElement::AssertDocumentOrder(mNotInElements, mForm);
|
||||
#endif
|
||||
|
||||
aControls.Clear();
|
||||
|
||||
// Merge the elements list and the not in elements list. Both lists are
|
||||
// already sorted.
|
||||
uint32_t elementsLen = mElements.Length();
|
||||
uint32_t notInElementsLen = mNotInElements.Length();
|
||||
aControls.SetCapacity(elementsLen + notInElementsLen);
|
||||
|
||||
uint32_t elementsIdx = 0;
|
||||
uint32_t notInElementsIdx = 0;
|
||||
|
||||
while (elementsIdx < elementsLen || notInElementsIdx < notInElementsLen) {
|
||||
// Check whether we're done with mElements
|
||||
if (elementsIdx == elementsLen) {
|
||||
NS_ASSERTION(notInElementsIdx < notInElementsLen,
|
||||
"Should have remaining not-in-elements");
|
||||
// Append the remaining mNotInElements elements
|
||||
if (!aControls.AppendElements(mNotInElements.Elements() +
|
||||
notInElementsIdx,
|
||||
notInElementsLen -
|
||||
notInElementsIdx)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Check whether we're done with mNotInElements
|
||||
if (notInElementsIdx == notInElementsLen) {
|
||||
NS_ASSERTION(elementsIdx < elementsLen,
|
||||
"Should have remaining in-elements");
|
||||
// Append the remaining mElements elements
|
||||
if (!aControls.AppendElements(mElements.Elements() +
|
||||
elementsIdx,
|
||||
elementsLen -
|
||||
elementsIdx)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Both lists have elements left.
|
||||
NS_ASSERTION(mElements[elementsIdx] &&
|
||||
mNotInElements[notInElementsIdx],
|
||||
"Should have remaining elements");
|
||||
// Determine which of the two elements should be ordered
|
||||
// first and add it to the end of the list.
|
||||
nsGenericHTMLFormElement* elementToAdd;
|
||||
if (HTMLFormElement::CompareFormControlPosition(
|
||||
mElements[elementsIdx], mNotInElements[notInElementsIdx], mForm) < 0) {
|
||||
elementToAdd = mElements[elementsIdx];
|
||||
++elementsIdx;
|
||||
} else {
|
||||
elementToAdd = mNotInElements[notInElementsIdx];
|
||||
++notInElementsIdx;
|
||||
}
|
||||
// Add the first element to the list.
|
||||
if (!aControls.AppendElement(elementToAdd)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
NS_ASSERTION(aControls.Length() == elementsLen + notInElementsLen,
|
||||
"Not all form controls were added to the sorted list");
|
||||
#ifdef DEBUG
|
||||
HTMLFormElement::AssertDocumentOrder(aControls, mForm);
|
||||
#endif
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
Element*
|
||||
HTMLFormControlsCollection::GetElementAt(uint32_t aIndex)
|
||||
{
|
||||
FlushPendingNotifications();
|
||||
|
||||
return mElements.SafeElementAt(aIndex, nullptr);
|
||||
}
|
||||
|
||||
/* virtual */ nsINode*
|
||||
HTMLFormControlsCollection::GetParentObject()
|
||||
{
|
||||
return mForm;
|
||||
}
|
||||
|
||||
/* virtual */ Element*
|
||||
HTMLFormControlsCollection::GetFirstNamedElement(const nsAString& aName, bool& aFound)
|
||||
{
|
||||
Nullable<OwningRadioNodeListOrElement> maybeResult;
|
||||
NamedGetter(aName, aFound, maybeResult);
|
||||
if (!aFound) {
|
||||
return nullptr;
|
||||
}
|
||||
MOZ_ASSERT(!maybeResult.IsNull());
|
||||
const OwningRadioNodeListOrElement& result = maybeResult.Value();
|
||||
if (result.IsElement()) {
|
||||
return result.GetAsElement().get();
|
||||
}
|
||||
if (result.IsRadioNodeList()) {
|
||||
RadioNodeList& nodelist = result.GetAsRadioNodeList();
|
||||
return nodelist.Item(0)->AsElement();
|
||||
}
|
||||
MOZ_ASSERT_UNREACHABLE("Should only have Elements and NodeLists here.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
HTMLFormControlsCollection::NamedGetter(const nsAString& aName,
|
||||
bool& aFound,
|
||||
Nullable<OwningRadioNodeListOrElement>& aResult)
|
||||
{
|
||||
nsISupports* item = NamedItemInternal(aName, true);
|
||||
if (!item) {
|
||||
aFound = false;
|
||||
return;
|
||||
}
|
||||
aFound = true;
|
||||
if (nsCOMPtr<Element> element = do_QueryInterface(item)) {
|
||||
aResult.SetValue().SetAsElement() = element;
|
||||
return;
|
||||
}
|
||||
if (nsCOMPtr<RadioNodeList> nodelist = do_QueryInterface(item)) {
|
||||
aResult.SetValue().SetAsRadioNodeList() = nodelist;
|
||||
return;
|
||||
}
|
||||
MOZ_ASSERT_UNREACHABLE("Should only have Elements and NodeLists here.");
|
||||
}
|
||||
|
||||
void
|
||||
HTMLFormControlsCollection::GetSupportedNames(nsTArray<nsString>& aNames)
|
||||
{
|
||||
FlushPendingNotifications();
|
||||
// Just enumerate mNameLookupTable. This won't guarantee order, but
|
||||
// that's OK, because the HTML5 spec doesn't define an order for
|
||||
// this enumeration.
|
||||
for (auto iter = mNameLookupTable.Iter(); !iter.Done(); iter.Next()) {
|
||||
aNames.AppendElement(iter.Key());
|
||||
}
|
||||
}
|
||||
|
||||
/* virtual */ JSObject*
|
||||
HTMLFormControlsCollection::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return HTMLFormControlsCollectionBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
125
dom/html/HTMLFormControlsCollection.h
Normal file
125
dom/html/HTMLFormControlsCollection.h
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_dom_HTMLFormControlsCollection_h
|
||||
#define mozilla_dom_HTMLFormControlsCollection_h
|
||||
|
||||
#include "mozilla/dom/Element.h" // DOMProxyHandler::getOwnPropertyDescriptor
|
||||
#include "nsIHTMLCollection.h"
|
||||
#include "nsInterfaceHashtable.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsWrapperCache.h"
|
||||
|
||||
class nsGenericHTMLFormElement;
|
||||
class nsIFormControl;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class HTMLFormElement;
|
||||
class HTMLImageElement;
|
||||
class OwningRadioNodeListOrElement;
|
||||
template<typename> struct Nullable;
|
||||
|
||||
class HTMLFormControlsCollection final : public nsIHTMLCollection
|
||||
, public nsWrapperCache
|
||||
{
|
||||
public:
|
||||
explicit HTMLFormControlsCollection(HTMLFormElement* aForm);
|
||||
|
||||
void DropFormReference();
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
|
||||
// nsIDOMHTMLCollection interface
|
||||
NS_DECL_NSIDOMHTMLCOLLECTION
|
||||
|
||||
virtual Element* GetElementAt(uint32_t index) override;
|
||||
virtual nsINode* GetParentObject() override;
|
||||
|
||||
virtual Element*
|
||||
GetFirstNamedElement(const nsAString& aName, bool& aFound) override;
|
||||
|
||||
void
|
||||
NamedGetter(const nsAString& aName,
|
||||
bool& aFound,
|
||||
Nullable<OwningRadioNodeListOrElement>& aResult);
|
||||
void
|
||||
NamedItem(const nsAString& aName,
|
||||
Nullable<OwningRadioNodeListOrElement>& aResult)
|
||||
{
|
||||
bool dummy;
|
||||
NamedGetter(aName, dummy, aResult);
|
||||
}
|
||||
virtual void GetSupportedNames(nsTArray<nsString>& aNames) override;
|
||||
|
||||
nsresult AddElementToTable(nsGenericHTMLFormElement* aChild,
|
||||
const nsAString& aName);
|
||||
nsresult AddImageElementToTable(HTMLImageElement* aChild,
|
||||
const nsAString& aName);
|
||||
nsresult RemoveElementFromTable(nsGenericHTMLFormElement* aChild,
|
||||
const nsAString& aName);
|
||||
nsresult IndexOfControl(nsIFormControl* aControl,
|
||||
int32_t* aIndex);
|
||||
|
||||
nsISupports* NamedItemInternal(const nsAString& aName, bool aFlushContent);
|
||||
|
||||
/**
|
||||
* Create a sorted list of form control elements. This list is sorted
|
||||
* in document order and contains the controls in the mElements and
|
||||
* mNotInElements list. This function does not add references to the
|
||||
* elements.
|
||||
*
|
||||
* @param aControls The list of sorted controls[out].
|
||||
* @return NS_OK or NS_ERROR_OUT_OF_MEMORY.
|
||||
*/
|
||||
nsresult GetSortedControls(nsTArray<nsGenericHTMLFormElement*>& aControls) const;
|
||||
|
||||
// nsWrapperCache
|
||||
using nsWrapperCache::GetWrapperPreserveColor;
|
||||
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
protected:
|
||||
virtual ~HTMLFormControlsCollection();
|
||||
virtual JSObject* GetWrapperPreserveColorInternal() override
|
||||
{
|
||||
return nsWrapperCache::GetWrapperPreserveColor();
|
||||
}
|
||||
public:
|
||||
|
||||
static bool ShouldBeInElements(nsIFormControl* aFormControl);
|
||||
|
||||
HTMLFormElement* mForm; // WEAK - the form owns me
|
||||
|
||||
nsTArray<nsGenericHTMLFormElement*> mElements; // Holds WEAK references - bug 36639
|
||||
|
||||
// This array holds on to all form controls that are not contained
|
||||
// in mElements (form.elements in JS, see ShouldBeInFormControl()).
|
||||
// This is needed to properly clean up the bi-directional references
|
||||
// (both weak and strong) between the form and its form controls.
|
||||
|
||||
nsTArray<nsGenericHTMLFormElement*> mNotInElements; // Holds WEAK references
|
||||
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(HTMLFormControlsCollection)
|
||||
|
||||
protected:
|
||||
// Drop all our references to the form elements
|
||||
void Clear();
|
||||
|
||||
// Flush out the content model so it's up to date.
|
||||
void FlushPendingNotifications();
|
||||
|
||||
// A map from an ID or NAME attribute to the form control(s), this
|
||||
// hash holds strong references either to the named form control, or
|
||||
// to a list of named form controls, in the case where this hash
|
||||
// holds on to a list of named form controls the list has weak
|
||||
// references to the form control.
|
||||
|
||||
nsInterfaceHashtable<nsStringHashKey,nsISupports> mNameLookupTable;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_HTMLFormControlsCollection_h
|
||||
2585
dom/html/HTMLFormElement.cpp
Normal file
2585
dom/html/HTMLFormElement.cpp
Normal file
File diff suppressed because it is too large
Load diff
650
dom/html/HTMLFormElement.h
Normal file
650
dom/html/HTMLFormElement.h
Normal file
|
|
@ -0,0 +1,650 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_dom_HTMLFormElement_h
|
||||
#define mozilla_dom_HTMLFormElement_h
|
||||
|
||||
#include "mozilla/AsyncEventDispatcher.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/dom/HTMLFormSubmission.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIForm.h"
|
||||
#include "nsIFormControl.h"
|
||||
#include "nsGenericHTMLElement.h"
|
||||
#include "nsIDOMHTMLFormElement.h"
|
||||
#include "nsIWebProgressListener.h"
|
||||
#include "nsIRadioGroupContainer.h"
|
||||
#include "nsIWeakReferenceUtils.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsInterfaceHashtable.h"
|
||||
#include "nsRefPtrHashtable.h"
|
||||
#include "nsDataHashtable.h"
|
||||
#include "jsfriendapi.h" // For js::ExpandoAndGeneration
|
||||
|
||||
class nsIMutableArray;
|
||||
class nsIURI;
|
||||
|
||||
namespace mozilla {
|
||||
class EventChainPostVisitor;
|
||||
class EventChainPreVisitor;
|
||||
namespace dom {
|
||||
class HTMLFormControlsCollection;
|
||||
class HTMLImageElement;
|
||||
|
||||
class HTMLFormElement final : public nsGenericHTMLElement,
|
||||
public nsIDOMHTMLFormElement,
|
||||
public nsIWebProgressListener,
|
||||
public nsIForm,
|
||||
public nsIRadioGroupContainer
|
||||
{
|
||||
friend class HTMLFormControlsCollection;
|
||||
|
||||
public:
|
||||
explicit HTMLFormElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
|
||||
|
||||
enum {
|
||||
FORM_CONTROL_LIST_HASHTABLE_LENGTH = 8
|
||||
};
|
||||
|
||||
// nsISupports
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
// nsIDOMHTMLFormElement
|
||||
NS_DECL_NSIDOMHTMLFORMELEMENT
|
||||
|
||||
// nsIWebProgressListener
|
||||
NS_DECL_NSIWEBPROGRESSLISTENER
|
||||
|
||||
// nsIForm
|
||||
NS_IMETHOD_(nsIFormControl*) GetElementAt(int32_t aIndex) const override;
|
||||
NS_IMETHOD_(uint32_t) GetElementCount() const override;
|
||||
NS_IMETHOD_(int32_t) IndexOfControl(nsIFormControl* aControl) override;
|
||||
NS_IMETHOD_(nsIFormControl*) GetDefaultSubmitElement() const override;
|
||||
|
||||
// nsIRadioGroupContainer
|
||||
void SetCurrentRadioButton(const nsAString& aName,
|
||||
HTMLInputElement* aRadio) override;
|
||||
HTMLInputElement* GetCurrentRadioButton(const nsAString& aName) override;
|
||||
NS_IMETHOD GetNextRadioButton(const nsAString& aName,
|
||||
const bool aPrevious,
|
||||
HTMLInputElement* aFocusedRadio,
|
||||
HTMLInputElement** aRadioOut) override;
|
||||
NS_IMETHOD WalkRadioGroup(const nsAString& aName, nsIRadioVisitor* aVisitor,
|
||||
bool aFlushContent) override;
|
||||
void AddToRadioGroup(const nsAString& aName, nsIFormControl* aRadio) override;
|
||||
void RemoveFromRadioGroup(const nsAString& aName, nsIFormControl* aRadio) override;
|
||||
virtual uint32_t GetRequiredRadioCount(const nsAString& aName) const override;
|
||||
virtual void RadioRequiredWillChange(const nsAString& aName,
|
||||
bool aRequiredAdded) override;
|
||||
virtual bool GetValueMissingState(const nsAString& aName) const override;
|
||||
virtual void SetValueMissingState(const nsAString& aName, bool aValue) override;
|
||||
|
||||
virtual EventStates IntrinsicState() const override;
|
||||
|
||||
// EventTarget
|
||||
virtual void AsyncEventRunning(AsyncEventDispatcher* aEvent) override;
|
||||
|
||||
// nsIContent
|
||||
virtual bool ParseAttribute(int32_t aNamespaceID,
|
||||
nsIAtom* aAttribute,
|
||||
const nsAString& aValue,
|
||||
nsAttrValue& aResult) override;
|
||||
virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override;
|
||||
virtual nsresult WillHandleEvent(
|
||||
EventChainPostVisitor& aVisitor) override;
|
||||
virtual nsresult PostHandleEvent(
|
||||
EventChainPostVisitor& aVisitor) override;
|
||||
|
||||
virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
||||
nsIContent* aBindingParent,
|
||||
bool aCompileEventHandlers) override;
|
||||
virtual void UnbindFromTree(bool aDeep = true,
|
||||
bool aNullParent = true) override;
|
||||
nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
const nsAString& aValue, bool aNotify)
|
||||
{
|
||||
return SetAttr(aNameSpaceID, aName, nullptr, aValue, aNotify);
|
||||
}
|
||||
virtual nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
nsIAtom* aPrefix, const nsAString& aValue,
|
||||
bool aNotify) override;
|
||||
virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
const nsAttrValue* aValue, bool aNotify) override;
|
||||
|
||||
/**
|
||||
* Forget all information about the current submission (and the fact that we
|
||||
* are currently submitting at all).
|
||||
*/
|
||||
void ForgetCurrentSubmission();
|
||||
|
||||
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
|
||||
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLFormElement,
|
||||
nsGenericHTMLElement)
|
||||
|
||||
/**
|
||||
* Remove an element from this form's list of elements
|
||||
*
|
||||
* @param aElement the element to remove
|
||||
* @param aUpdateValidity If true, updates the form validity.
|
||||
* @return NS_OK if the element was successfully removed.
|
||||
*/
|
||||
nsresult RemoveElement(nsGenericHTMLFormElement* aElement,
|
||||
bool aUpdateValidity);
|
||||
|
||||
/**
|
||||
* Remove an element from the lookup table maintained by the form.
|
||||
* We can't fold this method into RemoveElement() because when
|
||||
* RemoveElement() is called it doesn't know if the element is
|
||||
* removed because the id attribute has changed, or bacause the
|
||||
* name attribute has changed.
|
||||
*
|
||||
* @param aElement the element to remove
|
||||
* @param aName the name or id of the element to remove
|
||||
* @param aRemoveReason describe why this element is removed. If the element
|
||||
* is removed because it's removed from the form, it will be removed
|
||||
* from the past names map too, otherwise it will stay in the past
|
||||
* names map.
|
||||
* @return NS_OK if the element was successfully removed.
|
||||
*/
|
||||
enum RemoveElementReason {
|
||||
AttributeUpdated,
|
||||
ElementRemoved
|
||||
};
|
||||
nsresult RemoveElementFromTable(nsGenericHTMLFormElement* aElement,
|
||||
const nsAString& aName,
|
||||
RemoveElementReason aRemoveReason);
|
||||
|
||||
/**
|
||||
* Add an element to end of this form's list of elements
|
||||
*
|
||||
* @param aElement the element to add
|
||||
* @param aUpdateValidity If true, the form validity will be updated.
|
||||
* @param aNotify If true, send nsIDocumentObserver notifications as needed.
|
||||
* @return NS_OK if the element was successfully added
|
||||
*/
|
||||
nsresult AddElement(nsGenericHTMLFormElement* aElement, bool aUpdateValidity,
|
||||
bool aNotify);
|
||||
|
||||
/**
|
||||
* Add an element to the lookup table maintained by the form.
|
||||
*
|
||||
* We can't fold this method into AddElement() because when
|
||||
* AddElement() is called, the form control has no
|
||||
* attributes. The name or id attributes of the form control
|
||||
* are used as a key into the table.
|
||||
*/
|
||||
nsresult AddElementToTable(nsGenericHTMLFormElement* aChild,
|
||||
const nsAString& aName);
|
||||
|
||||
/**
|
||||
* Remove an image element from this form's list of image elements
|
||||
*
|
||||
* @param aElement the image element to remove
|
||||
* @return NS_OK if the element was successfully removed.
|
||||
*/
|
||||
nsresult RemoveImageElement(mozilla::dom::HTMLImageElement* aElement);
|
||||
|
||||
/**
|
||||
* Remove an image element from the lookup table maintained by the form.
|
||||
* We can't fold this method into RemoveImageElement() because when
|
||||
* RemoveImageElement() is called it doesn't know if the element is
|
||||
* removed because the id attribute has changed, or because the
|
||||
* name attribute has changed.
|
||||
*
|
||||
* @param aElement the image element to remove
|
||||
* @param aName the name or id of the element to remove
|
||||
* @return NS_OK if the element was successfully removed.
|
||||
*/
|
||||
nsresult RemoveImageElementFromTable(mozilla::dom::HTMLImageElement* aElement,
|
||||
const nsAString& aName,
|
||||
RemoveElementReason aRemoveReason);
|
||||
/**
|
||||
* Add an image element to the end of this form's list of image elements
|
||||
*
|
||||
* @param aElement the element to add
|
||||
* @return NS_OK if the element was successfully added
|
||||
*/
|
||||
nsresult AddImageElement(mozilla::dom::HTMLImageElement* aElement);
|
||||
|
||||
/**
|
||||
* Add an image element to the lookup table maintained by the form.
|
||||
*
|
||||
* We can't fold this method into AddImageElement() because when
|
||||
* AddImageElement() is called, the image attributes can change.
|
||||
* The name or id attributes of the image are used as a key into the table.
|
||||
*/
|
||||
nsresult AddImageElementToTable(mozilla::dom::HTMLImageElement* aChild,
|
||||
const nsAString& aName);
|
||||
|
||||
/**
|
||||
* Returns true if implicit submission of this form is disabled. For more
|
||||
* on implicit submission see:
|
||||
*
|
||||
* http://www.whatwg.org/specs/web-apps/current-work/multipage/association-of-controls-and-forms.html#implicit-submission
|
||||
*/
|
||||
bool ImplicitSubmissionIsDisabled() const;
|
||||
|
||||
/**
|
||||
* Check whether a given nsIFormControl is the default submit
|
||||
* element. This is different from just comparing to
|
||||
* GetDefaultSubmitElement() in certain situations inside an update
|
||||
* when GetDefaultSubmitElement() might not be up to date. aControl
|
||||
* is expected to not be null.
|
||||
*/
|
||||
bool IsDefaultSubmitElement(const nsIFormControl* aControl) const;
|
||||
|
||||
/**
|
||||
* Flag the form to know that a button or image triggered scripted form
|
||||
* submission. In that case the form will defer the submission until the
|
||||
* script handler returns and the return value is known.
|
||||
*/
|
||||
void OnSubmitClickBegin(nsIContent* aOriginatingElement);
|
||||
void OnSubmitClickEnd();
|
||||
|
||||
/**
|
||||
* This method will update the form validity so the submit controls states
|
||||
* will be updated (for -moz-submit-invalid pseudo-class).
|
||||
* This method has to be called by form elements whenever their validity state
|
||||
* or status regarding constraint validation changes.
|
||||
*
|
||||
* @note This method isn't used for CheckValidity().
|
||||
* @note If an element becomes barred from constraint validation, it has to be
|
||||
* considered as valid.
|
||||
*
|
||||
* @param aElementValidityState the new validity state of the element
|
||||
*/
|
||||
void UpdateValidity(bool aElementValidityState);
|
||||
|
||||
/**
|
||||
* Returns the form validity based on the last UpdateValidity() call.
|
||||
*
|
||||
* @return Whether the form was valid the last time UpdateValidity() was called.
|
||||
*
|
||||
* @note This method may not return the *current* validity state!
|
||||
*/
|
||||
bool GetValidity() const { return !mInvalidElementsCount; }
|
||||
|
||||
/**
|
||||
* This method check the form validity and make invalid form elements send
|
||||
* invalid event if needed.
|
||||
*
|
||||
* @return Whether the form is valid.
|
||||
*
|
||||
* @note Do not call this method if novalidate/formnovalidate is used.
|
||||
* @note This method might disappear with bug 592124, hopefuly.
|
||||
*/
|
||||
bool CheckValidFormSubmission();
|
||||
|
||||
/**
|
||||
* Check whether submission can proceed for this form. This basically
|
||||
* implements steps 1-4 (more or less) of
|
||||
* <https://html.spec.whatwg.org/multipage/forms.html#concept-form-submit>.
|
||||
* aSubmitter, if not null, is the "submitter" from that algorithm. Therefore
|
||||
* it must be a valid submit control.
|
||||
*/
|
||||
bool SubmissionCanProceed(Element* aSubmitter);
|
||||
|
||||
/**
|
||||
* Walk over the form elements and call SubmitNamesValues() on them to get
|
||||
* their data pumped into the FormSubmitter.
|
||||
*
|
||||
* @param aFormSubmission the form submission object
|
||||
*/
|
||||
nsresult WalkFormElements(HTMLFormSubmission* aFormSubmission);
|
||||
|
||||
/**
|
||||
* Whether the submission of this form has been ever prevented because of
|
||||
* being invalid.
|
||||
*
|
||||
* @return Whether the submission of this form has been prevented because of
|
||||
* being invalid.
|
||||
*/
|
||||
bool HasEverTriedInvalidSubmit() const { return mEverTriedInvalidSubmit; }
|
||||
|
||||
/**
|
||||
* Implements form[name]. Returns form controls in this form with the correct
|
||||
* value of the name attribute.
|
||||
*/
|
||||
already_AddRefed<nsISupports>
|
||||
FindNamedItem(const nsAString& aName, nsWrapperCache** aCache);
|
||||
|
||||
// WebIDL
|
||||
|
||||
void GetAcceptCharset(DOMString& aValue)
|
||||
{
|
||||
GetHTMLAttr(nsGkAtoms::acceptcharset, aValue);
|
||||
}
|
||||
|
||||
void SetAcceptCharset(const nsAString& aValue, ErrorResult& aRv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::acceptcharset, aValue, aRv);
|
||||
}
|
||||
|
||||
// XPCOM GetAction() is OK
|
||||
void SetAction(const nsAString& aValue, ErrorResult& aRv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::action, aValue, aRv);
|
||||
}
|
||||
|
||||
// XPCOM GetAutocomplete() is OK
|
||||
void SetAutocomplete(const nsAString& aValue, ErrorResult& aRv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::autocomplete, aValue, aRv);
|
||||
}
|
||||
|
||||
// XPCOM GetEnctype() is OK
|
||||
void SetEnctype(const nsAString& aValue, ErrorResult& aRv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::enctype, aValue, aRv);
|
||||
}
|
||||
|
||||
// XPCOM GetEncoding() is OK
|
||||
void SetEncoding(const nsAString& aValue, ErrorResult& aRv)
|
||||
{
|
||||
SetEnctype(aValue, aRv);
|
||||
}
|
||||
|
||||
// XPCOM GetMethod() is OK
|
||||
void SetMethod(const nsAString& aValue, ErrorResult& aRv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::method, aValue, aRv);
|
||||
}
|
||||
|
||||
void GetName(DOMString& aValue)
|
||||
{
|
||||
GetHTMLAttr(nsGkAtoms::name, aValue);
|
||||
}
|
||||
|
||||
void SetName(const nsAString& aValue, ErrorResult& aRv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::name, aValue, aRv);
|
||||
}
|
||||
|
||||
bool NoValidate() const
|
||||
{
|
||||
return GetBoolAttr(nsGkAtoms::novalidate);
|
||||
}
|
||||
|
||||
void SetNoValidate(bool aValue, ErrorResult& aRv)
|
||||
{
|
||||
SetHTMLBoolAttr(nsGkAtoms::novalidate, aValue, aRv);
|
||||
}
|
||||
|
||||
void GetTarget(DOMString& aValue)
|
||||
{
|
||||
GetHTMLAttr(nsGkAtoms::target, aValue);
|
||||
}
|
||||
|
||||
void SetTarget(const nsAString& aValue, ErrorResult& aRv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::target, aValue, aRv);
|
||||
}
|
||||
|
||||
// it's only out-of-line because the class definition is not available in the
|
||||
// header
|
||||
nsIHTMLCollection* Elements();
|
||||
|
||||
int32_t Length();
|
||||
|
||||
void Submit(ErrorResult& aRv);
|
||||
|
||||
// XPCOM Reset() is OK
|
||||
|
||||
bool CheckValidity()
|
||||
{
|
||||
return CheckFormValidity(nullptr);
|
||||
}
|
||||
|
||||
bool ReportValidity()
|
||||
{
|
||||
return CheckValidFormSubmission();
|
||||
}
|
||||
|
||||
Element*
|
||||
IndexedGetter(uint32_t aIndex, bool &aFound);
|
||||
|
||||
already_AddRefed<nsISupports>
|
||||
NamedGetter(const nsAString& aName, bool &aFound);
|
||||
|
||||
void GetSupportedNames(nsTArray<nsString>& aRetval);
|
||||
|
||||
static int32_t
|
||||
CompareFormControlPosition(Element* aElement1, Element* aElement2,
|
||||
const nsIContent* aForm);
|
||||
#ifdef DEBUG
|
||||
static void
|
||||
AssertDocumentOrder(const nsTArray<nsGenericHTMLFormElement*>& aControls,
|
||||
nsIContent* aForm);
|
||||
#endif
|
||||
|
||||
js::ExpandoAndGeneration mExpandoAndGeneration;
|
||||
|
||||
void RequestAutocomplete();
|
||||
|
||||
protected:
|
||||
virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
void PostPasswordEvent();
|
||||
|
||||
RefPtr<AsyncEventDispatcher> mFormPasswordEventDispatcher;
|
||||
|
||||
class RemoveElementRunnable;
|
||||
friend class RemoveElementRunnable;
|
||||
|
||||
class RemoveElementRunnable : public Runnable {
|
||||
public:
|
||||
explicit RemoveElementRunnable(HTMLFormElement* aForm)
|
||||
: mForm(aForm)
|
||||
{}
|
||||
|
||||
NS_IMETHOD Run() override {
|
||||
mForm->HandleDefaultSubmitRemoval();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
RefPtr<HTMLFormElement> mForm;
|
||||
};
|
||||
|
||||
nsresult DoSubmitOrReset(WidgetEvent* aEvent,
|
||||
EventMessage aMessage);
|
||||
nsresult DoReset();
|
||||
|
||||
// Async callback to handle removal of our default submit
|
||||
void HandleDefaultSubmitRemoval();
|
||||
|
||||
//
|
||||
// Submit Helpers
|
||||
//
|
||||
//
|
||||
/**
|
||||
* Attempt to submit (submission might be deferred)
|
||||
* (called by DoSubmitOrReset)
|
||||
*
|
||||
* @param aPresContext the presentation context
|
||||
* @param aEvent the DOM event that was passed to us for the submit
|
||||
*/
|
||||
nsresult DoSubmit(WidgetEvent* aEvent);
|
||||
|
||||
/**
|
||||
* Prepare the submission object (called by DoSubmit)
|
||||
*
|
||||
* @param aFormSubmission the submission object
|
||||
* @param aEvent the DOM event that was passed to us for the submit
|
||||
*/
|
||||
nsresult BuildSubmission(HTMLFormSubmission** aFormSubmission,
|
||||
WidgetEvent* aEvent);
|
||||
/**
|
||||
* Perform the submission (called by DoSubmit and FlushPendingSubmission)
|
||||
*
|
||||
* @param aFormSubmission the submission object
|
||||
*/
|
||||
nsresult SubmitSubmission(HTMLFormSubmission* aFormSubmission);
|
||||
|
||||
/**
|
||||
* Notify any submit observers of the submit.
|
||||
*
|
||||
* @param aActionURL the URL being submitted to
|
||||
* @param aCancelSubmit out param where submit observers can specify that the
|
||||
* submit should be cancelled.
|
||||
*/
|
||||
nsresult NotifySubmitObservers(nsIURI* aActionURL, bool* aCancelSubmit,
|
||||
bool aEarlyNotify);
|
||||
|
||||
/**
|
||||
* If this form submission is secure -> insecure, ask the user if they want
|
||||
* to continue.
|
||||
*
|
||||
* @param aActionURL the URL being submitted to
|
||||
* @param aCancelSubmit out param: will be true if the user wants to cancel
|
||||
*/
|
||||
nsresult DoSecureToInsecureSubmitCheck(nsIURI* aActionURL,
|
||||
bool* aCancelSubmit);
|
||||
|
||||
/**
|
||||
* Find form controls in this form with the correct value in the name
|
||||
* attribute.
|
||||
*/
|
||||
already_AddRefed<nsISupports> DoResolveName(const nsAString& aName, bool aFlushContent);
|
||||
|
||||
/**
|
||||
* Get the full URL to submit to. Do not submit if the returned URL is null.
|
||||
*
|
||||
* @param aActionURL the full, unadulterated URL you'll be submitting to [OUT]
|
||||
* @param aOriginatingElement the originating element of the form submission [IN]
|
||||
*/
|
||||
nsresult GetActionURL(nsIURI** aActionURL, nsIContent* aOriginatingElement);
|
||||
|
||||
/**
|
||||
* Check the form validity following this algorithm:
|
||||
* http://www.whatwg.org/specs/web-apps/current-work/#statically-validate-the-constraints
|
||||
*
|
||||
* @param aInvalidElements [out] parameter containing the list of unhandled
|
||||
* invalid controls.
|
||||
*
|
||||
* @return Whether the form is currently valid.
|
||||
*/
|
||||
bool CheckFormValidity(nsIMutableArray* aInvalidElements) const;
|
||||
|
||||
// Clear the mImageNameLookupTable and mImageElements.
|
||||
void Clear();
|
||||
|
||||
// Insert a element into the past names map.
|
||||
void AddToPastNamesMap(const nsAString& aName, nsISupports* aChild);
|
||||
|
||||
nsresult
|
||||
AddElementToTableInternal(
|
||||
nsInterfaceHashtable<nsStringHashKey,nsISupports>& aTable,
|
||||
nsIContent* aChild, const nsAString& aName);
|
||||
|
||||
nsresult
|
||||
RemoveElementFromTableInternal(
|
||||
nsInterfaceHashtable<nsStringHashKey,nsISupports>& aTable,
|
||||
nsIContent* aChild, const nsAString& aName);
|
||||
|
||||
public:
|
||||
/**
|
||||
* Flush a possible pending submission. If there was a scripted submission
|
||||
* triggered by a button or image, the submission was defered. This method
|
||||
* forces the pending submission to be submitted. (happens when the handler
|
||||
* returns false or there is an action/target change in the script)
|
||||
*/
|
||||
void FlushPendingSubmission();
|
||||
protected:
|
||||
|
||||
//
|
||||
// Data members
|
||||
//
|
||||
/** The list of controls (form.elements as well as stuff not in elements) */
|
||||
RefPtr<HTMLFormControlsCollection> mControls;
|
||||
/** The currently selected radio button of each group */
|
||||
nsRefPtrHashtable<nsStringCaseInsensitiveHashKey, HTMLInputElement> mSelectedRadioButtons;
|
||||
/** The number of required radio button of each group */
|
||||
nsDataHashtable<nsStringCaseInsensitiveHashKey,uint32_t> mRequiredRadioButtonCounts;
|
||||
/** The value missing state of each group */
|
||||
nsDataHashtable<nsStringCaseInsensitiveHashKey,bool> mValueMissingRadioGroups;
|
||||
/** Whether we are currently processing a submit event or not */
|
||||
bool mGeneratingSubmit;
|
||||
/** Whether we are currently processing a reset event or not */
|
||||
bool mGeneratingReset;
|
||||
/** Whether we are submitting currently */
|
||||
bool mIsSubmitting;
|
||||
/** Whether the submission is to be deferred in case a script triggers it */
|
||||
bool mDeferSubmission;
|
||||
/** Whether we notified NS_FORMSUBMIT_SUBJECT listeners already */
|
||||
bool mNotifiedObservers;
|
||||
/** If we notified the listeners early, what was the result? */
|
||||
bool mNotifiedObserversResult;
|
||||
/** Keep track of what the popup state was when the submit was initiated */
|
||||
PopupControlState mSubmitPopupState;
|
||||
/** Keep track of whether a submission was user-initiated or not */
|
||||
bool mSubmitInitiatedFromUserInput;
|
||||
|
||||
/** The pending submission object */
|
||||
nsAutoPtr<HTMLFormSubmission> mPendingSubmission;
|
||||
/** The request currently being submitted */
|
||||
nsCOMPtr<nsIRequest> mSubmittingRequest;
|
||||
/** The web progress object we are currently listening to */
|
||||
nsWeakPtr mWebProgress;
|
||||
|
||||
/** The default submit element -- WEAK */
|
||||
nsGenericHTMLFormElement* mDefaultSubmitElement;
|
||||
|
||||
/** The first submit element in mElements -- WEAK */
|
||||
nsGenericHTMLFormElement* mFirstSubmitInElements;
|
||||
|
||||
/** The first submit element in mNotInElements -- WEAK */
|
||||
nsGenericHTMLFormElement* mFirstSubmitNotInElements;
|
||||
|
||||
// This array holds on to all HTMLImageElement(s).
|
||||
// This is needed to properly clean up the bi-directional references
|
||||
// (both weak and strong) between the form and its HTMLImageElements.
|
||||
|
||||
nsTArray<mozilla::dom::HTMLImageElement*> mImageElements; // Holds WEAK references
|
||||
|
||||
// A map from an ID or NAME attribute to the HTMLImageElement(s), this
|
||||
// hash holds strong references either to the named HTMLImageElement, or
|
||||
// to a list of named HTMLImageElement(s), in the case where this hash
|
||||
// holds on to a list of named HTMLImageElement(s) the list has weak
|
||||
// references to the HTMLImageElement.
|
||||
|
||||
nsInterfaceHashtable<nsStringHashKey,nsISupports> mImageNameLookupTable;
|
||||
|
||||
// A map from names to elements that were gotten by those names from this
|
||||
// form in that past. See "past names map" in the HTML5 specification.
|
||||
|
||||
nsInterfaceHashtable<nsStringHashKey,nsISupports> mPastNameLookupTable;
|
||||
|
||||
/**
|
||||
* Number of invalid and candidate for constraint validation elements in the
|
||||
* form the last time UpdateValidity has been called.
|
||||
* @note Should only be used by UpdateValidity() and GetValidity()!
|
||||
*/
|
||||
int32_t mInvalidElementsCount;
|
||||
|
||||
/**
|
||||
* Whether the submission of this form has been ever prevented because of
|
||||
* being invalid.
|
||||
*/
|
||||
bool mEverTriedInvalidSubmit;
|
||||
|
||||
protected:
|
||||
/** Detection of first form to notify observers */
|
||||
static bool gFirstFormSubmitted;
|
||||
/** Detection of first password input to initialize the password manager */
|
||||
static bool gPasswordManagerInitialized;
|
||||
|
||||
private:
|
||||
~HTMLFormElement();
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_HTMLFormElement_h
|
||||
980
dom/html/HTMLFormSubmission.cpp
Normal file
980
dom/html/HTMLFormSubmission.cpp
Normal file
|
|
@ -0,0 +1,980 @@
|
|||
/* -*- 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 "HTMLFormSubmission.h"
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIForm.h"
|
||||
#include "nsILinkHandler.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsIFormControl.h"
|
||||
#include "nsIDOMHTMLFormElement.h"
|
||||
#include "nsError.h"
|
||||
#include "nsGenericHTMLElement.h"
|
||||
#include "nsAttrValueInlines.h"
|
||||
#include "nsISaveAsCharset.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsDirectoryServiceDefs.h"
|
||||
#include "nsStringStream.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsIURL.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsLinebreakConverter.h"
|
||||
#include "nsEscape.h"
|
||||
#include "nsUnicharUtils.h"
|
||||
#include "nsIMultiplexInputStream.h"
|
||||
#include "nsIMIMEInputStream.h"
|
||||
#include "nsIMIMEService.h"
|
||||
#include "nsIConsoleService.h"
|
||||
#include "nsIScriptError.h"
|
||||
#include "nsIStringBundle.h"
|
||||
#include "nsCExternalHandlerService.h"
|
||||
#include "nsIFileStreams.h"
|
||||
#include "nsContentUtils.h"
|
||||
|
||||
#include "mozilla/dom/Directory.h"
|
||||
#include "mozilla/dom/EncodingUtils.h"
|
||||
#include "mozilla/dom/File.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
namespace {
|
||||
|
||||
void
|
||||
SendJSWarning(nsIDocument* aDocument,
|
||||
const char* aWarningName,
|
||||
const char16_t** aWarningArgs, uint32_t aWarningArgsLen)
|
||||
{
|
||||
nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
|
||||
NS_LITERAL_CSTRING("HTML"), aDocument,
|
||||
nsContentUtils::eFORMS_PROPERTIES,
|
||||
aWarningName,
|
||||
aWarningArgs, aWarningArgsLen);
|
||||
}
|
||||
|
||||
void
|
||||
RetrieveFileName(Blob* aBlob, nsAString& aFilename)
|
||||
{
|
||||
if (!aBlob) {
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<File> file = aBlob->ToFile();
|
||||
if (file) {
|
||||
file->GetName(aFilename);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
RetrieveDirectoryName(Directory* aDirectory, nsAString& aDirname)
|
||||
{
|
||||
MOZ_ASSERT(aDirectory);
|
||||
|
||||
ErrorResult rv;
|
||||
aDirectory->GetName(aDirname, rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
rv.SuppressException();
|
||||
aDirname.Truncate();
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
class FSURLEncoded : public EncodingFormSubmission
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @param aCharset the charset of the form as a string
|
||||
* @param aMethod the method of the submit (either NS_FORM_METHOD_GET or
|
||||
* NS_FORM_METHOD_POST).
|
||||
*/
|
||||
FSURLEncoded(const nsACString& aCharset,
|
||||
int32_t aMethod,
|
||||
nsIDocument* aDocument,
|
||||
nsIContent* aOriginatingElement)
|
||||
: EncodingFormSubmission(aCharset, aOriginatingElement),
|
||||
mMethod(aMethod),
|
||||
mDocument(aDocument),
|
||||
mWarnedFileControl(false)
|
||||
{
|
||||
}
|
||||
|
||||
virtual nsresult
|
||||
AddNameValuePair(const nsAString& aName, const nsAString& aValue) override;
|
||||
|
||||
virtual nsresult
|
||||
AddNameBlobOrNullPair(const nsAString& aName, Blob* aBlob) override;
|
||||
|
||||
virtual nsresult
|
||||
AddNameDirectoryPair(const nsAString& aName, Directory* aDirectory) override;
|
||||
|
||||
virtual nsresult
|
||||
GetEncodedSubmission(nsIURI* aURI, nsIInputStream** aPostDataStream) override;
|
||||
|
||||
virtual bool SupportsIsindexSubmission() override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual nsresult AddIsindex(const nsAString& aValue) override;
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* URL encode a Unicode string by encoding it to bytes, converting linebreaks
|
||||
* properly, and then escaping many bytes as %xx.
|
||||
*
|
||||
* @param aStr the string to encode
|
||||
* @param aEncoded the encoded string [OUT]
|
||||
* @throws NS_ERROR_OUT_OF_MEMORY if we run out of memory
|
||||
*/
|
||||
nsresult URLEncode(const nsAString& aStr, nsACString& aEncoded);
|
||||
|
||||
private:
|
||||
/**
|
||||
* The method of the submit (either NS_FORM_METHOD_GET or
|
||||
* NS_FORM_METHOD_POST).
|
||||
*/
|
||||
int32_t mMethod;
|
||||
|
||||
/** The query string so far (the part after the ?) */
|
||||
nsCString mQueryString;
|
||||
|
||||
/** The document whose URI to use when reporting errors */
|
||||
nsCOMPtr<nsIDocument> mDocument;
|
||||
|
||||
/** Whether or not we have warned about a file control not being submitted */
|
||||
bool mWarnedFileControl;
|
||||
};
|
||||
|
||||
nsresult
|
||||
FSURLEncoded::AddNameValuePair(const nsAString& aName,
|
||||
const nsAString& aValue)
|
||||
{
|
||||
// Encode value
|
||||
nsCString convValue;
|
||||
nsresult rv = URLEncode(aValue, convValue);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Encode name
|
||||
nsAutoCString convName;
|
||||
rv = URLEncode(aName, convName);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
|
||||
// Append data to string
|
||||
if (mQueryString.IsEmpty()) {
|
||||
mQueryString += convName + NS_LITERAL_CSTRING("=") + convValue;
|
||||
} else {
|
||||
mQueryString += NS_LITERAL_CSTRING("&") + convName
|
||||
+ NS_LITERAL_CSTRING("=") + convValue;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
FSURLEncoded::AddIsindex(const nsAString& aValue)
|
||||
{
|
||||
// Encode value
|
||||
nsCString convValue;
|
||||
nsresult rv = URLEncode(aValue, convValue);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Append data to string
|
||||
if (mQueryString.IsEmpty()) {
|
||||
mQueryString.Assign(convValue);
|
||||
} else {
|
||||
mQueryString += NS_LITERAL_CSTRING("&isindex=") + convValue;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
FSURLEncoded::AddNameBlobOrNullPair(const nsAString& aName,
|
||||
Blob* aBlob)
|
||||
{
|
||||
if (!mWarnedFileControl) {
|
||||
SendJSWarning(mDocument, "ForgotFileEnctypeWarning", nullptr, 0);
|
||||
mWarnedFileControl = true;
|
||||
}
|
||||
|
||||
nsAutoString filename;
|
||||
RetrieveFileName(aBlob, filename);
|
||||
return AddNameValuePair(aName, filename);
|
||||
}
|
||||
|
||||
nsresult
|
||||
FSURLEncoded::AddNameDirectoryPair(const nsAString& aName,
|
||||
Directory* aDirectory)
|
||||
{
|
||||
// No warning about because Directory objects are never sent via form.
|
||||
|
||||
nsAutoString dirname;
|
||||
RetrieveDirectoryName(aDirectory, dirname);
|
||||
return AddNameValuePair(aName, dirname);
|
||||
}
|
||||
|
||||
void
|
||||
HandleMailtoSubject(nsCString& aPath)
|
||||
{
|
||||
// Walk through the string and see if we have a subject already.
|
||||
bool hasSubject = false;
|
||||
bool hasParams = false;
|
||||
int32_t paramSep = aPath.FindChar('?');
|
||||
while (paramSep != kNotFound && paramSep < (int32_t)aPath.Length()) {
|
||||
hasParams = true;
|
||||
|
||||
// Get the end of the name at the = op. If it is *after* the next &,
|
||||
// assume that someone made a parameter without an = in it
|
||||
int32_t nameEnd = aPath.FindChar('=', paramSep+1);
|
||||
int32_t nextParamSep = aPath.FindChar('&', paramSep+1);
|
||||
if (nextParamSep == kNotFound) {
|
||||
nextParamSep = aPath.Length();
|
||||
}
|
||||
|
||||
// If the = op is after the &, this parameter is a name without value.
|
||||
// If there is no = op, same thing.
|
||||
if (nameEnd == kNotFound || nextParamSep < nameEnd) {
|
||||
nameEnd = nextParamSep;
|
||||
}
|
||||
|
||||
if (nameEnd != kNotFound) {
|
||||
if (Substring(aPath, paramSep+1, nameEnd-(paramSep+1)).
|
||||
LowerCaseEqualsLiteral("subject")) {
|
||||
hasSubject = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
paramSep = nextParamSep;
|
||||
}
|
||||
|
||||
// If there is no subject, append a preformed subject to the mailto line
|
||||
if (!hasSubject) {
|
||||
if (hasParams) {
|
||||
aPath.Append('&');
|
||||
} else {
|
||||
aPath.Append('?');
|
||||
}
|
||||
|
||||
// Get the default subject
|
||||
nsXPIDLString brandName;
|
||||
nsresult rv =
|
||||
nsContentUtils::GetLocalizedString(nsContentUtils::eBRAND_PROPERTIES,
|
||||
"brandShortName", brandName);
|
||||
if (NS_FAILED(rv))
|
||||
return;
|
||||
const char16_t *formatStrings[] = { brandName.get() };
|
||||
nsXPIDLString subjectStr;
|
||||
rv = nsContentUtils::FormatLocalizedString(
|
||||
nsContentUtils::eFORMS_PROPERTIES,
|
||||
"DefaultFormSubject",
|
||||
formatStrings,
|
||||
subjectStr);
|
||||
if (NS_FAILED(rv))
|
||||
return;
|
||||
aPath.AppendLiteral("subject=");
|
||||
nsCString subjectStrEscaped;
|
||||
rv = NS_EscapeURL(NS_ConvertUTF16toUTF8(subjectStr), esc_Query,
|
||||
subjectStrEscaped, mozilla::fallible);
|
||||
if (NS_FAILED(rv))
|
||||
return;
|
||||
|
||||
aPath.Append(subjectStrEscaped);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
FSURLEncoded::GetEncodedSubmission(nsIURI* aURI,
|
||||
nsIInputStream** aPostDataStream)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
*aPostDataStream = nullptr;
|
||||
|
||||
if (mMethod == NS_FORM_METHOD_POST) {
|
||||
|
||||
bool isMailto = false;
|
||||
aURI->SchemeIs("mailto", &isMailto);
|
||||
if (isMailto) {
|
||||
|
||||
nsAutoCString path;
|
||||
rv = aURI->GetPath(path);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
HandleMailtoSubject(path);
|
||||
|
||||
// Append the body to and force-plain-text args to the mailto line
|
||||
nsAutoCString escapedBody;
|
||||
if (NS_WARN_IF(!NS_Escape(mQueryString, escapedBody, url_XAlphas))) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
path += NS_LITERAL_CSTRING("&force-plain-text=Y&body=") + escapedBody;
|
||||
|
||||
rv = aURI->SetPath(path);
|
||||
|
||||
} else {
|
||||
|
||||
nsCOMPtr<nsIInputStream> dataStream;
|
||||
// XXX We *really* need to either get the string to disown its data (and
|
||||
// not destroy it), or make a string input stream that owns the CString
|
||||
// that is passed to it. Right now this operation does a copy.
|
||||
rv = NS_NewCStringInputStream(getter_AddRefs(dataStream), mQueryString);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIMIMEInputStream> mimeStream(
|
||||
do_CreateInstance("@mozilla.org/network/mime-input-stream;1", &rv));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
#ifdef SPECIFY_CHARSET_IN_CONTENT_TYPE
|
||||
mimeStream->AddHeader("Content-Type",
|
||||
PromiseFlatString(
|
||||
"application/x-www-form-urlencoded; charset="
|
||||
+ mCharset
|
||||
).get());
|
||||
#else
|
||||
mimeStream->AddHeader("Content-Type",
|
||||
"application/x-www-form-urlencoded");
|
||||
#endif
|
||||
mimeStream->SetAddContentLength(true);
|
||||
mimeStream->SetData(dataStream);
|
||||
|
||||
*aPostDataStream = mimeStream;
|
||||
NS_ADDREF(*aPostDataStream);
|
||||
}
|
||||
|
||||
} else {
|
||||
// Get the full query string
|
||||
bool schemeIsJavaScript;
|
||||
rv = aURI->SchemeIs("javascript", &schemeIsJavaScript);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (schemeIsJavaScript) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURL> url = do_QueryInterface(aURI);
|
||||
if (url) {
|
||||
url->SetQuery(mQueryString);
|
||||
}
|
||||
else {
|
||||
nsAutoCString path;
|
||||
rv = aURI->GetPath(path);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
// Bug 42616: Trim off named anchor and save it to add later
|
||||
int32_t namedAnchorPos = path.FindChar('#');
|
||||
nsAutoCString namedAnchor;
|
||||
if (kNotFound != namedAnchorPos) {
|
||||
path.Right(namedAnchor, (path.Length() - namedAnchorPos));
|
||||
path.Truncate(namedAnchorPos);
|
||||
}
|
||||
|
||||
// Chop off old query string (bug 25330, 57333)
|
||||
// Only do this for GET not POST (bug 41585)
|
||||
int32_t queryStart = path.FindChar('?');
|
||||
if (kNotFound != queryStart) {
|
||||
path.Truncate(queryStart);
|
||||
}
|
||||
|
||||
path.Append('?');
|
||||
// Bug 42616: Add named anchor to end after query string
|
||||
path.Append(mQueryString + namedAnchor);
|
||||
|
||||
aURI->SetPath(path);
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
// i18n helper routines
|
||||
nsresult
|
||||
FSURLEncoded::URLEncode(const nsAString& aStr, nsACString& aEncoded)
|
||||
{
|
||||
// convert to CRLF breaks
|
||||
int32_t convertedBufLength = 0;
|
||||
char16_t* convertedBuf =
|
||||
nsLinebreakConverter::ConvertUnicharLineBreaks(aStr.BeginReading(),
|
||||
nsLinebreakConverter::eLinebreakAny,
|
||||
nsLinebreakConverter::eLinebreakNet,
|
||||
aStr.Length(),
|
||||
&convertedBufLength);
|
||||
NS_ENSURE_TRUE(convertedBuf, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
nsAutoString convertedString;
|
||||
convertedString.Adopt(convertedBuf, convertedBufLength);
|
||||
|
||||
nsAutoCString encodedBuf;
|
||||
nsresult rv = EncodeVal(convertedString, encodedBuf, false);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (NS_WARN_IF(!NS_Escape(encodedBuf, aEncoded, url_XPAlphas))) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
FSMultipartFormData::FSMultipartFormData(const nsACString& aCharset,
|
||||
nsIContent* aOriginatingElement)
|
||||
: EncodingFormSubmission(aCharset, aOriginatingElement)
|
||||
{
|
||||
mPostDataStream =
|
||||
do_CreateInstance("@mozilla.org/io/multiplex-input-stream;1");
|
||||
mTotalLength = 0;
|
||||
|
||||
mBoundary.AssignLiteral("---------------------------");
|
||||
mBoundary.AppendInt(rand());
|
||||
mBoundary.AppendInt(rand());
|
||||
mBoundary.AppendInt(rand());
|
||||
}
|
||||
|
||||
FSMultipartFormData::~FSMultipartFormData()
|
||||
{
|
||||
NS_ASSERTION(mPostDataChunk.IsEmpty(), "Left unsubmitted data");
|
||||
}
|
||||
|
||||
nsIInputStream*
|
||||
FSMultipartFormData::GetSubmissionBody(uint64_t* aContentLength)
|
||||
{
|
||||
// Finish data
|
||||
mPostDataChunk += NS_LITERAL_CSTRING("--") + mBoundary
|
||||
+ NS_LITERAL_CSTRING("--" CRLF);
|
||||
|
||||
// Add final data input stream
|
||||
AddPostDataStream();
|
||||
|
||||
*aContentLength = mTotalLength;
|
||||
return mPostDataStream;
|
||||
}
|
||||
|
||||
nsresult
|
||||
FSMultipartFormData::AddNameValuePair(const nsAString& aName,
|
||||
const nsAString& aValue)
|
||||
{
|
||||
nsCString valueStr;
|
||||
nsAutoCString encodedVal;
|
||||
nsresult rv = EncodeVal(aValue, encodedVal, false);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
valueStr.Adopt(nsLinebreakConverter::
|
||||
ConvertLineBreaks(encodedVal.get(),
|
||||
nsLinebreakConverter::eLinebreakAny,
|
||||
nsLinebreakConverter::eLinebreakNet));
|
||||
|
||||
nsAutoCString nameStr;
|
||||
rv = EncodeVal(aName, nameStr, true);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Make MIME block for name/value pair
|
||||
|
||||
// XXX: name parameter should be encoded per RFC 2231
|
||||
// RFC 2388 specifies that RFC 2047 be used, but I think it's not
|
||||
// consistent with MIME standard.
|
||||
mPostDataChunk += NS_LITERAL_CSTRING("--") + mBoundary
|
||||
+ NS_LITERAL_CSTRING(CRLF)
|
||||
+ NS_LITERAL_CSTRING("Content-Disposition: form-data; name=\"")
|
||||
+ nameStr + NS_LITERAL_CSTRING("\"" CRLF CRLF)
|
||||
+ valueStr + NS_LITERAL_CSTRING(CRLF);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
FSMultipartFormData::AddNameBlobOrNullPair(const nsAString& aName, Blob* aBlob)
|
||||
{
|
||||
// Encode the control name
|
||||
nsAutoCString nameStr;
|
||||
nsresult rv = EncodeVal(aName, nameStr, true);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
ErrorResult error;
|
||||
|
||||
uint64_t size = 0;
|
||||
nsAutoCString filename;
|
||||
nsAutoCString contentType;
|
||||
nsCOMPtr<nsIInputStream> fileStream;
|
||||
|
||||
if (aBlob) {
|
||||
nsAutoString filename16;
|
||||
|
||||
RefPtr<File> file = aBlob->ToFile();
|
||||
if (file) {
|
||||
nsAutoString relativePath;
|
||||
file->GetRelativePath(relativePath);
|
||||
if (Directory::WebkitBlinkDirectoryPickerEnabled(nullptr, nullptr) &&
|
||||
!relativePath.IsEmpty()) {
|
||||
filename16 = relativePath;
|
||||
}
|
||||
|
||||
if (filename16.IsEmpty()) {
|
||||
RetrieveFileName(aBlob, filename16);
|
||||
}
|
||||
}
|
||||
|
||||
rv = EncodeVal(filename16, filename, true);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Get content type
|
||||
nsAutoString contentType16;
|
||||
aBlob->GetType(contentType16);
|
||||
if (contentType16.IsEmpty()) {
|
||||
contentType16.AssignLiteral("application/octet-stream");
|
||||
}
|
||||
|
||||
contentType.Adopt(nsLinebreakConverter::
|
||||
ConvertLineBreaks(NS_ConvertUTF16toUTF8(contentType16).get(),
|
||||
nsLinebreakConverter::eLinebreakAny,
|
||||
nsLinebreakConverter::eLinebreakSpace));
|
||||
|
||||
// Get input stream
|
||||
aBlob->GetInternalStream(getter_AddRefs(fileStream), error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.StealNSResult();
|
||||
}
|
||||
|
||||
// Get size
|
||||
size = aBlob->GetSize(error);
|
||||
if (error.Failed()) {
|
||||
error.SuppressException();
|
||||
fileStream = nullptr;
|
||||
}
|
||||
|
||||
if (fileStream) {
|
||||
// Create buffered stream (for efficiency)
|
||||
nsCOMPtr<nsIInputStream> bufferedStream;
|
||||
rv = NS_NewBufferedInputStream(getter_AddRefs(bufferedStream),
|
||||
fileStream, 8192);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
fileStream = bufferedStream;
|
||||
}
|
||||
} else {
|
||||
contentType.AssignLiteral("application/octet-stream");
|
||||
}
|
||||
|
||||
AddDataChunk(nameStr, filename, contentType, fileStream, size);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
FSMultipartFormData::AddNameDirectoryPair(const nsAString& aName,
|
||||
Directory* aDirectory)
|
||||
{
|
||||
if (!Directory::WebkitBlinkDirectoryPickerEnabled(nullptr, nullptr)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Encode the control name
|
||||
nsAutoCString nameStr;
|
||||
nsresult rv = EncodeVal(aName, nameStr, true);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsAutoCString dirname;
|
||||
nsAutoString dirname16;
|
||||
|
||||
ErrorResult error;
|
||||
nsAutoString path;
|
||||
aDirectory->GetPath(path, error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
error.SuppressException();
|
||||
} else {
|
||||
dirname16 = path;
|
||||
}
|
||||
|
||||
if (dirname16.IsEmpty()) {
|
||||
RetrieveDirectoryName(aDirectory, dirname16);
|
||||
}
|
||||
|
||||
rv = EncodeVal(dirname16, dirname, true);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
AddDataChunk(nameStr, dirname,
|
||||
NS_LITERAL_CSTRING("application/octet-stream"),
|
||||
nullptr, 0);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
FSMultipartFormData::AddDataChunk(const nsACString& aName,
|
||||
const nsACString& aFilename,
|
||||
const nsACString& aContentType,
|
||||
nsIInputStream* aInputStream,
|
||||
uint64_t aInputStreamSize)
|
||||
{
|
||||
//
|
||||
// Make MIME block for name/value pair
|
||||
//
|
||||
// more appropriate than always using binary?
|
||||
mPostDataChunk += NS_LITERAL_CSTRING("--") + mBoundary
|
||||
+ NS_LITERAL_CSTRING(CRLF);
|
||||
// XXX: name/filename parameter should be encoded per RFC 2231
|
||||
// RFC 2388 specifies that RFC 2047 be used, but I think it's not
|
||||
// consistent with the MIME standard.
|
||||
mPostDataChunk +=
|
||||
NS_LITERAL_CSTRING("Content-Disposition: form-data; name=\"")
|
||||
+ aName + NS_LITERAL_CSTRING("\"; filename=\"")
|
||||
+ aFilename + NS_LITERAL_CSTRING("\"" CRLF)
|
||||
+ NS_LITERAL_CSTRING("Content-Type: ")
|
||||
+ aContentType + NS_LITERAL_CSTRING(CRLF CRLF);
|
||||
|
||||
// We should not try to append an invalid stream. That will happen for example
|
||||
// if we try to update a file that actually do not exist.
|
||||
if (aInputStream) {
|
||||
// We need to dump the data up to this point into the POST data stream
|
||||
// here, since we're about to add the file input stream
|
||||
AddPostDataStream();
|
||||
|
||||
mPostDataStream->AppendStream(aInputStream);
|
||||
mTotalLength += aInputStreamSize;
|
||||
}
|
||||
|
||||
// CRLF after file
|
||||
mPostDataChunk.AppendLiteral(CRLF);
|
||||
}
|
||||
|
||||
nsresult
|
||||
FSMultipartFormData::GetEncodedSubmission(nsIURI* aURI,
|
||||
nsIInputStream** aPostDataStream)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
// Make header
|
||||
nsCOMPtr<nsIMIMEInputStream> mimeStream
|
||||
= do_CreateInstance("@mozilla.org/network/mime-input-stream;1", &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsAutoCString contentType;
|
||||
GetContentType(contentType);
|
||||
mimeStream->AddHeader("Content-Type", contentType.get());
|
||||
mimeStream->SetAddContentLength(true);
|
||||
uint64_t unused;
|
||||
mimeStream->SetData(GetSubmissionBody(&unused));
|
||||
|
||||
mimeStream.forget(aPostDataStream);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
FSMultipartFormData::AddPostDataStream()
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
nsCOMPtr<nsIInputStream> postDataChunkStream;
|
||||
rv = NS_NewCStringInputStream(getter_AddRefs(postDataChunkStream),
|
||||
mPostDataChunk);
|
||||
NS_ASSERTION(postDataChunkStream, "Could not open a stream for POST!");
|
||||
if (postDataChunkStream) {
|
||||
mPostDataStream->AppendStream(postDataChunkStream);
|
||||
mTotalLength += mPostDataChunk.Length();
|
||||
}
|
||||
|
||||
mPostDataChunk.Truncate();
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
namespace {
|
||||
|
||||
class FSTextPlain : public EncodingFormSubmission
|
||||
{
|
||||
public:
|
||||
FSTextPlain(const nsACString& aCharset, nsIContent* aOriginatingElement)
|
||||
: EncodingFormSubmission(aCharset, aOriginatingElement)
|
||||
{
|
||||
}
|
||||
|
||||
virtual nsresult
|
||||
AddNameValuePair(const nsAString& aName, const nsAString& aValue) override;
|
||||
|
||||
virtual nsresult
|
||||
AddNameBlobOrNullPair(const nsAString& aName, Blob* aBlob) override;
|
||||
|
||||
virtual nsresult
|
||||
AddNameDirectoryPair(const nsAString& aName, Directory* aDirectory) override;
|
||||
|
||||
virtual nsresult
|
||||
GetEncodedSubmission(nsIURI* aURI, nsIInputStream** aPostDataStream) override;
|
||||
|
||||
private:
|
||||
nsString mBody;
|
||||
};
|
||||
|
||||
nsresult
|
||||
FSTextPlain::AddNameValuePair(const nsAString& aName, const nsAString& aValue)
|
||||
{
|
||||
// XXX This won't work well with a name like "a=b" or "a\nb" but I suppose
|
||||
// text/plain doesn't care about that. Parsers aren't built for escaped
|
||||
// values so we'll have to live with it.
|
||||
mBody.Append(aName + NS_LITERAL_STRING("=") + aValue +
|
||||
NS_LITERAL_STRING(CRLF));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
FSTextPlain::AddNameBlobOrNullPair(const nsAString& aName, Blob* aBlob)
|
||||
{
|
||||
nsAutoString filename;
|
||||
RetrieveFileName(aBlob, filename);
|
||||
AddNameValuePair(aName, filename);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
FSTextPlain::AddNameDirectoryPair(const nsAString& aName,
|
||||
Directory* aDirectory)
|
||||
{
|
||||
nsAutoString dirname;
|
||||
RetrieveDirectoryName(aDirectory, dirname);
|
||||
AddNameValuePair(aName, dirname);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
FSTextPlain::GetEncodedSubmission(nsIURI* aURI,
|
||||
nsIInputStream** aPostDataStream)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
// XXX HACK We are using the standard URL mechanism to give the body to the
|
||||
// mailer instead of passing the post data stream to it, since that sounds
|
||||
// hard.
|
||||
bool isMailto = false;
|
||||
aURI->SchemeIs("mailto", &isMailto);
|
||||
if (isMailto) {
|
||||
nsAutoCString path;
|
||||
rv = aURI->GetPath(path);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
HandleMailtoSubject(path);
|
||||
|
||||
// Append the body to and force-plain-text args to the mailto line
|
||||
nsAutoCString escapedBody;
|
||||
if (NS_WARN_IF(!NS_Escape(NS_ConvertUTF16toUTF8(mBody), escapedBody,
|
||||
url_XAlphas))) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
path += NS_LITERAL_CSTRING("&force-plain-text=Y&body=") + escapedBody;
|
||||
|
||||
rv = aURI->SetPath(path);
|
||||
|
||||
} else {
|
||||
// Create data stream.
|
||||
// We do want to send the data through the charset encoder and we want to
|
||||
// normalize linebreaks to use the "standard net" format (\r\n), but we
|
||||
// don't want to perform any other encoding. This means that names and
|
||||
// values which contains '=' or newlines are potentially ambigiously
|
||||
// encoded, but that how text/plain is specced.
|
||||
nsCString cbody;
|
||||
EncodeVal(mBody, cbody, false);
|
||||
cbody.Adopt(nsLinebreakConverter::
|
||||
ConvertLineBreaks(cbody.get(),
|
||||
nsLinebreakConverter::eLinebreakAny,
|
||||
nsLinebreakConverter::eLinebreakNet));
|
||||
nsCOMPtr<nsIInputStream> bodyStream;
|
||||
rv = NS_NewCStringInputStream(getter_AddRefs(bodyStream), cbody);
|
||||
if (!bodyStream) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
// Create mime stream with headers and such
|
||||
nsCOMPtr<nsIMIMEInputStream> mimeStream
|
||||
= do_CreateInstance("@mozilla.org/network/mime-input-stream;1", &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mimeStream->AddHeader("Content-Type", "text/plain");
|
||||
mimeStream->SetAddContentLength(true);
|
||||
mimeStream->SetData(bodyStream);
|
||||
CallQueryInterface(mimeStream, aPostDataStream);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
EncodingFormSubmission::EncodingFormSubmission(const nsACString& aCharset,
|
||||
nsIContent* aOriginatingElement)
|
||||
: HTMLFormSubmission(aCharset, aOriginatingElement)
|
||||
, mEncoder(aCharset)
|
||||
{
|
||||
if (!(aCharset.EqualsLiteral("UTF-8") || aCharset.EqualsLiteral("gb18030"))) {
|
||||
NS_ConvertUTF8toUTF16 charsetUtf16(aCharset);
|
||||
const char16_t* charsetPtr = charsetUtf16.get();
|
||||
SendJSWarning(aOriginatingElement ? aOriginatingElement->GetOwnerDocument()
|
||||
: nullptr,
|
||||
"CannotEncodeAllUnicode",
|
||||
&charsetPtr,
|
||||
1);
|
||||
}
|
||||
}
|
||||
|
||||
EncodingFormSubmission::~EncodingFormSubmission()
|
||||
{
|
||||
}
|
||||
|
||||
// i18n helper routines
|
||||
nsresult
|
||||
EncodingFormSubmission::EncodeVal(const nsAString& aStr, nsCString& aOut,
|
||||
bool aHeaderEncode)
|
||||
{
|
||||
if (!mEncoder.Encode(aStr, aOut)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
if (aHeaderEncode) {
|
||||
aOut.Adopt(nsLinebreakConverter::
|
||||
ConvertLineBreaks(aOut.get(),
|
||||
nsLinebreakConverter::eLinebreakAny,
|
||||
nsLinebreakConverter::eLinebreakSpace));
|
||||
aOut.ReplaceSubstring(NS_LITERAL_CSTRING("\""),
|
||||
NS_LITERAL_CSTRING("\\\""));
|
||||
}
|
||||
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
namespace {
|
||||
|
||||
void
|
||||
GetSubmitCharset(nsGenericHTMLElement* aForm,
|
||||
nsACString& oCharset)
|
||||
{
|
||||
oCharset.AssignLiteral("UTF-8"); // default to utf-8
|
||||
|
||||
nsAutoString acceptCharsetValue;
|
||||
aForm->GetAttr(kNameSpaceID_None, nsGkAtoms::acceptcharset,
|
||||
acceptCharsetValue);
|
||||
|
||||
int32_t charsetLen = acceptCharsetValue.Length();
|
||||
if (charsetLen > 0) {
|
||||
int32_t offset=0;
|
||||
int32_t spPos=0;
|
||||
// get charset from charsets one by one
|
||||
do {
|
||||
spPos = acceptCharsetValue.FindChar(char16_t(' '), offset);
|
||||
int32_t cnt = ((-1==spPos)?(charsetLen-offset):(spPos-offset));
|
||||
if (cnt > 0) {
|
||||
nsAutoString uCharset;
|
||||
acceptCharsetValue.Mid(uCharset, offset, cnt);
|
||||
|
||||
if (EncodingUtils::FindEncodingForLabelNoReplacement(uCharset, oCharset))
|
||||
return;
|
||||
}
|
||||
offset = spPos + 1;
|
||||
} while (spPos != -1);
|
||||
}
|
||||
// if there are no accept-charset or all the charset are not supported
|
||||
// Get the charset from document
|
||||
nsIDocument* doc = aForm->GetComposedDoc();
|
||||
if (doc) {
|
||||
oCharset = doc->GetDocumentCharacterSet();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GetEnumAttr(nsGenericHTMLElement* aContent,
|
||||
nsIAtom* atom, int32_t* aValue)
|
||||
{
|
||||
const nsAttrValue* value = aContent->GetParsedAttr(atom);
|
||||
if (value && value->Type() == nsAttrValue::eEnum) {
|
||||
*aValue = value->GetEnumValue();
|
||||
}
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
/* static */ nsresult
|
||||
HTMLFormSubmission::GetFromForm(nsGenericHTMLElement* aForm,
|
||||
nsGenericHTMLElement* aOriginatingElement,
|
||||
HTMLFormSubmission** aFormSubmission)
|
||||
{
|
||||
// Get all the information necessary to encode the form data
|
||||
NS_ASSERTION(aForm->GetComposedDoc(),
|
||||
"Should have doc if we're building submission!");
|
||||
|
||||
// Get encoding type (default: urlencoded)
|
||||
int32_t enctype = NS_FORM_ENCTYPE_URLENCODED;
|
||||
if (aOriginatingElement &&
|
||||
aOriginatingElement->HasAttr(kNameSpaceID_None, nsGkAtoms::formenctype)) {
|
||||
GetEnumAttr(aOriginatingElement, nsGkAtoms::formenctype, &enctype);
|
||||
} else {
|
||||
GetEnumAttr(aForm, nsGkAtoms::enctype, &enctype);
|
||||
}
|
||||
|
||||
// Get method (default: GET)
|
||||
int32_t method = NS_FORM_METHOD_GET;
|
||||
if (aOriginatingElement &&
|
||||
aOriginatingElement->HasAttr(kNameSpaceID_None, nsGkAtoms::formmethod)) {
|
||||
GetEnumAttr(aOriginatingElement, nsGkAtoms::formmethod, &method);
|
||||
} else {
|
||||
GetEnumAttr(aForm, nsGkAtoms::method, &method);
|
||||
}
|
||||
|
||||
// Get charset
|
||||
nsAutoCString charset;
|
||||
GetSubmitCharset(aForm, charset);
|
||||
|
||||
// We now have a canonical charset name, so we only have to check it
|
||||
// against canonical names.
|
||||
|
||||
// use UTF-8 for UTF-16* (per WHATWG and existing practice of
|
||||
// MS IE/Opera).
|
||||
if (StringBeginsWith(charset, NS_LITERAL_CSTRING("UTF-16"))) {
|
||||
charset.AssignLiteral("UTF-8");
|
||||
}
|
||||
|
||||
// Choose encoder
|
||||
if (method == NS_FORM_METHOD_POST &&
|
||||
enctype == NS_FORM_ENCTYPE_MULTIPART) {
|
||||
*aFormSubmission = new FSMultipartFormData(charset, aOriginatingElement);
|
||||
} else if (method == NS_FORM_METHOD_POST &&
|
||||
enctype == NS_FORM_ENCTYPE_TEXTPLAIN) {
|
||||
*aFormSubmission = new FSTextPlain(charset, aOriginatingElement);
|
||||
} else {
|
||||
nsIDocument* doc = aForm->OwnerDoc();
|
||||
if (enctype == NS_FORM_ENCTYPE_MULTIPART ||
|
||||
enctype == NS_FORM_ENCTYPE_TEXTPLAIN) {
|
||||
nsAutoString enctypeStr;
|
||||
if (aOriginatingElement &&
|
||||
aOriginatingElement->HasAttr(kNameSpaceID_None,
|
||||
nsGkAtoms::formenctype)) {
|
||||
aOriginatingElement->GetAttr(kNameSpaceID_None, nsGkAtoms::formenctype,
|
||||
enctypeStr);
|
||||
} else {
|
||||
aForm->GetAttr(kNameSpaceID_None, nsGkAtoms::enctype, enctypeStr);
|
||||
}
|
||||
const char16_t* enctypeStrPtr = enctypeStr.get();
|
||||
SendJSWarning(doc, "ForgotPostWarning",
|
||||
&enctypeStrPtr, 1);
|
||||
}
|
||||
*aFormSubmission = new FSURLEncoded(charset, method, doc,
|
||||
aOriginatingElement);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // dom namespace
|
||||
} // mozilla namespace
|
||||
251
dom/html/HTMLFormSubmission.h
Normal file
251
dom/html/HTMLFormSubmission.h
Normal file
|
|
@ -0,0 +1,251 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_dom_HTMLFormSubmission_h
|
||||
#define mozilla_dom_HTMLFormSubmission_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsNCRFallbackEncoderWrapper.h"
|
||||
#include "nsString.h"
|
||||
|
||||
class nsIURI;
|
||||
class nsIInputStream;
|
||||
class nsGenericHTMLElement;
|
||||
class nsIMultiplexInputStream;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class Blob;
|
||||
class Directory;
|
||||
|
||||
/**
|
||||
* Class for form submissions; encompasses the function to call to submit as
|
||||
* well as the form submission name/value pairs
|
||||
*/
|
||||
class HTMLFormSubmission
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Get a submission object based on attributes in the form (ENCTYPE and
|
||||
* METHOD)
|
||||
*
|
||||
* @param aForm the form to get a submission object based on
|
||||
* @param aOriginatingElement the originating element (can be null)
|
||||
* @param aFormSubmission the form submission object (out param)
|
||||
*/
|
||||
static nsresult
|
||||
GetFromForm(nsGenericHTMLElement* aForm,
|
||||
nsGenericHTMLElement* aOriginatingElement,
|
||||
HTMLFormSubmission** aFormSubmission);
|
||||
|
||||
virtual ~HTMLFormSubmission()
|
||||
{
|
||||
MOZ_COUNT_DTOR(HTMLFormSubmission);
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit a name/value pair
|
||||
*
|
||||
* @param aName the name of the parameter
|
||||
* @param aValue the value of the parameter
|
||||
*/
|
||||
virtual nsresult
|
||||
AddNameValuePair(const nsAString& aName, const nsAString& aValue) = 0;
|
||||
|
||||
/**
|
||||
* Submit a name/blob pair
|
||||
*
|
||||
* @param aName the name of the parameter
|
||||
* @param aBlob the blob to submit. The file's name will be used if the Blob
|
||||
* is actually a File, otherwise 'blob' string is used instead if the aBlob is
|
||||
* not null.
|
||||
*/
|
||||
virtual nsresult
|
||||
AddNameBlobOrNullPair(const nsAString& aName, Blob* aBlob) = 0;
|
||||
|
||||
/**
|
||||
* Submit a name/directory pair
|
||||
*
|
||||
* @param aName the name of the parameter
|
||||
* @param aBlob the directory to submit.
|
||||
*/
|
||||
virtual nsresult AddNameDirectoryPair(const nsAString& aName,
|
||||
Directory* aDirectory) = 0;
|
||||
|
||||
/**
|
||||
* Reports whether the instance supports AddIsindex().
|
||||
*
|
||||
* @return true if supported.
|
||||
*/
|
||||
virtual bool SupportsIsindexSubmission()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an isindex value to the submission.
|
||||
*
|
||||
* @param aValue the field value
|
||||
*/
|
||||
virtual nsresult AddIsindex(const nsAString& aValue)
|
||||
{
|
||||
NS_NOTREACHED("AddIsindex called when not supported");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a URI and the current submission, create the final URI and data
|
||||
* stream that will be submitted. Subclasses *must* implement this.
|
||||
*
|
||||
* @param aURI the URI being submitted to [INOUT]
|
||||
* @param aPostDataStream a data stream for POST data [OUT]
|
||||
*/
|
||||
virtual nsresult
|
||||
GetEncodedSubmission(nsIURI* aURI, nsIInputStream** aPostDataStream) = 0;
|
||||
|
||||
/**
|
||||
* Get the charset that will be used for submission.
|
||||
*/
|
||||
void GetCharset(nsACString& aCharset)
|
||||
{
|
||||
aCharset = mCharset;
|
||||
}
|
||||
|
||||
nsIContent* GetOriginatingElement() const
|
||||
{
|
||||
return mOriginatingElement.get();
|
||||
}
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Can only be constructed by subclasses.
|
||||
*
|
||||
* @param aCharset the charset of the form as a string
|
||||
* @param aOriginatingElement the originating element (can be null)
|
||||
*/
|
||||
HTMLFormSubmission(const nsACString& aCharset,
|
||||
nsIContent* aOriginatingElement)
|
||||
: mCharset(aCharset)
|
||||
, mOriginatingElement(aOriginatingElement)
|
||||
{
|
||||
MOZ_COUNT_CTOR(HTMLFormSubmission);
|
||||
}
|
||||
|
||||
// The name of the encoder charset
|
||||
nsCString mCharset;
|
||||
|
||||
// Originating element.
|
||||
nsCOMPtr<nsIContent> mOriginatingElement;
|
||||
};
|
||||
|
||||
class EncodingFormSubmission : public HTMLFormSubmission
|
||||
{
|
||||
public:
|
||||
EncodingFormSubmission(const nsACString& aCharset,
|
||||
nsIContent* aOriginatingElement);
|
||||
|
||||
virtual ~EncodingFormSubmission();
|
||||
|
||||
/**
|
||||
* Encode a Unicode string to bytes using the encoder (or just copy the input
|
||||
* if there is no encoder).
|
||||
* @param aStr the string to encode
|
||||
* @param aResult the encoded string [OUT]
|
||||
* @param aHeaderEncode If true, turns all linebreaks into spaces and escapes
|
||||
* all quotes
|
||||
* @throws an error if UnicodeToNewBytes fails
|
||||
*/
|
||||
nsresult EncodeVal(const nsAString& aStr, nsCString& aResult,
|
||||
bool aHeaderEncode);
|
||||
|
||||
private:
|
||||
// The encoder that will encode Unicode names and values
|
||||
nsNCRFallbackEncoderWrapper mEncoder;
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle multipart/form-data encoding, which does files as well as normal
|
||||
* inputs. This always does POST.
|
||||
*/
|
||||
class FSMultipartFormData : public EncodingFormSubmission
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @param aCharset the charset of the form as a string
|
||||
*/
|
||||
FSMultipartFormData(const nsACString& aCharset,
|
||||
nsIContent* aOriginatingElement);
|
||||
~FSMultipartFormData();
|
||||
|
||||
virtual nsresult
|
||||
AddNameValuePair(const nsAString& aName, const nsAString& aValue) override;
|
||||
|
||||
virtual nsresult
|
||||
AddNameBlobOrNullPair(const nsAString& aName, Blob* aBlob) override;
|
||||
|
||||
virtual nsresult
|
||||
AddNameDirectoryPair(const nsAString& aName, Directory* aDirectory) override;
|
||||
|
||||
virtual nsresult
|
||||
GetEncodedSubmission(nsIURI* aURI, nsIInputStream** aPostDataStream) override;
|
||||
|
||||
void GetContentType(nsACString& aContentType)
|
||||
{
|
||||
aContentType =
|
||||
NS_LITERAL_CSTRING("multipart/form-data; boundary=") + mBoundary;
|
||||
}
|
||||
|
||||
nsIInputStream* GetSubmissionBody(uint64_t* aContentLength);
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* Roll up the data we have so far and add it to the multiplexed data stream.
|
||||
*/
|
||||
nsresult AddPostDataStream();
|
||||
|
||||
private:
|
||||
void AddDataChunk(const nsACString& aName,
|
||||
const nsACString& aFilename,
|
||||
const nsACString& aContentType,
|
||||
nsIInputStream* aInputStream,
|
||||
uint64_t aInputStreamSize);
|
||||
/**
|
||||
* The post data stream as it is so far. This is a collection of smaller
|
||||
* chunks--string streams and file streams interleaved to make one big POST
|
||||
* stream.
|
||||
*/
|
||||
nsCOMPtr<nsIMultiplexInputStream> mPostDataStream;
|
||||
|
||||
/**
|
||||
* The current string chunk. When a file is hit, the string chunk gets
|
||||
* wrapped up into an input stream and put into mPostDataStream so that the
|
||||
* file input stream can then be appended and everything is in the right
|
||||
* order. Then the string chunk gets appended to again as we process more
|
||||
* name/value pairs.
|
||||
*/
|
||||
nsCString mPostDataChunk;
|
||||
|
||||
/**
|
||||
* The boundary string to use after each "part" (the boundary that marks the
|
||||
* end of a value). This is computed randomly and is different for each
|
||||
* submission.
|
||||
*/
|
||||
nsCString mBoundary;
|
||||
|
||||
/**
|
||||
* The total length in bytes of the streams that make up mPostDataStream
|
||||
*/
|
||||
uint64_t mTotalLength;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* mozilla_dom_HTMLFormSubmission_h */
|
||||
31
dom/html/HTMLFormSubmissionConstants.h
Normal file
31
dom/html/HTMLFormSubmissionConstants.h
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_dom_HTMLFormSubmissionConstants_h
|
||||
#define mozilla_dom_HTMLFormSubmissionConstants_h
|
||||
|
||||
#include "nsIForm.h"
|
||||
|
||||
static const nsAttrValue::EnumTable kFormMethodTable[] = {
|
||||
{ "get", NS_FORM_METHOD_GET },
|
||||
{ "post", NS_FORM_METHOD_POST },
|
||||
{ nullptr, 0 }
|
||||
};
|
||||
|
||||
// Default method is 'get'.
|
||||
static const nsAttrValue::EnumTable* kFormDefaultMethod = &kFormMethodTable[0];
|
||||
|
||||
static const nsAttrValue::EnumTable kFormEnctypeTable[] = {
|
||||
{ "multipart/form-data", NS_FORM_ENCTYPE_MULTIPART },
|
||||
{ "application/x-www-form-urlencoded", NS_FORM_ENCTYPE_URLENCODED },
|
||||
{ "text/plain", NS_FORM_ENCTYPE_TEXTPLAIN },
|
||||
{ nullptr, 0 }
|
||||
};
|
||||
|
||||
// Default method is 'application/x-www-form-urlencoded'.
|
||||
static const nsAttrValue::EnumTable* kFormDefaultEnctype = &kFormEnctypeTable[1];
|
||||
|
||||
#endif // mozilla_dom_HTMLFormSubmissionConstants_h
|
||||
85
dom/html/HTMLFrameElement.cpp
Normal file
85
dom/html/HTMLFrameElement.cpp
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
/* -*- 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/HTMLFrameElement.h"
|
||||
#include "mozilla/dom/HTMLFrameElementBinding.h"
|
||||
|
||||
class nsIDOMDocument;
|
||||
|
||||
NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER(Frame)
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
HTMLFrameElement::HTMLFrameElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo,
|
||||
FromParser aFromParser)
|
||||
: nsGenericHTMLFrameElement(aNodeInfo, aFromParser)
|
||||
{
|
||||
}
|
||||
|
||||
HTMLFrameElement::~HTMLFrameElement()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED(HTMLFrameElement, nsGenericHTMLFrameElement,
|
||||
nsIDOMHTMLFrameElement)
|
||||
|
||||
NS_IMPL_ELEMENT_CLONE(HTMLFrameElement)
|
||||
|
||||
|
||||
NS_IMPL_STRING_ATTR(HTMLFrameElement, FrameBorder, frameborder)
|
||||
NS_IMPL_URI_ATTR(HTMLFrameElement, LongDesc, longdesc)
|
||||
NS_IMPL_STRING_ATTR(HTMLFrameElement, MarginHeight, marginheight)
|
||||
NS_IMPL_STRING_ATTR(HTMLFrameElement, MarginWidth, marginwidth)
|
||||
NS_IMPL_STRING_ATTR(HTMLFrameElement, Name, name)
|
||||
NS_IMPL_BOOL_ATTR(HTMLFrameElement, NoResize, noresize)
|
||||
NS_IMPL_STRING_ATTR(HTMLFrameElement, Scrolling, scrolling)
|
||||
NS_IMPL_URI_ATTR(HTMLFrameElement, Src, src)
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLFrameElement::GetContentDocument(nsIDOMDocument** aContentDocument)
|
||||
{
|
||||
return nsGenericHTMLFrameElement::GetContentDocument(aContentDocument);
|
||||
}
|
||||
|
||||
bool
|
||||
HTMLFrameElement::ParseAttribute(int32_t aNamespaceID,
|
||||
nsIAtom* aAttribute,
|
||||
const nsAString& aValue,
|
||||
nsAttrValue& aResult)
|
||||
{
|
||||
if (aNamespaceID == kNameSpaceID_None) {
|
||||
if (aAttribute == nsGkAtoms::bordercolor) {
|
||||
return aResult.ParseColor(aValue);
|
||||
}
|
||||
if (aAttribute == nsGkAtoms::frameborder) {
|
||||
return ParseFrameborderValue(aValue, aResult);
|
||||
}
|
||||
if (aAttribute == nsGkAtoms::marginwidth) {
|
||||
return aResult.ParseSpecialIntValue(aValue);
|
||||
}
|
||||
if (aAttribute == nsGkAtoms::marginheight) {
|
||||
return aResult.ParseSpecialIntValue(aValue);
|
||||
}
|
||||
if (aAttribute == nsGkAtoms::scrolling) {
|
||||
return ParseScrollingValue(aValue, aResult);
|
||||
}
|
||||
}
|
||||
|
||||
return nsGenericHTMLFrameElement::ParseAttribute(aNamespaceID, aAttribute,
|
||||
aValue, aResult);
|
||||
}
|
||||
|
||||
JSObject*
|
||||
HTMLFrameElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return HTMLFrameElementBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
108
dom/html/HTMLFrameElement.h
Normal file
108
dom/html/HTMLFrameElement.h
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_dom_HTMLFrameElement_h
|
||||
#define mozilla_dom_HTMLFrameElement_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsIDOMHTMLFrameElement.h"
|
||||
#include "nsGenericHTMLFrameElement.h"
|
||||
#include "nsGkAtoms.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class HTMLFrameElement final : public nsGenericHTMLFrameElement,
|
||||
public nsIDOMHTMLFrameElement
|
||||
{
|
||||
public:
|
||||
using nsGenericHTMLFrameElement::SwapFrameLoaders;
|
||||
|
||||
explicit HTMLFrameElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo,
|
||||
FromParser aFromParser = NOT_FROM_PARSER);
|
||||
|
||||
// nsISupports
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
// nsIDOMHTMLFrameElement
|
||||
NS_DECL_NSIDOMHTMLFRAMEELEMENT
|
||||
|
||||
// nsIContent
|
||||
virtual bool ParseAttribute(int32_t aNamespaceID,
|
||||
nsIAtom* aAttribute,
|
||||
const nsAString& aValue,
|
||||
nsAttrValue& aResult) override;
|
||||
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
|
||||
|
||||
// WebIDL API
|
||||
// The XPCOM GetFrameBorder is OK for us
|
||||
void SetFrameBorder(const nsAString& aFrameBorder, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::frameborder, aFrameBorder, aError);
|
||||
}
|
||||
|
||||
// The XPCOM GetLongDesc is OK for us
|
||||
void SetLongDesc(const nsAString& aLongDesc, ErrorResult& aError)
|
||||
{
|
||||
SetAttrHelper(nsGkAtoms::longdesc, aLongDesc);
|
||||
}
|
||||
|
||||
// The XPCOM GetMarginHeight is OK for us
|
||||
void SetMarginHeight(const nsAString& aMarginHeight, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::marginheight, aMarginHeight, aError);
|
||||
}
|
||||
|
||||
// The XPCOM GetMarginWidth is OK for us
|
||||
void SetMarginWidth(const nsAString& aMarginWidth, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::marginwidth, aMarginWidth, aError);
|
||||
}
|
||||
|
||||
// The XPCOM GetName is OK for us
|
||||
void SetName(const nsAString& aName, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::name, aName, aError);
|
||||
}
|
||||
|
||||
bool NoResize() const
|
||||
{
|
||||
return GetBoolAttr(nsGkAtoms::noresize);
|
||||
}
|
||||
void SetNoResize(bool& aNoResize, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLBoolAttr(nsGkAtoms::noresize, aNoResize, aError);
|
||||
}
|
||||
|
||||
// The XPCOM GetScrolling is OK for us
|
||||
void SetScrolling(const nsAString& aScrolling, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::scrolling, aScrolling, aError);
|
||||
}
|
||||
|
||||
// The XPCOM GetSrc is OK for us
|
||||
void SetSrc(const nsAString& aSrc, ErrorResult& aError)
|
||||
{
|
||||
SetAttrHelper(nsGkAtoms::src, aSrc);
|
||||
}
|
||||
|
||||
using nsGenericHTMLFrameElement::GetContentDocument;
|
||||
using nsGenericHTMLFrameElement::GetContentWindow;
|
||||
|
||||
protected:
|
||||
virtual ~HTMLFrameElement();
|
||||
|
||||
virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
private:
|
||||
static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
|
||||
nsRuleData* aData);
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_HTMLFrameElement_h
|
||||
381
dom/html/HTMLFrameSetElement.cpp
Normal file
381
dom/html/HTMLFrameSetElement.cpp
Normal file
|
|
@ -0,0 +1,381 @@
|
|||
/* -*- 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 "HTMLFrameSetElement.h"
|
||||
#include "mozilla/dom/HTMLFrameSetElementBinding.h"
|
||||
#include "mozilla/dom/EventHandlerBinding.h"
|
||||
#include "nsGlobalWindow.h"
|
||||
#include "mozilla/UniquePtrExtensions.h"
|
||||
|
||||
NS_IMPL_NS_NEW_HTML_ELEMENT(FrameSet)
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
HTMLFrameSetElement::~HTMLFrameSetElement()
|
||||
{
|
||||
}
|
||||
|
||||
JSObject*
|
||||
HTMLFrameSetElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return HTMLFrameSetElementBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED(HTMLFrameSetElement, nsGenericHTMLElement,
|
||||
nsIDOMHTMLFrameSetElement)
|
||||
|
||||
NS_IMPL_ELEMENT_CLONE(HTMLFrameSetElement)
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLFrameSetElement::SetCols(const nsAString& aCols)
|
||||
{
|
||||
ErrorResult rv;
|
||||
SetCols(aCols, rv);
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLFrameSetElement::GetCols(nsAString& aCols)
|
||||
{
|
||||
DOMString cols;
|
||||
GetCols(cols);
|
||||
cols.ToString(aCols);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLFrameSetElement::SetRows(const nsAString& aRows)
|
||||
{
|
||||
ErrorResult rv;
|
||||
SetRows(aRows, rv);
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLFrameSetElement::GetRows(nsAString& aRows)
|
||||
{
|
||||
DOMString rows;
|
||||
GetRows(rows);
|
||||
rows.ToString(aRows);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLFrameSetElement::SetAttr(int32_t aNameSpaceID,
|
||||
nsIAtom* aAttribute,
|
||||
nsIAtom* aPrefix,
|
||||
const nsAString& aValue,
|
||||
bool aNotify)
|
||||
{
|
||||
nsresult rv;
|
||||
/* The main goal here is to see whether the _number_ of rows or
|
||||
* columns has changed. If it has, we need to reframe; otherwise
|
||||
* we want to reflow. So we set mCurrentRowColHint here, then call
|
||||
* nsGenericHTMLElement::SetAttr, which will end up calling
|
||||
* GetAttributeChangeHint and notifying layout with that hint.
|
||||
* Once nsGenericHTMLElement::SetAttr returns, we want to go back to our
|
||||
* normal hint, which is NS_STYLE_HINT_REFLOW.
|
||||
*/
|
||||
if (aAttribute == nsGkAtoms::rows && aNameSpaceID == kNameSpaceID_None) {
|
||||
int32_t oldRows = mNumRows;
|
||||
ParseRowCol(aValue, mNumRows, &mRowSpecs);
|
||||
|
||||
if (mNumRows != oldRows) {
|
||||
mCurrentRowColHint = nsChangeHint_ReconstructFrame;
|
||||
}
|
||||
} else if (aAttribute == nsGkAtoms::cols &&
|
||||
aNameSpaceID == kNameSpaceID_None) {
|
||||
int32_t oldCols = mNumCols;
|
||||
ParseRowCol(aValue, mNumCols, &mColSpecs);
|
||||
|
||||
if (mNumCols != oldCols) {
|
||||
mCurrentRowColHint = nsChangeHint_ReconstructFrame;
|
||||
}
|
||||
}
|
||||
|
||||
rv = nsGenericHTMLElement::SetAttr(aNameSpaceID, aAttribute, aPrefix,
|
||||
aValue, aNotify);
|
||||
mCurrentRowColHint = NS_STYLE_HINT_REFLOW;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLFrameSetElement::GetRowSpec(int32_t *aNumValues,
|
||||
const nsFramesetSpec** aSpecs)
|
||||
{
|
||||
NS_PRECONDITION(aNumValues, "Must have a pointer to an integer here!");
|
||||
NS_PRECONDITION(aSpecs, "Must have a pointer to an array of nsFramesetSpecs");
|
||||
*aNumValues = 0;
|
||||
*aSpecs = nullptr;
|
||||
|
||||
if (!mRowSpecs) {
|
||||
const nsAttrValue* value = GetParsedAttr(nsGkAtoms::rows);
|
||||
if (value && value->Type() == nsAttrValue::eString) {
|
||||
nsresult rv = ParseRowCol(value->GetStringValue(), mNumRows,
|
||||
&mRowSpecs);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
if (!mRowSpecs) { // we may not have had an attr or had an empty attr
|
||||
mRowSpecs = MakeUnique<nsFramesetSpec[]>(1);
|
||||
mNumRows = 1;
|
||||
mRowSpecs[0].mUnit = eFramesetUnit_Relative;
|
||||
mRowSpecs[0].mValue = 1;
|
||||
}
|
||||
}
|
||||
|
||||
*aSpecs = mRowSpecs.get();
|
||||
*aNumValues = mNumRows;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLFrameSetElement::GetColSpec(int32_t *aNumValues,
|
||||
const nsFramesetSpec** aSpecs)
|
||||
{
|
||||
NS_PRECONDITION(aNumValues, "Must have a pointer to an integer here!");
|
||||
NS_PRECONDITION(aSpecs, "Must have a pointer to an array of nsFramesetSpecs");
|
||||
*aNumValues = 0;
|
||||
*aSpecs = nullptr;
|
||||
|
||||
if (!mColSpecs) {
|
||||
const nsAttrValue* value = GetParsedAttr(nsGkAtoms::cols);
|
||||
if (value && value->Type() == nsAttrValue::eString) {
|
||||
nsresult rv = ParseRowCol(value->GetStringValue(), mNumCols,
|
||||
&mColSpecs);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
if (!mColSpecs) { // we may not have had an attr or had an empty attr
|
||||
mColSpecs = MakeUnique<nsFramesetSpec[]>(1);
|
||||
mNumCols = 1;
|
||||
mColSpecs[0].mUnit = eFramesetUnit_Relative;
|
||||
mColSpecs[0].mValue = 1;
|
||||
}
|
||||
}
|
||||
|
||||
*aSpecs = mColSpecs.get();
|
||||
*aNumValues = mNumCols;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
HTMLFrameSetElement::ParseAttribute(int32_t aNamespaceID,
|
||||
nsIAtom* aAttribute,
|
||||
const nsAString& aValue,
|
||||
nsAttrValue& aResult)
|
||||
{
|
||||
if (aNamespaceID == kNameSpaceID_None) {
|
||||
if (aAttribute == nsGkAtoms::bordercolor) {
|
||||
return aResult.ParseColor(aValue);
|
||||
}
|
||||
if (aAttribute == nsGkAtoms::frameborder) {
|
||||
return nsGenericHTMLElement::ParseFrameborderValue(aValue, aResult);
|
||||
}
|
||||
if (aAttribute == nsGkAtoms::border) {
|
||||
return aResult.ParseIntWithBounds(aValue, 0, 100);
|
||||
}
|
||||
}
|
||||
|
||||
return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
|
||||
aResult);
|
||||
}
|
||||
|
||||
nsChangeHint
|
||||
HTMLFrameSetElement::GetAttributeChangeHint(const nsIAtom* aAttribute,
|
||||
int32_t aModType) const
|
||||
{
|
||||
nsChangeHint retval =
|
||||
nsGenericHTMLElement::GetAttributeChangeHint(aAttribute, aModType);
|
||||
if (aAttribute == nsGkAtoms::rows ||
|
||||
aAttribute == nsGkAtoms::cols) {
|
||||
retval |= mCurrentRowColHint;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate a "rows" or "cols" spec into an array of nsFramesetSpecs
|
||||
*/
|
||||
nsresult
|
||||
HTMLFrameSetElement::ParseRowCol(const nsAString & aValue,
|
||||
int32_t& aNumSpecs,
|
||||
UniquePtr<nsFramesetSpec[]>* aSpecs)
|
||||
{
|
||||
if (aValue.IsEmpty()) {
|
||||
aNumSpecs = 0;
|
||||
*aSpecs = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static const char16_t sAster('*');
|
||||
static const char16_t sPercent('%');
|
||||
static const char16_t sComma(',');
|
||||
|
||||
nsAutoString spec(aValue);
|
||||
// remove whitespace (Bug 33699) and quotation marks (bug 224598)
|
||||
// also remove leading/trailing commas (bug 31482)
|
||||
spec.StripChars(" \n\r\t\"\'");
|
||||
spec.Trim(",");
|
||||
|
||||
// Count the commas. Don't count more than X commas (bug 576447).
|
||||
static_assert(NS_MAX_FRAMESET_SPEC_COUNT * sizeof(nsFramesetSpec) < (1 << 30),
|
||||
"Too many frameset specs allowed to allocate");
|
||||
int32_t commaX = spec.FindChar(sComma);
|
||||
int32_t count = 1;
|
||||
while (commaX != kNotFound && count < NS_MAX_FRAMESET_SPEC_COUNT) {
|
||||
count++;
|
||||
commaX = spec.FindChar(sComma, commaX + 1);
|
||||
}
|
||||
|
||||
auto specs = MakeUniqueFallible<nsFramesetSpec[]>(count);
|
||||
if (!specs) {
|
||||
*aSpecs = nullptr;
|
||||
aNumSpecs = 0;
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
// Pre-grab the compat mode; we may need it later in the loop.
|
||||
bool isInQuirks = InNavQuirksMode(OwnerDoc());
|
||||
|
||||
// Parse each comma separated token
|
||||
|
||||
int32_t start = 0;
|
||||
int32_t specLen = spec.Length();
|
||||
|
||||
for (int32_t i = 0; i < count; i++) {
|
||||
// Find our comma
|
||||
commaX = spec.FindChar(sComma, start);
|
||||
NS_ASSERTION(i == count - 1 || commaX != kNotFound,
|
||||
"Failed to find comma, somehow");
|
||||
int32_t end = (commaX == kNotFound) ? specLen : commaX;
|
||||
|
||||
// Note: If end == start then it means that the token has no
|
||||
// data in it other than a terminating comma (or the end of the spec).
|
||||
// So default to a fixed width of 0.
|
||||
specs[i].mUnit = eFramesetUnit_Fixed;
|
||||
specs[i].mValue = 0;
|
||||
if (end > start) {
|
||||
int32_t numberEnd = end;
|
||||
char16_t ch = spec.CharAt(numberEnd - 1);
|
||||
if (sAster == ch) {
|
||||
specs[i].mUnit = eFramesetUnit_Relative;
|
||||
numberEnd--;
|
||||
} else if (sPercent == ch) {
|
||||
specs[i].mUnit = eFramesetUnit_Percent;
|
||||
numberEnd--;
|
||||
// check for "*%"
|
||||
if (numberEnd > start) {
|
||||
ch = spec.CharAt(numberEnd - 1);
|
||||
if (sAster == ch) {
|
||||
specs[i].mUnit = eFramesetUnit_Relative;
|
||||
numberEnd--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Translate value to an integer
|
||||
nsAutoString token;
|
||||
spec.Mid(token, start, numberEnd - start);
|
||||
|
||||
// Treat * as 1*
|
||||
if ((eFramesetUnit_Relative == specs[i].mUnit) &&
|
||||
(0 == token.Length())) {
|
||||
specs[i].mValue = 1;
|
||||
}
|
||||
else {
|
||||
// Otherwise just convert to integer.
|
||||
nsresult err;
|
||||
specs[i].mValue = token.ToInteger(&err);
|
||||
if (NS_FAILED(err)) {
|
||||
specs[i].mValue = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Treat 0* as 1* in quirks mode (bug 40383)
|
||||
if (isInQuirks) {
|
||||
if ((eFramesetUnit_Relative == specs[i].mUnit) &&
|
||||
(0 == specs[i].mValue)) {
|
||||
specs[i].mValue = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Catch zero and negative frame sizes for Nav compatibility
|
||||
// Nav resized absolute and relative frames to "1" and
|
||||
// percent frames to an even percentage of the width
|
||||
//
|
||||
//if (isInQuirks && (specs[i].mValue <= 0)) {
|
||||
// if (eFramesetUnit_Percent == specs[i].mUnit) {
|
||||
// specs[i].mValue = 100 / count;
|
||||
// } else {
|
||||
// specs[i].mValue = 1;
|
||||
// }
|
||||
//} else {
|
||||
|
||||
// In standards mode, just set negative sizes to zero
|
||||
if (specs[i].mValue < 0) {
|
||||
specs[i].mValue = 0;
|
||||
}
|
||||
start = end + 1;
|
||||
}
|
||||
}
|
||||
|
||||
aNumSpecs = count;
|
||||
// Transfer ownership to caller here
|
||||
*aSpecs = Move(specs);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
HTMLFrameSetElement::IsEventAttributeName(nsIAtom *aName)
|
||||
{
|
||||
return nsContentUtils::IsEventAttributeName(aName,
|
||||
EventNameType_HTML |
|
||||
EventNameType_HTMLBodyOrFramesetOnly);
|
||||
}
|
||||
|
||||
|
||||
#define EVENT(name_, id_, type_, struct_) /* nothing; handled by the shim */
|
||||
// nsGenericHTMLElement::GetOnError returns
|
||||
// already_AddRefed<EventHandlerNonNull> while other getters return
|
||||
// EventHandlerNonNull*, so allow passing in the type to use here.
|
||||
#define WINDOW_EVENT_HELPER(name_, type_) \
|
||||
type_* \
|
||||
HTMLFrameSetElement::GetOn##name_() \
|
||||
{ \
|
||||
if (nsPIDOMWindowInner* win = OwnerDoc()->GetInnerWindow()) { \
|
||||
nsGlobalWindow* globalWin = nsGlobalWindow::Cast(win); \
|
||||
return globalWin->GetOn##name_(); \
|
||||
} \
|
||||
return nullptr; \
|
||||
} \
|
||||
void \
|
||||
HTMLFrameSetElement::SetOn##name_(type_* handler) \
|
||||
{ \
|
||||
nsPIDOMWindowInner* win = OwnerDoc()->GetInnerWindow(); \
|
||||
if (!win) { \
|
||||
return; \
|
||||
} \
|
||||
\
|
||||
nsGlobalWindow* globalWin = nsGlobalWindow::Cast(win); \
|
||||
return globalWin->SetOn##name_(handler); \
|
||||
}
|
||||
#define WINDOW_EVENT(name_, id_, type_, struct_) \
|
||||
WINDOW_EVENT_HELPER(name_, EventHandlerNonNull)
|
||||
#define BEFOREUNLOAD_EVENT(name_, id_, type_, struct_) \
|
||||
WINDOW_EVENT_HELPER(name_, OnBeforeUnloadEventHandlerNonNull)
|
||||
#include "mozilla/EventNameList.h" // IWYU pragma: keep
|
||||
#undef BEFOREUNLOAD_EVENT
|
||||
#undef WINDOW_EVENT
|
||||
#undef WINDOW_EVENT_HELPER
|
||||
#undef EVENT
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
177
dom/html/HTMLFrameSetElement.h
Normal file
177
dom/html/HTMLFrameSetElement.h
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef HTMLFrameSetElement_h
|
||||
#define HTMLFrameSetElement_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "nsIDOMHTMLFrameSetElement.h"
|
||||
#include "nsGenericHTMLElement.h"
|
||||
|
||||
/**
|
||||
* The nsFramesetUnit enum is used to denote the type of each entry
|
||||
* in the row or column spec.
|
||||
*/
|
||||
enum nsFramesetUnit {
|
||||
eFramesetUnit_Fixed = 0,
|
||||
eFramesetUnit_Percent,
|
||||
eFramesetUnit_Relative
|
||||
};
|
||||
|
||||
/**
|
||||
* The nsFramesetSpec struct is used to hold a single entry in the
|
||||
* row or column spec.
|
||||
*/
|
||||
struct nsFramesetSpec {
|
||||
nsFramesetUnit mUnit;
|
||||
nscoord mValue;
|
||||
};
|
||||
|
||||
/**
|
||||
* The maximum number of entries allowed in the frame set element row
|
||||
* or column spec.
|
||||
*/
|
||||
#define NS_MAX_FRAMESET_SPEC_COUNT 16000
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class OnBeforeUnloadEventHandlerNonNull;
|
||||
|
||||
class HTMLFrameSetElement final : public nsGenericHTMLElement,
|
||||
public nsIDOMHTMLFrameSetElement
|
||||
{
|
||||
public:
|
||||
explicit HTMLFrameSetElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
|
||||
: nsGenericHTMLElement(aNodeInfo),
|
||||
mNumRows(0),
|
||||
mNumCols(0),
|
||||
mCurrentRowColHint(NS_STYLE_HINT_REFLOW)
|
||||
{
|
||||
SetHasWeirdParserInsertionMode();
|
||||
}
|
||||
|
||||
NS_IMPL_FROMCONTENT_HTML_WITH_TAG(HTMLFrameSetElement, frameset)
|
||||
|
||||
// nsISupports
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
// nsIDOMHTMLFrameSetElement
|
||||
NS_DECL_NSIDOMHTMLFRAMESETELEMENT
|
||||
|
||||
void GetCols(DOMString& aCols)
|
||||
{
|
||||
GetHTMLAttr(nsGkAtoms::cols, aCols);
|
||||
}
|
||||
void SetCols(const nsAString& aCols, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::cols, aCols, aError);
|
||||
}
|
||||
void GetRows(DOMString& aRows)
|
||||
{
|
||||
GetHTMLAttr(nsGkAtoms::rows, aRows);
|
||||
}
|
||||
void SetRows(const nsAString& aRows, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::rows, aRows, aError);
|
||||
}
|
||||
|
||||
virtual bool IsEventAttributeName(nsIAtom *aName) override;
|
||||
|
||||
// Event listener stuff; we need to declare only the ones we need to
|
||||
// forward to window that don't come from nsIDOMHTMLFrameSetElement.
|
||||
#define EVENT(name_, id_, type_, struct_) /* nothing; handled by the superclass */
|
||||
#define WINDOW_EVENT_HELPER(name_, type_) \
|
||||
type_* GetOn##name_(); \
|
||||
void SetOn##name_(type_* handler);
|
||||
#define WINDOW_EVENT(name_, id_, type_, struct_) \
|
||||
WINDOW_EVENT_HELPER(name_, EventHandlerNonNull)
|
||||
#define BEFOREUNLOAD_EVENT(name_, id_, type_, struct_) \
|
||||
WINDOW_EVENT_HELPER(name_, OnBeforeUnloadEventHandlerNonNull)
|
||||
#include "mozilla/EventNameList.h" // IWYU pragma: keep
|
||||
#undef BEFOREUNLOAD_EVENT
|
||||
#undef WINDOW_EVENT
|
||||
#undef WINDOW_EVENT_HELPER
|
||||
#undef EVENT
|
||||
|
||||
// These override the SetAttr methods in nsGenericHTMLElement (need
|
||||
// both here to silence compiler warnings).
|
||||
nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
const nsAString& aValue, bool aNotify)
|
||||
{
|
||||
return SetAttr(aNameSpaceID, aName, nullptr, aValue, aNotify);
|
||||
}
|
||||
virtual nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
nsIAtom* aPrefix, const nsAString& aValue,
|
||||
bool aNotify) override;
|
||||
|
||||
/**
|
||||
* GetRowSpec is used to get the "rows" spec.
|
||||
* @param out int32_t aNumValues The number of row sizes specified.
|
||||
* @param out nsFramesetSpec* aSpecs The array of size specifications.
|
||||
This is _not_ owned by the caller, but by the nsFrameSetElement
|
||||
implementation. DO NOT DELETE IT.
|
||||
*/
|
||||
nsresult GetRowSpec(int32_t *aNumValues, const nsFramesetSpec** aSpecs);
|
||||
/**
|
||||
* GetColSpec is used to get the "cols" spec
|
||||
* @param out int32_t aNumValues The number of row sizes specified.
|
||||
* @param out nsFramesetSpec* aSpecs The array of size specifications.
|
||||
This is _not_ owned by the caller, but by the nsFrameSetElement
|
||||
implementation. DO NOT DELETE IT.
|
||||
*/
|
||||
nsresult GetColSpec(int32_t *aNumValues, const nsFramesetSpec** aSpecs);
|
||||
|
||||
|
||||
virtual bool ParseAttribute(int32_t aNamespaceID,
|
||||
nsIAtom* aAttribute,
|
||||
const nsAString& aValue,
|
||||
nsAttrValue& aResult) override;
|
||||
virtual nsChangeHint GetAttributeChangeHint(const nsIAtom* aAttribute,
|
||||
int32_t aModType) const override;
|
||||
|
||||
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
|
||||
|
||||
protected:
|
||||
virtual ~HTMLFrameSetElement();
|
||||
|
||||
virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
private:
|
||||
nsresult ParseRowCol(const nsAString& aValue,
|
||||
int32_t& aNumSpecs,
|
||||
UniquePtr<nsFramesetSpec[]>* aSpecs);
|
||||
|
||||
/**
|
||||
* The number of size specs in our "rows" attr
|
||||
*/
|
||||
int32_t mNumRows;
|
||||
/**
|
||||
* The number of size specs in our "cols" attr
|
||||
*/
|
||||
int32_t mNumCols;
|
||||
/**
|
||||
* The style hint to return for the rows/cols attrs in
|
||||
* GetAttributeChangeHint
|
||||
*/
|
||||
nsChangeHint mCurrentRowColHint;
|
||||
/**
|
||||
* The parsed representation of the "rows" attribute
|
||||
*/
|
||||
UniquePtr<nsFramesetSpec[]> mRowSpecs; // parsed, non-computed dimensions
|
||||
/**
|
||||
* The parsed representation of the "cols" attribute
|
||||
*/
|
||||
UniquePtr<nsFramesetSpec[]> mColSpecs; // parsed, non-computed dimensions
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // HTMLFrameSetElement_h
|
||||
267
dom/html/HTMLHRElement.cpp
Normal file
267
dom/html/HTMLHRElement.cpp
Normal file
|
|
@ -0,0 +1,267 @@
|
|||
/* -*- 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/HTMLHRElement.h"
|
||||
#include "mozilla/dom/HTMLHRElementBinding.h"
|
||||
|
||||
NS_IMPL_NS_NEW_HTML_ELEMENT(HR)
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
HTMLHRElement::HTMLHRElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
|
||||
: nsGenericHTMLElement(aNodeInfo)
|
||||
{
|
||||
}
|
||||
|
||||
HTMLHRElement::~HTMLHRElement()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED(HTMLHRElement, nsGenericHTMLElement,
|
||||
nsIDOMHTMLHRElement)
|
||||
|
||||
NS_IMPL_ELEMENT_CLONE(HTMLHRElement)
|
||||
|
||||
|
||||
NS_IMPL_STRING_ATTR(HTMLHRElement, Align, align)
|
||||
NS_IMPL_BOOL_ATTR(HTMLHRElement, NoShade, noshade)
|
||||
NS_IMPL_STRING_ATTR(HTMLHRElement, Size, size)
|
||||
NS_IMPL_STRING_ATTR(HTMLHRElement, Width, width)
|
||||
NS_IMPL_STRING_ATTR(HTMLHRElement, Color, color)
|
||||
|
||||
bool
|
||||
HTMLHRElement::ParseAttribute(int32_t aNamespaceID,
|
||||
nsIAtom* aAttribute,
|
||||
const nsAString& aValue,
|
||||
nsAttrValue& aResult)
|
||||
{
|
||||
static const nsAttrValue::EnumTable kAlignTable[] = {
|
||||
{ "left", NS_STYLE_TEXT_ALIGN_LEFT },
|
||||
{ "right", NS_STYLE_TEXT_ALIGN_RIGHT },
|
||||
{ "center", NS_STYLE_TEXT_ALIGN_CENTER },
|
||||
{ nullptr, 0 }
|
||||
};
|
||||
|
||||
if (aNamespaceID == kNameSpaceID_None) {
|
||||
if (aAttribute == nsGkAtoms::width) {
|
||||
return aResult.ParseSpecialIntValue(aValue);
|
||||
}
|
||||
if (aAttribute == nsGkAtoms::size) {
|
||||
return aResult.ParseIntWithBounds(aValue, 1, 1000);
|
||||
}
|
||||
if (aAttribute == nsGkAtoms::align) {
|
||||
return aResult.ParseEnumValue(aValue, kAlignTable, false);
|
||||
}
|
||||
if (aAttribute == nsGkAtoms::color) {
|
||||
return aResult.ParseColor(aValue);
|
||||
}
|
||||
}
|
||||
|
||||
return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
|
||||
aResult);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLHRElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
|
||||
nsRuleData* aData)
|
||||
{
|
||||
bool noshade = false;
|
||||
|
||||
const nsAttrValue* colorValue = aAttributes->GetAttr(nsGkAtoms::color);
|
||||
nscolor color;
|
||||
bool colorIsSet = colorValue && colorValue->GetColorValue(color);
|
||||
|
||||
if (aData->mSIDs & (NS_STYLE_INHERIT_BIT(Position) |
|
||||
NS_STYLE_INHERIT_BIT(Border))) {
|
||||
if (colorIsSet) {
|
||||
noshade = true;
|
||||
} else {
|
||||
noshade = !!aAttributes->GetAttr(nsGkAtoms::noshade);
|
||||
}
|
||||
}
|
||||
|
||||
if (aData->mSIDs & NS_STYLE_INHERIT_BIT(Margin)) {
|
||||
// align: enum
|
||||
const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::align);
|
||||
if (value && value->Type() == nsAttrValue::eEnum) {
|
||||
// Map align attribute into auto side margins
|
||||
nsCSSValue* marginLeft = aData->ValueForMarginLeft();
|
||||
nsCSSValue* marginRight = aData->ValueForMarginRight();
|
||||
switch (value->GetEnumValue()) {
|
||||
case NS_STYLE_TEXT_ALIGN_LEFT:
|
||||
if (marginLeft->GetUnit() == eCSSUnit_Null)
|
||||
marginLeft->SetFloatValue(0.0f, eCSSUnit_Pixel);
|
||||
if (marginRight->GetUnit() == eCSSUnit_Null)
|
||||
marginRight->SetAutoValue();
|
||||
break;
|
||||
case NS_STYLE_TEXT_ALIGN_RIGHT:
|
||||
if (marginLeft->GetUnit() == eCSSUnit_Null)
|
||||
marginLeft->SetAutoValue();
|
||||
if (marginRight->GetUnit() == eCSSUnit_Null)
|
||||
marginRight->SetFloatValue(0.0f, eCSSUnit_Pixel);
|
||||
break;
|
||||
case NS_STYLE_TEXT_ALIGN_CENTER:
|
||||
if (marginLeft->GetUnit() == eCSSUnit_Null)
|
||||
marginLeft->SetAutoValue();
|
||||
if (marginRight->GetUnit() == eCSSUnit_Null)
|
||||
marginRight->SetAutoValue();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (aData->mSIDs & NS_STYLE_INHERIT_BIT(Position)) {
|
||||
// width: integer, percent
|
||||
nsCSSValue* width = aData->ValueForWidth();
|
||||
if (width->GetUnit() == eCSSUnit_Null) {
|
||||
const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::width);
|
||||
if (value && value->Type() == nsAttrValue::eInteger) {
|
||||
width->SetFloatValue((float)value->GetIntegerValue(), eCSSUnit_Pixel);
|
||||
} else if (value && value->Type() == nsAttrValue::ePercent) {
|
||||
width->SetPercentValue(value->GetPercentValue());
|
||||
}
|
||||
}
|
||||
|
||||
nsCSSValue* height = aData->ValueForHeight();
|
||||
if (height->GetUnit() == eCSSUnit_Null) {
|
||||
// size: integer
|
||||
if (noshade) {
|
||||
// noshade case: size is set using the border
|
||||
height->SetAutoValue();
|
||||
} else {
|
||||
// normal case
|
||||
// the height includes the top and bottom borders that are initially 1px.
|
||||
// for size=1, html.css has a special case rule that makes this work by
|
||||
// removing all but the top border.
|
||||
const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::size);
|
||||
if (value && value->Type() == nsAttrValue::eInteger) {
|
||||
height->SetFloatValue((float)value->GetIntegerValue(), eCSSUnit_Pixel);
|
||||
} // else use default value from html.css
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((aData->mSIDs & NS_STYLE_INHERIT_BIT(Border)) && noshade) { // if not noshade, border styles are dealt with by html.css
|
||||
// size: integer
|
||||
// if a size is set, use half of it per side, otherwise, use 1px per side
|
||||
float sizePerSide;
|
||||
bool allSides = true;
|
||||
const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::size);
|
||||
if (value && value->Type() == nsAttrValue::eInteger) {
|
||||
sizePerSide = (float)value->GetIntegerValue() / 2.0f;
|
||||
if (sizePerSide < 1.0f) {
|
||||
// XXX When the pixel bug is fixed, all the special casing for
|
||||
// subpixel borders should be removed.
|
||||
// In the meantime, this makes http://www.microsoft.com/ look right.
|
||||
sizePerSide = 1.0f;
|
||||
allSides = false;
|
||||
}
|
||||
} else {
|
||||
sizePerSide = 1.0f; // default to a 2px high line
|
||||
}
|
||||
nsCSSValue* borderTopWidth = aData->ValueForBorderTopWidth();
|
||||
if (borderTopWidth->GetUnit() == eCSSUnit_Null) {
|
||||
borderTopWidth->SetFloatValue(sizePerSide, eCSSUnit_Pixel);
|
||||
}
|
||||
if (allSides) {
|
||||
nsCSSValue* borderRightWidth = aData->ValueForBorderRightWidth();
|
||||
if (borderRightWidth->GetUnit() == eCSSUnit_Null) {
|
||||
borderRightWidth->SetFloatValue(sizePerSide, eCSSUnit_Pixel);
|
||||
}
|
||||
nsCSSValue* borderBottomWidth = aData->ValueForBorderBottomWidth();
|
||||
if (borderBottomWidth->GetUnit() == eCSSUnit_Null) {
|
||||
borderBottomWidth->SetFloatValue(sizePerSide, eCSSUnit_Pixel);
|
||||
}
|
||||
nsCSSValue* borderLeftWidth = aData->ValueForBorderLeftWidth();
|
||||
if (borderLeftWidth->GetUnit() == eCSSUnit_Null) {
|
||||
borderLeftWidth->SetFloatValue(sizePerSide, eCSSUnit_Pixel);
|
||||
}
|
||||
}
|
||||
|
||||
nsCSSValue* borderTopStyle = aData->ValueForBorderTopStyle();
|
||||
if (borderTopStyle->GetUnit() == eCSSUnit_Null) {
|
||||
borderTopStyle->SetIntValue(NS_STYLE_BORDER_STYLE_SOLID,
|
||||
eCSSUnit_Enumerated);
|
||||
}
|
||||
if (allSides) {
|
||||
nsCSSValue* borderRightStyle = aData->ValueForBorderRightStyle();
|
||||
if (borderRightStyle->GetUnit() == eCSSUnit_Null) {
|
||||
borderRightStyle->SetIntValue(NS_STYLE_BORDER_STYLE_SOLID,
|
||||
eCSSUnit_Enumerated);
|
||||
}
|
||||
nsCSSValue* borderBottomStyle = aData->ValueForBorderBottomStyle();
|
||||
if (borderBottomStyle->GetUnit() == eCSSUnit_Null) {
|
||||
borderBottomStyle->SetIntValue(NS_STYLE_BORDER_STYLE_SOLID,
|
||||
eCSSUnit_Enumerated);
|
||||
}
|
||||
nsCSSValue* borderLeftStyle = aData->ValueForBorderLeftStyle();
|
||||
if (borderLeftStyle->GetUnit() == eCSSUnit_Null) {
|
||||
borderLeftStyle->SetIntValue(NS_STYLE_BORDER_STYLE_SOLID,
|
||||
eCSSUnit_Enumerated);
|
||||
}
|
||||
|
||||
// If it would be noticeable, set the border radius to
|
||||
// 10000px on all corners; this triggers the clamping to make
|
||||
// circular ends. This assumes the <hr> isn't larger than
|
||||
// that in *both* dimensions.
|
||||
for (const nsCSSPropertyID* props =
|
||||
nsCSSProps::SubpropertyEntryFor(eCSSProperty_border_radius);
|
||||
*props != eCSSProperty_UNKNOWN; ++props) {
|
||||
nsCSSValue* dimen = aData->ValueFor(*props);
|
||||
if (dimen->GetUnit() == eCSSUnit_Null) {
|
||||
dimen->SetFloatValue(10000.0f, eCSSUnit_Pixel);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (aData->mSIDs & NS_STYLE_INHERIT_BIT(Color)) {
|
||||
// color: a color
|
||||
// (we got the color attribute earlier)
|
||||
nsCSSValue* colorValue = aData->ValueForColor();
|
||||
if (colorIsSet &&
|
||||
colorValue->GetUnit() == eCSSUnit_Null &&
|
||||
aData->mPresContext->UseDocumentColors()) {
|
||||
colorValue->SetColorValue(color);
|
||||
}
|
||||
}
|
||||
|
||||
nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aData);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(bool)
|
||||
HTMLHRElement::IsAttributeMapped(const nsIAtom* aAttribute) const
|
||||
{
|
||||
static const MappedAttributeEntry attributes[] = {
|
||||
{ &nsGkAtoms::align },
|
||||
{ &nsGkAtoms::width },
|
||||
{ &nsGkAtoms::size },
|
||||
{ &nsGkAtoms::color },
|
||||
{ &nsGkAtoms::noshade },
|
||||
{ nullptr },
|
||||
};
|
||||
|
||||
static const MappedAttributeEntry* const map[] = {
|
||||
attributes,
|
||||
sCommonAttributeMap,
|
||||
};
|
||||
|
||||
return FindAttributeDependence(aAttribute, map);
|
||||
}
|
||||
|
||||
|
||||
nsMapRuleToAttributesFunc
|
||||
HTMLHRElement::GetAttributeMappingFunction() const
|
||||
{
|
||||
return &MapAttributesIntoRule;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
HTMLHRElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return HTMLHRElementBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
86
dom/html/HTMLHRElement.h
Normal file
86
dom/html/HTMLHRElement.h
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
|
||||
#ifndef mozilla_dom_HTMLHRElement_h
|
||||
#define mozilla_dom_HTMLHRElement_h
|
||||
|
||||
#include "nsGenericHTMLElement.h"
|
||||
#include "nsIDOMHTMLHRElement.h"
|
||||
#include "nsMappedAttributes.h"
|
||||
#include "nsAttrValueInlines.h"
|
||||
#include "nsRuleData.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class HTMLHRElement final : public nsGenericHTMLElement,
|
||||
public nsIDOMHTMLHRElement
|
||||
{
|
||||
public:
|
||||
explicit HTMLHRElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
|
||||
|
||||
// nsISupports
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
// nsIDOMHTMLHRElement
|
||||
NS_DECL_NSIDOMHTMLHRELEMENT
|
||||
|
||||
virtual bool ParseAttribute(int32_t aNamespaceID,
|
||||
nsIAtom* aAttribute,
|
||||
const nsAString& aValue,
|
||||
nsAttrValue& aResult) override;
|
||||
NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
|
||||
virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const override;
|
||||
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
|
||||
|
||||
// WebIDL API
|
||||
void SetAlign(const nsAString& aAlign, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::align, aAlign, aError);
|
||||
}
|
||||
|
||||
// The XPCOM GetColor is OK for us
|
||||
void SetColor(const nsAString& aColor, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::color, aColor, aError);
|
||||
}
|
||||
|
||||
bool NoShade() const
|
||||
{
|
||||
return GetBoolAttr(nsGkAtoms::noshade);
|
||||
}
|
||||
void SetNoShade(bool aNoShade, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLBoolAttr(nsGkAtoms::noshade, aNoShade, aError);
|
||||
}
|
||||
|
||||
// The XPCOM GetSize is OK for us
|
||||
void SetSize(const nsAString& aSize, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::size, aSize, aError);
|
||||
}
|
||||
|
||||
// The XPCOM GetWidth is OK for us
|
||||
void SetWidth(const nsAString& aWidth, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::width, aWidth, aError);
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual ~HTMLHRElement();
|
||||
|
||||
virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
private:
|
||||
static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
|
||||
nsRuleData* aData);
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_HTMLHRElement_h
|
||||
74
dom/html/HTMLHeadingElement.cpp
Normal file
74
dom/html/HTMLHeadingElement.cpp
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
/* -*- 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/HTMLHeadingElement.h"
|
||||
#include "mozilla/dom/HTMLHeadingElementBinding.h"
|
||||
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsStyleConsts.h"
|
||||
#include "nsMappedAttributes.h"
|
||||
#include "nsRuleData.h"
|
||||
#include "mozAutoDocUpdate.h"
|
||||
|
||||
NS_IMPL_NS_NEW_HTML_ELEMENT(Heading)
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
HTMLHeadingElement::~HTMLHeadingElement()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMPL_ELEMENT_CLONE(HTMLHeadingElement)
|
||||
|
||||
JSObject*
|
||||
HTMLHeadingElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return HTMLHeadingElementBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
bool
|
||||
HTMLHeadingElement::ParseAttribute(int32_t aNamespaceID,
|
||||
nsIAtom* aAttribute,
|
||||
const nsAString& aValue,
|
||||
nsAttrValue& aResult)
|
||||
{
|
||||
if (aAttribute == nsGkAtoms::align && aNamespaceID == kNameSpaceID_None) {
|
||||
return ParseDivAlignValue(aValue, aResult);
|
||||
}
|
||||
|
||||
return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
|
||||
aResult);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLHeadingElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
|
||||
nsRuleData* aData)
|
||||
{
|
||||
nsGenericHTMLElement::MapDivAlignAttributeInto(aAttributes, aData);
|
||||
nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aData);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(bool)
|
||||
HTMLHeadingElement::IsAttributeMapped(const nsIAtom* aAttribute) const
|
||||
{
|
||||
static const MappedAttributeEntry* const map[] = {
|
||||
sDivAlignAttributeMap,
|
||||
sCommonAttributeMap
|
||||
};
|
||||
|
||||
return FindAttributeDependence(aAttribute, map);
|
||||
}
|
||||
|
||||
|
||||
nsMapRuleToAttributesFunc
|
||||
HTMLHeadingElement::GetAttributeMappingFunction() const
|
||||
{
|
||||
return &MapAttributesIntoRule;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
54
dom/html/HTMLHeadingElement.h
Normal file
54
dom/html/HTMLHeadingElement.h
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_dom_HTMLHeadingElement_h
|
||||
#define mozilla_dom_HTMLHeadingElement_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsGenericHTMLElement.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class HTMLHeadingElement final : public nsGenericHTMLElement
|
||||
{
|
||||
public:
|
||||
explicit HTMLHeadingElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
|
||||
: nsGenericHTMLElement(aNodeInfo)
|
||||
{
|
||||
}
|
||||
|
||||
virtual bool ParseAttribute(int32_t aNamespaceID,
|
||||
nsIAtom* aAttribute,
|
||||
const nsAString& aValue,
|
||||
nsAttrValue& aResult) override;
|
||||
NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
|
||||
nsMapRuleToAttributesFunc GetAttributeMappingFunction() const override;
|
||||
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
|
||||
|
||||
void SetAlign(const nsAString& aAlign, ErrorResult& aError)
|
||||
{
|
||||
return SetHTMLAttr(nsGkAtoms::align, aAlign, aError);
|
||||
}
|
||||
void GetAlign(DOMString& aAlign) const
|
||||
{
|
||||
return GetHTMLAttr(nsGkAtoms::align, aAlign);
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual ~HTMLHeadingElement();
|
||||
|
||||
virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
private:
|
||||
static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
|
||||
nsRuleData* aData);
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_HTMLHeadingElement_h
|
||||
253
dom/html/HTMLIFrameElement.cpp
Normal file
253
dom/html/HTMLIFrameElement.cpp
Normal file
|
|
@ -0,0 +1,253 @@
|
|||
/* -*- 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/HTMLIFrameElement.h"
|
||||
#include "mozilla/dom/HTMLIFrameElementBinding.h"
|
||||
#include "nsMappedAttributes.h"
|
||||
#include "nsAttrValueInlines.h"
|
||||
#include "nsError.h"
|
||||
#include "nsRuleData.h"
|
||||
#include "nsStyleConsts.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsSandboxFlags.h"
|
||||
|
||||
NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER(IFrame)
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
// static
|
||||
const DOMTokenListSupportedToken HTMLIFrameElement::sSupportedSandboxTokens[] = {
|
||||
#define SANDBOX_KEYWORD(string, atom, flags) string,
|
||||
#include "IframeSandboxKeywordList.h"
|
||||
#undef SANDBOX_KEYWORD
|
||||
nullptr
|
||||
};
|
||||
|
||||
HTMLIFrameElement::HTMLIFrameElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo,
|
||||
FromParser aFromParser)
|
||||
: nsGenericHTMLFrameElement(aNodeInfo, aFromParser)
|
||||
{
|
||||
}
|
||||
|
||||
HTMLIFrameElement::~HTMLIFrameElement()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED(HTMLIFrameElement, nsGenericHTMLFrameElement,
|
||||
nsIDOMHTMLIFrameElement)
|
||||
|
||||
NS_IMPL_ELEMENT_CLONE(HTMLIFrameElement)
|
||||
|
||||
NS_IMPL_STRING_ATTR(HTMLIFrameElement, Align, align)
|
||||
NS_IMPL_STRING_ATTR(HTMLIFrameElement, FrameBorder, frameborder)
|
||||
NS_IMPL_STRING_ATTR(HTMLIFrameElement, Height, height)
|
||||
NS_IMPL_URI_ATTR(HTMLIFrameElement, LongDesc, longdesc)
|
||||
NS_IMPL_STRING_ATTR(HTMLIFrameElement, MarginHeight, marginheight)
|
||||
NS_IMPL_STRING_ATTR(HTMLIFrameElement, MarginWidth, marginwidth)
|
||||
NS_IMPL_STRING_ATTR(HTMLIFrameElement, Name, name)
|
||||
NS_IMPL_STRING_ATTR(HTMLIFrameElement, Scrolling, scrolling)
|
||||
NS_IMPL_URI_ATTR(HTMLIFrameElement, Src, src)
|
||||
NS_IMPL_STRING_ATTR(HTMLIFrameElement, Width, width)
|
||||
NS_IMPL_BOOL_ATTR(HTMLIFrameElement, AllowFullscreen, allowfullscreen)
|
||||
NS_IMPL_STRING_ATTR(HTMLIFrameElement, Srcdoc, srcdoc)
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLIFrameElement::GetContentDocument(nsIDOMDocument** aContentDocument)
|
||||
{
|
||||
return nsGenericHTMLFrameElement::GetContentDocument(aContentDocument);
|
||||
}
|
||||
|
||||
bool
|
||||
HTMLIFrameElement::ParseAttribute(int32_t aNamespaceID,
|
||||
nsIAtom* aAttribute,
|
||||
const nsAString& aValue,
|
||||
nsAttrValue& aResult)
|
||||
{
|
||||
if (aNamespaceID == kNameSpaceID_None) {
|
||||
if (aAttribute == nsGkAtoms::marginwidth) {
|
||||
return aResult.ParseSpecialIntValue(aValue);
|
||||
}
|
||||
if (aAttribute == nsGkAtoms::marginheight) {
|
||||
return aResult.ParseSpecialIntValue(aValue);
|
||||
}
|
||||
if (aAttribute == nsGkAtoms::width) {
|
||||
return aResult.ParseSpecialIntValue(aValue);
|
||||
}
|
||||
if (aAttribute == nsGkAtoms::height) {
|
||||
return aResult.ParseSpecialIntValue(aValue);
|
||||
}
|
||||
if (aAttribute == nsGkAtoms::frameborder) {
|
||||
return ParseFrameborderValue(aValue, aResult);
|
||||
}
|
||||
if (aAttribute == nsGkAtoms::scrolling) {
|
||||
return ParseScrollingValue(aValue, aResult);
|
||||
}
|
||||
if (aAttribute == nsGkAtoms::align) {
|
||||
return ParseAlignValue(aValue, aResult);
|
||||
}
|
||||
if (aAttribute == nsGkAtoms::sandbox) {
|
||||
aResult.ParseAtomArray(aValue);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return nsGenericHTMLFrameElement::ParseAttribute(aNamespaceID, aAttribute,
|
||||
aValue, aResult);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLIFrameElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
|
||||
nsRuleData* aData)
|
||||
{
|
||||
if (aData->mSIDs & NS_STYLE_INHERIT_BIT(Border)) {
|
||||
// frameborder: 0 | 1 (| NO | YES in quirks mode)
|
||||
// If frameborder is 0 or No, set border to 0
|
||||
// else leave it as the value set in html.css
|
||||
const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::frameborder);
|
||||
if (value && value->Type() == nsAttrValue::eEnum) {
|
||||
int32_t frameborder = value->GetEnumValue();
|
||||
if (NS_STYLE_FRAME_0 == frameborder ||
|
||||
NS_STYLE_FRAME_NO == frameborder ||
|
||||
NS_STYLE_FRAME_OFF == frameborder) {
|
||||
nsCSSValue* borderLeftWidth = aData->ValueForBorderLeftWidth();
|
||||
if (borderLeftWidth->GetUnit() == eCSSUnit_Null)
|
||||
borderLeftWidth->SetFloatValue(0.0f, eCSSUnit_Pixel);
|
||||
nsCSSValue* borderRightWidth = aData->ValueForBorderRightWidth();
|
||||
if (borderRightWidth->GetUnit() == eCSSUnit_Null)
|
||||
borderRightWidth->SetFloatValue(0.0f, eCSSUnit_Pixel);
|
||||
nsCSSValue* borderTopWidth = aData->ValueForBorderTopWidth();
|
||||
if (borderTopWidth->GetUnit() == eCSSUnit_Null)
|
||||
borderTopWidth->SetFloatValue(0.0f, eCSSUnit_Pixel);
|
||||
nsCSSValue* borderBottomWidth = aData->ValueForBorderBottomWidth();
|
||||
if (borderBottomWidth->GetUnit() == eCSSUnit_Null)
|
||||
borderBottomWidth->SetFloatValue(0.0f, eCSSUnit_Pixel);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (aData->mSIDs & NS_STYLE_INHERIT_BIT(Position)) {
|
||||
// width: value
|
||||
nsCSSValue* width = aData->ValueForWidth();
|
||||
if (width->GetUnit() == eCSSUnit_Null) {
|
||||
const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::width);
|
||||
if (value && value->Type() == nsAttrValue::eInteger)
|
||||
width->SetFloatValue((float)value->GetIntegerValue(), eCSSUnit_Pixel);
|
||||
else if (value && value->Type() == nsAttrValue::ePercent)
|
||||
width->SetPercentValue(value->GetPercentValue());
|
||||
}
|
||||
|
||||
// height: value
|
||||
nsCSSValue* height = aData->ValueForHeight();
|
||||
if (height->GetUnit() == eCSSUnit_Null) {
|
||||
const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::height);
|
||||
if (value && value->Type() == nsAttrValue::eInteger)
|
||||
height->SetFloatValue((float)value->GetIntegerValue(), eCSSUnit_Pixel);
|
||||
else if (value && value->Type() == nsAttrValue::ePercent)
|
||||
height->SetPercentValue(value->GetPercentValue());
|
||||
}
|
||||
}
|
||||
|
||||
nsGenericHTMLElement::MapImageAlignAttributeInto(aAttributes, aData);
|
||||
nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aData);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(bool)
|
||||
HTMLIFrameElement::IsAttributeMapped(const nsIAtom* aAttribute) const
|
||||
{
|
||||
static const MappedAttributeEntry attributes[] = {
|
||||
{ &nsGkAtoms::width },
|
||||
{ &nsGkAtoms::height },
|
||||
{ &nsGkAtoms::frameborder },
|
||||
{ nullptr },
|
||||
};
|
||||
|
||||
static const MappedAttributeEntry* const map[] = {
|
||||
attributes,
|
||||
sImageAlignAttributeMap,
|
||||
sCommonAttributeMap,
|
||||
};
|
||||
|
||||
return FindAttributeDependence(aAttribute, map);
|
||||
}
|
||||
|
||||
|
||||
|
||||
nsMapRuleToAttributesFunc
|
||||
HTMLIFrameElement::GetAttributeMappingFunction() const
|
||||
{
|
||||
return &MapAttributesIntoRule;
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLIFrameElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
nsIAtom* aPrefix, const nsAString& aValue,
|
||||
bool aNotify)
|
||||
{
|
||||
nsresult rv = nsGenericHTMLFrameElement::SetAttr(aNameSpaceID, aName,
|
||||
aPrefix, aValue, aNotify);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::srcdoc) {
|
||||
// Don't propagate error here. The attribute was successfully set, that's
|
||||
// what we should reflect.
|
||||
LoadSrc();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLIFrameElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
const nsAttrValue* aValue,
|
||||
bool aNotify)
|
||||
{
|
||||
if (aName == nsGkAtoms::sandbox &&
|
||||
aNameSpaceID == kNameSpaceID_None && mFrameLoader) {
|
||||
// If we have an nsFrameLoader, apply the new sandbox flags.
|
||||
// Since this is called after the setter, the sandbox flags have
|
||||
// alreay been updated.
|
||||
mFrameLoader->ApplySandboxFlags(GetSandboxFlags());
|
||||
}
|
||||
return nsGenericHTMLFrameElement::AfterSetAttr(aNameSpaceID, aName, aValue,
|
||||
aNotify);
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLIFrameElement::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
|
||||
bool aNotify)
|
||||
{
|
||||
// Invoke on the superclass.
|
||||
nsresult rv = nsGenericHTMLFrameElement::UnsetAttr(aNameSpaceID, aAttribute, aNotify);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (aNameSpaceID == kNameSpaceID_None &&
|
||||
aAttribute == nsGkAtoms::srcdoc) {
|
||||
// Fall back to the src attribute, if any
|
||||
LoadSrc();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
HTMLIFrameElement::GetSandboxFlags()
|
||||
{
|
||||
const nsAttrValue* sandboxAttr = GetParsedAttr(nsGkAtoms::sandbox);
|
||||
// No sandbox attribute, no sandbox flags.
|
||||
if (!sandboxAttr) {
|
||||
return SANDBOXED_NONE;
|
||||
}
|
||||
return nsContentUtils::ParseSandboxAttributeToFlags(sandboxAttr);
|
||||
}
|
||||
|
||||
JSObject*
|
||||
HTMLIFrameElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return HTMLIFrameElementBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
209
dom/html/HTMLIFrameElement.h
Normal file
209
dom/html/HTMLIFrameElement.h
Normal file
|
|
@ -0,0 +1,209 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_dom_HTMLIFrameElement_h
|
||||
#define mozilla_dom_HTMLIFrameElement_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsGenericHTMLFrameElement.h"
|
||||
#include "nsIDOMHTMLIFrameElement.h"
|
||||
#include "nsDOMTokenList.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class HTMLIFrameElement final : public nsGenericHTMLFrameElement
|
||||
, public nsIDOMHTMLIFrameElement
|
||||
{
|
||||
public:
|
||||
explicit HTMLIFrameElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo,
|
||||
FromParser aFromParser = NOT_FROM_PARSER);
|
||||
|
||||
NS_IMPL_FROMCONTENT_HTML_WITH_TAG(HTMLIFrameElement, iframe)
|
||||
|
||||
// nsISupports
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
// Element
|
||||
virtual bool IsInteractiveHTMLContent(bool aIgnoreTabindex) const override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// nsIDOMHTMLIFrameElement
|
||||
NS_DECL_NSIDOMHTMLIFRAMEELEMENT
|
||||
|
||||
// nsIContent
|
||||
virtual bool ParseAttribute(int32_t aNamespaceID,
|
||||
nsIAtom* aAttribute,
|
||||
const nsAString& aValue,
|
||||
nsAttrValue& aResult) override;
|
||||
NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
|
||||
virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const override;
|
||||
|
||||
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
|
||||
|
||||
nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
const nsAString& aValue, bool aNotify)
|
||||
{
|
||||
return SetAttr(aNameSpaceID, aName, nullptr, aValue, aNotify);
|
||||
}
|
||||
virtual nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
nsIAtom* aPrefix, const nsAString& aValue,
|
||||
bool aNotify) override;
|
||||
virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
const nsAttrValue* aValue,
|
||||
bool aNotify) override;
|
||||
virtual nsresult UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
|
||||
bool aNotify) override;
|
||||
|
||||
uint32_t GetSandboxFlags();
|
||||
|
||||
// Web IDL binding methods
|
||||
// The XPCOM GetSrc is fine for our purposes
|
||||
void SetSrc(const nsAString& aSrc, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::src, aSrc, aError);
|
||||
}
|
||||
void GetSrcdoc(DOMString& aSrcdoc)
|
||||
{
|
||||
GetHTMLAttr(nsGkAtoms::srcdoc, aSrcdoc);
|
||||
}
|
||||
void SetSrcdoc(const nsAString& aSrcdoc, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::srcdoc, aSrcdoc, aError);
|
||||
}
|
||||
void GetName(DOMString& aName)
|
||||
{
|
||||
GetHTMLAttr(nsGkAtoms::name, aName);
|
||||
}
|
||||
void SetName(const nsAString& aName, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::name, aName, aError);
|
||||
}
|
||||
nsDOMTokenList* Sandbox()
|
||||
{
|
||||
return GetTokenList(nsGkAtoms::sandbox, sSupportedSandboxTokens);
|
||||
}
|
||||
bool AllowFullscreen() const
|
||||
{
|
||||
return GetBoolAttr(nsGkAtoms::allowfullscreen);
|
||||
}
|
||||
void SetAllowFullscreen(bool aAllow, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLBoolAttr(nsGkAtoms::allowfullscreen, aAllow, aError);
|
||||
}
|
||||
void GetWidth(DOMString& aWidth)
|
||||
{
|
||||
GetHTMLAttr(nsGkAtoms::width, aWidth);
|
||||
}
|
||||
void SetWidth(const nsAString& aWidth, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::width, aWidth, aError);
|
||||
}
|
||||
void GetHeight(DOMString& aHeight)
|
||||
{
|
||||
GetHTMLAttr(nsGkAtoms::height, aHeight);
|
||||
}
|
||||
void SetHeight(const nsAString& aHeight, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::height, aHeight, aError);
|
||||
}
|
||||
using nsGenericHTMLFrameElement::GetContentDocument;
|
||||
using nsGenericHTMLFrameElement::GetContentWindow;
|
||||
void GetAlign(DOMString& aAlign)
|
||||
{
|
||||
GetHTMLAttr(nsGkAtoms::align, aAlign);
|
||||
}
|
||||
void SetAlign(const nsAString& aAlign, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::align, aAlign, aError);
|
||||
}
|
||||
void GetScrolling(DOMString& aScrolling)
|
||||
{
|
||||
GetHTMLAttr(nsGkAtoms::scrolling, aScrolling);
|
||||
}
|
||||
void SetScrolling(const nsAString& aScrolling, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::scrolling, aScrolling, aError);
|
||||
}
|
||||
void GetFrameBorder(DOMString& aFrameBorder)
|
||||
{
|
||||
GetHTMLAttr(nsGkAtoms::frameborder, aFrameBorder);
|
||||
}
|
||||
void SetFrameBorder(const nsAString& aFrameBorder, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::frameborder, aFrameBorder, aError);
|
||||
}
|
||||
// The XPCOM GetLongDesc is fine
|
||||
void SetLongDesc(const nsAString& aLongDesc, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::longdesc, aLongDesc, aError);
|
||||
}
|
||||
void GetMarginWidth(DOMString& aMarginWidth)
|
||||
{
|
||||
GetHTMLAttr(nsGkAtoms::marginwidth, aMarginWidth);
|
||||
}
|
||||
void SetMarginWidth(const nsAString& aMarginWidth, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::marginwidth, aMarginWidth, aError);
|
||||
}
|
||||
void GetMarginHeight(DOMString& aMarginHeight)
|
||||
{
|
||||
GetHTMLAttr(nsGkAtoms::marginheight, aMarginHeight);
|
||||
}
|
||||
void SetMarginHeight(const nsAString& aMarginHeight, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::marginheight, aMarginHeight, aError);
|
||||
}
|
||||
void SetReferrerPolicy(const nsAString& aReferrer, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::referrerpolicy, aReferrer, aError);
|
||||
}
|
||||
void GetReferrerPolicy(nsAString& aReferrer)
|
||||
{
|
||||
GetEnumAttr(nsGkAtoms::referrerpolicy, EmptyCString().get(), aReferrer);
|
||||
}
|
||||
nsIDocument*
|
||||
GetSVGDocument(nsIPrincipal& aSubjectPrincipal)
|
||||
{
|
||||
return GetContentDocument(aSubjectPrincipal);
|
||||
}
|
||||
bool Mozbrowser() const
|
||||
{
|
||||
return GetBoolAttr(nsGkAtoms::mozbrowser);
|
||||
}
|
||||
void SetMozbrowser(bool aAllow, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLBoolAttr(nsGkAtoms::mozbrowser, aAllow, aError);
|
||||
}
|
||||
using nsGenericHTMLFrameElement::SetMozbrowser;
|
||||
// nsGenericHTMLFrameElement::GetFrameLoader is fine
|
||||
// nsGenericHTMLFrameElement::GetAppManifestURL is fine
|
||||
|
||||
// The fullscreen flag is set to true only when requestFullscreen is
|
||||
// explicitly called on this <iframe> element. In case this flag is
|
||||
// set, the fullscreen state of this element will not be reverted
|
||||
// automatically when its subdocument exits fullscreen.
|
||||
bool FullscreenFlag() const { return mFullscreenFlag; }
|
||||
void SetFullscreenFlag(bool aValue) { mFullscreenFlag = aValue; }
|
||||
|
||||
protected:
|
||||
virtual ~HTMLIFrameElement();
|
||||
|
||||
virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
private:
|
||||
static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
|
||||
nsRuleData* aData);
|
||||
|
||||
static const DOMTokenListSupportedToken sSupportedSandboxTokens[];
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
1354
dom/html/HTMLImageElement.cpp
Normal file
1354
dom/html/HTMLImageElement.cpp
Normal file
File diff suppressed because it is too large
Load diff
377
dom/html/HTMLImageElement.h
Normal file
377
dom/html/HTMLImageElement.h
Normal file
|
|
@ -0,0 +1,377 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_dom_HTMLImageElement_h
|
||||
#define mozilla_dom_HTMLImageElement_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsGenericHTMLElement.h"
|
||||
#include "nsImageLoadingContent.h"
|
||||
#include "nsIDOMHTMLImageElement.h"
|
||||
#include "imgRequestProxy.h"
|
||||
#include "Units.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
|
||||
namespace mozilla {
|
||||
class EventChainPreVisitor;
|
||||
namespace dom {
|
||||
|
||||
class ImageLoadTask;
|
||||
|
||||
class ResponsiveImageSelector;
|
||||
class HTMLImageElement final : public nsGenericHTMLElement,
|
||||
public nsImageLoadingContent,
|
||||
public nsIDOMHTMLImageElement
|
||||
{
|
||||
friend class HTMLSourceElement;
|
||||
friend class HTMLPictureElement;
|
||||
friend class ImageLoadTask;
|
||||
public:
|
||||
explicit HTMLImageElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
|
||||
|
||||
static already_AddRefed<HTMLImageElement>
|
||||
Image(const GlobalObject& aGlobal,
|
||||
const Optional<uint32_t>& aWidth,
|
||||
const Optional<uint32_t>& aHeight,
|
||||
ErrorResult& aError);
|
||||
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLImageElement,
|
||||
nsGenericHTMLElement)
|
||||
|
||||
// nsISupports
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
virtual bool Draggable() const override;
|
||||
|
||||
// Element
|
||||
virtual bool IsInteractiveHTMLContent(bool aIgnoreTabindex) const override;
|
||||
|
||||
// EventTarget
|
||||
virtual void AsyncEventRunning(AsyncEventDispatcher* aEvent) override;
|
||||
|
||||
// nsIDOMHTMLImageElement
|
||||
NS_DECL_NSIDOMHTMLIMAGEELEMENT
|
||||
|
||||
NS_IMPL_FROMCONTENT_HTML_WITH_TAG(HTMLImageElement, img)
|
||||
|
||||
// override from nsImageLoadingContent
|
||||
CORSMode GetCORSMode() override;
|
||||
|
||||
// nsIContent
|
||||
virtual bool ParseAttribute(int32_t aNamespaceID,
|
||||
nsIAtom* aAttribute,
|
||||
const nsAString& aValue,
|
||||
nsAttrValue& aResult) override;
|
||||
virtual nsChangeHint GetAttributeChangeHint(const nsIAtom* aAttribute,
|
||||
int32_t aModType) const override;
|
||||
NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
|
||||
virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const override;
|
||||
|
||||
virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override;
|
||||
|
||||
bool IsHTMLFocusable(bool aWithMouse, bool *aIsFocusable, int32_t *aTabIndex) override;
|
||||
|
||||
// SetAttr override. C++ is stupid, so have to override both
|
||||
// overloaded methods.
|
||||
nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
const nsAString& aValue, bool aNotify)
|
||||
{
|
||||
return SetAttr(aNameSpaceID, aName, nullptr, aValue, aNotify);
|
||||
}
|
||||
virtual nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
nsIAtom* aPrefix, const nsAString& aValue,
|
||||
bool aNotify) override;
|
||||
|
||||
virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
||||
nsIContent* aBindingParent,
|
||||
bool aCompileEventHandlers) override;
|
||||
virtual void UnbindFromTree(bool aDeep, bool aNullParent) override;
|
||||
|
||||
virtual EventStates IntrinsicState() const override;
|
||||
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
|
||||
|
||||
virtual void NodeInfoChanged() override;
|
||||
|
||||
nsresult CopyInnerTo(Element* aDest);
|
||||
|
||||
void MaybeLoadImage();
|
||||
|
||||
bool IsMap()
|
||||
{
|
||||
return GetBoolAttr(nsGkAtoms::ismap);
|
||||
}
|
||||
void SetIsMap(bool aIsMap, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLBoolAttr(nsGkAtoms::ismap, aIsMap, aError);
|
||||
}
|
||||
uint32_t Width()
|
||||
{
|
||||
return GetWidthHeightForImage(mCurrentRequest).width;
|
||||
}
|
||||
void SetWidth(uint32_t aWidth, ErrorResult& aError)
|
||||
{
|
||||
SetUnsignedIntAttr(nsGkAtoms::width, aWidth, 0, aError);
|
||||
}
|
||||
uint32_t Height()
|
||||
{
|
||||
return GetWidthHeightForImage(mCurrentRequest).height;
|
||||
}
|
||||
void SetHeight(uint32_t aHeight, ErrorResult& aError)
|
||||
{
|
||||
SetUnsignedIntAttr(nsGkAtoms::height, aHeight, 0, aError);
|
||||
}
|
||||
uint32_t NaturalWidth();
|
||||
uint32_t NaturalHeight();
|
||||
bool Complete();
|
||||
uint32_t Hspace()
|
||||
{
|
||||
return GetUnsignedIntAttr(nsGkAtoms::hspace, 0);
|
||||
}
|
||||
void SetHspace(uint32_t aHspace, ErrorResult& aError)
|
||||
{
|
||||
SetUnsignedIntAttr(nsGkAtoms::hspace, aHspace, 0, aError);
|
||||
}
|
||||
uint32_t Vspace()
|
||||
{
|
||||
return GetUnsignedIntAttr(nsGkAtoms::vspace, 0);
|
||||
}
|
||||
void SetVspace(uint32_t aVspace, ErrorResult& aError)
|
||||
{
|
||||
SetUnsignedIntAttr(nsGkAtoms::vspace, aVspace, 0, aError);
|
||||
}
|
||||
|
||||
// The XPCOM versions of the following getters work for Web IDL bindings as well
|
||||
void SetAlt(const nsAString& aAlt, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::alt, aAlt, aError);
|
||||
}
|
||||
void SetSrc(const nsAString& aSrc, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::src, aSrc, aError);
|
||||
}
|
||||
void SetSrcset(const nsAString& aSrcset, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::srcset, aSrcset, aError);
|
||||
}
|
||||
void GetCrossOrigin(nsAString& aResult)
|
||||
{
|
||||
// Null for both missing and invalid defaults is ok, since we
|
||||
// always parse to an enum value, so we don't need an invalid
|
||||
// default, and we _want_ the missing default to be null.
|
||||
GetEnumAttr(nsGkAtoms::crossorigin, nullptr, aResult);
|
||||
}
|
||||
void SetCrossOrigin(const nsAString& aCrossOrigin, ErrorResult& aError)
|
||||
{
|
||||
SetOrRemoveNullableStringAttr(nsGkAtoms::crossorigin, aCrossOrigin, aError);
|
||||
}
|
||||
void SetUseMap(const nsAString& aUseMap, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::usemap, aUseMap, aError);
|
||||
}
|
||||
void SetName(const nsAString& aName, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::name, aName, aError);
|
||||
}
|
||||
void SetAlign(const nsAString& aAlign, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::align, aAlign, aError);
|
||||
}
|
||||
void SetLongDesc(const nsAString& aLongDesc, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::longdesc, aLongDesc, aError);
|
||||
}
|
||||
void SetSizes(const nsAString& aSizes, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::sizes, aSizes, aError);
|
||||
}
|
||||
void SetBorder(const nsAString& aBorder, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::border, aBorder, aError);
|
||||
}
|
||||
void SetReferrerPolicy(const nsAString& aReferrer, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::referrerpolicy, aReferrer, aError);
|
||||
}
|
||||
void GetReferrerPolicy(nsAString& aReferrer)
|
||||
{
|
||||
GetEnumAttr(nsGkAtoms::referrerpolicy, EmptyCString().get(), aReferrer);
|
||||
}
|
||||
|
||||
net::ReferrerPolicy
|
||||
GetImageReferrerPolicy() override
|
||||
{
|
||||
return GetReferrerPolicyAsEnum();
|
||||
}
|
||||
|
||||
int32_t X();
|
||||
int32_t Y();
|
||||
// Uses XPCOM GetLowsrc.
|
||||
void SetLowsrc(const nsAString& aLowsrc, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::lowsrc, aLowsrc, aError);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
nsIDOMHTMLFormElement* GetForm() const;
|
||||
#endif
|
||||
void SetForm(nsIDOMHTMLFormElement* aForm);
|
||||
void ClearForm(bool aRemoveFromForm);
|
||||
|
||||
virtual void DestroyContent() override;
|
||||
|
||||
void MediaFeatureValuesChanged();
|
||||
|
||||
/**
|
||||
* Given a hypothetical <img> or <source> tag with the given parameters,
|
||||
* return what URI we would attempt to use, if any. Used by the preloader to
|
||||
* resolve sources prior to DOM creation.
|
||||
*
|
||||
* @param aDocument The document this image would be for, for referencing
|
||||
* viewport width and DPI/zoom
|
||||
* @param aIsSourceTag If these parameters are for a <source> tag (as in a
|
||||
* <picture>) rather than an <img> tag. Note that some attrs are unused
|
||||
* when this is true an vice versa
|
||||
* @param aSrcAttr [ignored if aIsSourceTag] The src attr for this image.
|
||||
* @param aSrcsetAttr The srcset attr for this image/source
|
||||
* @param aSizesAttr The sizes attr for this image/source
|
||||
* @param aTypeAttr [ignored if !aIsSourceTag] The type attr for this source.
|
||||
* Should be a void string to differentiate no type attribute
|
||||
* from an empty one.
|
||||
* @param aMediaAttr [ignored if !aIsSourceTag] The media attr for this
|
||||
* source. Should be a void string to differentiate no
|
||||
* media attribute from an empty one.
|
||||
* @param aResult A reference to store the resulting URL spec in if we
|
||||
* selected a source. This value is not guaranteed to parse to
|
||||
* a valid URL, merely the URL that the tag would attempt to
|
||||
* resolve and load (which may be the empty string). This
|
||||
* parameter is not modified if return value is false.
|
||||
* @return True if we were able to select a final source, false if further
|
||||
* sources would be considered. It follows that this always returns
|
||||
* true if !aIsSourceTag.
|
||||
*
|
||||
* Note that the return value may be true with an empty string as the result,
|
||||
* which implies that the parameters provided describe a tag that would select
|
||||
* no source. This is distinct from a return of false which implies that
|
||||
* further <source> or <img> tags would be considered.
|
||||
*/
|
||||
static bool
|
||||
SelectSourceForTagWithAttrs(nsIDocument *aDocument,
|
||||
bool aIsSourceTag,
|
||||
const nsAString& aSrcAttr,
|
||||
const nsAString& aSrcsetAttr,
|
||||
const nsAString& aSizesAttr,
|
||||
const nsAString& aTypeAttr,
|
||||
const nsAString& aMediaAttr,
|
||||
nsAString& aResult);
|
||||
|
||||
/**
|
||||
* If this image's src pointers to an SVG document, flush the SVG document's
|
||||
* use counters to telemetry. Only used for testing purposes.
|
||||
*/
|
||||
void FlushUseCounters();
|
||||
|
||||
protected:
|
||||
virtual ~HTMLImageElement();
|
||||
|
||||
// Queues a task to run LoadSelectedImage pending stable state.
|
||||
//
|
||||
// Pending Bug 1076583 this is only used by the responsive image
|
||||
// algorithm (InResponsiveMode()) -- synchronous actions when just
|
||||
// using img.src will bypass this, and update source and kick off
|
||||
// image load synchronously.
|
||||
void QueueImageLoadTask(bool aAlwaysLoad);
|
||||
|
||||
// True if we have a srcset attribute or a <picture> parent, regardless of if
|
||||
// any valid responsive sources were parsed from either.
|
||||
bool HaveSrcsetOrInPicture();
|
||||
|
||||
// True if we are using the newer image loading algorithm. This will be the
|
||||
// only mode after Bug 1076583
|
||||
bool InResponsiveMode();
|
||||
|
||||
// True if the given URL and density equal the last URL and density that was loaded by this element.
|
||||
bool SelectedSourceMatchesLast(nsIURI* aSelectedSource, double aSelectedDensity);
|
||||
|
||||
// Resolve and load the current mResponsiveSelector (responsive mode) or src
|
||||
// attr image.
|
||||
nsresult LoadSelectedImage(bool aForce, bool aNotify, bool aAlwaysLoad);
|
||||
|
||||
// True if this string represents a type we would support on <source type>
|
||||
static bool SupportedPictureSourceType(const nsAString& aType);
|
||||
|
||||
// Update/create/destroy mResponsiveSelector
|
||||
void PictureSourceSrcsetChanged(nsIContent *aSourceNode,
|
||||
const nsAString& aNewValue, bool aNotify);
|
||||
void PictureSourceSizesChanged(nsIContent *aSourceNode,
|
||||
const nsAString& aNewValue, bool aNotify);
|
||||
// As we re-run the source selection on these mutations regardless,
|
||||
// we don't actually care which changed or to what
|
||||
void PictureSourceMediaOrTypeChanged(nsIContent *aSourceNode, bool aNotify);
|
||||
|
||||
void PictureSourceAdded(nsIContent *aSourceNode);
|
||||
// This should be called prior to the unbind, such that nextsibling works
|
||||
void PictureSourceRemoved(nsIContent *aSourceNode);
|
||||
|
||||
// Re-evaluates all source nodes (picture <source>,<img>) and finds
|
||||
// the best source set for mResponsiveSelector. If a better source
|
||||
// is found, creates a new selector and feeds the source to it. If
|
||||
// the current ResponsiveSelector is not changed, runs
|
||||
// SelectImage(true) to re-evaluate its candidates.
|
||||
//
|
||||
// Because keeping the existing selector is the common case (and we
|
||||
// often do no-op reselections), this does not re-parse values for
|
||||
// the existing mResponsiveSelector, meaning you need to update its
|
||||
// parameters as appropriate before calling (or null it out to force
|
||||
// recreation)
|
||||
//
|
||||
// Returns true if the source has changed, and false otherwise.
|
||||
bool UpdateResponsiveSource();
|
||||
|
||||
// Given a <source> node that is a previous sibling *or* ourselves, try to
|
||||
// create a ResponsiveSelector.
|
||||
|
||||
// If the node's srcset/sizes make for an invalid selector, returns
|
||||
// false. This does not guarantee the resulting selector matches an image,
|
||||
// only that it is valid.
|
||||
bool TryCreateResponsiveSelector(nsIContent *aSourceNode);
|
||||
|
||||
CSSIntPoint GetXY();
|
||||
virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
void UpdateFormOwner();
|
||||
|
||||
virtual nsresult BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
nsAttrValueOrString* aValue,
|
||||
bool aNotify) override;
|
||||
|
||||
virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
const nsAttrValue* aValue, bool aNotify) override;
|
||||
|
||||
// This is a weak reference that this element and the HTMLFormElement
|
||||
// cooperate in maintaining.
|
||||
HTMLFormElement* mForm;
|
||||
|
||||
// Created when we're tracking responsive image state
|
||||
RefPtr<ResponsiveImageSelector> mResponsiveSelector;
|
||||
|
||||
private:
|
||||
bool SourceElementMatches(nsIContent* aSourceNode);
|
||||
|
||||
static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
|
||||
nsRuleData* aData);
|
||||
|
||||
bool mInDocResponsiveContent;
|
||||
RefPtr<ImageLoadTask> mPendingImageLoadTask;
|
||||
|
||||
// Last URL that was attempted to load by this element.
|
||||
nsCOMPtr<nsIURI> mLastSelectedSource;
|
||||
// Last pixel density that was selected.
|
||||
double mCurrentDensity;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* mozilla_dom_HTMLImageElement_h */
|
||||
8806
dom/html/HTMLInputElement.cpp
Normal file
8806
dom/html/HTMLInputElement.cpp
Normal file
File diff suppressed because it is too large
Load diff
1691
dom/html/HTMLInputElement.h
Normal file
1691
dom/html/HTMLInputElement.h
Normal file
File diff suppressed because it is too large
Load diff
119
dom/html/HTMLLIElement.cpp
Normal file
119
dom/html/HTMLLIElement.cpp
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
/* -*- 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/HTMLLIElement.h"
|
||||
#include "mozilla/dom/HTMLLIElementBinding.h"
|
||||
|
||||
#include "nsAttrValueInlines.h"
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsStyleConsts.h"
|
||||
#include "nsMappedAttributes.h"
|
||||
#include "nsRuleData.h"
|
||||
|
||||
NS_IMPL_NS_NEW_HTML_ELEMENT(LI)
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
HTMLLIElement::~HTMLLIElement()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED(HTMLLIElement, nsGenericHTMLElement,
|
||||
nsIDOMHTMLLIElement)
|
||||
|
||||
NS_IMPL_ELEMENT_CLONE(HTMLLIElement)
|
||||
|
||||
NS_IMPL_STRING_ATTR(HTMLLIElement, Type, type)
|
||||
NS_IMPL_INT_ATTR(HTMLLIElement, Value, value)
|
||||
|
||||
// values that are handled case-insensitively
|
||||
static const nsAttrValue::EnumTable kUnorderedListItemTypeTable[] = {
|
||||
{ "disc", NS_STYLE_LIST_STYLE_DISC },
|
||||
{ "circle", NS_STYLE_LIST_STYLE_CIRCLE },
|
||||
{ "round", NS_STYLE_LIST_STYLE_CIRCLE },
|
||||
{ "square", NS_STYLE_LIST_STYLE_SQUARE },
|
||||
{ nullptr, 0 }
|
||||
};
|
||||
|
||||
// values that are handled case-sensitively
|
||||
static const nsAttrValue::EnumTable kOrderedListItemTypeTable[] = {
|
||||
{ "A", NS_STYLE_LIST_STYLE_UPPER_ALPHA },
|
||||
{ "a", NS_STYLE_LIST_STYLE_LOWER_ALPHA },
|
||||
{ "I", NS_STYLE_LIST_STYLE_UPPER_ROMAN },
|
||||
{ "i", NS_STYLE_LIST_STYLE_LOWER_ROMAN },
|
||||
{ "1", NS_STYLE_LIST_STYLE_DECIMAL },
|
||||
{ nullptr, 0 }
|
||||
};
|
||||
|
||||
bool
|
||||
HTMLLIElement::ParseAttribute(int32_t aNamespaceID,
|
||||
nsIAtom* aAttribute,
|
||||
const nsAString& aValue,
|
||||
nsAttrValue& aResult)
|
||||
{
|
||||
if (aNamespaceID == kNameSpaceID_None) {
|
||||
if (aAttribute == nsGkAtoms::type) {
|
||||
return aResult.ParseEnumValue(aValue, kOrderedListItemTypeTable,
|
||||
true) ||
|
||||
aResult.ParseEnumValue(aValue, kUnorderedListItemTypeTable, false);
|
||||
}
|
||||
if (aAttribute == nsGkAtoms::value) {
|
||||
return aResult.ParseIntValue(aValue);
|
||||
}
|
||||
}
|
||||
|
||||
return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
|
||||
aResult);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLLIElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
|
||||
nsRuleData* aData)
|
||||
{
|
||||
if (aData->mSIDs & NS_STYLE_INHERIT_BIT(List)) {
|
||||
nsCSSValue* listStyleType = aData->ValueForListStyleType();
|
||||
if (listStyleType->GetUnit() == eCSSUnit_Null) {
|
||||
// type: enum
|
||||
const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::type);
|
||||
if (value && value->Type() == nsAttrValue::eEnum)
|
||||
listStyleType->SetIntValue(value->GetEnumValue(), eCSSUnit_Enumerated);
|
||||
}
|
||||
}
|
||||
|
||||
nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aData);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(bool)
|
||||
HTMLLIElement::IsAttributeMapped(const nsIAtom* aAttribute) const
|
||||
{
|
||||
static const MappedAttributeEntry attributes[] = {
|
||||
{ &nsGkAtoms::type },
|
||||
{ nullptr },
|
||||
};
|
||||
|
||||
static const MappedAttributeEntry* const map[] = {
|
||||
attributes,
|
||||
sCommonAttributeMap,
|
||||
};
|
||||
|
||||
return FindAttributeDependence(aAttribute, map);
|
||||
}
|
||||
|
||||
nsMapRuleToAttributesFunc
|
||||
HTMLLIElement::GetAttributeMappingFunction() const
|
||||
{
|
||||
return &MapAttributesIntoRule;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
HTMLLIElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return HTMLLIElementBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
72
dom/html/HTMLLIElement.h
Normal file
72
dom/html/HTMLLIElement.h
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_dom_HTMLLIElement_h
|
||||
#define mozilla_dom_HTMLLIElement_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
#include "nsIDOMHTMLLIElement.h"
|
||||
#include "nsGenericHTMLElement.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class HTMLLIElement final : public nsGenericHTMLElement,
|
||||
public nsIDOMHTMLLIElement
|
||||
{
|
||||
public:
|
||||
explicit HTMLLIElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
|
||||
: nsGenericHTMLElement(aNodeInfo)
|
||||
{
|
||||
}
|
||||
|
||||
// nsISupports
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
// nsIDOMHTMLLIElement
|
||||
NS_DECL_NSIDOMHTMLLIELEMENT
|
||||
|
||||
virtual bool ParseAttribute(int32_t aNamespaceID,
|
||||
nsIAtom* aAttribute,
|
||||
const nsAString& aValue,
|
||||
nsAttrValue& aResult) override;
|
||||
NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
|
||||
virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const override;
|
||||
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
|
||||
|
||||
// WebIDL API
|
||||
void GetType(DOMString& aType)
|
||||
{
|
||||
GetHTMLAttr(nsGkAtoms::type, aType);
|
||||
}
|
||||
void SetType(const nsAString& aType, mozilla::ErrorResult& rv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::type, aType, rv);
|
||||
}
|
||||
int32_t Value() const
|
||||
{
|
||||
return GetIntAttr(nsGkAtoms::value, 0);
|
||||
}
|
||||
void SetValue(int32_t aValue, mozilla::ErrorResult& rv)
|
||||
{
|
||||
SetHTMLIntAttr(nsGkAtoms::value, aValue, rv);
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual ~HTMLLIElement();
|
||||
|
||||
virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
private:
|
||||
static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
|
||||
nsRuleData* aData);
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_HTMLLIElement_h
|
||||
304
dom/html/HTMLLabelElement.cpp
Normal file
304
dom/html/HTMLLabelElement.cpp
Normal file
|
|
@ -0,0 +1,304 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
/**
|
||||
* Implementation of HTML <label> elements.
|
||||
*/
|
||||
#include "HTMLLabelElement.h"
|
||||
#include "mozilla/EventDispatcher.h"
|
||||
#include "mozilla/MouseEvents.h"
|
||||
#include "mozilla/dom/HTMLLabelElementBinding.h"
|
||||
#include "nsFocusManager.h"
|
||||
#include "nsIDOMMouseEvent.h"
|
||||
#include "nsQueryObject.h"
|
||||
|
||||
// construction, destruction
|
||||
|
||||
NS_IMPL_NS_NEW_HTML_ELEMENT(Label)
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
HTMLLabelElement::~HTMLLabelElement()
|
||||
{
|
||||
}
|
||||
|
||||
JSObject*
|
||||
HTMLLabelElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return HTMLLabelElementBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
// nsISupports
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED(HTMLLabelElement, nsGenericHTMLElement,
|
||||
nsIDOMHTMLLabelElement)
|
||||
|
||||
// nsIDOMHTMLLabelElement
|
||||
|
||||
NS_IMPL_ELEMENT_CLONE(HTMLLabelElement)
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLLabelElement::GetForm(nsIDOMHTMLFormElement** aForm)
|
||||
{
|
||||
RefPtr<nsIDOMHTMLFormElement> form = GetForm();
|
||||
form.forget(aForm);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLLabelElement::GetControl(nsIDOMHTMLElement** aElement)
|
||||
{
|
||||
nsCOMPtr<nsIDOMHTMLElement> element = do_QueryObject(GetLabeledElement());
|
||||
element.forget(aElement);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLLabelElement::SetHtmlFor(const nsAString& aHtmlFor)
|
||||
{
|
||||
ErrorResult rv;
|
||||
SetHtmlFor(aHtmlFor, rv);
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLLabelElement::GetHtmlFor(nsAString& aHtmlFor)
|
||||
{
|
||||
nsString htmlFor;
|
||||
GetHtmlFor(htmlFor);
|
||||
aHtmlFor = htmlFor;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
HTMLFormElement*
|
||||
HTMLLabelElement::GetForm() const
|
||||
{
|
||||
nsGenericHTMLElement* control = GetControl();
|
||||
if (!control) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Not all labeled things have a form association. Stick to the ones that do.
|
||||
nsCOMPtr<nsIFormControl> formControl = do_QueryObject(control);
|
||||
if (!formControl) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return static_cast<HTMLFormElement*>(formControl->GetFormElement());
|
||||
}
|
||||
|
||||
void
|
||||
HTMLLabelElement::Focus(ErrorResult& aError)
|
||||
{
|
||||
// retarget the focus method at the for content
|
||||
nsIFocusManager* fm = nsFocusManager::GetFocusManager();
|
||||
if (fm) {
|
||||
nsCOMPtr<nsIDOMElement> elem = do_QueryObject(GetLabeledElement());
|
||||
if (elem)
|
||||
fm->SetFocus(elem, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
InInteractiveHTMLContent(nsIContent* aContent, nsIContent* aStop)
|
||||
{
|
||||
nsIContent* content = aContent;
|
||||
while (content && content != aStop) {
|
||||
if (content->IsElement() &&
|
||||
content->AsElement()->IsInteractiveHTMLContent(true)) {
|
||||
return true;
|
||||
}
|
||||
content = content->GetParent();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLLabelElement::PostHandleEvent(EventChainPostVisitor& aVisitor)
|
||||
{
|
||||
WidgetMouseEvent* mouseEvent = aVisitor.mEvent->AsMouseEvent();
|
||||
if (mHandlingEvent ||
|
||||
(!(mouseEvent && mouseEvent->IsLeftClickEvent()) &&
|
||||
aVisitor.mEvent->mMessage != eMouseDown) ||
|
||||
aVisitor.mEventStatus == nsEventStatus_eConsumeNoDefault ||
|
||||
!aVisitor.mPresContext ||
|
||||
// Don't handle the event if it's already been handled by another label
|
||||
aVisitor.mEvent->mFlags.mMultipleActionsPrevented) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIContent> target = do_QueryInterface(aVisitor.mEvent->mTarget);
|
||||
if (InInteractiveHTMLContent(target, this)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Strong ref because event dispatch is going to happen.
|
||||
RefPtr<Element> content = GetLabeledElement();
|
||||
|
||||
if (content) {
|
||||
mHandlingEvent = true;
|
||||
switch (aVisitor.mEvent->mMessage) {
|
||||
case eMouseDown:
|
||||
if (mouseEvent->button == WidgetMouseEvent::eLeftButton) {
|
||||
// We reset the mouse-down point on every event because there is
|
||||
// no guarantee we will reach the eMouseClick code below.
|
||||
LayoutDeviceIntPoint* curPoint =
|
||||
new LayoutDeviceIntPoint(mouseEvent->mRefPoint);
|
||||
SetProperty(nsGkAtoms::labelMouseDownPtProperty,
|
||||
static_cast<void*>(curPoint),
|
||||
nsINode::DeleteProperty<LayoutDeviceIntPoint>);
|
||||
}
|
||||
break;
|
||||
|
||||
case eMouseClick:
|
||||
if (mouseEvent->IsLeftClickEvent()) {
|
||||
LayoutDeviceIntPoint* mouseDownPoint =
|
||||
static_cast<LayoutDeviceIntPoint*>(
|
||||
GetProperty(nsGkAtoms::labelMouseDownPtProperty));
|
||||
|
||||
bool dragSelect = false;
|
||||
if (mouseDownPoint) {
|
||||
LayoutDeviceIntPoint dragDistance = *mouseDownPoint;
|
||||
DeleteProperty(nsGkAtoms::labelMouseDownPtProperty);
|
||||
|
||||
dragDistance -= mouseEvent->mRefPoint;
|
||||
const int CLICK_DISTANCE = 2;
|
||||
dragSelect = dragDistance.x > CLICK_DISTANCE ||
|
||||
dragDistance.x < -CLICK_DISTANCE ||
|
||||
dragDistance.y > CLICK_DISTANCE ||
|
||||
dragDistance.y < -CLICK_DISTANCE;
|
||||
}
|
||||
// Don't click the for-content if we did drag-select text or if we
|
||||
// have a kbd modifier (which adjusts a selection).
|
||||
if (dragSelect || mouseEvent->IsShift() || mouseEvent->IsControl() ||
|
||||
mouseEvent->IsAlt() || mouseEvent->IsMeta()) {
|
||||
break;
|
||||
}
|
||||
// Only set focus on the first click of multiple clicks to prevent
|
||||
// to prevent immediate de-focus.
|
||||
if (mouseEvent->mClickCount <= 1) {
|
||||
nsIFocusManager* fm = nsFocusManager::GetFocusManager();
|
||||
if (fm) {
|
||||
// Use FLAG_BYMOVEFOCUS here so that the label is scrolled to.
|
||||
// Also, within HTMLInputElement::PostHandleEvent, inputs will
|
||||
// be selected only when focused via a key or when the navigation
|
||||
// flag is used and we want to select the text on label clicks as
|
||||
// well.
|
||||
// If the label has been clicked by the user, we also want to
|
||||
// pass FLAG_BYMOUSE so that we get correct focus ring behavior,
|
||||
// but we don't want to pass FLAG_BYMOUSE if this click event was
|
||||
// caused by the user pressing an accesskey.
|
||||
nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(content);
|
||||
bool byMouse = (mouseEvent->inputSource != nsIDOMMouseEvent::MOZ_SOURCE_KEYBOARD);
|
||||
bool byTouch = (mouseEvent->inputSource == nsIDOMMouseEvent::MOZ_SOURCE_TOUCH);
|
||||
fm->SetFocus(elem, nsIFocusManager::FLAG_BYMOVEFOCUS |
|
||||
(byMouse ? nsIFocusManager::FLAG_BYMOUSE : 0) |
|
||||
(byTouch ? nsIFocusManager::FLAG_BYTOUCH : 0));
|
||||
}
|
||||
}
|
||||
// Dispatch a new click event to |content|
|
||||
// (For compatibility with IE, we do only left click. If
|
||||
// we wanted to interpret the HTML spec very narrowly, we
|
||||
// would do nothing. If we wanted to do something
|
||||
// sensible, we might send more events through like
|
||||
// this.) See bug 7554, bug 49897, and bug 96813.
|
||||
nsEventStatus status = aVisitor.mEventStatus;
|
||||
// Ok to use aVisitor.mEvent as parameter because DispatchClickEvent
|
||||
// will actually create a new event.
|
||||
EventFlags eventFlags;
|
||||
eventFlags.mMultipleActionsPrevented = true;
|
||||
DispatchClickEvent(aVisitor.mPresContext, mouseEvent,
|
||||
content, false, &eventFlags, &status);
|
||||
// Do we care about the status this returned? I don't think we do...
|
||||
// Don't run another <label> off of this click
|
||||
mouseEvent->mFlags.mMultipleActionsPrevented = true;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
mHandlingEvent = false;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
HTMLLabelElement::PerformAccesskey(bool aKeyCausesActivation,
|
||||
bool aIsTrustedEvent)
|
||||
{
|
||||
if (!aKeyCausesActivation) {
|
||||
RefPtr<Element> element = GetLabeledElement();
|
||||
if (element) {
|
||||
return element->PerformAccesskey(aKeyCausesActivation, aIsTrustedEvent);
|
||||
}
|
||||
} else {
|
||||
nsPresContext *presContext = GetPresContext(eForUncomposedDoc);
|
||||
if (!presContext) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Click on it if the users prefs indicate to do so.
|
||||
WidgetMouseEvent event(aIsTrustedEvent, eMouseClick,
|
||||
nullptr, WidgetMouseEvent::eReal);
|
||||
event.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_KEYBOARD;
|
||||
|
||||
nsAutoPopupStatePusher popupStatePusher(aIsTrustedEvent ?
|
||||
openAllowed : openAbused);
|
||||
|
||||
EventDispatcher::Dispatch(static_cast<nsIContent*>(this), presContext,
|
||||
&event);
|
||||
}
|
||||
|
||||
return aKeyCausesActivation;
|
||||
}
|
||||
|
||||
nsGenericHTMLElement*
|
||||
HTMLLabelElement::GetLabeledElement() const
|
||||
{
|
||||
nsAutoString elementId;
|
||||
|
||||
if (!GetAttr(kNameSpaceID_None, nsGkAtoms::_for, elementId)) {
|
||||
// No @for, so we are a label for our first form control element.
|
||||
// Do a depth-first traversal to look for the first form control element.
|
||||
return GetFirstLabelableDescendant();
|
||||
}
|
||||
|
||||
// We have a @for. The id has to be linked to an element in the same document
|
||||
// and this element should be a labelable form control.
|
||||
//XXXsmaug It is unclear how this should work in case the element is in
|
||||
// Shadow DOM.
|
||||
// See https://www.w3.org/Bugs/Public/show_bug.cgi?id=26365.
|
||||
nsIDocument* doc = GetUncomposedDoc();
|
||||
if (!doc) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Element* element = doc->GetElementById(elementId);
|
||||
if (element && element->IsLabelable()) {
|
||||
return static_cast<nsGenericHTMLElement*>(element);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsGenericHTMLElement*
|
||||
HTMLLabelElement::GetFirstLabelableDescendant() const
|
||||
{
|
||||
for (nsIContent* cur = nsINode::GetFirstChild(); cur;
|
||||
cur = cur->GetNextNode(this)) {
|
||||
Element* element = cur->IsElement() ? cur->AsElement() : nullptr;
|
||||
if (element && element->IsLabelable()) {
|
||||
return static_cast<nsGenericHTMLElement*>(element);
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
86
dom/html/HTMLLabelElement.h
Normal file
86
dom/html/HTMLLabelElement.h
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
/**
|
||||
* Declaration of HTML <label> elements.
|
||||
*/
|
||||
#ifndef HTMLLabelElement_h
|
||||
#define HTMLLabelElement_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsGenericHTMLElement.h"
|
||||
#include "nsIDOMHTMLLabelElement.h"
|
||||
|
||||
namespace mozilla {
|
||||
class EventChainPostVisitor;
|
||||
namespace dom {
|
||||
|
||||
class HTMLLabelElement final : public nsGenericHTMLElement,
|
||||
public nsIDOMHTMLLabelElement
|
||||
{
|
||||
public:
|
||||
explicit HTMLLabelElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
|
||||
: nsGenericHTMLElement(aNodeInfo),
|
||||
mHandlingEvent(false)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMPL_FROMCONTENT_HTML_WITH_TAG(HTMLLabelElement, label)
|
||||
|
||||
// nsISupports
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
// Element
|
||||
virtual bool IsInteractiveHTMLContent(bool aIgnoreTabindex) const override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// nsIDOMHTMLLabelElement
|
||||
NS_DECL_NSIDOMHTMLLABELELEMENT
|
||||
|
||||
HTMLFormElement* GetForm() const;
|
||||
void GetHtmlFor(nsString& aHtmlFor)
|
||||
{
|
||||
GetHTMLAttr(nsGkAtoms::_for, aHtmlFor);
|
||||
}
|
||||
void SetHtmlFor(const nsAString& aHtmlFor, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::_for, aHtmlFor, aError);
|
||||
}
|
||||
nsGenericHTMLElement* GetControl() const
|
||||
{
|
||||
return GetLabeledElement();
|
||||
}
|
||||
|
||||
using nsGenericHTMLElement::Focus;
|
||||
virtual void Focus(mozilla::ErrorResult& aError) override;
|
||||
|
||||
virtual bool IsDisabled() const override { return false; }
|
||||
|
||||
// nsIContent
|
||||
virtual nsresult PostHandleEvent(
|
||||
EventChainPostVisitor& aVisitor) override;
|
||||
virtual bool PerformAccesskey(bool aKeyCausesActivation,
|
||||
bool aIsTrustedEvent) override;
|
||||
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
|
||||
|
||||
nsGenericHTMLElement* GetLabeledElement() const;
|
||||
protected:
|
||||
virtual ~HTMLLabelElement();
|
||||
|
||||
virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
nsGenericHTMLElement* GetFirstLabelableDescendant() const;
|
||||
|
||||
// XXX It would be nice if we could use an event flag instead.
|
||||
bool mHandlingEvent;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* HTMLLabelElement_h */
|
||||
157
dom/html/HTMLLegendElement.cpp
Normal file
157
dom/html/HTMLLegendElement.cpp
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
/* -*- 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/HTMLLegendElement.h"
|
||||
#include "mozilla/dom/HTMLLegendElementBinding.h"
|
||||
#include "nsIDOMHTMLFormElement.h"
|
||||
#include "nsFocusManager.h"
|
||||
#include "nsIFrame.h"
|
||||
|
||||
NS_IMPL_NS_NEW_HTML_ELEMENT(Legend)
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
|
||||
HTMLLegendElement::~HTMLLegendElement()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMPL_ELEMENT_CLONE(HTMLLegendElement)
|
||||
|
||||
nsIContent*
|
||||
HTMLLegendElement::GetFieldSet() const
|
||||
{
|
||||
nsIContent* parent = GetParent();
|
||||
|
||||
if (parent && parent->IsHTMLElement(nsGkAtoms::fieldset)) {
|
||||
return parent;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
HTMLLegendElement::ParseAttribute(int32_t aNamespaceID,
|
||||
nsIAtom* aAttribute,
|
||||
const nsAString& aValue,
|
||||
nsAttrValue& aResult)
|
||||
{
|
||||
// this contains center, because IE4 does
|
||||
static const nsAttrValue::EnumTable kAlignTable[] = {
|
||||
{ "left", NS_STYLE_TEXT_ALIGN_LEFT },
|
||||
{ "right", NS_STYLE_TEXT_ALIGN_RIGHT },
|
||||
{ "center", NS_STYLE_TEXT_ALIGN_CENTER },
|
||||
{ "bottom", NS_STYLE_VERTICAL_ALIGN_BOTTOM },
|
||||
{ "top", NS_STYLE_VERTICAL_ALIGN_TOP },
|
||||
{ nullptr, 0 }
|
||||
};
|
||||
|
||||
if (aAttribute == nsGkAtoms::align && aNamespaceID == kNameSpaceID_None) {
|
||||
return aResult.ParseEnumValue(aValue, kAlignTable, false);
|
||||
}
|
||||
|
||||
return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
|
||||
aResult);
|
||||
}
|
||||
|
||||
nsChangeHint
|
||||
HTMLLegendElement::GetAttributeChangeHint(const nsIAtom* aAttribute,
|
||||
int32_t aModType) const
|
||||
{
|
||||
nsChangeHint retval =
|
||||
nsGenericHTMLElement::GetAttributeChangeHint(aAttribute, aModType);
|
||||
if (aAttribute == nsGkAtoms::align) {
|
||||
retval |= NS_STYLE_HINT_REFLOW;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLLegendElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
|
||||
nsIAtom* aPrefix, const nsAString& aValue,
|
||||
bool aNotify)
|
||||
{
|
||||
return nsGenericHTMLElement::SetAttr(aNameSpaceID, aAttribute,
|
||||
aPrefix, aValue, aNotify);
|
||||
}
|
||||
nsresult
|
||||
HTMLLegendElement::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
|
||||
bool aNotify)
|
||||
{
|
||||
return nsGenericHTMLElement::UnsetAttr(aNameSpaceID, aAttribute, aNotify);
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLLegendElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
||||
nsIContent* aBindingParent,
|
||||
bool aCompileEventHandlers)
|
||||
{
|
||||
return nsGenericHTMLElement::BindToTree(aDocument, aParent,
|
||||
aBindingParent,
|
||||
aCompileEventHandlers);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLLegendElement::UnbindFromTree(bool aDeep, bool aNullParent)
|
||||
{
|
||||
nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLLegendElement::Focus(ErrorResult& aError)
|
||||
{
|
||||
nsIFrame* frame = GetPrimaryFrame();
|
||||
if (!frame) {
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t tabIndex;
|
||||
if (frame->IsFocusable(&tabIndex, false)) {
|
||||
nsGenericHTMLElement::Focus(aError);
|
||||
return;
|
||||
}
|
||||
|
||||
// If the legend isn't focusable, focus whatever is focusable following
|
||||
// the legend instead, bug 81481.
|
||||
nsIFocusManager* fm = nsFocusManager::GetFocusManager();
|
||||
if (!fm) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMElement> result;
|
||||
aError = fm->MoveFocus(nullptr, this, nsIFocusManager::MOVEFOCUS_FORWARD,
|
||||
nsIFocusManager::FLAG_NOPARENTFRAME,
|
||||
getter_AddRefs(result));
|
||||
}
|
||||
|
||||
bool
|
||||
HTMLLegendElement::PerformAccesskey(bool aKeyCausesActivation,
|
||||
bool aIsTrustedEvent)
|
||||
{
|
||||
// just use the same behaviour as the focus method
|
||||
ErrorResult rv;
|
||||
Focus(rv);
|
||||
return NS_SUCCEEDED(rv.StealNSResult());
|
||||
}
|
||||
|
||||
already_AddRefed<HTMLFormElement>
|
||||
HTMLLegendElement::GetForm()
|
||||
{
|
||||
Element* form = GetFormElement();
|
||||
MOZ_ASSERT_IF(form, form->IsHTMLElement(nsGkAtoms::form));
|
||||
RefPtr<HTMLFormElement> ret = static_cast<HTMLFormElement*>(form);
|
||||
return ret.forget();
|
||||
}
|
||||
|
||||
JSObject*
|
||||
HTMLLegendElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return HTMLLegendElementBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
102
dom/html/HTMLLegendElement.h
Normal file
102
dom/html/HTMLLegendElement.h
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_dom_HTMLLegendElement_h
|
||||
#define mozilla_dom_HTMLLegendElement_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsGenericHTMLElement.h"
|
||||
#include "mozilla/dom/HTMLFormElement.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class HTMLLegendElement final : public nsGenericHTMLElement
|
||||
{
|
||||
public:
|
||||
explicit HTMLLegendElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
|
||||
: nsGenericHTMLElement(aNodeInfo)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMPL_FROMCONTENT_HTML_WITH_TAG(HTMLLegendElement, legend)
|
||||
|
||||
using nsGenericHTMLElement::Focus;
|
||||
virtual void Focus(ErrorResult& aError) override;
|
||||
|
||||
virtual bool PerformAccesskey(bool aKeyCausesActivation,
|
||||
bool aIsTrustedEvent) override;
|
||||
|
||||
// nsIContent
|
||||
virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
||||
nsIContent* aBindingParent,
|
||||
bool aCompileEventHandlers) override;
|
||||
virtual void UnbindFromTree(bool aDeep = true,
|
||||
bool aNullParent = true) override;
|
||||
virtual bool ParseAttribute(int32_t aNamespaceID,
|
||||
nsIAtom* aAttribute,
|
||||
const nsAString& aValue,
|
||||
nsAttrValue& aResult) override;
|
||||
virtual nsChangeHint GetAttributeChangeHint(const nsIAtom* aAttribute,
|
||||
int32_t aModType) const override;
|
||||
nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
const nsAString& aValue, bool aNotify)
|
||||
{
|
||||
return SetAttr(aNameSpaceID, aName, nullptr, aValue, aNotify);
|
||||
}
|
||||
virtual nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
nsIAtom* aPrefix, const nsAString& aValue,
|
||||
bool aNotify) override;
|
||||
virtual nsresult UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
|
||||
bool aNotify) override;
|
||||
|
||||
virtual nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult) const override;
|
||||
|
||||
Element* GetFormElement() const
|
||||
{
|
||||
nsCOMPtr<nsIFormControl> fieldsetControl = do_QueryInterface(GetFieldSet());
|
||||
|
||||
return fieldsetControl ? fieldsetControl->GetFormElement() : nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* WebIDL Interface
|
||||
*/
|
||||
|
||||
already_AddRefed<HTMLFormElement> GetForm();
|
||||
|
||||
void GetAlign(DOMString& aAlign)
|
||||
{
|
||||
GetHTMLAttr(nsGkAtoms::align, aAlign);
|
||||
}
|
||||
|
||||
void SetAlign(const nsAString& aAlign, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::align, aAlign, aError);
|
||||
}
|
||||
|
||||
nsINode* GetScopeChainParent() const override
|
||||
{
|
||||
Element* form = GetFormElement();
|
||||
return form ? form : nsGenericHTMLElement::GetScopeChainParent();
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual ~HTMLLegendElement();
|
||||
|
||||
virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
/**
|
||||
* Get the fieldset content element that contains this legend.
|
||||
* Returns null if there is no fieldset containing this legend.
|
||||
*/
|
||||
nsIContent* GetFieldSet() const;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* mozilla_dom_HTMLLegendElement_h */
|
||||
584
dom/html/HTMLLinkElement.cpp
Normal file
584
dom/html/HTMLLinkElement.cpp
Normal file
|
|
@ -0,0 +1,584 @@
|
|||
/* -*- 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/HTMLLinkElement.h"
|
||||
|
||||
#include "mozilla/AsyncEventDispatcher.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/EventDispatcher.h"
|
||||
#include "mozilla/EventStates.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/dom/HTMLLinkElementBinding.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsGenericHTMLElement.h"
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsDOMTokenList.h"
|
||||
#include "nsIContentInlines.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIDOMEvent.h"
|
||||
#include "nsIDOMStyleSheet.h"
|
||||
#include "nsINode.h"
|
||||
#include "nsIStyleSheetLinkingElement.h"
|
||||
#include "nsIURL.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "nsReadableUtils.h"
|
||||
#include "nsStyleConsts.h"
|
||||
#include "nsStyleLinkElement.h"
|
||||
#include "nsUnicharUtils.h"
|
||||
|
||||
#define LINK_ELEMENT_FLAG_BIT(n_) \
|
||||
NODE_FLAG_BIT(ELEMENT_TYPE_SPECIFIC_BITS_OFFSET + (n_))
|
||||
|
||||
// Link element specific bits
|
||||
enum {
|
||||
// Indicates that a DNS Prefetch has been requested from this Link element.
|
||||
HTML_LINK_DNS_PREFETCH_REQUESTED = LINK_ELEMENT_FLAG_BIT(0),
|
||||
|
||||
// Indicates that a DNS Prefetch was added to the deferral queue
|
||||
HTML_LINK_DNS_PREFETCH_DEFERRED = LINK_ELEMENT_FLAG_BIT(1)
|
||||
};
|
||||
|
||||
#undef LINK_ELEMENT_FLAG_BIT
|
||||
|
||||
ASSERT_NODE_FLAGS_SPACE(ELEMENT_TYPE_SPECIFIC_BITS_OFFSET + 2);
|
||||
|
||||
NS_IMPL_NS_NEW_HTML_ELEMENT(Link)
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
HTMLLinkElement::HTMLLinkElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
|
||||
: nsGenericHTMLElement(aNodeInfo)
|
||||
, Link(this)
|
||||
{
|
||||
}
|
||||
|
||||
HTMLLinkElement::~HTMLLinkElement()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(HTMLLinkElement)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLLinkElement,
|
||||
nsGenericHTMLElement)
|
||||
tmp->nsStyleLinkElement::Traverse(cb);
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRelList)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mImportLoader)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLLinkElement,
|
||||
nsGenericHTMLElement)
|
||||
tmp->nsStyleLinkElement::Unlink();
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mRelList)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mImportLoader)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(HTMLLinkElement, Element)
|
||||
NS_IMPL_RELEASE_INHERITED(HTMLLinkElement, Element)
|
||||
|
||||
|
||||
// QueryInterface implementation for HTMLLinkElement
|
||||
NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(HTMLLinkElement)
|
||||
NS_INTERFACE_TABLE_INHERITED(HTMLLinkElement,
|
||||
nsIDOMHTMLLinkElement,
|
||||
nsIStyleSheetLinkingElement,
|
||||
Link)
|
||||
NS_INTERFACE_TABLE_TAIL_INHERITING(nsGenericHTMLElement)
|
||||
|
||||
|
||||
NS_IMPL_ELEMENT_CLONE(HTMLLinkElement)
|
||||
|
||||
bool
|
||||
HTMLLinkElement::Disabled()
|
||||
{
|
||||
StyleSheet* ss = GetSheet();
|
||||
return ss && ss->Disabled();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLLinkElement::GetMozDisabled(bool* aDisabled)
|
||||
{
|
||||
*aDisabled = Disabled();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
HTMLLinkElement::SetDisabled(bool aDisabled)
|
||||
{
|
||||
if (StyleSheet* ss = GetSheet()) {
|
||||
ss->SetDisabled(aDisabled);
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLLinkElement::SetMozDisabled(bool aDisabled)
|
||||
{
|
||||
SetDisabled(aDisabled);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
NS_IMPL_STRING_ATTR(HTMLLinkElement, Charset, charset)
|
||||
NS_IMPL_URI_ATTR(HTMLLinkElement, Href, href)
|
||||
NS_IMPL_STRING_ATTR(HTMLLinkElement, Hreflang, hreflang)
|
||||
NS_IMPL_STRING_ATTR(HTMLLinkElement, Media, media)
|
||||
NS_IMPL_STRING_ATTR(HTMLLinkElement, Rel, rel)
|
||||
NS_IMPL_STRING_ATTR(HTMLLinkElement, Rev, rev)
|
||||
NS_IMPL_STRING_ATTR(HTMLLinkElement, Target, target)
|
||||
NS_IMPL_STRING_ATTR(HTMLLinkElement, Type, type)
|
||||
|
||||
void
|
||||
HTMLLinkElement::OnDNSPrefetchRequested()
|
||||
{
|
||||
UnsetFlags(HTML_LINK_DNS_PREFETCH_DEFERRED);
|
||||
SetFlags(HTML_LINK_DNS_PREFETCH_REQUESTED);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLLinkElement::OnDNSPrefetchDeferred()
|
||||
{
|
||||
UnsetFlags(HTML_LINK_DNS_PREFETCH_REQUESTED);
|
||||
SetFlags(HTML_LINK_DNS_PREFETCH_DEFERRED);
|
||||
}
|
||||
|
||||
bool
|
||||
HTMLLinkElement::HasDeferredDNSPrefetchRequest()
|
||||
{
|
||||
return HasFlag(HTML_LINK_DNS_PREFETCH_DEFERRED);
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLLinkElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
||||
nsIContent* aBindingParent,
|
||||
bool aCompileEventHandlers)
|
||||
{
|
||||
Link::ResetLinkState(false, Link::ElementHasHref());
|
||||
|
||||
nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent,
|
||||
aBindingParent,
|
||||
aCompileEventHandlers);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Link must be inert in ShadowRoot.
|
||||
if (aDocument && !GetContainingShadow()) {
|
||||
aDocument->RegisterPendingLinkUpdate(this);
|
||||
}
|
||||
|
||||
if (IsInComposedDoc()) {
|
||||
TryDNSPrefetchPreconnectOrPrefetch();
|
||||
}
|
||||
|
||||
void (HTMLLinkElement::*update)() = &HTMLLinkElement::UpdateStyleSheetInternal;
|
||||
nsContentUtils::AddScriptRunner(NewRunnableMethod(this, update));
|
||||
|
||||
void (HTMLLinkElement::*updateImport)() = &HTMLLinkElement::UpdateImport;
|
||||
nsContentUtils::AddScriptRunner(NewRunnableMethod(this, updateImport));
|
||||
|
||||
CreateAndDispatchEvent(aDocument, NS_LITERAL_STRING("DOMLinkAdded"));
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
void
|
||||
HTMLLinkElement::LinkAdded()
|
||||
{
|
||||
CreateAndDispatchEvent(OwnerDoc(), NS_LITERAL_STRING("DOMLinkAdded"));
|
||||
}
|
||||
|
||||
void
|
||||
HTMLLinkElement::LinkRemoved()
|
||||
{
|
||||
CreateAndDispatchEvent(OwnerDoc(), NS_LITERAL_STRING("DOMLinkRemoved"));
|
||||
}
|
||||
|
||||
void
|
||||
HTMLLinkElement::UnbindFromTree(bool aDeep, bool aNullParent)
|
||||
{
|
||||
// Cancel any DNS prefetches
|
||||
// Note: Must come before ResetLinkState. If called after, it will recreate
|
||||
// mCachedURI based on data that is invalid - due to a call to GetHostname.
|
||||
CancelDNSPrefetch(HTML_LINK_DNS_PREFETCH_DEFERRED,
|
||||
HTML_LINK_DNS_PREFETCH_REQUESTED);
|
||||
CancelPrefetch();
|
||||
|
||||
// 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());
|
||||
|
||||
// If this is reinserted back into the document it will not be
|
||||
// from the parser.
|
||||
nsCOMPtr<nsIDocument> oldDoc = GetUncomposedDoc();
|
||||
|
||||
// Check for a ShadowRoot because link elements are inert in a
|
||||
// ShadowRoot.
|
||||
ShadowRoot* oldShadowRoot = GetBindingParent() ?
|
||||
GetBindingParent()->GetShadowRoot() : nullptr;
|
||||
|
||||
OwnerDoc()->UnregisterPendingLinkUpdate(this);
|
||||
|
||||
CreateAndDispatchEvent(oldDoc, NS_LITERAL_STRING("DOMLinkRemoved"));
|
||||
nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
|
||||
|
||||
UpdateStyleSheetInternal(oldDoc, oldShadowRoot);
|
||||
UpdateImport();
|
||||
}
|
||||
|
||||
bool
|
||||
HTMLLinkElement::ParseAttribute(int32_t aNamespaceID,
|
||||
nsIAtom* aAttribute,
|
||||
const nsAString& aValue,
|
||||
nsAttrValue& aResult)
|
||||
{
|
||||
if (aNamespaceID == kNameSpaceID_None) {
|
||||
if (aAttribute == nsGkAtoms::crossorigin) {
|
||||
ParseCORSValue(aValue, aResult);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (aAttribute == nsGkAtoms::sizes) {
|
||||
aResult.ParseAtomArray(aValue);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (aAttribute == nsGkAtoms::integrity) {
|
||||
aResult.ParseStringOrAtom(aValue);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
|
||||
aResult);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLLinkElement::CreateAndDispatchEvent(nsIDocument* aDoc,
|
||||
const nsAString& aEventName)
|
||||
{
|
||||
if (!aDoc)
|
||||
return;
|
||||
|
||||
// In the unlikely case that both rev is specified *and* rel=stylesheet,
|
||||
// this code will cause the event to fire, on the principle that maybe the
|
||||
// page really does want to specify that its author is a stylesheet. Since
|
||||
// this should never actually happen and the performance hit is minimal,
|
||||
// doing the "right" thing costs virtually nothing here, even if it doesn't
|
||||
// make much sense.
|
||||
static nsIContent::AttrValuesArray strings[] =
|
||||
{&nsGkAtoms::_empty, &nsGkAtoms::stylesheet, nullptr};
|
||||
|
||||
if (!nsContentUtils::HasNonEmptyAttr(this, kNameSpaceID_None,
|
||||
nsGkAtoms::rev) &&
|
||||
FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::rel,
|
||||
strings, eIgnoreCase) != ATTR_VALUE_NO_MATCH)
|
||||
return;
|
||||
|
||||
RefPtr<AsyncEventDispatcher> asyncDispatcher =
|
||||
new AsyncEventDispatcher(this, aEventName, true, true);
|
||||
// Always run async in order to avoid running script when the content
|
||||
// sink isn't expecting it.
|
||||
asyncDispatcher->PostDOMEvent();
|
||||
}
|
||||
|
||||
void
|
||||
HTMLLinkElement::UpdateImport()
|
||||
{
|
||||
// 1. link node should be attached to the document.
|
||||
nsCOMPtr<nsIDocument> doc = GetUncomposedDoc();
|
||||
if (!doc) {
|
||||
// We might have been just removed from the document, so
|
||||
// let's remove ourself from the list of link nodes of
|
||||
// the import and reset mImportLoader.
|
||||
if (mImportLoader) {
|
||||
mImportLoader->RemoveLinkElement(this);
|
||||
mImportLoader = nullptr;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. rel type should be import.
|
||||
nsAutoString rel;
|
||||
GetAttr(kNameSpaceID_None, nsGkAtoms::rel, rel);
|
||||
uint32_t linkTypes = nsStyleLinkElement::ParseLinkTypes(rel, NodePrincipal());
|
||||
if (!(linkTypes & eHTMLIMPORT)) {
|
||||
mImportLoader = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> uri = GetHrefURI();
|
||||
if (!uri) {
|
||||
mImportLoader = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!nsStyleLinkElement::IsImportEnabled()) {
|
||||
// For now imports are hidden behind a pref...
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<ImportManager> manager = doc->ImportManager();
|
||||
MOZ_ASSERT(manager, "ImportManager should be created lazily when needed");
|
||||
|
||||
{
|
||||
// The load even might fire sooner than we could set mImportLoader so
|
||||
// we must use async event and a scriptBlocker here.
|
||||
nsAutoScriptBlocker scriptBlocker;
|
||||
// CORS check will happen at the start of the load.
|
||||
mImportLoader = manager->Get(uri, this, doc);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLLinkElement::BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
nsAttrValueOrString* aValue, bool aNotify)
|
||||
{
|
||||
if (aNameSpaceID == kNameSpaceID_None &&
|
||||
(aName == nsGkAtoms::href || aName == nsGkAtoms::rel)) {
|
||||
CancelDNSPrefetch(HTML_LINK_DNS_PREFETCH_DEFERRED,
|
||||
HTML_LINK_DNS_PREFETCH_REQUESTED);
|
||||
CancelPrefetch();
|
||||
}
|
||||
|
||||
return nsGenericHTMLElement::BeforeSetAttr(aNameSpaceID, aName,
|
||||
aValue, aNotify);
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLLinkElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
const nsAttrValue* aValue, bool aNotify)
|
||||
{
|
||||
// It's safe to call ResetLinkState here because our new attr value has
|
||||
// already been set or unset. ResetLinkState needs 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 && kNameSpaceID_None == aNameSpaceID) {
|
||||
bool hasHref = aValue;
|
||||
Link::ResetLinkState(!!aNotify, hasHref);
|
||||
if (IsInUncomposedDoc()) {
|
||||
CreateAndDispatchEvent(OwnerDoc(), NS_LITERAL_STRING("DOMLinkChanged"));
|
||||
}
|
||||
}
|
||||
|
||||
if (aValue) {
|
||||
if (aNameSpaceID == kNameSpaceID_None &&
|
||||
(aName == nsGkAtoms::href ||
|
||||
aName == nsGkAtoms::rel ||
|
||||
aName == nsGkAtoms::title ||
|
||||
aName == nsGkAtoms::media ||
|
||||
aName == nsGkAtoms::type)) {
|
||||
bool dropSheet = false;
|
||||
if (aName == nsGkAtoms::rel) {
|
||||
nsAutoString value;
|
||||
aValue->ToString(value);
|
||||
uint32_t linkTypes = nsStyleLinkElement::ParseLinkTypes(value,
|
||||
NodePrincipal());
|
||||
if (GetSheet()) {
|
||||
dropSheet = !(linkTypes & nsStyleLinkElement::eSTYLESHEET);
|
||||
} else if (linkTypes & eHTMLIMPORT) {
|
||||
UpdateImport();
|
||||
}
|
||||
}
|
||||
|
||||
if (aName == nsGkAtoms::href) {
|
||||
UpdateImport();
|
||||
}
|
||||
|
||||
if ((aName == nsGkAtoms::rel || aName == nsGkAtoms::href) &&
|
||||
IsInComposedDoc()) {
|
||||
TryDNSPrefetchPreconnectOrPrefetch();
|
||||
}
|
||||
|
||||
UpdateStyleSheetInternal(nullptr, nullptr,
|
||||
dropSheet ||
|
||||
(aName == nsGkAtoms::title ||
|
||||
aName == nsGkAtoms::media ||
|
||||
aName == nsGkAtoms::type));
|
||||
}
|
||||
} else {
|
||||
// Since removing href or rel makes us no longer link to a
|
||||
// stylesheet, force updates for those too.
|
||||
if (aNameSpaceID == kNameSpaceID_None) {
|
||||
if (aName == nsGkAtoms::href ||
|
||||
aName == nsGkAtoms::rel ||
|
||||
aName == nsGkAtoms::title ||
|
||||
aName == nsGkAtoms::media ||
|
||||
aName == nsGkAtoms::type) {
|
||||
UpdateStyleSheetInternal(nullptr, nullptr, true);
|
||||
}
|
||||
if (aName == nsGkAtoms::href ||
|
||||
aName == nsGkAtoms::rel) {
|
||||
UpdateImport();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName, aValue,
|
||||
aNotify);
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLLinkElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
{
|
||||
return PreHandleEventForAnchors(aVisitor);
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLLinkElement::PostHandleEvent(EventChainPostVisitor& aVisitor)
|
||||
{
|
||||
return PostHandleEventForAnchors(aVisitor);
|
||||
}
|
||||
|
||||
bool
|
||||
HTMLLinkElement::IsLink(nsIURI** aURI) const
|
||||
{
|
||||
return IsHTMLLink(aURI);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLLinkElement::GetLinkTarget(nsAString& aTarget)
|
||||
{
|
||||
GetAttr(kNameSpaceID_None, nsGkAtoms::target, aTarget);
|
||||
if (aTarget.IsEmpty()) {
|
||||
GetBaseTarget(aTarget);
|
||||
}
|
||||
}
|
||||
|
||||
static const DOMTokenListSupportedToken sSupportedRelValues[] = {
|
||||
// Keep this in sync with ToLinkMask in nsStyleLinkElement.cpp.
|
||||
// "import" must come first because it's conditional.
|
||||
"import",
|
||||
"prefetch",
|
||||
"dns-prefetch",
|
||||
"stylesheet",
|
||||
"next",
|
||||
"alternate",
|
||||
"preconnect",
|
||||
"icon",
|
||||
"search",
|
||||
nullptr
|
||||
};
|
||||
|
||||
nsDOMTokenList*
|
||||
HTMLLinkElement::RelList()
|
||||
{
|
||||
if (!mRelList) {
|
||||
const DOMTokenListSupportedTokenArray relValues =
|
||||
nsStyleLinkElement::IsImportEnabled() ?
|
||||
sSupportedRelValues : &sSupportedRelValues[1];
|
||||
|
||||
mRelList = new nsDOMTokenList(this, nsGkAtoms::rel, relValues);
|
||||
}
|
||||
return mRelList;
|
||||
}
|
||||
|
||||
already_AddRefed<nsIURI>
|
||||
HTMLLinkElement::GetHrefURI() const
|
||||
{
|
||||
return GetHrefURIForAnchors();
|
||||
}
|
||||
|
||||
already_AddRefed<nsIURI>
|
||||
HTMLLinkElement::GetStyleSheetURL(bool* aIsInline)
|
||||
{
|
||||
*aIsInline = false;
|
||||
nsAutoString href;
|
||||
GetAttr(kNameSpaceID_None, nsGkAtoms::href, href);
|
||||
if (href.IsEmpty()) {
|
||||
return nullptr;
|
||||
}
|
||||
nsCOMPtr<nsIURI> uri = Link::GetURI();
|
||||
return uri.forget();
|
||||
}
|
||||
|
||||
void
|
||||
HTMLLinkElement::GetStyleSheetInfo(nsAString& aTitle,
|
||||
nsAString& aType,
|
||||
nsAString& aMedia,
|
||||
bool* aIsScoped,
|
||||
bool* aIsAlternate)
|
||||
{
|
||||
aTitle.Truncate();
|
||||
aType.Truncate();
|
||||
aMedia.Truncate();
|
||||
*aIsScoped = false;
|
||||
*aIsAlternate = false;
|
||||
|
||||
nsAutoString rel;
|
||||
GetAttr(kNameSpaceID_None, nsGkAtoms::rel, rel);
|
||||
uint32_t linkTypes = nsStyleLinkElement::ParseLinkTypes(rel, NodePrincipal());
|
||||
// Is it a stylesheet link?
|
||||
if (!(linkTypes & nsStyleLinkElement::eSTYLESHEET)) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsAutoString title;
|
||||
GetAttr(kNameSpaceID_None, nsGkAtoms::title, title);
|
||||
title.CompressWhitespace();
|
||||
aTitle.Assign(title);
|
||||
|
||||
// If alternate, does it have title?
|
||||
if (linkTypes & nsStyleLinkElement::eALTERNATE) {
|
||||
if (aTitle.IsEmpty()) { // alternates must have title
|
||||
return;
|
||||
} else {
|
||||
*aIsAlternate = true;
|
||||
}
|
||||
}
|
||||
|
||||
GetAttr(kNameSpaceID_None, nsGkAtoms::media, aMedia);
|
||||
// The HTML5 spec is formulated in terms of the CSSOM spec, which specifies
|
||||
// that media queries should be ASCII lowercased during serialization.
|
||||
nsContentUtils::ASCIIToLower(aMedia);
|
||||
|
||||
nsAutoString mimeType;
|
||||
nsAutoString notUsed;
|
||||
GetAttr(kNameSpaceID_None, nsGkAtoms::type, aType);
|
||||
nsContentUtils::SplitMimeType(aType, mimeType, notUsed);
|
||||
if (!mimeType.IsEmpty() && !mimeType.LowerCaseEqualsLiteral("text/css")) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If we get here we assume that we're loading a css file, so set the
|
||||
// type to 'text/css'
|
||||
aType.AssignLiteral("text/css");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
CORSMode
|
||||
HTMLLinkElement::GetCORSMode() const
|
||||
{
|
||||
return AttrValueToCORSMode(GetParsedAttr(nsGkAtoms::crossorigin));
|
||||
}
|
||||
|
||||
EventStates
|
||||
HTMLLinkElement::IntrinsicState() const
|
||||
{
|
||||
return Link::LinkState() | nsGenericHTMLElement::IntrinsicState();
|
||||
}
|
||||
|
||||
size_t
|
||||
HTMLLinkElement::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
|
||||
{
|
||||
return nsGenericHTMLElement::SizeOfExcludingThis(aMallocSizeOf) +
|
||||
Link::SizeOfExcludingThis(aMallocSizeOf);
|
||||
}
|
||||
|
||||
JSObject*
|
||||
HTMLLinkElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return HTMLLinkElementBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
already_AddRefed<nsIDocument>
|
||||
HTMLLinkElement::GetImport()
|
||||
{
|
||||
return mImportLoader ? RefPtr<nsIDocument>(mImportLoader->GetImport()).forget() : nullptr;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
193
dom/html/HTMLLinkElement.h
Normal file
193
dom/html/HTMLLinkElement.h
Normal file
|
|
@ -0,0 +1,193 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_dom_HTMLLinkElement_h
|
||||
#define mozilla_dom_HTMLLinkElement_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/dom/Link.h"
|
||||
#include "ImportManager.h"
|
||||
#include "nsGenericHTMLElement.h"
|
||||
#include "nsIDOMHTMLLinkElement.h"
|
||||
#include "nsStyleLinkElement.h"
|
||||
|
||||
namespace mozilla {
|
||||
class EventChainPostVisitor;
|
||||
class EventChainPreVisitor;
|
||||
namespace dom {
|
||||
|
||||
class HTMLLinkElement final : public nsGenericHTMLElement,
|
||||
public nsIDOMHTMLLinkElement,
|
||||
public nsStyleLinkElement,
|
||||
public Link
|
||||
{
|
||||
public:
|
||||
explicit HTMLLinkElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
|
||||
|
||||
// nsISupports
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
// CC
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLLinkElement,
|
||||
nsGenericHTMLElement)
|
||||
|
||||
// nsIDOMHTMLLinkElement
|
||||
NS_DECL_NSIDOMHTMLLINKELEMENT
|
||||
|
||||
// DOM memory reporter participant
|
||||
NS_DECL_SIZEOF_EXCLUDING_THIS
|
||||
|
||||
void LinkAdded();
|
||||
void LinkRemoved();
|
||||
|
||||
void UpdateImport();
|
||||
|
||||
// nsIDOMEventTarget
|
||||
virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override;
|
||||
virtual nsresult PostHandleEvent(
|
||||
EventChainPostVisitor& aVisitor) override;
|
||||
|
||||
// nsINode
|
||||
virtual nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult) const override;
|
||||
virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
// nsIContent
|
||||
virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
||||
nsIContent* aBindingParent,
|
||||
bool aCompileEventHandlers) override;
|
||||
virtual void UnbindFromTree(bool aDeep = true,
|
||||
bool aNullParent = true) override;
|
||||
virtual nsresult BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
nsAttrValueOrString* aValue,
|
||||
bool aNotify) override;
|
||||
virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
const nsAttrValue* aValue,
|
||||
bool aNotify) override;
|
||||
virtual bool IsLink(nsIURI** aURI) const override;
|
||||
virtual already_AddRefed<nsIURI> GetHrefURI() const override;
|
||||
|
||||
// Element
|
||||
virtual bool ParseAttribute(int32_t aNamespaceID,
|
||||
nsIAtom* aAttribute,
|
||||
const nsAString& aValue,
|
||||
nsAttrValue& aResult) override;
|
||||
virtual void GetLinkTarget(nsAString& aTarget) override;
|
||||
virtual EventStates IntrinsicState() const override;
|
||||
|
||||
void CreateAndDispatchEvent(nsIDocument* aDoc, const nsAString& aEventName);
|
||||
|
||||
virtual void OnDNSPrefetchDeferred() override;
|
||||
virtual void OnDNSPrefetchRequested() override;
|
||||
virtual bool HasDeferredDNSPrefetchRequest() override;
|
||||
|
||||
// WebIDL
|
||||
bool Disabled();
|
||||
void SetDisabled(bool aDisabled);
|
||||
// XPCOM GetHref is fine.
|
||||
void SetHref(const nsAString& aHref, ErrorResult& aRv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::href, aHref, aRv);
|
||||
}
|
||||
void GetCrossOrigin(nsAString& aResult)
|
||||
{
|
||||
// Null for both missing and invalid defaults is ok, since we
|
||||
// always parse to an enum value, so we don't need an invalid
|
||||
// default, and we _want_ the missing default to be null.
|
||||
GetEnumAttr(nsGkAtoms::crossorigin, nullptr, aResult);
|
||||
}
|
||||
void SetCrossOrigin(const nsAString& aCrossOrigin, ErrorResult& aError)
|
||||
{
|
||||
SetOrRemoveNullableStringAttr(nsGkAtoms::crossorigin, aCrossOrigin, aError);
|
||||
}
|
||||
// XPCOM GetRel is fine.
|
||||
void SetRel(const nsAString& aRel, ErrorResult& aRv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::rel, aRel, aRv);
|
||||
}
|
||||
nsDOMTokenList* RelList();
|
||||
// XPCOM GetMedia is fine.
|
||||
void SetMedia(const nsAString& aMedia, ErrorResult& aRv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::media, aMedia, aRv);
|
||||
}
|
||||
// XPCOM GetHreflang is fine.
|
||||
void SetHreflang(const nsAString& aHreflang, ErrorResult& aRv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::hreflang, aHreflang, aRv);
|
||||
}
|
||||
nsDOMTokenList* Sizes()
|
||||
{
|
||||
return GetTokenList(nsGkAtoms::sizes);
|
||||
}
|
||||
// XPCOM GetType is fine.
|
||||
void SetType(const nsAString& aType, ErrorResult& aRv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::type, aType, aRv);
|
||||
}
|
||||
// XPCOM GetCharset is fine.
|
||||
void SetCharset(const nsAString& aCharset, ErrorResult& aRv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::charset, aCharset, aRv);
|
||||
}
|
||||
// XPCOM GetRev is fine.
|
||||
void SetRev(const nsAString& aRev, ErrorResult& aRv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::rev, aRev, aRv);
|
||||
}
|
||||
// XPCOM GetTarget is fine.
|
||||
void SetTarget(const nsAString& aTarget, ErrorResult& aRv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::target, aTarget, aRv);
|
||||
}
|
||||
void GetIntegrity(nsAString& aIntegrity) const
|
||||
{
|
||||
GetHTMLAttr(nsGkAtoms::integrity, aIntegrity);
|
||||
}
|
||||
void SetIntegrity(const nsAString& aIntegrity, ErrorResult& aRv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::integrity, aIntegrity, aRv);
|
||||
}
|
||||
void SetReferrerPolicy(const nsAString& aReferrer, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::referrerpolicy, aReferrer, aError);
|
||||
}
|
||||
void GetReferrerPolicy(nsAString& aReferrer)
|
||||
{
|
||||
GetEnumAttr(nsGkAtoms::referrerpolicy, EmptyCString().get(), aReferrer);
|
||||
}
|
||||
mozilla::net::ReferrerPolicy GetLinkReferrerPolicy() override
|
||||
{
|
||||
return GetReferrerPolicyAsEnum();
|
||||
}
|
||||
|
||||
already_AddRefed<nsIDocument> GetImport();
|
||||
already_AddRefed<ImportLoader> GetImportLoader()
|
||||
{
|
||||
return RefPtr<ImportLoader>(mImportLoader).forget();
|
||||
}
|
||||
|
||||
virtual CORSMode GetCORSMode() const override;
|
||||
protected:
|
||||
virtual ~HTMLLinkElement();
|
||||
|
||||
// nsStyleLinkElement
|
||||
virtual already_AddRefed<nsIURI> GetStyleSheetURL(bool* aIsInline) override;
|
||||
virtual void GetStyleSheetInfo(nsAString& aTitle,
|
||||
nsAString& aType,
|
||||
nsAString& aMedia,
|
||||
bool* aIsScoped,
|
||||
bool* aIsAlternate) override;
|
||||
protected:
|
||||
RefPtr<nsDOMTokenList> mRelList;
|
||||
|
||||
private:
|
||||
RefPtr<ImportLoader> mImportLoader;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_HTMLLinkElement_h
|
||||
77
dom/html/HTMLMapElement.cpp
Normal file
77
dom/html/HTMLMapElement.cpp
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
/* -*- 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/HTMLMapElement.h"
|
||||
#include "mozilla/dom/HTMLMapElementBinding.h"
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsStyleConsts.h"
|
||||
#include "nsContentList.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
NS_IMPL_NS_NEW_HTML_ELEMENT(Map)
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
HTMLMapElement::HTMLMapElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
|
||||
: nsGenericHTMLElement(aNodeInfo)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(HTMLMapElement)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLMapElement,
|
||||
nsGenericHTMLElement)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAreas)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(HTMLMapElement, Element)
|
||||
NS_IMPL_RELEASE_INHERITED(HTMLMapElement, Element)
|
||||
|
||||
|
||||
// QueryInterface implementation for HTMLMapElement
|
||||
NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(HTMLMapElement)
|
||||
NS_INTERFACE_TABLE_INHERITED(HTMLMapElement, nsIDOMHTMLMapElement)
|
||||
NS_INTERFACE_TABLE_TAIL_INHERITING(nsGenericHTMLElement)
|
||||
|
||||
NS_IMPL_ELEMENT_CLONE(HTMLMapElement)
|
||||
|
||||
|
||||
nsIHTMLCollection*
|
||||
HTMLMapElement::Areas()
|
||||
{
|
||||
if (!mAreas) {
|
||||
// Not using NS_GetContentList because this should not be cached
|
||||
mAreas = new nsContentList(this,
|
||||
kNameSpaceID_XHTML,
|
||||
nsGkAtoms::area,
|
||||
nsGkAtoms::area,
|
||||
false);
|
||||
}
|
||||
|
||||
return mAreas;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLMapElement::GetAreas(nsIDOMHTMLCollection** aAreas)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aAreas);
|
||||
NS_ADDREF(*aAreas = Areas());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
NS_IMPL_STRING_ATTR(HTMLMapElement, Name, name)
|
||||
|
||||
|
||||
JSObject*
|
||||
HTMLMapElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return HTMLMapElementBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
55
dom/html/HTMLMapElement.h
Normal file
55
dom/html/HTMLMapElement.h
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_dom_HTMLMapElement_h
|
||||
#define mozilla_dom_HTMLMapElement_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsGenericHTMLElement.h"
|
||||
#include "nsIDOMHTMLMapElement.h"
|
||||
#include "nsGkAtoms.h"
|
||||
|
||||
class nsContentList;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class HTMLMapElement final : public nsGenericHTMLElement,
|
||||
public nsIDOMHTMLMapElement
|
||||
{
|
||||
public:
|
||||
explicit HTMLMapElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
|
||||
|
||||
// nsISupports
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
// nsIDOMHTMLMapElement
|
||||
NS_DECL_NSIDOMHTMLMAPELEMENT
|
||||
|
||||
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
|
||||
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED_NO_UNLINK(HTMLMapElement,
|
||||
nsGenericHTMLElement)
|
||||
|
||||
// XPCOM GetName is fine.
|
||||
void SetName(const nsAString& aName, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::name, aName, aError);
|
||||
}
|
||||
nsIHTMLCollection* Areas();
|
||||
|
||||
virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
protected:
|
||||
~HTMLMapElement() {}
|
||||
|
||||
RefPtr<nsContentList> mAreas;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_HTMLMapElement_h
|
||||
6883
dom/html/HTMLMediaElement.cpp
Normal file
6883
dom/html/HTMLMediaElement.cpp
Normal file
File diff suppressed because it is too large
Load diff
1756
dom/html/HTMLMediaElement.h
Normal file
1756
dom/html/HTMLMediaElement.h
Normal file
File diff suppressed because it is too large
Load diff
268
dom/html/HTMLMenuElement.cpp
Normal file
268
dom/html/HTMLMenuElement.cpp
Normal file
|
|
@ -0,0 +1,268 @@
|
|||
/* -*- 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/HTMLMenuElement.h"
|
||||
|
||||
#include "mozilla/BasicEvents.h"
|
||||
#include "mozilla/EventDispatcher.h"
|
||||
#include "mozilla/dom/HTMLMenuElementBinding.h"
|
||||
#include "mozilla/dom/HTMLMenuItemElement.h"
|
||||
#include "nsIMenuBuilder.h"
|
||||
#include "nsAttrValueInlines.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsIURI.h"
|
||||
|
||||
#define HTMLMENUBUILDER_CONTRACTID "@mozilla.org/content/html-menu-builder;1"
|
||||
|
||||
NS_IMPL_NS_NEW_HTML_ELEMENT(Menu)
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
enum MenuType : uint8_t
|
||||
{
|
||||
MENU_TYPE_CONTEXT = 1,
|
||||
MENU_TYPE_TOOLBAR,
|
||||
MENU_TYPE_LIST
|
||||
};
|
||||
|
||||
static const nsAttrValue::EnumTable kMenuTypeTable[] = {
|
||||
{ "context", MENU_TYPE_CONTEXT },
|
||||
{ "toolbar", MENU_TYPE_TOOLBAR },
|
||||
{ "list", MENU_TYPE_LIST },
|
||||
{ nullptr, 0 }
|
||||
};
|
||||
|
||||
static const nsAttrValue::EnumTable* kMenuDefaultType =
|
||||
&kMenuTypeTable[2];
|
||||
|
||||
enum SeparatorType
|
||||
{
|
||||
ST_TRUE_INIT = -1,
|
||||
ST_FALSE = 0,
|
||||
ST_TRUE = 1
|
||||
};
|
||||
|
||||
|
||||
|
||||
HTMLMenuElement::HTMLMenuElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
|
||||
: nsGenericHTMLElement(aNodeInfo), mType(MENU_TYPE_LIST)
|
||||
{
|
||||
}
|
||||
|
||||
HTMLMenuElement::~HTMLMenuElement()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED(HTMLMenuElement, nsGenericHTMLElement,
|
||||
nsIDOMHTMLMenuElement, nsIHTMLMenu)
|
||||
|
||||
NS_IMPL_ELEMENT_CLONE(HTMLMenuElement)
|
||||
|
||||
NS_IMPL_BOOL_ATTR(HTMLMenuElement, Compact, compact)
|
||||
NS_IMPL_ENUM_ATTR_DEFAULT_VALUE(HTMLMenuElement, Type, type,
|
||||
kMenuDefaultType->tag)
|
||||
NS_IMPL_STRING_ATTR(HTMLMenuElement, Label, label)
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLMenuElement::SendShowEvent()
|
||||
{
|
||||
NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_DOM_SECURITY_ERR);
|
||||
|
||||
nsCOMPtr<nsIDocument> document = GetComposedDoc();
|
||||
if (!document) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
WidgetEvent event(true, eShow);
|
||||
event.mFlags.mBubbles = false;
|
||||
event.mFlags.mCancelable = false;
|
||||
|
||||
nsCOMPtr<nsIPresShell> shell = document->GetShell();
|
||||
if (!shell) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
RefPtr<nsPresContext> presContext = shell->GetPresContext();
|
||||
nsEventStatus status = nsEventStatus_eIgnore;
|
||||
EventDispatcher::Dispatch(static_cast<nsIContent*>(this), presContext,
|
||||
&event, nullptr, &status);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLMenuElement::CreateBuilder(nsIMenuBuilder** _retval)
|
||||
{
|
||||
NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_DOM_SECURITY_ERR);
|
||||
|
||||
nsCOMPtr<nsIMenuBuilder> builder = CreateBuilder();
|
||||
builder.swap(*_retval);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
already_AddRefed<nsIMenuBuilder>
|
||||
HTMLMenuElement::CreateBuilder()
|
||||
{
|
||||
if (mType != MENU_TYPE_CONTEXT) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIMenuBuilder> builder = do_CreateInstance(HTMLMENUBUILDER_CONTRACTID);
|
||||
NS_WARNING_ASSERTION(builder, "No builder available");
|
||||
return builder.forget();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLMenuElement::Build(nsIMenuBuilder* aBuilder)
|
||||
{
|
||||
NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_DOM_SECURITY_ERR);
|
||||
|
||||
if (!aBuilder) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
BuildSubmenu(EmptyString(), this, aBuilder);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
HTMLMenuElement::ParseAttribute(int32_t aNamespaceID,
|
||||
nsIAtom* aAttribute,
|
||||
const nsAString& aValue,
|
||||
nsAttrValue& aResult)
|
||||
{
|
||||
if (aNamespaceID == kNameSpaceID_None && aAttribute == nsGkAtoms::type) {
|
||||
bool success = aResult.ParseEnumValue(aValue, kMenuTypeTable,
|
||||
false);
|
||||
if (success) {
|
||||
mType = aResult.GetEnumValue();
|
||||
} else {
|
||||
mType = kMenuDefaultType->value;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
|
||||
aResult);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLMenuElement::BuildSubmenu(const nsAString& aLabel,
|
||||
nsIContent* aContent,
|
||||
nsIMenuBuilder* aBuilder)
|
||||
{
|
||||
aBuilder->OpenContainer(aLabel);
|
||||
|
||||
int8_t separator = ST_TRUE_INIT;
|
||||
TraverseContent(aContent, aBuilder, separator);
|
||||
|
||||
if (separator == ST_TRUE) {
|
||||
aBuilder->UndoAddSeparator();
|
||||
}
|
||||
|
||||
aBuilder->CloseContainer();
|
||||
}
|
||||
|
||||
// static
|
||||
bool
|
||||
HTMLMenuElement::CanLoadIcon(nsIContent* aContent, const nsAString& aIcon)
|
||||
{
|
||||
if (aIcon.IsEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsIDocument* doc = aContent->OwnerDoc();
|
||||
|
||||
nsCOMPtr<nsIURI> baseURI = aContent->GetBaseURI();
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(uri), aIcon, doc,
|
||||
baseURI);
|
||||
|
||||
if (!uri) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return nsContentUtils::CanLoadImage(uri, aContent, doc,
|
||||
aContent->NodePrincipal());
|
||||
}
|
||||
|
||||
void
|
||||
HTMLMenuElement::TraverseContent(nsIContent* aContent,
|
||||
nsIMenuBuilder* aBuilder,
|
||||
int8_t& aSeparator)
|
||||
{
|
||||
nsCOMPtr<nsIContent> child;
|
||||
for (child = aContent->GetFirstChild(); child;
|
||||
child = child->GetNextSibling()) {
|
||||
nsGenericHTMLElement* element = nsGenericHTMLElement::FromContent(child);
|
||||
if (!element) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (child->IsHTMLElement(nsGkAtoms::menuitem)) {
|
||||
HTMLMenuItemElement* menuitem = HTMLMenuItemElement::FromContent(child);
|
||||
|
||||
if (menuitem->IsHidden()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nsAutoString label;
|
||||
menuitem->GetLabel(label);
|
||||
if (label.IsEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nsAutoString icon;
|
||||
menuitem->GetIcon(icon);
|
||||
|
||||
aBuilder->AddItemFor(menuitem, CanLoadIcon(child, icon));
|
||||
|
||||
aSeparator = ST_FALSE;
|
||||
} else if (child->IsHTMLElement(nsGkAtoms::hr)) {
|
||||
aBuilder->AddSeparator();
|
||||
} else if (child->IsHTMLElement(nsGkAtoms::menu) && !element->IsHidden()) {
|
||||
if (child->HasAttr(kNameSpaceID_None, nsGkAtoms::label)) {
|
||||
nsAutoString label;
|
||||
child->GetAttr(kNameSpaceID_None, nsGkAtoms::label, label);
|
||||
|
||||
BuildSubmenu(label, child, aBuilder);
|
||||
|
||||
aSeparator = ST_FALSE;
|
||||
} else {
|
||||
AddSeparator(aBuilder, aSeparator);
|
||||
|
||||
TraverseContent(child, aBuilder, aSeparator);
|
||||
|
||||
AddSeparator(aBuilder, aSeparator);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
HTMLMenuElement::AddSeparator(nsIMenuBuilder* aBuilder, int8_t& aSeparator)
|
||||
{
|
||||
if (aSeparator) {
|
||||
return;
|
||||
}
|
||||
|
||||
aBuilder->AddSeparator();
|
||||
aSeparator = ST_TRUE;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
HTMLMenuElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return HTMLMenuElementBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
99
dom/html/HTMLMenuElement.h
Normal file
99
dom/html/HTMLMenuElement.h
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_dom_HTMLMenuElement_h
|
||||
#define mozilla_dom_HTMLMenuElement_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsIDOMHTMLMenuElement.h"
|
||||
#include "nsIHTMLMenu.h"
|
||||
#include "nsGenericHTMLElement.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class HTMLMenuElement final : public nsGenericHTMLElement,
|
||||
public nsIDOMHTMLMenuElement,
|
||||
public nsIHTMLMenu
|
||||
{
|
||||
public:
|
||||
explicit HTMLMenuElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
|
||||
|
||||
NS_IMPL_FROMCONTENT_HTML_WITH_TAG(HTMLMenuElement, menu)
|
||||
|
||||
// nsISupports
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
// nsIDOMHTMLMenuElement
|
||||
NS_DECL_NSIDOMHTMLMENUELEMENT
|
||||
|
||||
// nsIHTMLMenu
|
||||
NS_DECL_NSIHTMLMENU
|
||||
|
||||
virtual bool ParseAttribute(int32_t aNamespaceID,
|
||||
nsIAtom* aAttribute,
|
||||
const nsAString& aValue,
|
||||
nsAttrValue& aResult) override;
|
||||
|
||||
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
|
||||
|
||||
uint8_t GetType() const { return mType; }
|
||||
|
||||
// WebIDL
|
||||
|
||||
// The XPCOM GetType is OK for us
|
||||
void SetType(const nsAString& aType, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::type, aType, aError);
|
||||
}
|
||||
|
||||
// The XPCOM GetLabel is OK for us
|
||||
void SetLabel(const nsAString& aLabel, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::label, aLabel, aError);
|
||||
}
|
||||
|
||||
bool Compact() const
|
||||
{
|
||||
return GetBoolAttr(nsGkAtoms::compact);
|
||||
}
|
||||
void SetCompact(bool aCompact, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLBoolAttr(nsGkAtoms::compact, aCompact, aError);
|
||||
}
|
||||
|
||||
// The XPCOM SendShowEvent is OK for us
|
||||
|
||||
already_AddRefed<nsIMenuBuilder> CreateBuilder();
|
||||
|
||||
// The XPCOM Build is OK for us
|
||||
|
||||
protected:
|
||||
virtual ~HTMLMenuElement();
|
||||
|
||||
virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
|
||||
protected:
|
||||
static bool CanLoadIcon(nsIContent* aContent, const nsAString& aIcon);
|
||||
|
||||
void BuildSubmenu(const nsAString& aLabel,
|
||||
nsIContent* aContent,
|
||||
nsIMenuBuilder* aBuilder);
|
||||
|
||||
void TraverseContent(nsIContent* aContent,
|
||||
nsIMenuBuilder* aBuilder,
|
||||
int8_t& aSeparator);
|
||||
|
||||
void AddSeparator(nsIMenuBuilder* aBuilder, int8_t& aSeparator);
|
||||
|
||||
uint8_t mType;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_HTMLMenuElement_h
|
||||
495
dom/html/HTMLMenuItemElement.cpp
Normal file
495
dom/html/HTMLMenuItemElement.cpp
Normal file
|
|
@ -0,0 +1,495 @@
|
|||
/* -*- 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/HTMLMenuItemElement.h"
|
||||
|
||||
#include "mozilla/BasicEvents.h"
|
||||
#include "mozilla/EventDispatcher.h"
|
||||
#include "mozilla/dom/HTMLMenuItemElementBinding.h"
|
||||
#include "nsAttrValueInlines.h"
|
||||
#include "nsContentUtils.h"
|
||||
|
||||
|
||||
NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER(MenuItem)
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
// First bits are needed for the menuitem type.
|
||||
#define NS_CHECKED_IS_TOGGLED (1 << 2)
|
||||
#define NS_ORIGINAL_CHECKED_VALUE (1 << 3)
|
||||
#define NS_MENUITEM_TYPE(bits) ((bits) & ~( \
|
||||
NS_CHECKED_IS_TOGGLED | NS_ORIGINAL_CHECKED_VALUE))
|
||||
|
||||
enum CmdType : uint8_t
|
||||
{
|
||||
CMD_TYPE_MENUITEM = 1,
|
||||
CMD_TYPE_CHECKBOX,
|
||||
CMD_TYPE_RADIO
|
||||
};
|
||||
|
||||
static const nsAttrValue::EnumTable kMenuItemTypeTable[] = {
|
||||
{ "menuitem", CMD_TYPE_MENUITEM },
|
||||
{ "checkbox", CMD_TYPE_CHECKBOX },
|
||||
{ "radio", CMD_TYPE_RADIO },
|
||||
{ nullptr, 0 }
|
||||
};
|
||||
|
||||
static const nsAttrValue::EnumTable* kMenuItemDefaultType =
|
||||
&kMenuItemTypeTable[0];
|
||||
|
||||
// A base class inherited by all radio visitors.
|
||||
class Visitor
|
||||
{
|
||||
public:
|
||||
Visitor() { }
|
||||
virtual ~Visitor() { }
|
||||
|
||||
/**
|
||||
* Visit a node in the tree. This is meant to be called on all radios in a
|
||||
* group, sequentially. If the method returns false then the iteration is
|
||||
* stopped.
|
||||
*/
|
||||
virtual bool Visit(HTMLMenuItemElement* aMenuItem) = 0;
|
||||
};
|
||||
|
||||
// Find the selected radio, see GetSelectedRadio().
|
||||
class GetCheckedVisitor : public Visitor
|
||||
{
|
||||
public:
|
||||
explicit GetCheckedVisitor(HTMLMenuItemElement** aResult)
|
||||
: mResult(aResult)
|
||||
{ }
|
||||
virtual bool Visit(HTMLMenuItemElement* aMenuItem)
|
||||
{
|
||||
if (aMenuItem->IsChecked()) {
|
||||
*mResult = aMenuItem;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
protected:
|
||||
HTMLMenuItemElement** mResult;
|
||||
};
|
||||
|
||||
// Deselect all radios except the one passed to the constructor.
|
||||
class ClearCheckedVisitor : public Visitor
|
||||
{
|
||||
public:
|
||||
explicit ClearCheckedVisitor(HTMLMenuItemElement* aExcludeMenuItem)
|
||||
: mExcludeMenuItem(aExcludeMenuItem)
|
||||
{ }
|
||||
virtual bool Visit(HTMLMenuItemElement* aMenuItem)
|
||||
{
|
||||
if (aMenuItem != mExcludeMenuItem && aMenuItem->IsChecked()) {
|
||||
aMenuItem->ClearChecked();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
protected:
|
||||
HTMLMenuItemElement* mExcludeMenuItem;
|
||||
};
|
||||
|
||||
// Get current value of the checked dirty flag. The same value is stored on all
|
||||
// radios in the group, so we need to check only the first one.
|
||||
class GetCheckedDirtyVisitor : public Visitor
|
||||
{
|
||||
public:
|
||||
GetCheckedDirtyVisitor(bool* aCheckedDirty,
|
||||
HTMLMenuItemElement* aExcludeMenuItem)
|
||||
: mCheckedDirty(aCheckedDirty),
|
||||
mExcludeMenuItem(aExcludeMenuItem)
|
||||
{ }
|
||||
virtual bool Visit(HTMLMenuItemElement* aMenuItem)
|
||||
{
|
||||
if (aMenuItem == mExcludeMenuItem) {
|
||||
return true;
|
||||
}
|
||||
*mCheckedDirty = aMenuItem->IsCheckedDirty();
|
||||
return false;
|
||||
}
|
||||
protected:
|
||||
bool* mCheckedDirty;
|
||||
HTMLMenuItemElement* mExcludeMenuItem;
|
||||
};
|
||||
|
||||
// Set checked dirty to true on all radios in the group.
|
||||
class SetCheckedDirtyVisitor : public Visitor
|
||||
{
|
||||
public:
|
||||
SetCheckedDirtyVisitor()
|
||||
{ }
|
||||
virtual bool Visit(HTMLMenuItemElement* aMenuItem)
|
||||
{
|
||||
aMenuItem->SetCheckedDirty();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// A helper visitor that is used to combine two operations (visitors) to avoid
|
||||
// iterating over radios twice.
|
||||
class CombinedVisitor : public Visitor
|
||||
{
|
||||
public:
|
||||
CombinedVisitor(Visitor* aVisitor1, Visitor* aVisitor2)
|
||||
: mVisitor1(aVisitor1), mVisitor2(aVisitor2),
|
||||
mContinue1(true), mContinue2(true)
|
||||
{ }
|
||||
virtual bool Visit(HTMLMenuItemElement* aMenuItem)
|
||||
{
|
||||
if (mContinue1) {
|
||||
mContinue1 = mVisitor1->Visit(aMenuItem);
|
||||
}
|
||||
if (mContinue2) {
|
||||
mContinue2 = mVisitor2->Visit(aMenuItem);
|
||||
}
|
||||
return mContinue1 || mContinue2;
|
||||
}
|
||||
protected:
|
||||
Visitor* mVisitor1;
|
||||
Visitor* mVisitor2;
|
||||
bool mContinue1;
|
||||
bool mContinue2;
|
||||
};
|
||||
|
||||
|
||||
HTMLMenuItemElement::HTMLMenuItemElement(
|
||||
already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo, FromParser aFromParser)
|
||||
: nsGenericHTMLElement(aNodeInfo),
|
||||
mType(kMenuItemDefaultType->value),
|
||||
mParserCreating(false),
|
||||
mShouldInitChecked(false),
|
||||
mCheckedDirty(false),
|
||||
mChecked(false)
|
||||
{
|
||||
mParserCreating = aFromParser;
|
||||
}
|
||||
|
||||
HTMLMenuItemElement::~HTMLMenuItemElement()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED(HTMLMenuItemElement, nsGenericHTMLElement,
|
||||
nsIDOMHTMLMenuItemElement)
|
||||
|
||||
//NS_IMPL_ELEMENT_CLONE(HTMLMenuItemElement)
|
||||
nsresult
|
||||
HTMLMenuItemElement::Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const
|
||||
{
|
||||
*aResult = nullptr;
|
||||
already_AddRefed<mozilla::dom::NodeInfo> ni = RefPtr<mozilla::dom::NodeInfo>(aNodeInfo).forget();
|
||||
RefPtr<HTMLMenuItemElement> it =
|
||||
new HTMLMenuItemElement(ni, NOT_FROM_PARSER);
|
||||
nsresult rv = const_cast<HTMLMenuItemElement*>(this)->CopyInnerTo(it);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
switch (mType) {
|
||||
case CMD_TYPE_CHECKBOX:
|
||||
case CMD_TYPE_RADIO:
|
||||
if (mCheckedDirty) {
|
||||
// We no longer have our original checked state. Set our
|
||||
// checked state on the clone.
|
||||
it->mCheckedDirty = true;
|
||||
it->mChecked = mChecked;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
it.forget(aResult);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
NS_IMPL_ENUM_ATTR_DEFAULT_VALUE(HTMLMenuItemElement, Type, type,
|
||||
kMenuItemDefaultType->tag)
|
||||
// GetText returns a whitespace compressed .textContent value.
|
||||
NS_IMPL_STRING_ATTR_WITH_FALLBACK(HTMLMenuItemElement, Label, label, GetText)
|
||||
NS_IMPL_URI_ATTR(HTMLMenuItemElement, Icon, icon)
|
||||
NS_IMPL_BOOL_ATTR(HTMLMenuItemElement, Disabled, disabled)
|
||||
NS_IMPL_BOOL_ATTR(HTMLMenuItemElement, DefaultChecked, checked)
|
||||
//NS_IMPL_BOOL_ATTR(HTMLMenuItemElement, Checked, checked)
|
||||
NS_IMPL_STRING_ATTR(HTMLMenuItemElement, Radiogroup, radiogroup)
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLMenuItemElement::GetChecked(bool* aChecked)
|
||||
{
|
||||
*aChecked = mChecked;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLMenuItemElement::SetChecked(bool aChecked)
|
||||
{
|
||||
bool checkedChanged = mChecked != aChecked;
|
||||
|
||||
mChecked = aChecked;
|
||||
|
||||
if (mType == CMD_TYPE_RADIO) {
|
||||
if (checkedChanged) {
|
||||
if (mCheckedDirty) {
|
||||
ClearCheckedVisitor visitor(this);
|
||||
WalkRadioGroup(&visitor);
|
||||
} else {
|
||||
ClearCheckedVisitor visitor1(this);
|
||||
SetCheckedDirtyVisitor visitor2;
|
||||
CombinedVisitor visitor(&visitor1, &visitor2);
|
||||
WalkRadioGroup(&visitor);
|
||||
}
|
||||
} else if (!mCheckedDirty) {
|
||||
SetCheckedDirtyVisitor visitor;
|
||||
WalkRadioGroup(&visitor);
|
||||
}
|
||||
} else {
|
||||
mCheckedDirty = true;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLMenuItemElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
{
|
||||
if (aVisitor.mEvent->mMessage == eMouseClick) {
|
||||
|
||||
bool originalCheckedValue = false;
|
||||
switch (mType) {
|
||||
case CMD_TYPE_CHECKBOX:
|
||||
originalCheckedValue = mChecked;
|
||||
SetChecked(!originalCheckedValue);
|
||||
aVisitor.mItemFlags |= NS_CHECKED_IS_TOGGLED;
|
||||
break;
|
||||
case CMD_TYPE_RADIO:
|
||||
nsCOMPtr<nsIDOMHTMLMenuItemElement> selectedRadio = GetSelectedRadio();
|
||||
aVisitor.mItemData = selectedRadio;
|
||||
|
||||
originalCheckedValue = mChecked;
|
||||
if (!originalCheckedValue) {
|
||||
SetChecked(true);
|
||||
aVisitor.mItemFlags |= NS_CHECKED_IS_TOGGLED;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (originalCheckedValue) {
|
||||
aVisitor.mItemFlags |= NS_ORIGINAL_CHECKED_VALUE;
|
||||
}
|
||||
|
||||
// We must cache type because mType may change during JS event.
|
||||
aVisitor.mItemFlags |= mType;
|
||||
}
|
||||
|
||||
return nsGenericHTMLElement::PreHandleEvent(aVisitor);
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLMenuItemElement::PostHandleEvent(EventChainPostVisitor& aVisitor)
|
||||
{
|
||||
// Check to see if the event was cancelled.
|
||||
if (aVisitor.mEvent->mMessage == eMouseClick &&
|
||||
aVisitor.mItemFlags & NS_CHECKED_IS_TOGGLED &&
|
||||
aVisitor.mEventStatus == nsEventStatus_eConsumeNoDefault) {
|
||||
bool originalCheckedValue =
|
||||
!!(aVisitor.mItemFlags & NS_ORIGINAL_CHECKED_VALUE);
|
||||
uint8_t oldType = NS_MENUITEM_TYPE(aVisitor.mItemFlags);
|
||||
|
||||
nsCOMPtr<nsIDOMHTMLMenuItemElement> selectedRadio =
|
||||
do_QueryInterface(aVisitor.mItemData);
|
||||
if (selectedRadio) {
|
||||
selectedRadio->SetChecked(true);
|
||||
if (mType != CMD_TYPE_RADIO) {
|
||||
SetChecked(false);
|
||||
}
|
||||
} else if (oldType == CMD_TYPE_CHECKBOX) {
|
||||
SetChecked(originalCheckedValue);
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLMenuItemElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
||||
nsIContent* aBindingParent,
|
||||
bool aCompileEventHandlers)
|
||||
{
|
||||
nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent,
|
||||
aBindingParent,
|
||||
aCompileEventHandlers);
|
||||
|
||||
if (NS_SUCCEEDED(rv) && aDocument && mType == CMD_TYPE_RADIO) {
|
||||
AddedToRadioGroup();
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
bool
|
||||
HTMLMenuItemElement::ParseAttribute(int32_t aNamespaceID,
|
||||
nsIAtom* aAttribute,
|
||||
const nsAString& aValue,
|
||||
nsAttrValue& aResult)
|
||||
{
|
||||
if (aNamespaceID == kNameSpaceID_None) {
|
||||
if (aAttribute == nsGkAtoms::type) {
|
||||
bool success = aResult.ParseEnumValue(aValue, kMenuItemTypeTable,
|
||||
false);
|
||||
if (success) {
|
||||
mType = aResult.GetEnumValue();
|
||||
} else {
|
||||
mType = kMenuItemDefaultType->value;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
if (aAttribute == nsGkAtoms::radiogroup) {
|
||||
aResult.ParseAtom(aValue);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
|
||||
aResult);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLMenuItemElement::DoneCreatingElement()
|
||||
{
|
||||
mParserCreating = false;
|
||||
|
||||
if (mShouldInitChecked) {
|
||||
InitChecked();
|
||||
mShouldInitChecked = false;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
HTMLMenuItemElement::GetText(nsAString& aText)
|
||||
{
|
||||
nsAutoString text;
|
||||
nsContentUtils::GetNodeTextContent(this, false, text);
|
||||
|
||||
text.CompressWhitespace(true, true);
|
||||
aText = text;
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLMenuItemElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
const nsAttrValue* aValue, bool aNotify)
|
||||
{
|
||||
if (aNameSpaceID == kNameSpaceID_None) {
|
||||
if ((aName == nsGkAtoms::radiogroup || aName == nsGkAtoms::type) &&
|
||||
mType == CMD_TYPE_RADIO &&
|
||||
!mParserCreating) {
|
||||
if (IsInUncomposedDoc() && GetParent()) {
|
||||
AddedToRadioGroup();
|
||||
}
|
||||
}
|
||||
|
||||
// Checked must be set no matter what type of menuitem it is, since
|
||||
// GetChecked() must reflect the new value
|
||||
if (aName == nsGkAtoms::checked &&
|
||||
!mCheckedDirty) {
|
||||
if (mParserCreating) {
|
||||
mShouldInitChecked = true;
|
||||
} else {
|
||||
InitChecked();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName, aValue,
|
||||
aNotify);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLMenuItemElement::WalkRadioGroup(Visitor* aVisitor)
|
||||
{
|
||||
nsIContent* parent = GetParent();
|
||||
if (!parent) {
|
||||
aVisitor->Visit(this);
|
||||
return;
|
||||
}
|
||||
|
||||
BorrowedAttrInfo info1(GetAttrInfo(kNameSpaceID_None,
|
||||
nsGkAtoms::radiogroup));
|
||||
bool info1Empty = !info1.mValue || info1.mValue->IsEmptyString();
|
||||
|
||||
for (nsIContent* cur = parent->GetFirstChild();
|
||||
cur;
|
||||
cur = cur->GetNextSibling()) {
|
||||
HTMLMenuItemElement* menuitem = HTMLMenuItemElement::FromContent(cur);
|
||||
|
||||
if (!menuitem || menuitem->GetType() != CMD_TYPE_RADIO) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BorrowedAttrInfo info2(menuitem->GetAttrInfo(kNameSpaceID_None,
|
||||
nsGkAtoms::radiogroup));
|
||||
bool info2Empty = !info2.mValue || info2.mValue->IsEmptyString();
|
||||
|
||||
if (info1Empty != info2Empty ||
|
||||
(info1.mValue && info2.mValue && !info1.mValue->Equals(*info2.mValue))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!aVisitor->Visit(menuitem)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HTMLMenuItemElement*
|
||||
HTMLMenuItemElement::GetSelectedRadio()
|
||||
{
|
||||
HTMLMenuItemElement* result = nullptr;
|
||||
|
||||
GetCheckedVisitor visitor(&result);
|
||||
WalkRadioGroup(&visitor);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
HTMLMenuItemElement::AddedToRadioGroup()
|
||||
{
|
||||
bool checkedDirty = mCheckedDirty;
|
||||
if (mChecked) {
|
||||
ClearCheckedVisitor visitor1(this);
|
||||
GetCheckedDirtyVisitor visitor2(&checkedDirty, this);
|
||||
CombinedVisitor visitor(&visitor1, &visitor2);
|
||||
WalkRadioGroup(&visitor);
|
||||
} else {
|
||||
GetCheckedDirtyVisitor visitor(&checkedDirty, this);
|
||||
WalkRadioGroup(&visitor);
|
||||
}
|
||||
mCheckedDirty = checkedDirty;
|
||||
}
|
||||
|
||||
void
|
||||
HTMLMenuItemElement::InitChecked()
|
||||
{
|
||||
bool defaultChecked;
|
||||
GetDefaultChecked(&defaultChecked);
|
||||
mChecked = defaultChecked;
|
||||
if (mType == CMD_TYPE_RADIO) {
|
||||
ClearCheckedVisitor visitor(this);
|
||||
WalkRadioGroup(&visitor);
|
||||
}
|
||||
}
|
||||
|
||||
JSObject*
|
||||
HTMLMenuItemElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return HTMLMenuItemElementBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#undef NS_ORIGINAL_CHECKED_VALUE
|
||||
154
dom/html/HTMLMenuItemElement.h
Normal file
154
dom/html/HTMLMenuItemElement.h
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_dom_HTMLMenuItemElement_h
|
||||
#define mozilla_dom_HTMLMenuItemElement_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsIDOMHTMLMenuItemElement.h"
|
||||
#include "nsGenericHTMLElement.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class EventChainPreVisitor;
|
||||
|
||||
namespace dom {
|
||||
|
||||
class Visitor;
|
||||
|
||||
class HTMLMenuItemElement final : public nsGenericHTMLElement,
|
||||
public nsIDOMHTMLMenuItemElement
|
||||
{
|
||||
public:
|
||||
using mozilla::dom::Element::GetText;
|
||||
|
||||
HTMLMenuItemElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo,
|
||||
mozilla::dom::FromParser aFromParser);
|
||||
|
||||
NS_IMPL_FROMCONTENT_HTML_WITH_TAG(HTMLMenuItemElement, menuitem)
|
||||
|
||||
// nsISupports
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
// nsIDOMHTMLMenuItemElement
|
||||
NS_DECL_NSIDOMHTMLMENUITEMELEMENT
|
||||
|
||||
virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override;
|
||||
virtual nsresult PostHandleEvent(
|
||||
EventChainPostVisitor& aVisitor) override;
|
||||
|
||||
virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
||||
nsIContent* aBindingParent,
|
||||
bool aCompileEventHandlers) override;
|
||||
|
||||
virtual bool ParseAttribute(int32_t aNamespaceID,
|
||||
nsIAtom* aAttribute,
|
||||
const nsAString& aValue,
|
||||
nsAttrValue& aResult) override;
|
||||
|
||||
virtual void DoneCreatingElement() override;
|
||||
|
||||
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
|
||||
|
||||
uint8_t GetType() const { return mType; }
|
||||
|
||||
/**
|
||||
* Syntax sugar to make it easier to check for checked and checked dirty
|
||||
*/
|
||||
bool IsChecked() const { return mChecked; }
|
||||
bool IsCheckedDirty() const { return mCheckedDirty; }
|
||||
|
||||
void GetText(nsAString& aText);
|
||||
|
||||
// WebIDL
|
||||
|
||||
// The XPCOM GetType is OK for us
|
||||
void SetType(const nsAString& aType, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::type, aType, aError);
|
||||
}
|
||||
|
||||
// The XPCOM GetLabel is OK for us
|
||||
void SetLabel(const nsAString& aLabel, ErrorResult& aError)
|
||||
{
|
||||
SetAttrHelper(nsGkAtoms::label, aLabel);
|
||||
}
|
||||
|
||||
// The XPCOM GetIcon is OK for us
|
||||
void SetIcon(const nsAString& aIcon, ErrorResult& aError)
|
||||
{
|
||||
SetAttrHelper(nsGkAtoms::icon, aIcon);
|
||||
}
|
||||
|
||||
bool Disabled() const
|
||||
{
|
||||
return GetBoolAttr(nsGkAtoms::disabled);
|
||||
}
|
||||
void SetDisabled(bool aDisabled, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLBoolAttr(nsGkAtoms::disabled, aDisabled, aError);
|
||||
}
|
||||
|
||||
bool Checked() const
|
||||
{
|
||||
return mChecked;
|
||||
}
|
||||
void SetChecked(bool aChecked, ErrorResult& aError)
|
||||
{
|
||||
aError = SetChecked(aChecked);
|
||||
}
|
||||
|
||||
// The XPCOM GetRadiogroup is OK for us
|
||||
void SetRadiogroup(const nsAString& aRadiogroup, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::radiogroup, aRadiogroup, aError);
|
||||
}
|
||||
|
||||
bool DefaultChecked() const
|
||||
{
|
||||
return GetBoolAttr(nsGkAtoms::checked);
|
||||
}
|
||||
void SetDefaultChecked(bool aDefault, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLBoolAttr(nsGkAtoms::checked, aDefault, aError);
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual ~HTMLMenuItemElement();
|
||||
|
||||
virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
|
||||
protected:
|
||||
virtual nsresult AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
|
||||
const nsAttrValue* aValue, bool aNotify) override;
|
||||
|
||||
void WalkRadioGroup(Visitor* aVisitor);
|
||||
|
||||
HTMLMenuItemElement* GetSelectedRadio();
|
||||
|
||||
void AddedToRadioGroup();
|
||||
|
||||
void InitChecked();
|
||||
|
||||
friend class ClearCheckedVisitor;
|
||||
friend class SetCheckedDirtyVisitor;
|
||||
|
||||
void ClearChecked() { mChecked = false; }
|
||||
void SetCheckedDirty() { mCheckedDirty = true; }
|
||||
|
||||
private:
|
||||
uint8_t mType : 2;
|
||||
bool mParserCreating : 1;
|
||||
bool mShouldInitChecked : 1;
|
||||
bool mCheckedDirty : 1;
|
||||
bool mChecked : 1;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_HTMLMenuItemElement_h
|
||||
172
dom/html/HTMLMetaElement.cpp
Normal file
172
dom/html/HTMLMetaElement.cpp
Normal file
|
|
@ -0,0 +1,172 @@
|
|||
/* -*- 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/AsyncEventDispatcher.h"
|
||||
#include "mozilla/dom/HTMLMetaElement.h"
|
||||
#include "mozilla/dom/HTMLMetaElementBinding.h"
|
||||
#include "mozilla/dom/nsCSPService.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsStyleConsts.h"
|
||||
#include "nsIContentSecurityPolicy.h"
|
||||
|
||||
NS_IMPL_NS_NEW_HTML_ELEMENT(Meta)
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
HTMLMetaElement::HTMLMetaElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
|
||||
: nsGenericHTMLElement(aNodeInfo)
|
||||
{
|
||||
}
|
||||
|
||||
HTMLMetaElement::~HTMLMetaElement()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED(HTMLMetaElement, nsGenericHTMLElement,
|
||||
nsIDOMHTMLMetaElement)
|
||||
|
||||
NS_IMPL_ELEMENT_CLONE(HTMLMetaElement)
|
||||
|
||||
|
||||
NS_IMPL_STRING_ATTR(HTMLMetaElement, Content, content)
|
||||
NS_IMPL_STRING_ATTR(HTMLMetaElement, HttpEquiv, httpEquiv)
|
||||
NS_IMPL_STRING_ATTR(HTMLMetaElement, Name, name)
|
||||
NS_IMPL_STRING_ATTR(HTMLMetaElement, Scheme, scheme)
|
||||
|
||||
nsresult
|
||||
HTMLMetaElement::SetMetaReferrer(nsIDocument* aDocument)
|
||||
{
|
||||
if (!aDocument ||
|
||||
!AttrValueIs(kNameSpaceID_None, nsGkAtoms::name, nsGkAtoms::referrer, eIgnoreCase)) {
|
||||
return NS_OK;
|
||||
}
|
||||
nsAutoString content;
|
||||
nsresult rv = GetContent(content);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
Element* headElt = aDocument->GetHeadElement();
|
||||
if (headElt && nsContentUtils::ContentIsDescendantOf(this, headElt)) {
|
||||
content = nsContentUtils::TrimWhitespace<nsContentUtils::IsHTMLWhitespace>(content);
|
||||
aDocument->SetHeaderData(nsGkAtoms::referrer, content);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLMetaElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
const nsAttrValue* aValue, bool aNotify)
|
||||
{
|
||||
if (aNameSpaceID == kNameSpaceID_None) {
|
||||
nsIDocument *document = GetUncomposedDoc();
|
||||
if (aName == nsGkAtoms::content) {
|
||||
if (document && AttrValueIs(kNameSpaceID_None, nsGkAtoms::name,
|
||||
nsGkAtoms::viewport, eIgnoreCase)) {
|
||||
nsAutoString content;
|
||||
nsresult rv = GetContent(content);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsContentUtils::ProcessViewportInfo(document, content);
|
||||
}
|
||||
CreateAndDispatchEvent(document, NS_LITERAL_STRING("DOMMetaChanged"));
|
||||
}
|
||||
// Update referrer policy when it got changed from JS
|
||||
nsresult rv = SetMetaReferrer(document);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName, aValue,
|
||||
aNotify);
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLMetaElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
||||
nsIContent* aBindingParent,
|
||||
bool aCompileEventHandlers)
|
||||
{
|
||||
nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent,
|
||||
aBindingParent,
|
||||
aCompileEventHandlers);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (aDocument &&
|
||||
AttrValueIs(kNameSpaceID_None, nsGkAtoms::name, nsGkAtoms::viewport, eIgnoreCase)) {
|
||||
nsAutoString content;
|
||||
rv = GetContent(content);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsContentUtils::ProcessViewportInfo(aDocument, content);
|
||||
}
|
||||
|
||||
if (CSPService::sCSPEnabled && aDocument &&
|
||||
AttrValueIs(kNameSpaceID_None, nsGkAtoms::httpEquiv, nsGkAtoms::headerCSP, eIgnoreCase)) {
|
||||
|
||||
// only accept <meta http-equiv="Content-Security-Policy" content=""> if it appears
|
||||
// in the <head> element.
|
||||
Element* headElt = aDocument->GetHeadElement();
|
||||
if (headElt && nsContentUtils::ContentIsDescendantOf(this, headElt)) {
|
||||
|
||||
nsAutoString content;
|
||||
rv = GetContent(content);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
content = nsContentUtils::TrimWhitespace<nsContentUtils::IsHTMLWhitespace>(content);
|
||||
|
||||
nsIPrincipal* principal = aDocument->NodePrincipal();
|
||||
nsCOMPtr<nsIContentSecurityPolicy> csp;
|
||||
nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(aDocument);
|
||||
principal->EnsureCSP(domDoc, getter_AddRefs(csp));
|
||||
if (csp) {
|
||||
// Multiple CSPs (delivered through either header of meta tag) need to be
|
||||
// joined together, see:
|
||||
// https://w3c.github.io/webappsec/specs/content-security-policy/#delivery-html-meta-element
|
||||
rv = csp->AppendPolicy(content,
|
||||
false, // csp via meta tag can not be report only
|
||||
true); // delivered through the meta tag
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
aDocument->ApplySettingsFromCSP(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Referrer Policy spec requires a <meta name="referrer" tag to be in the
|
||||
// <head> element.
|
||||
rv = SetMetaReferrer(aDocument);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
CreateAndDispatchEvent(aDocument, NS_LITERAL_STRING("DOMMetaAdded"));
|
||||
return rv;
|
||||
}
|
||||
|
||||
void
|
||||
HTMLMetaElement::UnbindFromTree(bool aDeep, bool aNullParent)
|
||||
{
|
||||
nsCOMPtr<nsIDocument> oldDoc = GetUncomposedDoc();
|
||||
CreateAndDispatchEvent(oldDoc, NS_LITERAL_STRING("DOMMetaRemoved"));
|
||||
nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLMetaElement::CreateAndDispatchEvent(nsIDocument* aDoc,
|
||||
const nsAString& aEventName)
|
||||
{
|
||||
if (!aDoc)
|
||||
return;
|
||||
|
||||
RefPtr<AsyncEventDispatcher> asyncDispatcher =
|
||||
new AsyncEventDispatcher(this, aEventName, true, true);
|
||||
asyncDispatcher->RunDOMEventWhenSafe();
|
||||
}
|
||||
|
||||
JSObject*
|
||||
HTMLMetaElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return HTMLMetaElementBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
75
dom/html/HTMLMetaElement.h
Normal file
75
dom/html/HTMLMetaElement.h
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_dom_HTMLMetaElement_h
|
||||
#define mozilla_dom_HTMLMetaElement_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsGenericHTMLElement.h"
|
||||
#include "nsIDOMHTMLMetaElement.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class HTMLMetaElement final : public nsGenericHTMLElement,
|
||||
public nsIDOMHTMLMetaElement
|
||||
{
|
||||
public:
|
||||
explicit HTMLMetaElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
|
||||
|
||||
// nsISupports
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
// nsIDOMHTMLMetaElement
|
||||
NS_DECL_NSIDOMHTMLMETAELEMENT
|
||||
|
||||
virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
||||
nsIContent* aBindingParent,
|
||||
bool aCompileEventHandlers) override;
|
||||
virtual void UnbindFromTree(bool aDeep = true,
|
||||
bool aNullParent = true) override;
|
||||
|
||||
virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
const nsAttrValue* aValue, bool aNotify) override;
|
||||
|
||||
void CreateAndDispatchEvent(nsIDocument* aDoc, const nsAString& aEventName);
|
||||
|
||||
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
|
||||
|
||||
// XPCOM GetName is fine.
|
||||
void SetName(const nsAString& aName, ErrorResult& aRv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::name, aName, aRv);
|
||||
}
|
||||
// XPCOM GetHttpEquiv is fine.
|
||||
void SetHttpEquiv(const nsAString& aHttpEquiv, ErrorResult& aRv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::httpEquiv, aHttpEquiv, aRv);
|
||||
}
|
||||
// XPCOM GetContent is fine.
|
||||
void SetContent(const nsAString& aContent, ErrorResult& aRv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::content, aContent, aRv);
|
||||
}
|
||||
// XPCOM GetScheme is fine.
|
||||
void SetScheme(const nsAString& aScheme, ErrorResult& aRv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::scheme, aScheme, aRv);
|
||||
}
|
||||
|
||||
virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
protected:
|
||||
virtual ~HTMLMetaElement();
|
||||
|
||||
private:
|
||||
nsresult SetMetaReferrer(nsIDocument* aDocument);
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_HTMLMetaElement_h
|
||||
266
dom/html/HTMLMeterElement.cpp
Normal file
266
dom/html/HTMLMeterElement.cpp
Normal file
|
|
@ -0,0 +1,266 @@
|
|||
/* -*- 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 "HTMLMeterElement.h"
|
||||
#include "mozilla/EventStates.h"
|
||||
#include "mozilla/dom/HTMLMeterElementBinding.h"
|
||||
|
||||
NS_IMPL_NS_NEW_HTML_ELEMENT(Meter)
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
const double HTMLMeterElement::kDefaultValue = 0.0;
|
||||
const double HTMLMeterElement::kDefaultMin = 0.0;
|
||||
const double HTMLMeterElement::kDefaultMax = 1.0;
|
||||
|
||||
|
||||
HTMLMeterElement::HTMLMeterElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
|
||||
: nsGenericHTMLElement(aNodeInfo)
|
||||
{
|
||||
}
|
||||
|
||||
HTMLMeterElement::~HTMLMeterElement()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMPL_ELEMENT_CLONE(HTMLMeterElement)
|
||||
|
||||
EventStates
|
||||
HTMLMeterElement::IntrinsicState() const
|
||||
{
|
||||
EventStates state = nsGenericHTMLElement::IntrinsicState();
|
||||
|
||||
state |= GetOptimumState();
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
bool
|
||||
HTMLMeterElement::ParseAttribute(int32_t aNamespaceID, nsIAtom* aAttribute,
|
||||
const nsAString& aValue, nsAttrValue& aResult)
|
||||
{
|
||||
if (aNamespaceID == kNameSpaceID_None) {
|
||||
if (aAttribute == nsGkAtoms::value || aAttribute == nsGkAtoms::max ||
|
||||
aAttribute == nsGkAtoms::min || aAttribute == nsGkAtoms::low ||
|
||||
aAttribute == nsGkAtoms::high || aAttribute == nsGkAtoms::optimum) {
|
||||
return aResult.ParseDoubleValue(aValue);
|
||||
}
|
||||
}
|
||||
|
||||
return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute,
|
||||
aValue, aResult);
|
||||
}
|
||||
|
||||
/*
|
||||
* Value getters :
|
||||
* const getters used by XPCOM methods and by IntrinsicState
|
||||
*/
|
||||
|
||||
double
|
||||
HTMLMeterElement::Min() const
|
||||
{
|
||||
/**
|
||||
* If the attribute min is defined, the minimum is this value.
|
||||
* Otherwise, the minimum is the default value.
|
||||
*/
|
||||
const nsAttrValue* attrMin = mAttrsAndChildren.GetAttr(nsGkAtoms::min);
|
||||
if (attrMin && attrMin->Type() == nsAttrValue::eDoubleValue) {
|
||||
return attrMin->GetDoubleValue();
|
||||
}
|
||||
return kDefaultMin;
|
||||
}
|
||||
|
||||
double
|
||||
HTMLMeterElement::Max() const
|
||||
{
|
||||
/**
|
||||
* If the attribute max is defined, the maximum is this value.
|
||||
* Otherwise, the maximum is the default value.
|
||||
* If the maximum value is less than the minimum value,
|
||||
* the maximum value is the same as the minimum value.
|
||||
*/
|
||||
double max;
|
||||
|
||||
const nsAttrValue* attrMax = mAttrsAndChildren.GetAttr(nsGkAtoms::max);
|
||||
if (attrMax && attrMax->Type() == nsAttrValue::eDoubleValue) {
|
||||
max = attrMax->GetDoubleValue();
|
||||
} else {
|
||||
max = kDefaultMax;
|
||||
}
|
||||
|
||||
return std::max(max, Min());
|
||||
}
|
||||
|
||||
double
|
||||
HTMLMeterElement::Value() const
|
||||
{
|
||||
/**
|
||||
* If the attribute value is defined, the actual value is this value.
|
||||
* Otherwise, the actual value is the default value.
|
||||
* If the actual value is less than the minimum value,
|
||||
* the actual value is the same as the minimum value.
|
||||
* If the actual value is greater than the maximum value,
|
||||
* the actual value is the same as the maximum value.
|
||||
*/
|
||||
double value;
|
||||
|
||||
const nsAttrValue* attrValue = mAttrsAndChildren.GetAttr(nsGkAtoms::value);
|
||||
if (attrValue && attrValue->Type() == nsAttrValue::eDoubleValue) {
|
||||
value = attrValue->GetDoubleValue();
|
||||
} else {
|
||||
value = kDefaultValue;
|
||||
}
|
||||
|
||||
double min = Min();
|
||||
|
||||
if (value <= min) {
|
||||
return min;
|
||||
}
|
||||
|
||||
return std::min(value, Max());
|
||||
}
|
||||
|
||||
double
|
||||
HTMLMeterElement::Low() const
|
||||
{
|
||||
/**
|
||||
* If the low value is defined, the low value is this value.
|
||||
* Otherwise, the low value is the minimum value.
|
||||
* If the low value is less than the minimum value,
|
||||
* the low value is the same as the minimum value.
|
||||
* If the low value is greater than the maximum value,
|
||||
* the low value is the same as the maximum value.
|
||||
*/
|
||||
|
||||
double min = Min();
|
||||
|
||||
const nsAttrValue* attrLow = mAttrsAndChildren.GetAttr(nsGkAtoms::low);
|
||||
if (!attrLow || attrLow->Type() != nsAttrValue::eDoubleValue) {
|
||||
return min;
|
||||
}
|
||||
|
||||
double low = attrLow->GetDoubleValue();
|
||||
|
||||
if (low <= min) {
|
||||
return min;
|
||||
}
|
||||
|
||||
return std::min(low, Max());
|
||||
}
|
||||
|
||||
double
|
||||
HTMLMeterElement::High() const
|
||||
{
|
||||
/**
|
||||
* If the high value is defined, the high value is this value.
|
||||
* Otherwise, the high value is the maximum value.
|
||||
* If the high value is less than the low value,
|
||||
* the high value is the same as the low value.
|
||||
* If the high value is greater than the maximum value,
|
||||
* the high value is the same as the maximum value.
|
||||
*/
|
||||
|
||||
double max = Max();
|
||||
|
||||
const nsAttrValue* attrHigh = mAttrsAndChildren.GetAttr(nsGkAtoms::high);
|
||||
if (!attrHigh || attrHigh->Type() != nsAttrValue::eDoubleValue) {
|
||||
return max;
|
||||
}
|
||||
|
||||
double high = attrHigh->GetDoubleValue();
|
||||
|
||||
if (high >= max) {
|
||||
return max;
|
||||
}
|
||||
|
||||
return std::max(high, Low());
|
||||
}
|
||||
|
||||
double
|
||||
HTMLMeterElement::Optimum() const
|
||||
{
|
||||
/**
|
||||
* If the optimum value is defined, the optimum value is this value.
|
||||
* Otherwise, the optimum value is the midpoint between
|
||||
* the minimum value and the maximum value :
|
||||
* min + (max - min)/2 = (min + max)/2
|
||||
* If the optimum value is less than the minimum value,
|
||||
* the optimum value is the same as the minimum value.
|
||||
* If the optimum value is greater than the maximum value,
|
||||
* the optimum value is the same as the maximum value.
|
||||
*/
|
||||
|
||||
double max = Max();
|
||||
|
||||
double min = Min();
|
||||
|
||||
const nsAttrValue* attrOptimum =
|
||||
mAttrsAndChildren.GetAttr(nsGkAtoms::optimum);
|
||||
if (!attrOptimum || attrOptimum->Type() != nsAttrValue::eDoubleValue) {
|
||||
return (min + max) / 2.0;
|
||||
}
|
||||
|
||||
double optimum = attrOptimum->GetDoubleValue();
|
||||
|
||||
if (optimum <= min) {
|
||||
return min;
|
||||
}
|
||||
|
||||
return std::min(optimum, max);
|
||||
}
|
||||
|
||||
EventStates
|
||||
HTMLMeterElement::GetOptimumState() const
|
||||
{
|
||||
/*
|
||||
* If the optimum value is in [minimum, low[,
|
||||
* return if the value is in optimal, suboptimal or sub-suboptimal region
|
||||
*
|
||||
* If the optimum value is in [low, high],
|
||||
* return if the value is in optimal or suboptimal region
|
||||
*
|
||||
* If the optimum value is in ]high, maximum],
|
||||
* return if the value is in optimal, suboptimal or sub-suboptimal region
|
||||
*/
|
||||
double value = Value();
|
||||
double low = Low();
|
||||
double high = High();
|
||||
double optimum = Optimum();
|
||||
|
||||
if (optimum < low) {
|
||||
if (value < low) {
|
||||
return NS_EVENT_STATE_OPTIMUM;
|
||||
}
|
||||
if (value <= high) {
|
||||
return NS_EVENT_STATE_SUB_OPTIMUM;
|
||||
}
|
||||
return NS_EVENT_STATE_SUB_SUB_OPTIMUM;
|
||||
}
|
||||
if (optimum > high) {
|
||||
if (value > high) {
|
||||
return NS_EVENT_STATE_OPTIMUM;
|
||||
}
|
||||
if (value >= low) {
|
||||
return NS_EVENT_STATE_SUB_OPTIMUM;
|
||||
}
|
||||
return NS_EVENT_STATE_SUB_SUB_OPTIMUM;
|
||||
}
|
||||
// optimum in [low, high]
|
||||
if (value >= low && value <= high) {
|
||||
return NS_EVENT_STATE_OPTIMUM;
|
||||
}
|
||||
return NS_EVENT_STATE_SUB_OPTIMUM;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
HTMLMeterElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return HTMLMeterElementBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
101
dom/html/HTMLMeterElement.h
Normal file
101
dom/html/HTMLMeterElement.h
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_dom_HTMLMeterElement_h
|
||||
#define mozilla_dom_HTMLMeterElement_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsGenericHTMLElement.h"
|
||||
#include "nsAttrValue.h"
|
||||
#include "nsAttrValueInlines.h"
|
||||
#include "nsAlgorithm.h"
|
||||
#include <algorithm>
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class HTMLMeterElement final : public nsGenericHTMLElement
|
||||
{
|
||||
public:
|
||||
explicit HTMLMeterElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
|
||||
|
||||
virtual EventStates IntrinsicState() const override;
|
||||
|
||||
nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult) const override;
|
||||
|
||||
bool ParseAttribute(int32_t aNamespaceID, nsIAtom* aAttribute,
|
||||
const nsAString& aValue, nsAttrValue& aResult) override;
|
||||
|
||||
// WebIDL
|
||||
|
||||
/* @return the value */
|
||||
double Value() const;
|
||||
void SetValue(double aValue, ErrorResult& aRv)
|
||||
{
|
||||
SetDoubleAttr(nsGkAtoms::value, aValue, aRv);
|
||||
}
|
||||
|
||||
/* @return the minimum value */
|
||||
double Min() const;
|
||||
void SetMin(double aValue, ErrorResult& aRv)
|
||||
{
|
||||
SetDoubleAttr(nsGkAtoms::min, aValue, aRv);
|
||||
}
|
||||
|
||||
/* @return the maximum value */
|
||||
double Max() const;
|
||||
void SetMax(double aValue, ErrorResult& aRv)
|
||||
{
|
||||
SetDoubleAttr(nsGkAtoms::max, aValue, aRv);
|
||||
}
|
||||
|
||||
/* @return the low value */
|
||||
double Low() const;
|
||||
void SetLow(double aValue, ErrorResult& aRv)
|
||||
{
|
||||
SetDoubleAttr(nsGkAtoms::low, aValue, aRv);
|
||||
}
|
||||
|
||||
/* @return the high value */
|
||||
double High() const;
|
||||
void SetHigh(double aValue, ErrorResult& aRv)
|
||||
{
|
||||
SetDoubleAttr(nsGkAtoms::high, aValue, aRv);
|
||||
}
|
||||
|
||||
/* @return the optimum value */
|
||||
double Optimum() const;
|
||||
void SetOptimum(double aValue, ErrorResult& aRv)
|
||||
{
|
||||
SetDoubleAttr(nsGkAtoms::optimum, aValue, aRv);
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual ~HTMLMeterElement();
|
||||
|
||||
virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
private:
|
||||
|
||||
static const double kDefaultValue;
|
||||
static const double kDefaultMin;
|
||||
static const double kDefaultMax;
|
||||
|
||||
/**
|
||||
* Returns the optimum state of the element.
|
||||
* NS_EVENT_STATE_OPTIMUM if the actual value is in the optimum region.
|
||||
* NS_EVENT_STATE_SUB_OPTIMUM if the actual value is in the sub-optimal region.
|
||||
* NS_EVENT_STATE_SUB_SUB_OPTIMUM if the actual value is in the sub-sub-optimal region.
|
||||
*
|
||||
* @return the optimum state of the element.
|
||||
*/
|
||||
EventStates GetOptimumState() const;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_HTMLMeterElement_h
|
||||
34
dom/html/HTMLModElement.cpp
Normal file
34
dom/html/HTMLModElement.cpp
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/* -*- 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/HTMLModElement.h"
|
||||
#include "mozilla/dom/HTMLModElementBinding.h"
|
||||
#include "nsStyleConsts.h"
|
||||
|
||||
NS_IMPL_NS_NEW_HTML_ELEMENT(Mod)
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
HTMLModElement::HTMLModElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
|
||||
: nsGenericHTMLElement(aNodeInfo)
|
||||
{
|
||||
}
|
||||
|
||||
HTMLModElement::~HTMLModElement()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMPL_ELEMENT_CLONE(HTMLModElement)
|
||||
|
||||
JSObject*
|
||||
HTMLModElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return HTMLModElementBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
50
dom/html/HTMLModElement.h
Normal file
50
dom/html/HTMLModElement.h
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_dom_HTMLModElement_h
|
||||
#define mozilla_dom_HTMLModElement_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsGenericHTMLElement.h"
|
||||
#include "nsGkAtoms.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class HTMLModElement final : public nsGenericHTMLElement
|
||||
{
|
||||
public:
|
||||
explicit HTMLModElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
|
||||
|
||||
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
|
||||
|
||||
void GetCite(nsString& aCite)
|
||||
{
|
||||
GetHTMLURIAttr(nsGkAtoms::cite, aCite);
|
||||
}
|
||||
void SetCite(const nsAString& aCite, ErrorResult& aRv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::cite, aCite, aRv);
|
||||
}
|
||||
void GetDateTime(DOMString& aDateTime)
|
||||
{
|
||||
GetHTMLAttr(nsGkAtoms::datetime, aDateTime);
|
||||
}
|
||||
void SetDateTime(const nsAString& aDateTime, ErrorResult& aRv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::datetime, aDateTime, aRv);
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual ~HTMLModElement();
|
||||
|
||||
virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_HTMLModElement_h
|
||||
601
dom/html/HTMLObjectElement.cpp
Normal file
601
dom/html/HTMLObjectElement.cpp
Normal file
|
|
@ -0,0 +1,601 @@
|
|||
/* -*- 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/EventStates.h"
|
||||
#include "mozilla/dom/HTMLFormSubmission.h"
|
||||
#include "mozilla/dom/HTMLObjectElement.h"
|
||||
#include "mozilla/dom/HTMLObjectElementBinding.h"
|
||||
#include "mozilla/dom/ElementInlines.h"
|
||||
#include "nsAttrValueInlines.h"
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsError.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIPluginDocument.h"
|
||||
#include "nsIDOMDocument.h"
|
||||
#include "nsIObjectFrame.h"
|
||||
#include "nsNPAPIPluginInstance.h"
|
||||
#include "nsIWidget.h"
|
||||
#include "nsContentUtils.h"
|
||||
#ifdef XP_MACOSX
|
||||
#include "mozilla/EventDispatcher.h"
|
||||
#include "mozilla/dom/Event.h"
|
||||
#include "nsFocusManager.h"
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
HTMLObjectElement::HTMLObjectElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo,
|
||||
FromParser aFromParser)
|
||||
: nsGenericHTMLFormElement(aNodeInfo),
|
||||
mIsDoneAddingChildren(!aFromParser)
|
||||
{
|
||||
RegisterActivityObserver();
|
||||
SetIsNetworkCreated(aFromParser == FROM_PARSER_NETWORK);
|
||||
|
||||
// <object> is always barred from constraint validation.
|
||||
SetBarredFromConstraintValidation(true);
|
||||
|
||||
// By default we're in the loading state
|
||||
AddStatesSilently(NS_EVENT_STATE_LOADING);
|
||||
}
|
||||
|
||||
HTMLObjectElement::~HTMLObjectElement()
|
||||
{
|
||||
#ifdef XP_MACOSX
|
||||
OnFocusBlurPlugin(this, false);
|
||||
#endif
|
||||
UnregisterActivityObserver();
|
||||
DestroyImageLoadingContent();
|
||||
}
|
||||
|
||||
bool
|
||||
HTMLObjectElement::IsInteractiveHTMLContent(bool aIgnoreTabindex) const
|
||||
{
|
||||
return HasAttr(kNameSpaceID_None, nsGkAtoms::usemap) ||
|
||||
nsGenericHTMLFormElement::IsInteractiveHTMLContent(aIgnoreTabindex);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLObjectElement::AsyncEventRunning(AsyncEventDispatcher* aEvent)
|
||||
{
|
||||
nsImageLoadingContent::AsyncEventRunning(aEvent);
|
||||
}
|
||||
|
||||
bool
|
||||
HTMLObjectElement::IsDoneAddingChildren()
|
||||
{
|
||||
return mIsDoneAddingChildren;
|
||||
}
|
||||
|
||||
void
|
||||
HTMLObjectElement::DoneAddingChildren(bool aHaveNotified)
|
||||
{
|
||||
mIsDoneAddingChildren = true;
|
||||
|
||||
// If we're already in a document, we need to trigger the load
|
||||
// Otherwise, BindToTree takes care of that.
|
||||
if (IsInComposedDoc()) {
|
||||
StartObjectLoad(aHaveNotified);
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(HTMLObjectElement)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLObjectElement,
|
||||
nsGenericHTMLFormElement)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mValidity)
|
||||
nsObjectLoadingContent::Traverse(tmp, cb);
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLObjectElement,
|
||||
nsGenericHTMLFormElement)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mValidity)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(HTMLObjectElement, Element)
|
||||
NS_IMPL_RELEASE_INHERITED(HTMLObjectElement, Element)
|
||||
|
||||
NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(HTMLObjectElement)
|
||||
NS_INTERFACE_TABLE_INHERITED(HTMLObjectElement,
|
||||
nsIDOMHTMLObjectElement,
|
||||
imgINotificationObserver,
|
||||
nsIRequestObserver,
|
||||
nsIStreamListener,
|
||||
nsIFrameLoaderOwner,
|
||||
nsIObjectLoadingContent,
|
||||
nsIImageLoadingContent,
|
||||
imgIOnloadBlocker,
|
||||
nsIChannelEventSink,
|
||||
nsIConstraintValidation)
|
||||
NS_INTERFACE_TABLE_TAIL_INHERITING(nsGenericHTMLFormElement)
|
||||
|
||||
NS_IMPL_ELEMENT_CLONE(HTMLObjectElement)
|
||||
|
||||
// nsIConstraintValidation
|
||||
NS_IMPL_NSICONSTRAINTVALIDATION(HTMLObjectElement)
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
|
||||
static nsIWidget* GetWidget(Element* aElement)
|
||||
{
|
||||
return nsContentUtils::WidgetForDocument(aElement->OwnerDoc());
|
||||
}
|
||||
|
||||
Element* HTMLObjectElement::sLastFocused = nullptr; // Weak
|
||||
|
||||
class PluginFocusSetter : public Runnable
|
||||
{
|
||||
public:
|
||||
PluginFocusSetter(nsIWidget* aWidget, Element* aElement)
|
||||
: mWidget(aWidget), mElement(aElement)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHOD Run() override
|
||||
{
|
||||
if (mElement) {
|
||||
HTMLObjectElement::sLastFocused = mElement;
|
||||
bool value = true;
|
||||
mWidget->SetPluginFocused(value);
|
||||
} else if (!HTMLObjectElement::sLastFocused) {
|
||||
bool value = false;
|
||||
mWidget->SetPluginFocused(value);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIWidget> mWidget;
|
||||
nsCOMPtr<Element> mElement;
|
||||
};
|
||||
|
||||
void
|
||||
HTMLObjectElement::OnFocusBlurPlugin(Element* aElement, bool aFocus)
|
||||
{
|
||||
// In general we don't want to call nsIWidget::SetPluginFocused() for any
|
||||
// Element that doesn't have a plugin running. But if SetPluginFocused(true)
|
||||
// was just called for aElement while it had a plugin running, we want to
|
||||
// make sure nsIWidget::SetPluginFocused(false) gets called for it now, even
|
||||
// if aFocus is true.
|
||||
if (aFocus) {
|
||||
nsCOMPtr<nsIObjectLoadingContent> olc = do_QueryInterface(aElement);
|
||||
bool hasRunningPlugin = false;
|
||||
if (olc) {
|
||||
// nsIObjectLoadingContent::GetHasRunningPlugin() fails when
|
||||
// nsContentUtils::IsCallerChrome() returns false (which it can do even
|
||||
// when we're processing a trusted focus event). We work around this by
|
||||
// calling nsObjectLoadingContent::HasRunningPlugin() directly.
|
||||
hasRunningPlugin =
|
||||
static_cast<nsObjectLoadingContent*>(olc.get())->HasRunningPlugin();
|
||||
}
|
||||
if (!hasRunningPlugin) {
|
||||
aFocus = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (aFocus || aElement == sLastFocused) {
|
||||
if (!aFocus) {
|
||||
sLastFocused = nullptr;
|
||||
}
|
||||
nsIWidget* widget = GetWidget(aElement);
|
||||
if (widget) {
|
||||
nsContentUtils::AddScriptRunner(
|
||||
new PluginFocusSetter(widget, aFocus ? aElement : nullptr));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
HTMLObjectElement::HandlePluginCrashed(Element* aElement)
|
||||
{
|
||||
OnFocusBlurPlugin(aElement, false);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLObjectElement::HandlePluginInstantiated(Element* aElement)
|
||||
{
|
||||
// If aElement is already focused when a plugin is instantiated, we need
|
||||
// to initiate a call to nsIWidget::SetPluginFocused(true). Otherwise
|
||||
// keyboard input won't work in a click-to-play plugin until aElement
|
||||
// loses focus and regains it.
|
||||
nsIContent* focusedContent = nullptr;
|
||||
nsFocusManager *fm = nsFocusManager::GetFocusManager();
|
||||
if (fm) {
|
||||
focusedContent = fm->GetFocusedContent();
|
||||
}
|
||||
if (SameCOMIdentity(focusedContent, aElement)) {
|
||||
OnFocusBlurPlugin(aElement, true);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
HTMLObjectElement::HandleFocusBlurPlugin(Element* aElement,
|
||||
WidgetEvent* aEvent)
|
||||
{
|
||||
if (!aEvent->IsTrusted()) {
|
||||
return;
|
||||
}
|
||||
switch (aEvent->mMessage) {
|
||||
case eFocus: {
|
||||
OnFocusBlurPlugin(aElement, true);
|
||||
break;
|
||||
}
|
||||
case eBlur: {
|
||||
OnFocusBlurPlugin(aElement, false);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLObjectElement::PostHandleEvent(EventChainPostVisitor& aVisitor)
|
||||
{
|
||||
HandleFocusBlurPlugin(this, aVisitor.mEvent);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
#endif // #ifdef XP_MACOSX
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLObjectElement::GetForm(nsIDOMHTMLFormElement **aForm)
|
||||
{
|
||||
return nsGenericHTMLFormElement::GetForm(aForm);
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLObjectElement::BindToTree(nsIDocument *aDocument,
|
||||
nsIContent *aParent,
|
||||
nsIContent *aBindingParent,
|
||||
bool aCompileEventHandlers)
|
||||
{
|
||||
nsresult rv = nsGenericHTMLFormElement::BindToTree(aDocument, aParent,
|
||||
aBindingParent,
|
||||
aCompileEventHandlers);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = nsObjectLoadingContent::BindToTree(aDocument, aParent,
|
||||
aBindingParent,
|
||||
aCompileEventHandlers);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Don't kick off load from being bound to a plugin document - the plugin
|
||||
// document will call nsObjectLoadingContent::InitializeFromChannel() for the
|
||||
// initial load.
|
||||
nsCOMPtr<nsIPluginDocument> pluginDoc = do_QueryInterface(aDocument);
|
||||
|
||||
// If we already have all the children, start the load.
|
||||
if (mIsDoneAddingChildren && !pluginDoc) {
|
||||
void (HTMLObjectElement::*start)() = &HTMLObjectElement::StartObjectLoad;
|
||||
nsContentUtils::AddScriptRunner(NewRunnableMethod(this, start));
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
HTMLObjectElement::UnbindFromTree(bool aDeep,
|
||||
bool aNullParent)
|
||||
{
|
||||
#ifdef XP_MACOSX
|
||||
// When a page is reloaded (when an nsIDocument's content is removed), the
|
||||
// focused element isn't necessarily sent an eBlur event. See
|
||||
// nsFocusManager::ContentRemoved(). This means that a widget may think it
|
||||
// still contains a focused plugin when it doesn't -- which in turn can
|
||||
// disable text input in the browser window. See bug 1137229.
|
||||
OnFocusBlurPlugin(this, false);
|
||||
#endif
|
||||
nsObjectLoadingContent::UnbindFromTree(aDeep, aNullParent);
|
||||
nsGenericHTMLFormElement::UnbindFromTree(aDeep, aNullParent);
|
||||
}
|
||||
|
||||
|
||||
|
||||
nsresult
|
||||
HTMLObjectElement::SetAttr(int32_t aNameSpaceID, nsIAtom *aName,
|
||||
nsIAtom *aPrefix, const nsAString &aValue,
|
||||
bool aNotify)
|
||||
{
|
||||
nsresult rv = nsGenericHTMLFormElement::SetAttr(aNameSpaceID, aName, aPrefix,
|
||||
aValue, aNotify);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// if aNotify is false, we are coming from the parser or some such place;
|
||||
// we'll get bound after all the attributes have been set, so we'll do the
|
||||
// object load from BindToTree/DoneAddingChildren.
|
||||
// Skip the LoadObject call in that case.
|
||||
// We also don't want to start loading the object when we're not yet in
|
||||
// a document, just in case that the caller wants to set additional
|
||||
// attributes before inserting the node into the document.
|
||||
if (aNotify && IsInComposedDoc() && mIsDoneAddingChildren &&
|
||||
aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::data) {
|
||||
return LoadObject(aNotify, true);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLObjectElement::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
|
||||
bool aNotify)
|
||||
{
|
||||
nsresult rv = nsGenericHTMLFormElement::UnsetAttr(aNameSpaceID,
|
||||
aAttribute, aNotify);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// See comment in SetAttr
|
||||
if (aNotify && IsInComposedDoc() && mIsDoneAddingChildren &&
|
||||
aNameSpaceID == kNameSpaceID_None && aAttribute == nsGkAtoms::data) {
|
||||
return LoadObject(aNotify, true);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
HTMLObjectElement::IsFocusableForTabIndex()
|
||||
{
|
||||
nsIDocument* doc = GetComposedDoc();
|
||||
if (!doc || doc->HasFlag(NODE_IS_EDITABLE)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return IsEditableRoot() ||
|
||||
(Type() == eType_Document &&
|
||||
nsContentUtils::IsSubDocumentTabbable(this));
|
||||
}
|
||||
|
||||
bool
|
||||
HTMLObjectElement::IsHTMLFocusable(bool aWithMouse,
|
||||
bool *aIsFocusable, int32_t *aTabIndex)
|
||||
{
|
||||
// TODO: this should probably be managed directly by IsHTMLFocusable.
|
||||
// See bug 597242.
|
||||
nsIDocument *doc = GetComposedDoc();
|
||||
if (!doc || doc->HasFlag(NODE_IS_EDITABLE)) {
|
||||
if (aTabIndex) {
|
||||
GetTabIndex(aTabIndex);
|
||||
}
|
||||
|
||||
*aIsFocusable = false;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// This method doesn't call nsGenericHTMLFormElement intentionally.
|
||||
// TODO: It should probably be changed when bug 597242 will be fixed.
|
||||
if (Type() == eType_Plugin || IsEditableRoot() ||
|
||||
(Type() == eType_Document && nsContentUtils::IsSubDocumentTabbable(this))) {
|
||||
// Has plugin content: let the plugin decide what to do in terms of
|
||||
// internal focus from mouse clicks
|
||||
if (aTabIndex) {
|
||||
GetTabIndex(aTabIndex);
|
||||
}
|
||||
|
||||
*aIsFocusable = true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: this should probably be managed directly by IsHTMLFocusable.
|
||||
// See bug 597242.
|
||||
const nsAttrValue* attrVal = mAttrsAndChildren.GetAttr(nsGkAtoms::tabindex);
|
||||
|
||||
*aIsFocusable = attrVal && attrVal->Type() == nsAttrValue::eInteger;
|
||||
|
||||
if (aTabIndex && *aIsFocusable) {
|
||||
*aTabIndex = attrVal->GetIntegerValue();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
nsIContent::IMEState
|
||||
HTMLObjectElement::GetDesiredIMEState()
|
||||
{
|
||||
if (Type() == eType_Plugin) {
|
||||
return IMEState(IMEState::PLUGIN);
|
||||
}
|
||||
|
||||
return nsGenericHTMLFormElement::GetDesiredIMEState();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLObjectElement::Reset()
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLObjectElement::SubmitNamesValues(HTMLFormSubmission *aFormSubmission)
|
||||
{
|
||||
nsAutoString name;
|
||||
if (!GetAttr(kNameSpaceID_None, nsGkAtoms::name, name)) {
|
||||
// No name, don't submit.
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsIFrame* frame = GetPrimaryFrame();
|
||||
|
||||
nsIObjectFrame *objFrame = do_QueryFrame(frame);
|
||||
if (!objFrame) {
|
||||
// No frame, nothing to submit.
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
RefPtr<nsNPAPIPluginInstance> pi;
|
||||
objFrame->GetPluginInstance(getter_AddRefs(pi));
|
||||
if (!pi)
|
||||
return NS_OK;
|
||||
|
||||
nsAutoString value;
|
||||
nsresult rv = pi->GetFormValue(value);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return aFormSubmission->AddNameValuePair(name, value);
|
||||
}
|
||||
|
||||
NS_IMPL_STRING_ATTR(HTMLObjectElement, Align, align)
|
||||
NS_IMPL_STRING_ATTR(HTMLObjectElement, Archive, archive)
|
||||
NS_IMPL_STRING_ATTR(HTMLObjectElement, Border, border)
|
||||
NS_IMPL_STRING_ATTR(HTMLObjectElement, Code, code)
|
||||
NS_IMPL_URI_ATTR(HTMLObjectElement, CodeBase, codebase)
|
||||
NS_IMPL_STRING_ATTR(HTMLObjectElement, CodeType, codetype)
|
||||
NS_IMPL_URI_ATTR_WITH_BASE(HTMLObjectElement, Data, data, codebase)
|
||||
NS_IMPL_BOOL_ATTR(HTMLObjectElement, Declare, declare)
|
||||
NS_IMPL_STRING_ATTR(HTMLObjectElement, Height, height)
|
||||
NS_IMPL_INT_ATTR(HTMLObjectElement, Hspace, hspace)
|
||||
NS_IMPL_STRING_ATTR(HTMLObjectElement, Name, name)
|
||||
NS_IMPL_STRING_ATTR(HTMLObjectElement, Standby, standby)
|
||||
NS_IMPL_STRING_ATTR(HTMLObjectElement, Type, type)
|
||||
NS_IMPL_STRING_ATTR(HTMLObjectElement, UseMap, usemap)
|
||||
NS_IMPL_INT_ATTR(HTMLObjectElement, Vspace, vspace)
|
||||
NS_IMPL_STRING_ATTR(HTMLObjectElement, Width, width)
|
||||
|
||||
int32_t
|
||||
HTMLObjectElement::TabIndexDefault()
|
||||
{
|
||||
return IsFocusableForTabIndex() ? 0 : -1;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLObjectElement::GetContentDocument(nsIDOMDocument **aContentDocument)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aContentDocument);
|
||||
|
||||
nsCOMPtr<nsIDOMDocument> domDoc =
|
||||
do_QueryInterface(GetContentDocument(*nsContentUtils::SubjectPrincipal()));
|
||||
domDoc.forget(aContentDocument);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsPIDOMWindowOuter*
|
||||
HTMLObjectElement::GetContentWindow(nsIPrincipal& aSubjectPrincipal)
|
||||
{
|
||||
nsIDocument* doc = GetContentDocument(aSubjectPrincipal);
|
||||
if (doc) {
|
||||
return doc->GetWindow();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
HTMLObjectElement::ParseAttribute(int32_t aNamespaceID,
|
||||
nsIAtom *aAttribute,
|
||||
const nsAString &aValue,
|
||||
nsAttrValue &aResult)
|
||||
{
|
||||
if (aNamespaceID == kNameSpaceID_None) {
|
||||
if (aAttribute == nsGkAtoms::align) {
|
||||
return ParseAlignValue(aValue, aResult);
|
||||
}
|
||||
if (ParseImageAttribute(aAttribute, aValue, aResult)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return nsGenericHTMLFormElement::ParseAttribute(aNamespaceID, aAttribute,
|
||||
aValue, aResult);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLObjectElement::MapAttributesIntoRule(const nsMappedAttributes *aAttributes,
|
||||
nsRuleData *aData)
|
||||
{
|
||||
nsGenericHTMLFormElement::MapImageAlignAttributeInto(aAttributes, aData);
|
||||
nsGenericHTMLFormElement::MapImageBorderAttributeInto(aAttributes, aData);
|
||||
nsGenericHTMLFormElement::MapImageMarginAttributeInto(aAttributes, aData);
|
||||
nsGenericHTMLFormElement::MapImageSizeAttributesInto(aAttributes, aData);
|
||||
nsGenericHTMLFormElement::MapCommonAttributesInto(aAttributes, aData);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(bool)
|
||||
HTMLObjectElement::IsAttributeMapped(const nsIAtom *aAttribute) const
|
||||
{
|
||||
static const MappedAttributeEntry* const map[] = {
|
||||
sCommonAttributeMap,
|
||||
sImageMarginSizeAttributeMap,
|
||||
sImageBorderAttributeMap,
|
||||
sImageAlignAttributeMap,
|
||||
};
|
||||
|
||||
return FindAttributeDependence(aAttribute, map);
|
||||
}
|
||||
|
||||
|
||||
nsMapRuleToAttributesFunc
|
||||
HTMLObjectElement::GetAttributeMappingFunction() const
|
||||
{
|
||||
return &MapAttributesIntoRule;
|
||||
}
|
||||
|
||||
void
|
||||
HTMLObjectElement::StartObjectLoad(bool aNotify)
|
||||
{
|
||||
// BindToTree can call us asynchronously, and we may be removed from the tree
|
||||
// in the interim
|
||||
if (!IsInComposedDoc() || !OwnerDoc()->IsActive()) {
|
||||
return;
|
||||
}
|
||||
|
||||
LoadObject(aNotify);
|
||||
SetIsNetworkCreated(false);
|
||||
}
|
||||
|
||||
EventStates
|
||||
HTMLObjectElement::IntrinsicState() const
|
||||
{
|
||||
return nsGenericHTMLFormElement::IntrinsicState() | ObjectState();
|
||||
}
|
||||
|
||||
uint32_t
|
||||
HTMLObjectElement::GetCapabilities() const
|
||||
{
|
||||
return nsObjectLoadingContent::GetCapabilities() | eSupportClassID;
|
||||
}
|
||||
|
||||
void
|
||||
HTMLObjectElement::DestroyContent()
|
||||
{
|
||||
nsObjectLoadingContent::DestroyContent();
|
||||
nsGenericHTMLFormElement::DestroyContent();
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLObjectElement::CopyInnerTo(Element* aDest)
|
||||
{
|
||||
nsresult rv = nsGenericHTMLFormElement::CopyInnerTo(aDest);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (aDest->OwnerDoc()->IsStaticDocument()) {
|
||||
CreateStaticClone(static_cast<HTMLObjectElement*>(aDest));
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
HTMLObjectElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
JS::Rooted<JSObject*> obj(aCx,
|
||||
HTMLObjectElementBinding::Wrap(aCx, this, aGivenProto));
|
||||
if (!obj) {
|
||||
return nullptr;
|
||||
}
|
||||
SetupProtoChain(aCx, obj);
|
||||
return obj;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER(Object)
|
||||
280
dom/html/HTMLObjectElement.h
Normal file
280
dom/html/HTMLObjectElement.h
Normal file
|
|
@ -0,0 +1,280 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_dom_HTMLObjectElement_h
|
||||
#define mozilla_dom_HTMLObjectElement_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsGenericHTMLElement.h"
|
||||
#include "nsObjectLoadingContent.h"
|
||||
#include "nsIDOMHTMLObjectElement.h"
|
||||
#include "nsIConstraintValidation.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class HTMLFormSubmission;
|
||||
|
||||
class HTMLObjectElement final : public nsGenericHTMLFormElement
|
||||
, public nsObjectLoadingContent
|
||||
, public nsIDOMHTMLObjectElement
|
||||
, public nsIConstraintValidation
|
||||
{
|
||||
public:
|
||||
explicit HTMLObjectElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo,
|
||||
FromParser aFromParser = NOT_FROM_PARSER);
|
||||
|
||||
// nsISupports
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
NS_IMPL_FROMCONTENT_HTML_WITH_TAG(HTMLObjectElement, object)
|
||||
virtual int32_t TabIndexDefault() override;
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
// nsIDOMEventTarget
|
||||
NS_IMETHOD PostHandleEvent(EventChainPostVisitor& aVisitor) override;
|
||||
// Helper methods
|
||||
static void OnFocusBlurPlugin(Element* aElement, bool aFocus);
|
||||
static void HandleFocusBlurPlugin(Element* aElement, WidgetEvent* aEvent);
|
||||
static void HandlePluginCrashed(Element* aElement);
|
||||
static void HandlePluginInstantiated(Element* aElement);
|
||||
// Weak pointer. Null if last action was blur.
|
||||
static Element* sLastFocused;
|
||||
#endif
|
||||
|
||||
// Element
|
||||
virtual bool IsInteractiveHTMLContent(bool aIgnoreTabindex) const override;
|
||||
|
||||
// EventTarget
|
||||
virtual void AsyncEventRunning(AsyncEventDispatcher* aEvent) override;
|
||||
|
||||
// nsIDOMHTMLObjectElement
|
||||
NS_DECL_NSIDOMHTMLOBJECTELEMENT
|
||||
|
||||
virtual nsresult BindToTree(nsIDocument *aDocument, nsIContent *aParent,
|
||||
nsIContent *aBindingParent,
|
||||
bool aCompileEventHandlers) override;
|
||||
virtual void UnbindFromTree(bool aDeep = true,
|
||||
bool aNullParent = true) override;
|
||||
virtual nsresult SetAttr(int32_t aNameSpaceID, nsIAtom *aName,
|
||||
nsIAtom *aPrefix, const nsAString &aValue,
|
||||
bool aNotify) override;
|
||||
virtual nsresult UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
|
||||
bool aNotify) override;
|
||||
|
||||
virtual bool IsHTMLFocusable(bool aWithMouse, bool *aIsFocusable, int32_t *aTabIndex) override;
|
||||
virtual IMEState GetDesiredIMEState() override;
|
||||
|
||||
// Overriden nsIFormControl methods
|
||||
NS_IMETHOD_(uint32_t) GetType() const override
|
||||
{
|
||||
return NS_FORM_OBJECT;
|
||||
}
|
||||
|
||||
NS_IMETHOD Reset() override;
|
||||
NS_IMETHOD SubmitNamesValues(HTMLFormSubmission *aFormSubmission) override;
|
||||
|
||||
virtual bool IsDisabled() const override { return false; }
|
||||
|
||||
virtual void DoneAddingChildren(bool aHaveNotified) override;
|
||||
virtual bool IsDoneAddingChildren() override;
|
||||
|
||||
virtual bool ParseAttribute(int32_t aNamespaceID,
|
||||
nsIAtom *aAttribute,
|
||||
const nsAString &aValue,
|
||||
nsAttrValue &aResult) override;
|
||||
virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const override;
|
||||
NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom *aAttribute) const override;
|
||||
virtual EventStates IntrinsicState() const override;
|
||||
virtual void DestroyContent() override;
|
||||
|
||||
// nsObjectLoadingContent
|
||||
virtual uint32_t GetCapabilities() const override;
|
||||
|
||||
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
|
||||
|
||||
nsresult CopyInnerTo(Element* aDest);
|
||||
|
||||
void StartObjectLoad() { StartObjectLoad(true); }
|
||||
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLObjectElement,
|
||||
nsGenericHTMLFormElement)
|
||||
|
||||
// Web IDL binding methods
|
||||
// XPCOM GetData is ok; note that it's a URI attribute with a weird base URI
|
||||
void SetData(const nsAString& aValue, ErrorResult& aRv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::data, aValue, aRv);
|
||||
}
|
||||
void GetType(DOMString& aValue)
|
||||
{
|
||||
GetHTMLAttr(nsGkAtoms::type, aValue);
|
||||
}
|
||||
void SetType(const nsAString& aValue, ErrorResult& aRv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::type, aValue, aRv);
|
||||
}
|
||||
bool TypeMustMatch()
|
||||
{
|
||||
return GetBoolAttr(nsGkAtoms::typemustmatch);
|
||||
}
|
||||
void SetTypeMustMatch(bool aValue, ErrorResult& aRv)
|
||||
{
|
||||
SetHTMLBoolAttr(nsGkAtoms::typemustmatch, aValue, aRv);
|
||||
}
|
||||
void GetName(DOMString& aValue)
|
||||
{
|
||||
GetHTMLAttr(nsGkAtoms::name, aValue);
|
||||
}
|
||||
void SetName(const nsAString& aValue, ErrorResult& aRv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::name, aValue, aRv);
|
||||
}
|
||||
void GetUseMap(DOMString& aValue)
|
||||
{
|
||||
GetHTMLAttr(nsGkAtoms::usemap, aValue);
|
||||
}
|
||||
void SetUseMap(const nsAString& aValue, ErrorResult& aRv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::usemap, aValue, aRv);
|
||||
}
|
||||
using nsGenericHTMLFormElement::GetForm;
|
||||
void GetWidth(DOMString& aValue)
|
||||
{
|
||||
GetHTMLAttr(nsGkAtoms::width, aValue);
|
||||
}
|
||||
void SetWidth(const nsAString& aValue, ErrorResult& aRv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::width, aValue, aRv);
|
||||
}
|
||||
void GetHeight(DOMString& aValue)
|
||||
{
|
||||
GetHTMLAttr(nsGkAtoms::height, aValue);
|
||||
}
|
||||
void SetHeight(const nsAString& aValue, ErrorResult& aRv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::height, aValue, aRv);
|
||||
}
|
||||
using nsObjectLoadingContent::GetContentDocument;
|
||||
|
||||
nsPIDOMWindowOuter*
|
||||
GetContentWindow(nsIPrincipal& aSubjectPrincipal);
|
||||
|
||||
using nsIConstraintValidation::CheckValidity;
|
||||
using nsIConstraintValidation::ReportValidity;
|
||||
using nsIConstraintValidation::GetValidationMessage;
|
||||
void GetAlign(DOMString& aValue)
|
||||
{
|
||||
GetHTMLAttr(nsGkAtoms::align, aValue);
|
||||
}
|
||||
void SetAlign(const nsAString& aValue, ErrorResult& aRv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::align, aValue, aRv);
|
||||
}
|
||||
void GetArchive(DOMString& aValue)
|
||||
{
|
||||
GetHTMLAttr(nsGkAtoms::archive, aValue);
|
||||
}
|
||||
void SetArchive(const nsAString& aValue, ErrorResult& aRv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::archive, aValue, aRv);
|
||||
}
|
||||
// XPCOM GetCode is ok
|
||||
void SetCode(const nsAString& aValue, ErrorResult& aRv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::code, aValue, aRv);
|
||||
}
|
||||
bool Declare()
|
||||
{
|
||||
return GetBoolAttr(nsGkAtoms::declare);
|
||||
}
|
||||
void SetDeclare(bool aValue, ErrorResult& aRv)
|
||||
{
|
||||
SetHTMLBoolAttr(nsGkAtoms::declare, aValue, aRv);
|
||||
}
|
||||
uint32_t Hspace()
|
||||
{
|
||||
return GetUnsignedIntAttr(nsGkAtoms::hspace, 0);
|
||||
}
|
||||
void SetHspace(uint32_t aValue, ErrorResult& aRv)
|
||||
{
|
||||
SetUnsignedIntAttr(nsGkAtoms::hspace, aValue, 0, aRv);
|
||||
}
|
||||
void GetStandby(DOMString& aValue)
|
||||
{
|
||||
GetHTMLAttr(nsGkAtoms::standby, aValue);
|
||||
}
|
||||
void SetStandby(const nsAString& aValue, ErrorResult& aRv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::standby, aValue, aRv);
|
||||
}
|
||||
uint32_t Vspace()
|
||||
{
|
||||
return GetUnsignedIntAttr(nsGkAtoms::vspace, 0);
|
||||
}
|
||||
void SetVspace(uint32_t aValue, ErrorResult& aRv)
|
||||
{
|
||||
SetUnsignedIntAttr(nsGkAtoms::vspace, aValue, 0, aRv);
|
||||
}
|
||||
// XPCOM GetCodebase is ok; note that it's a URI attribute
|
||||
void SetCodeBase(const nsAString& aValue, ErrorResult& aRv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::codebase, aValue, aRv);
|
||||
}
|
||||
void GetCodeType(DOMString& aValue)
|
||||
{
|
||||
GetHTMLAttr(nsGkAtoms::codetype, aValue);
|
||||
}
|
||||
void SetCodeType(const nsAString& aValue, ErrorResult& aRv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::codetype, aValue, aRv);
|
||||
}
|
||||
void GetBorder(DOMString& aValue)
|
||||
{
|
||||
GetHTMLAttr(nsGkAtoms::border, aValue);
|
||||
}
|
||||
void SetBorder(const nsAString& aValue, ErrorResult& aRv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::border, aValue, aRv);
|
||||
}
|
||||
|
||||
nsIDocument*
|
||||
GetSVGDocument(nsIPrincipal& aSubjectPrincipal)
|
||||
{
|
||||
return GetContentDocument(aSubjectPrincipal);
|
||||
}
|
||||
|
||||
private:
|
||||
/**
|
||||
* Calls LoadObject with the correct arguments to start the plugin load.
|
||||
*/
|
||||
void StartObjectLoad(bool aNotify);
|
||||
|
||||
/**
|
||||
* Returns if the element is currently focusable regardless of it's tabindex
|
||||
* value. This is used to know the default tabindex value.
|
||||
*/
|
||||
bool IsFocusableForTabIndex();
|
||||
|
||||
nsContentPolicyType GetContentPolicyType() const override
|
||||
{
|
||||
return nsIContentPolicy::TYPE_INTERNAL_OBJECT;
|
||||
}
|
||||
|
||||
virtual ~HTMLObjectElement();
|
||||
|
||||
virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
|
||||
nsRuleData* aData);
|
||||
|
||||
bool mIsDoneAddingChildren;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_HTMLObjectElement_h
|
||||
146
dom/html/HTMLOptGroupElement.cpp
Normal file
146
dom/html/HTMLOptGroupElement.cpp
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
/* -*- 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/EventDispatcher.h"
|
||||
#include "mozilla/EventStates.h"
|
||||
#include "mozilla/dom/HTMLOptGroupElement.h"
|
||||
#include "mozilla/dom/HTMLOptGroupElementBinding.h"
|
||||
#include "mozilla/dom/HTMLSelectElement.h" // SafeOptionListMutation
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsStyleConsts.h"
|
||||
#include "nsIFrame.h"
|
||||
#include "nsIFormControlFrame.h"
|
||||
|
||||
NS_IMPL_NS_NEW_HTML_ELEMENT(OptGroup)
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
/**
|
||||
* The implementation of <optgroup>
|
||||
*/
|
||||
|
||||
|
||||
|
||||
HTMLOptGroupElement::HTMLOptGroupElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
|
||||
: nsGenericHTMLElement(aNodeInfo)
|
||||
{
|
||||
// We start off enabled
|
||||
AddStatesSilently(NS_EVENT_STATE_ENABLED);
|
||||
}
|
||||
|
||||
HTMLOptGroupElement::~HTMLOptGroupElement()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED(HTMLOptGroupElement, nsGenericHTMLElement,
|
||||
nsIDOMHTMLOptGroupElement)
|
||||
|
||||
NS_IMPL_ELEMENT_CLONE(HTMLOptGroupElement)
|
||||
|
||||
|
||||
NS_IMPL_BOOL_ATTR(HTMLOptGroupElement, Disabled, disabled)
|
||||
NS_IMPL_STRING_ATTR(HTMLOptGroupElement, Label, label)
|
||||
|
||||
|
||||
nsresult
|
||||
HTMLOptGroupElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
{
|
||||
aVisitor.mCanHandle = false;
|
||||
// Do not process any DOM events if the element is disabled
|
||||
// XXXsmaug This is not the right thing to do. But what is?
|
||||
if (HasAttr(kNameSpaceID_None, nsGkAtoms::disabled)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsIFrame* frame = GetPrimaryFrame();
|
||||
if (frame) {
|
||||
const nsStyleUserInterface* uiStyle = frame->StyleUserInterface();
|
||||
if (uiStyle->mUserInput == StyleUserInput::None ||
|
||||
uiStyle->mUserInput == StyleUserInput::Disabled) {
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return nsGenericHTMLElement::PreHandleEvent(aVisitor);
|
||||
}
|
||||
|
||||
Element*
|
||||
HTMLOptGroupElement::GetSelect()
|
||||
{
|
||||
Element* parent = nsINode::GetParentElement();
|
||||
if (!parent || !parent->IsHTMLElement(nsGkAtoms::select)) {
|
||||
return nullptr;
|
||||
}
|
||||
return parent;
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLOptGroupElement::InsertChildAt(nsIContent* aKid,
|
||||
uint32_t aIndex,
|
||||
bool aNotify)
|
||||
{
|
||||
SafeOptionListMutation safeMutation(GetSelect(), this, aKid, aIndex, aNotify);
|
||||
nsresult rv = nsGenericHTMLElement::InsertChildAt(aKid, aIndex, aNotify);
|
||||
if (NS_FAILED(rv)) {
|
||||
safeMutation.MutationFailed();
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
void
|
||||
HTMLOptGroupElement::RemoveChildAt(uint32_t aIndex, bool aNotify)
|
||||
{
|
||||
SafeOptionListMutation safeMutation(GetSelect(), this, nullptr, aIndex,
|
||||
aNotify);
|
||||
nsGenericHTMLElement::RemoveChildAt(aIndex, aNotify);
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLOptGroupElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
const nsAttrValue* aValue, bool aNotify)
|
||||
{
|
||||
if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::disabled) {
|
||||
// All our children <option> have their :disabled state depending on our
|
||||
// disabled attribute. We should make sure their state is updated.
|
||||
for (nsIContent* child = nsINode::GetFirstChild(); child;
|
||||
child = child->GetNextSibling()) {
|
||||
if (child->IsHTMLElement(nsGkAtoms::option)) {
|
||||
// No need to call |IsElement()| because it's an HTML element.
|
||||
child->AsElement()->UpdateState(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName, aValue,
|
||||
aNotify);
|
||||
}
|
||||
|
||||
EventStates
|
||||
HTMLOptGroupElement::IntrinsicState() const
|
||||
{
|
||||
EventStates state = nsGenericHTMLElement::IntrinsicState();
|
||||
|
||||
if (HasAttr(kNameSpaceID_None, nsGkAtoms::disabled)) {
|
||||
state |= NS_EVENT_STATE_DISABLED;
|
||||
state &= ~NS_EVENT_STATE_ENABLED;
|
||||
} else {
|
||||
state &= ~NS_EVENT_STATE_DISABLED;
|
||||
state |= NS_EVENT_STATE_ENABLED;
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
HTMLOptGroupElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return HTMLOptGroupElementBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
85
dom/html/HTMLOptGroupElement.h
Normal file
85
dom/html/HTMLOptGroupElement.h
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_dom_HTMLOptGroupElement_h
|
||||
#define mozilla_dom_HTMLOptGroupElement_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsIDOMHTMLOptGroupElement.h"
|
||||
#include "nsGenericHTMLElement.h"
|
||||
|
||||
namespace mozilla {
|
||||
class EventChainPreVisitor;
|
||||
namespace dom {
|
||||
|
||||
class HTMLOptGroupElement final : public nsGenericHTMLElement,
|
||||
public nsIDOMHTMLOptGroupElement
|
||||
{
|
||||
public:
|
||||
explicit HTMLOptGroupElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
|
||||
|
||||
NS_IMPL_FROMCONTENT_HTML_WITH_TAG(HTMLOptGroupElement, optgroup)
|
||||
|
||||
// nsISupports
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
// nsIDOMHTMLOptGroupElement
|
||||
NS_DECL_NSIDOMHTMLOPTGROUPELEMENT
|
||||
|
||||
// nsINode
|
||||
virtual nsresult InsertChildAt(nsIContent* aKid, uint32_t aIndex,
|
||||
bool aNotify) override;
|
||||
virtual void RemoveChildAt(uint32_t aIndex, bool aNotify) override;
|
||||
|
||||
// nsIContent
|
||||
virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override;
|
||||
|
||||
virtual EventStates IntrinsicState() const override;
|
||||
|
||||
virtual nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult) const override;
|
||||
|
||||
virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
const nsAttrValue* aValue, bool aNotify) override;
|
||||
|
||||
virtual nsIDOMNode* AsDOMNode() override { return this; }
|
||||
|
||||
virtual bool IsDisabled() const override {
|
||||
return HasAttr(kNameSpaceID_None, nsGkAtoms::disabled);
|
||||
}
|
||||
|
||||
bool Disabled() const
|
||||
{
|
||||
return GetBoolAttr(nsGkAtoms::disabled);
|
||||
}
|
||||
void SetDisabled(bool aValue, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLBoolAttr(nsGkAtoms::disabled, aValue, aError);
|
||||
}
|
||||
|
||||
// The XPCOM GetLabel is OK for us
|
||||
void SetLabel(const nsAString& aLabel, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::label, aLabel, aError);
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual ~HTMLOptGroupElement();
|
||||
|
||||
virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* Get the select content element that contains this option
|
||||
* @param aSelectElement the select element [OUT]
|
||||
*/
|
||||
Element* GetSelect();
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* mozilla_dom_HTMLOptGroupElement_h */
|
||||
458
dom/html/HTMLOptionElement.cpp
Normal file
458
dom/html/HTMLOptionElement.cpp
Normal file
|
|
@ -0,0 +1,458 @@
|
|||
/* -*- 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/HTMLOptionElement.h"
|
||||
#include "mozilla/dom/HTMLOptionElementBinding.h"
|
||||
#include "mozilla/dom/HTMLSelectElement.h"
|
||||
#include "nsIDOMHTMLOptGroupElement.h"
|
||||
#include "nsIDOMHTMLFormElement.h"
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsStyleConsts.h"
|
||||
#include "nsIFormControl.h"
|
||||
#include "nsIForm.h"
|
||||
#include "nsIDOMNode.h"
|
||||
#include "nsIDOMHTMLCollection.h"
|
||||
#include "nsISelectControlFrame.h"
|
||||
|
||||
// Notify/query select frame for selected state
|
||||
#include "nsIFormControlFrame.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIDOMHTMLSelectElement.h"
|
||||
#include "nsNodeInfoManager.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "mozilla/EventStates.h"
|
||||
#include "nsContentCreatorFunctions.h"
|
||||
#include "mozAutoDocUpdate.h"
|
||||
#include "nsTextNode.h"
|
||||
|
||||
/**
|
||||
* Implementation of <option>
|
||||
*/
|
||||
|
||||
NS_IMPL_NS_NEW_HTML_ELEMENT(Option)
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
HTMLOptionElement::HTMLOptionElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
|
||||
: nsGenericHTMLElement(aNodeInfo),
|
||||
mSelectedChanged(false),
|
||||
mIsSelected(false),
|
||||
mIsInSetDefaultSelected(false)
|
||||
{
|
||||
// We start off enabled
|
||||
AddStatesSilently(NS_EVENT_STATE_ENABLED);
|
||||
}
|
||||
|
||||
HTMLOptionElement::~HTMLOptionElement()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED(HTMLOptionElement, nsGenericHTMLElement,
|
||||
nsIDOMHTMLOptionElement)
|
||||
|
||||
NS_IMPL_ELEMENT_CLONE(HTMLOptionElement)
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLOptionElement::GetForm(nsIDOMHTMLFormElement** aForm)
|
||||
{
|
||||
NS_IF_ADDREF(*aForm = GetForm());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mozilla::dom::HTMLFormElement*
|
||||
HTMLOptionElement::GetForm()
|
||||
{
|
||||
HTMLSelectElement* selectControl = GetSelect();
|
||||
return selectControl ? selectControl->GetForm() : nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
HTMLOptionElement::SetSelectedInternal(bool aValue, bool aNotify)
|
||||
{
|
||||
mSelectedChanged = true;
|
||||
mIsSelected = aValue;
|
||||
|
||||
// When mIsInSetDefaultSelected is true, the state change will be handled by
|
||||
// SetAttr/UnsetAttr.
|
||||
if (!mIsInSetDefaultSelected) {
|
||||
UpdateState(aNotify);
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLOptionElement::GetSelected(bool* aValue)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aValue);
|
||||
*aValue = Selected();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLOptionElement::SetSelected(bool aValue)
|
||||
{
|
||||
// Note: The select content obj maintains all the PresState
|
||||
// so defer to it to get the answer
|
||||
HTMLSelectElement* selectInt = GetSelect();
|
||||
if (selectInt) {
|
||||
int32_t index = Index();
|
||||
uint32_t mask = HTMLSelectElement::SET_DISABLED | HTMLSelectElement::NOTIFY;
|
||||
if (aValue) {
|
||||
mask |= HTMLSelectElement::IS_SELECTED;
|
||||
}
|
||||
|
||||
// This should end up calling SetSelectedInternal
|
||||
selectInt->SetOptionsSelectedByIndex(index, index, mask);
|
||||
} else {
|
||||
SetSelectedInternal(aValue, true);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMPL_BOOL_ATTR(HTMLOptionElement, DefaultSelected, selected)
|
||||
// GetText returns a whitespace compressed .textContent value.
|
||||
NS_IMPL_STRING_ATTR_WITH_FALLBACK(HTMLOptionElement, Label, label, GetText)
|
||||
NS_IMPL_STRING_ATTR_WITH_FALLBACK(HTMLOptionElement, Value, value, GetText)
|
||||
NS_IMPL_BOOL_ATTR(HTMLOptionElement, Disabled, disabled)
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLOptionElement::GetIndex(int32_t* aIndex)
|
||||
{
|
||||
*aIndex = Index();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
int32_t
|
||||
HTMLOptionElement::Index()
|
||||
{
|
||||
static int32_t defaultIndex = 0;
|
||||
|
||||
// Only select elements can contain a list of options.
|
||||
HTMLSelectElement* selectElement = GetSelect();
|
||||
if (!selectElement) {
|
||||
return defaultIndex;
|
||||
}
|
||||
|
||||
HTMLOptionsCollection* options = selectElement->GetOptions();
|
||||
if (!options) {
|
||||
return defaultIndex;
|
||||
}
|
||||
|
||||
int32_t index = defaultIndex;
|
||||
MOZ_ALWAYS_SUCCEEDS(options->GetOptionIndex(this, 0, true, &index));
|
||||
return index;
|
||||
}
|
||||
|
||||
bool
|
||||
HTMLOptionElement::Selected() const
|
||||
{
|
||||
// If we haven't been explictly selected or deselected, use our default value
|
||||
if (!mSelectedChanged) {
|
||||
return DefaultSelected();
|
||||
}
|
||||
|
||||
return mIsSelected;
|
||||
}
|
||||
|
||||
bool
|
||||
HTMLOptionElement::DefaultSelected() const
|
||||
{
|
||||
return HasAttr(kNameSpaceID_None, nsGkAtoms::selected);
|
||||
}
|
||||
|
||||
nsChangeHint
|
||||
HTMLOptionElement::GetAttributeChangeHint(const nsIAtom* aAttribute,
|
||||
int32_t aModType) const
|
||||
{
|
||||
nsChangeHint retval =
|
||||
nsGenericHTMLElement::GetAttributeChangeHint(aAttribute, aModType);
|
||||
|
||||
if (aAttribute == nsGkAtoms::label ||
|
||||
aAttribute == nsGkAtoms::text) {
|
||||
retval |= NS_STYLE_HINT_REFLOW;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLOptionElement::BeforeSetAttr(int32_t aNamespaceID, nsIAtom* aName,
|
||||
nsAttrValueOrString* aValue,
|
||||
bool aNotify)
|
||||
{
|
||||
nsresult rv = nsGenericHTMLElement::BeforeSetAttr(aNamespaceID, aName,
|
||||
aValue, aNotify);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (aNamespaceID != kNameSpaceID_None || aName != nsGkAtoms::selected ||
|
||||
mSelectedChanged) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool defaultSelected = aValue;
|
||||
// First make sure we actually set our mIsSelected state to reflect our new
|
||||
// defaultSelected state. If that turns out to be wrong,
|
||||
// SetOptionsSelectedByIndex will fix it up. But otherwise we can end up in a
|
||||
// situation where mIsSelected is still false, but mSelectedChanged becomes
|
||||
// true (later in this method, when we compare mIsSelected to
|
||||
// defaultSelected), and then we start returning false for Selected() even
|
||||
// though we're actually selected.
|
||||
mIsSelected = defaultSelected;
|
||||
|
||||
// We just changed out selected state (since we look at the "selected"
|
||||
// attribute when mSelectedChanged is false). Let's tell our select about
|
||||
// it.
|
||||
HTMLSelectElement* selectInt = GetSelect();
|
||||
if (!selectInt) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_ASSERTION(!mSelectedChanged, "Shouldn't be here");
|
||||
|
||||
bool inSetDefaultSelected = mIsInSetDefaultSelected;
|
||||
mIsInSetDefaultSelected = true;
|
||||
|
||||
int32_t index = Index();
|
||||
uint32_t mask = HTMLSelectElement::SET_DISABLED;
|
||||
if (defaultSelected) {
|
||||
mask |= HTMLSelectElement::IS_SELECTED;
|
||||
}
|
||||
|
||||
if (aNotify) {
|
||||
mask |= HTMLSelectElement::NOTIFY;
|
||||
}
|
||||
|
||||
// This can end up calling SetSelectedInternal if our selected state needs to
|
||||
// change, which we will allow to take effect so that parts of
|
||||
// SetOptionsSelectedByIndex that might depend on it working don't get
|
||||
// confused.
|
||||
selectInt->SetOptionsSelectedByIndex(index, index, mask);
|
||||
|
||||
// Now reset our members; when we finish the attr set we'll end up with the
|
||||
// rigt selected state.
|
||||
mIsInSetDefaultSelected = inSetDefaultSelected;
|
||||
// mIsSelected might have been changed by SetOptionsSelectedByIndex. Possibly
|
||||
// more than once; make sure our mSelectedChanged state is set correctly.
|
||||
mSelectedChanged = mIsSelected != defaultSelected;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLOptionElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
const nsAttrValue* aValue, bool aNotify)
|
||||
{
|
||||
if (aNameSpaceID == kNameSpaceID_None &&
|
||||
aName == nsGkAtoms::value && Selected()) {
|
||||
// Since this option is selected, changing value
|
||||
// may have changed missing validity state of the
|
||||
// Select element
|
||||
HTMLSelectElement* select = GetSelect();
|
||||
if (select) {
|
||||
select->UpdateValueMissingValidityState();
|
||||
}
|
||||
}
|
||||
|
||||
return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName,
|
||||
aValue, aNotify);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLOptionElement::GetText(nsAString& aText)
|
||||
{
|
||||
nsAutoString text;
|
||||
|
||||
nsIContent* child = nsINode::GetFirstChild();
|
||||
while (child) {
|
||||
if (child->NodeType() == nsIDOMNode::TEXT_NODE ||
|
||||
child->NodeType() == nsIDOMNode::CDATA_SECTION_NODE) {
|
||||
child->AppendTextTo(text);
|
||||
}
|
||||
if (child->IsHTMLElement(nsGkAtoms::script) ||
|
||||
child->IsSVGElement(nsGkAtoms::script)) {
|
||||
child = child->GetNextNonChildNode(this);
|
||||
} else {
|
||||
child = child->GetNextNode(this);
|
||||
}
|
||||
}
|
||||
|
||||
// XXX No CompressWhitespace for nsAString. Sad.
|
||||
text.CompressWhitespace(true, true);
|
||||
aText = text;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLOptionElement::SetText(const nsAString& aText)
|
||||
{
|
||||
return nsContentUtils::SetNodeTextContent(this, aText, true);
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLOptionElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
||||
nsIContent* aBindingParent,
|
||||
bool aCompileEventHandlers)
|
||||
{
|
||||
nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent,
|
||||
aBindingParent,
|
||||
aCompileEventHandlers);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Our new parent might change :disabled/:enabled state.
|
||||
UpdateState(false);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
HTMLOptionElement::UnbindFromTree(bool aDeep, bool aNullParent)
|
||||
{
|
||||
nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
|
||||
|
||||
// Our previous parent could have been involved in :disabled/:enabled state.
|
||||
UpdateState(false);
|
||||
}
|
||||
|
||||
EventStates
|
||||
HTMLOptionElement::IntrinsicState() const
|
||||
{
|
||||
EventStates state = nsGenericHTMLElement::IntrinsicState();
|
||||
if (Selected()) {
|
||||
state |= NS_EVENT_STATE_CHECKED;
|
||||
}
|
||||
if (DefaultSelected()) {
|
||||
state |= NS_EVENT_STATE_DEFAULT;
|
||||
}
|
||||
|
||||
// An <option> is disabled if it has @disabled set or if it's <optgroup> has
|
||||
// @disabled set.
|
||||
if (HasAttr(kNameSpaceID_None, nsGkAtoms::disabled)) {
|
||||
state |= NS_EVENT_STATE_DISABLED;
|
||||
state &= ~NS_EVENT_STATE_ENABLED;
|
||||
} else {
|
||||
nsIContent* parent = GetParent();
|
||||
if (parent && parent->IsHTMLElement(nsGkAtoms::optgroup) &&
|
||||
parent->HasAttr(kNameSpaceID_None, nsGkAtoms::disabled)) {
|
||||
state |= NS_EVENT_STATE_DISABLED;
|
||||
state &= ~NS_EVENT_STATE_ENABLED;
|
||||
} else {
|
||||
state &= ~NS_EVENT_STATE_DISABLED;
|
||||
state |= NS_EVENT_STATE_ENABLED;
|
||||
}
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
// Get the select content element that contains this option
|
||||
HTMLSelectElement*
|
||||
HTMLOptionElement::GetSelect()
|
||||
{
|
||||
nsIContent* parent = GetParent();
|
||||
if (!parent) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
HTMLSelectElement* select = HTMLSelectElement::FromContent(parent);
|
||||
if (select) {
|
||||
return select;
|
||||
}
|
||||
|
||||
if (!parent->IsHTMLElement(nsGkAtoms::optgroup)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return HTMLSelectElement::FromContentOrNull(parent->GetParent());
|
||||
}
|
||||
|
||||
already_AddRefed<HTMLOptionElement>
|
||||
HTMLOptionElement::Option(const GlobalObject& aGlobal,
|
||||
const Optional<nsAString>& aText,
|
||||
const Optional<nsAString>& aValue,
|
||||
const Optional<bool>& aDefaultSelected,
|
||||
const Optional<bool>& aSelected, ErrorResult& aError)
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindowInner> win = do_QueryInterface(aGlobal.GetAsSupports());
|
||||
nsIDocument* doc;
|
||||
if (!win || !(doc = win->GetExtantDoc())) {
|
||||
aError.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
already_AddRefed<mozilla::dom::NodeInfo> nodeInfo =
|
||||
doc->NodeInfoManager()->GetNodeInfo(nsGkAtoms::option, nullptr,
|
||||
kNameSpaceID_XHTML,
|
||||
nsIDOMNode::ELEMENT_NODE);
|
||||
|
||||
RefPtr<HTMLOptionElement> option = new HTMLOptionElement(nodeInfo);
|
||||
|
||||
if (aText.WasPassed()) {
|
||||
// Create a new text node and append it to the option
|
||||
RefPtr<nsTextNode> textContent =
|
||||
new nsTextNode(option->NodeInfo()->NodeInfoManager());
|
||||
|
||||
textContent->SetText(aText.Value(), false);
|
||||
|
||||
aError = option->AppendChildTo(textContent, false);
|
||||
if (aError.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (aValue.WasPassed()) {
|
||||
// Set the value attribute for this element. We're calling SetAttr
|
||||
// directly because we want to pass aNotify == false.
|
||||
aError = option->SetAttr(kNameSpaceID_None, nsGkAtoms::value,
|
||||
aValue.Value(), false);
|
||||
if (aError.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (aDefaultSelected.WasPassed()) {
|
||||
if (aDefaultSelected.Value()) {
|
||||
// We're calling SetAttr directly because we want to pass
|
||||
// aNotify == false.
|
||||
aError = option->SetAttr(kNameSpaceID_None, nsGkAtoms::selected,
|
||||
EmptyString(), false);
|
||||
if (aError.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (aSelected.WasPassed()) {
|
||||
option->SetSelected(aSelected.Value(), aError);
|
||||
if (aError.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return option.forget();
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLOptionElement::CopyInnerTo(Element* aDest)
|
||||
{
|
||||
nsresult rv = nsGenericHTMLElement::CopyInnerTo(aDest);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (aDest->OwnerDoc()->IsStaticDocument()) {
|
||||
static_cast<HTMLOptionElement*>(aDest)->SetSelected(Selected());
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
HTMLOptionElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return HTMLOptionElementBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
141
dom/html/HTMLOptionElement.h
Normal file
141
dom/html/HTMLOptionElement.h
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_dom_HTMLOptionElement_h__
|
||||
#define mozilla_dom_HTMLOptionElement_h__
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsGenericHTMLElement.h"
|
||||
#include "nsIDOMHTMLOptionElement.h"
|
||||
#include "mozilla/dom/HTMLFormElement.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class HTMLSelectElement;
|
||||
|
||||
class HTMLOptionElement final : public nsGenericHTMLElement,
|
||||
public nsIDOMHTMLOptionElement
|
||||
{
|
||||
public:
|
||||
explicit HTMLOptionElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
|
||||
|
||||
static already_AddRefed<HTMLOptionElement>
|
||||
Option(const GlobalObject& aGlobal,
|
||||
const Optional<nsAString>& aText,
|
||||
const Optional<nsAString>& aValue,
|
||||
const Optional<bool>& aDefaultSelected,
|
||||
const Optional<bool>& aSelected, ErrorResult& aError);
|
||||
|
||||
NS_IMPL_FROMCONTENT_HTML_WITH_TAG(HTMLOptionElement, option)
|
||||
|
||||
// nsISupports
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
// nsIDOMHTMLOptionElement
|
||||
using mozilla::dom::Element::SetText;
|
||||
using mozilla::dom::Element::GetText;
|
||||
NS_DECL_NSIDOMHTMLOPTIONELEMENT
|
||||
|
||||
bool Selected() const;
|
||||
bool DefaultSelected() const;
|
||||
|
||||
virtual nsChangeHint GetAttributeChangeHint(const nsIAtom* aAttribute,
|
||||
int32_t aModType) const override;
|
||||
|
||||
virtual nsresult BeforeSetAttr(int32_t aNamespaceID, nsIAtom* aName,
|
||||
nsAttrValueOrString* aValue,
|
||||
bool aNotify) override;
|
||||
virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
const nsAttrValue* aValue, bool aNotify) override;
|
||||
|
||||
void SetSelectedInternal(bool aValue, bool aNotify);
|
||||
|
||||
virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
||||
nsIContent* aBindingParent,
|
||||
bool aCompileEventHandlers) override;
|
||||
virtual void UnbindFromTree(bool aDeep = true,
|
||||
bool aNullParent = true) override;
|
||||
|
||||
// nsIContent
|
||||
virtual EventStates IntrinsicState() const override;
|
||||
|
||||
virtual nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult) const override;
|
||||
|
||||
nsresult CopyInnerTo(mozilla::dom::Element* aDest);
|
||||
|
||||
virtual bool IsDisabled() const override {
|
||||
return HasAttr(kNameSpaceID_None, nsGkAtoms::disabled);
|
||||
}
|
||||
|
||||
bool Disabled() const
|
||||
{
|
||||
return GetBoolAttr(nsGkAtoms::disabled);
|
||||
}
|
||||
|
||||
void SetDisabled(bool aValue, ErrorResult& aRv)
|
||||
{
|
||||
SetHTMLBoolAttr(nsGkAtoms::disabled, aValue, aRv);
|
||||
}
|
||||
|
||||
HTMLFormElement* GetForm();
|
||||
|
||||
// The XPCOM GetLabel is OK for us
|
||||
void SetLabel(const nsAString& aLabel, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::label, aLabel, aError);
|
||||
}
|
||||
|
||||
// The XPCOM DefaultSelected is OK for us
|
||||
void SetDefaultSelected(bool aValue, ErrorResult& aRv)
|
||||
{
|
||||
SetHTMLBoolAttr(nsGkAtoms::selected, aValue, aRv);
|
||||
}
|
||||
|
||||
// The XPCOM Selected is OK for us
|
||||
void SetSelected(bool aValue, ErrorResult& aRv)
|
||||
{
|
||||
aRv = SetSelected(aValue);
|
||||
}
|
||||
|
||||
// The XPCOM GetValue is OK for us
|
||||
void SetValue(const nsAString& aValue, ErrorResult& aRv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::value, aValue, aRv);
|
||||
}
|
||||
|
||||
// The XPCOM GetText is OK for us
|
||||
void SetText(const nsAString& aValue, ErrorResult& aRv)
|
||||
{
|
||||
aRv = SetText(aValue);
|
||||
}
|
||||
|
||||
int32_t Index();
|
||||
|
||||
protected:
|
||||
virtual ~HTMLOptionElement();
|
||||
|
||||
virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
/**
|
||||
* Get the select content element that contains this option, this
|
||||
* intentionally does not return nsresult, all we care about is if
|
||||
* there's a select associated with this option or not.
|
||||
*/
|
||||
HTMLSelectElement* GetSelect();
|
||||
|
||||
bool mSelectedChanged;
|
||||
bool mIsSelected;
|
||||
|
||||
// True only while we're under the SetOptionsSelectedByIndex call when our
|
||||
// "selected" attribute is changing and mSelectedChanged is false.
|
||||
bool mIsInSetDefaultSelected;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_HTMLOptionElement_h__
|
||||
375
dom/html/HTMLOptionsCollection.cpp
Normal file
375
dom/html/HTMLOptionsCollection.cpp
Normal file
|
|
@ -0,0 +1,375 @@
|
|||
/* -*- 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/HTMLOptionsCollection.h"
|
||||
|
||||
#include "HTMLOptGroupElement.h"
|
||||
#include "mozAutoDocUpdate.h"
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/HTMLFormSubmission.h"
|
||||
#include "mozilla/dom/HTMLOptionElement.h"
|
||||
#include "mozilla/dom/HTMLOptionsCollectionBinding.h"
|
||||
#include "mozilla/dom/HTMLSelectElement.h"
|
||||
#include "nsContentCreatorFunctions.h"
|
||||
#include "nsError.h"
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsIComboboxControlFrame.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIDOMHTMLOptGroupElement.h"
|
||||
#include "nsIFormControlFrame.h"
|
||||
#include "nsIForm.h"
|
||||
#include "nsIFormProcessor.h"
|
||||
#include "nsIListControlFrame.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
#include "nsMappedAttributes.h"
|
||||
#include "nsRuleData.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsStyleConsts.h"
|
||||
#include "jsfriendapi.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
HTMLOptionsCollection::HTMLOptionsCollection(HTMLSelectElement* aSelect)
|
||||
{
|
||||
// Do not maintain a reference counted reference. When
|
||||
// the select goes away, it will let us know.
|
||||
mSelect = aSelect;
|
||||
}
|
||||
|
||||
HTMLOptionsCollection::~HTMLOptionsCollection()
|
||||
{
|
||||
DropReference();
|
||||
}
|
||||
|
||||
void
|
||||
HTMLOptionsCollection::DropReference()
|
||||
{
|
||||
// Drop our (non ref-counted) reference
|
||||
mSelect = nullptr;
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLOptionsCollection::GetOptionIndex(Element* aOption,
|
||||
int32_t aStartIndex,
|
||||
bool aForward,
|
||||
int32_t* aIndex)
|
||||
{
|
||||
// NOTE: aIndex shouldn't be set if the returned value isn't NS_OK.
|
||||
|
||||
int32_t index;
|
||||
|
||||
// Make the common case fast
|
||||
if (aStartIndex == 0 && aForward) {
|
||||
index = mElements.IndexOf(aOption);
|
||||
if (index == -1) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
*aIndex = index;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
int32_t high = mElements.Length();
|
||||
int32_t step = aForward ? 1 : -1;
|
||||
|
||||
for (index = aStartIndex; index < high && index > -1; index += step) {
|
||||
if (mElements[index] == aOption) {
|
||||
*aIndex = index;
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(HTMLOptionsCollection, mElements)
|
||||
|
||||
// nsISupports
|
||||
|
||||
// QueryInterface implementation for HTMLOptionsCollection
|
||||
NS_INTERFACE_TABLE_HEAD(HTMLOptionsCollection)
|
||||
NS_WRAPPERCACHE_INTERFACE_TABLE_ENTRY
|
||||
NS_INTERFACE_TABLE(HTMLOptionsCollection,
|
||||
nsIHTMLCollection,
|
||||
nsIDOMHTMLOptionsCollection,
|
||||
nsIDOMHTMLCollection)
|
||||
NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(HTMLOptionsCollection)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(HTMLOptionsCollection)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(HTMLOptionsCollection)
|
||||
|
||||
|
||||
JSObject*
|
||||
HTMLOptionsCollection::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return HTMLOptionsCollectionBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLOptionsCollection::GetLength(uint32_t* aLength)
|
||||
{
|
||||
*aLength = mElements.Length();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLOptionsCollection::SetLength(uint32_t aLength)
|
||||
{
|
||||
if (!mSelect) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
return mSelect->SetLength(aLength);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLOptionsCollection::SetOption(uint32_t aIndex,
|
||||
nsIDOMHTMLOptionElement* aOption)
|
||||
{
|
||||
if (!mSelect) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// if the new option is null, just remove this option. Note that it's safe
|
||||
// to pass a too-large aIndex in here.
|
||||
if (!aOption) {
|
||||
mSelect->Remove(aIndex);
|
||||
|
||||
// We're done.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
uint32_t index = uint32_t(aIndex);
|
||||
|
||||
// Now we're going to be setting an option in our collection
|
||||
if (index > mElements.Length()) {
|
||||
// Fill our array with blank options up to (but not including, since we're
|
||||
// about to change it) aIndex, for compat with other browsers.
|
||||
rv = SetLength(index);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
NS_ASSERTION(index <= mElements.Length(), "SetLength lied");
|
||||
|
||||
nsCOMPtr<nsIDOMNode> ret;
|
||||
if (index == mElements.Length()) {
|
||||
nsCOMPtr<nsIDOMNode> node = do_QueryInterface(aOption);
|
||||
rv = mSelect->AppendChild(node, getter_AddRefs(ret));
|
||||
} else {
|
||||
// Find the option they're talking about and replace it
|
||||
// hold a strong reference to follow COM rules.
|
||||
RefPtr<HTMLOptionElement> refChild = ItemAsOption(index);
|
||||
NS_ENSURE_TRUE(refChild, NS_ERROR_UNEXPECTED);
|
||||
|
||||
nsCOMPtr<nsINode> parent = refChild->GetParent();
|
||||
if (parent) {
|
||||
nsCOMPtr<nsINode> node = do_QueryInterface(aOption);
|
||||
ErrorResult res;
|
||||
parent->ReplaceChild(*node, *refChild, res);
|
||||
rv = res.StealNSResult();
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
int32_t
|
||||
HTMLOptionsCollection::GetSelectedIndex(ErrorResult& aError)
|
||||
{
|
||||
if (!mSelect) {
|
||||
aError.Throw(NS_ERROR_UNEXPECTED);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t selectedIndex;
|
||||
aError = mSelect->GetSelectedIndex(&selectedIndex);
|
||||
return selectedIndex;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLOptionsCollection::GetSelectedIndex(int32_t* aSelectedIndex)
|
||||
{
|
||||
ErrorResult rv;
|
||||
*aSelectedIndex = GetSelectedIndex(rv);
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
|
||||
void
|
||||
HTMLOptionsCollection::SetSelectedIndex(int32_t aSelectedIndex,
|
||||
ErrorResult& aError)
|
||||
{
|
||||
if (!mSelect) {
|
||||
aError.Throw(NS_ERROR_UNEXPECTED);
|
||||
return;
|
||||
}
|
||||
|
||||
aError = mSelect->SetSelectedIndex(aSelectedIndex);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLOptionsCollection::SetSelectedIndex(int32_t aSelectedIndex)
|
||||
{
|
||||
ErrorResult rv;
|
||||
SetSelectedIndex(aSelectedIndex, rv);
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLOptionsCollection::Item(uint32_t aIndex, nsIDOMNode** aReturn)
|
||||
{
|
||||
nsISupports* item = GetElementAt(aIndex);
|
||||
if (!item) {
|
||||
*aReturn = nullptr;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return CallQueryInterface(item, aReturn);
|
||||
}
|
||||
|
||||
Element*
|
||||
HTMLOptionsCollection::GetElementAt(uint32_t aIndex)
|
||||
{
|
||||
return ItemAsOption(aIndex);
|
||||
}
|
||||
|
||||
HTMLOptionElement*
|
||||
HTMLOptionsCollection::NamedGetter(const nsAString& aName, bool& aFound)
|
||||
{
|
||||
uint32_t count = mElements.Length();
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
HTMLOptionElement* content = mElements.ElementAt(i);
|
||||
if (content &&
|
||||
(content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::name, aName,
|
||||
eCaseMatters) ||
|
||||
content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::id, aName,
|
||||
eCaseMatters))) {
|
||||
aFound = true;
|
||||
return content;
|
||||
}
|
||||
}
|
||||
|
||||
aFound = false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsINode*
|
||||
HTMLOptionsCollection::GetParentObject()
|
||||
{
|
||||
return mSelect;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLOptionsCollection::NamedItem(const nsAString& aName,
|
||||
nsIDOMNode** aReturn)
|
||||
{
|
||||
NS_IF_ADDREF(*aReturn = GetNamedItem(aName));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
HTMLOptionsCollection::GetSupportedNames(nsTArray<nsString>& aNames)
|
||||
{
|
||||
AutoTArray<nsIAtom*, 8> atoms;
|
||||
for (uint32_t i = 0; i < mElements.Length(); ++i) {
|
||||
HTMLOptionElement* content = mElements.ElementAt(i);
|
||||
if (content) {
|
||||
// Note: HasName means the names is exposed on the document,
|
||||
// which is false for options, so we don't check it here.
|
||||
const nsAttrValue* val = content->GetParsedAttr(nsGkAtoms::name);
|
||||
if (val && val->Type() == nsAttrValue::eAtom) {
|
||||
nsIAtom* name = val->GetAtomValue();
|
||||
if (!atoms.Contains(name)) {
|
||||
atoms.AppendElement(name);
|
||||
}
|
||||
}
|
||||
if (content->HasID()) {
|
||||
nsIAtom* id = content->GetID();
|
||||
if (!atoms.Contains(id)) {
|
||||
atoms.AppendElement(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t atomsLen = atoms.Length();
|
||||
nsString* names = aNames.AppendElements(atomsLen);
|
||||
for (uint32_t i = 0; i < atomsLen; ++i) {
|
||||
atoms[i]->ToString(names[i]);
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLOptionsCollection::GetSelect(nsIDOMHTMLSelectElement** aReturn)
|
||||
{
|
||||
NS_IF_ADDREF(*aReturn = mSelect);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLOptionsCollection::Add(nsIDOMHTMLOptionElement* aOption,
|
||||
nsIVariant* aBefore)
|
||||
{
|
||||
if (!aOption) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (!mSelect) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMHTMLElement> elem = do_QueryInterface(aOption);
|
||||
return mSelect->Add(elem, aBefore);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLOptionsCollection::Add(const HTMLOptionOrOptGroupElement& aElement,
|
||||
const Nullable<HTMLElementOrLong>& aBefore,
|
||||
ErrorResult& aError)
|
||||
{
|
||||
if (!mSelect) {
|
||||
aError.Throw(NS_ERROR_NOT_INITIALIZED);
|
||||
return;
|
||||
}
|
||||
|
||||
mSelect->Add(aElement, aBefore, aError);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLOptionsCollection::Remove(int32_t aIndex, ErrorResult& aError)
|
||||
{
|
||||
if (!mSelect) {
|
||||
aError.Throw(NS_ERROR_UNEXPECTED);
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t len = 0;
|
||||
mSelect->GetLength(&len);
|
||||
if (aIndex < 0 || (uint32_t)aIndex >= len)
|
||||
aIndex = 0;
|
||||
|
||||
aError = mSelect->Remove(aIndex);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLOptionsCollection::Remove(int32_t aIndex)
|
||||
{
|
||||
ErrorResult rv;
|
||||
Remove(aIndex, rv);
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
170
dom/html/HTMLOptionsCollection.h
Normal file
170
dom/html/HTMLOptionsCollection.h
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
/* -*- 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/. */
|
||||
#ifndef mozilla_dom_HTMLOptionsCollection_h
|
||||
#define mozilla_dom_HTMLOptionsCollection_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsIHTMLCollection.h"
|
||||
#include "nsIDOMHTMLOptionsCollection.h"
|
||||
#include "nsWrapperCache.h"
|
||||
|
||||
#include "mozilla/dom/HTMLOptionElement.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsError.h"
|
||||
#include "nsGenericHTMLElement.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
class nsIDOMHTMLOptionElement;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class HTMLElementOrLong;
|
||||
class HTMLOptionElementOrHTMLOptGroupElement;
|
||||
class HTMLSelectElement;
|
||||
|
||||
/**
|
||||
* The collection of options in the select (what you get back when you do
|
||||
* select.options in DOM)
|
||||
*/
|
||||
class HTMLOptionsCollection final : public nsIHTMLCollection
|
||||
, public nsIDOMHTMLOptionsCollection
|
||||
, public nsWrapperCache
|
||||
{
|
||||
typedef HTMLOptionElementOrHTMLOptGroupElement HTMLOptionOrOptGroupElement;
|
||||
public:
|
||||
explicit HTMLOptionsCollection(HTMLSelectElement* aSelect);
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
|
||||
// nsWrapperCache
|
||||
using nsWrapperCache::GetWrapperPreserveColor;
|
||||
using nsWrapperCache::GetWrapper;
|
||||
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
protected:
|
||||
virtual ~HTMLOptionsCollection();
|
||||
|
||||
virtual JSObject* GetWrapperPreserveColorInternal() override
|
||||
{
|
||||
return nsWrapperCache::GetWrapperPreserveColor();
|
||||
}
|
||||
public:
|
||||
|
||||
// nsIDOMHTMLOptionsCollection interface
|
||||
NS_DECL_NSIDOMHTMLOPTIONSCOLLECTION
|
||||
|
||||
// nsIDOMHTMLCollection interface, all its methods are defined in
|
||||
// nsIDOMHTMLOptionsCollection
|
||||
|
||||
virtual Element* GetElementAt(uint32_t aIndex) override;
|
||||
virtual nsINode* GetParentObject() override;
|
||||
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(HTMLOptionsCollection,
|
||||
nsIHTMLCollection)
|
||||
|
||||
// Helpers for HTMLSelectElement
|
||||
/**
|
||||
* Insert an option
|
||||
* @param aOption the option to insert
|
||||
* @param aIndex the index to insert at
|
||||
*/
|
||||
void InsertOptionAt(mozilla::dom::HTMLOptionElement* aOption, uint32_t aIndex)
|
||||
{
|
||||
mElements.InsertElementAt(aIndex, aOption);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an option
|
||||
* @param aIndex the index of the option to remove
|
||||
*/
|
||||
void RemoveOptionAt(uint32_t aIndex)
|
||||
{
|
||||
mElements.RemoveElementAt(aIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the option at the index
|
||||
* @param aIndex the index
|
||||
* @param aReturn the option returned [OUT]
|
||||
*/
|
||||
mozilla::dom::HTMLOptionElement* ItemAsOption(uint32_t aIndex)
|
||||
{
|
||||
return mElements.SafeElementAt(aIndex, nullptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears out all options
|
||||
*/
|
||||
void Clear()
|
||||
{
|
||||
mElements.Clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Append an option to end of array
|
||||
*/
|
||||
void AppendOption(mozilla::dom::HTMLOptionElement* aOption)
|
||||
{
|
||||
mElements.AppendElement(aOption);
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop the reference to the select. Called during select destruction.
|
||||
*/
|
||||
void DropReference();
|
||||
|
||||
/**
|
||||
* Finds the index of a given option element.
|
||||
* If the option isn't part of the collection, return NS_ERROR_FAILURE
|
||||
* without setting aIndex.
|
||||
*
|
||||
* @param aOption the option to get the index of
|
||||
* @param aStartIndex the index to start looking at
|
||||
* @param aForward TRUE to look forward, FALSE to look backward
|
||||
* @return the option index
|
||||
*/
|
||||
nsresult GetOptionIndex(Element* aOption,
|
||||
int32_t aStartIndex, bool aForward,
|
||||
int32_t* aIndex);
|
||||
|
||||
HTMLOptionElement* GetNamedItem(const nsAString& aName)
|
||||
{
|
||||
bool dummy;
|
||||
return NamedGetter(aName, dummy);
|
||||
}
|
||||
HTMLOptionElement* NamedGetter(const nsAString& aName, bool& aFound);
|
||||
virtual Element*
|
||||
GetFirstNamedElement(const nsAString& aName, bool& aFound) override
|
||||
{
|
||||
return NamedGetter(aName, aFound);
|
||||
}
|
||||
|
||||
void Add(const HTMLOptionOrOptGroupElement& aElement,
|
||||
const Nullable<HTMLElementOrLong>& aBefore,
|
||||
ErrorResult& aError);
|
||||
void Remove(int32_t aIndex, ErrorResult& aError);
|
||||
int32_t GetSelectedIndex(ErrorResult& aError);
|
||||
void SetSelectedIndex(int32_t aSelectedIndex, ErrorResult& aError);
|
||||
void IndexedSetter(uint32_t aIndex, nsIDOMHTMLOptionElement* aOption,
|
||||
ErrorResult& aError)
|
||||
{
|
||||
aError = SetOption(aIndex, aOption);
|
||||
}
|
||||
virtual void GetSupportedNames(nsTArray<nsString>& aNames) override;
|
||||
|
||||
private:
|
||||
/** The list of options (holds strong references). This is infallible, so
|
||||
* various members such as InsertOptionAt are also infallible. */
|
||||
nsTArray<RefPtr<mozilla::dom::HTMLOptionElement> > mElements;
|
||||
/** The select element that contains this array */
|
||||
HTMLSelectElement* mSelect;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_HTMLOptionsCollection_h
|
||||
226
dom/html/HTMLOutputElement.cpp
Normal file
226
dom/html/HTMLOutputElement.cpp
Normal file
|
|
@ -0,0 +1,226 @@
|
|||
/* -*- 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/HTMLOutputElement.h"
|
||||
|
||||
#include "mozAutoDocUpdate.h"
|
||||
#include "mozilla/EventStates.h"
|
||||
#include "mozilla/dom/HTMLFormElement.h"
|
||||
#include "mozilla/dom/HTMLFormSubmission.h"
|
||||
#include "mozilla/dom/HTMLOutputElementBinding.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsDOMTokenList.h"
|
||||
|
||||
NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER(Output)
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
HTMLOutputElement::HTMLOutputElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo,
|
||||
FromParser aFromParser)
|
||||
: nsGenericHTMLFormElement(aNodeInfo)
|
||||
, mValueModeFlag(eModeDefault)
|
||||
, mIsDoneAddingChildren(!aFromParser)
|
||||
{
|
||||
AddMutationObserver(this);
|
||||
|
||||
// We start out valid and ui-valid (since we have no form).
|
||||
AddStatesSilently(NS_EVENT_STATE_VALID | NS_EVENT_STATE_MOZ_UI_VALID);
|
||||
}
|
||||
|
||||
HTMLOutputElement::~HTMLOutputElement()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(HTMLOutputElement)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLOutputElement,
|
||||
nsGenericHTMLFormElement)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mValidity)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mTokenList)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLOutputElement,
|
||||
nsGenericHTMLFormElement)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mValidity)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTokenList)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(HTMLOutputElement, Element)
|
||||
NS_IMPL_RELEASE_INHERITED(HTMLOutputElement, Element)
|
||||
|
||||
NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(HTMLOutputElement)
|
||||
NS_INTERFACE_TABLE_INHERITED(HTMLOutputElement,
|
||||
nsIMutationObserver,
|
||||
nsIConstraintValidation)
|
||||
NS_INTERFACE_TABLE_TAIL_INHERITING(nsGenericHTMLFormElement)
|
||||
|
||||
NS_IMPL_ELEMENT_CLONE(HTMLOutputElement)
|
||||
|
||||
void
|
||||
HTMLOutputElement::SetCustomValidity(const nsAString& aError)
|
||||
{
|
||||
nsIConstraintValidation::SetCustomValidity(aError);
|
||||
|
||||
UpdateState(true);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLOutputElement::Reset()
|
||||
{
|
||||
mValueModeFlag = eModeDefault;
|
||||
return nsContentUtils::SetNodeTextContent(this, mDefaultValue, true);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLOutputElement::SubmitNamesValues(HTMLFormSubmission* aFormSubmission)
|
||||
{
|
||||
// The output element is not submittable.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
HTMLOutputElement::ParseAttribute(int32_t aNamespaceID, nsIAtom* aAttribute,
|
||||
const nsAString& aValue, nsAttrValue& aResult)
|
||||
{
|
||||
if (aNamespaceID == kNameSpaceID_None) {
|
||||
if (aAttribute == nsGkAtoms::_for) {
|
||||
aResult.ParseAtomArray(aValue);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return nsGenericHTMLFormElement::ParseAttribute(aNamespaceID, aAttribute,
|
||||
aValue, aResult);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLOutputElement::DoneAddingChildren(bool aHaveNotified)
|
||||
{
|
||||
mIsDoneAddingChildren = true;
|
||||
}
|
||||
|
||||
EventStates
|
||||
HTMLOutputElement::IntrinsicState() const
|
||||
{
|
||||
EventStates states = nsGenericHTMLFormElement::IntrinsicState();
|
||||
|
||||
// We don't have to call IsCandidateForConstraintValidation()
|
||||
// because <output> can't be barred from constraint validation.
|
||||
if (IsValid()) {
|
||||
states |= NS_EVENT_STATE_VALID;
|
||||
if (!mForm || !mForm->HasAttr(kNameSpaceID_None, nsGkAtoms::novalidate)) {
|
||||
states |= NS_EVENT_STATE_MOZ_UI_VALID;
|
||||
}
|
||||
} else {
|
||||
states |= NS_EVENT_STATE_INVALID;
|
||||
if (!mForm || !mForm->HasAttr(kNameSpaceID_None, nsGkAtoms::novalidate)) {
|
||||
states |= NS_EVENT_STATE_MOZ_UI_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
return states;
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLOutputElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
||||
nsIContent* aBindingParent,
|
||||
bool aCompileEventHandlers)
|
||||
{
|
||||
nsresult rv = nsGenericHTMLFormElement::BindToTree(aDocument, aParent,
|
||||
aBindingParent,
|
||||
aCompileEventHandlers);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Unfortunately, we can actually end up having to change our state
|
||||
// as a result of being bound to a tree even from the parser: we
|
||||
// might end up a in a novalidate form, and unlike other form
|
||||
// controls that on its own is enough to make change ui-valid state.
|
||||
// So just go ahead and update our state now.
|
||||
UpdateState(false);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
void
|
||||
HTMLOutputElement::GetValue(nsAString& aValue)
|
||||
{
|
||||
nsContentUtils::GetNodeTextContent(this, true, aValue);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLOutputElement::SetValue(const nsAString& aValue, ErrorResult& aRv)
|
||||
{
|
||||
mValueModeFlag = eModeValue;
|
||||
aRv = nsContentUtils::SetNodeTextContent(this, aValue, true);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLOutputElement::SetDefaultValue(const nsAString& aDefaultValue, ErrorResult& aRv)
|
||||
{
|
||||
mDefaultValue = aDefaultValue;
|
||||
if (mValueModeFlag == eModeDefault) {
|
||||
aRv = nsContentUtils::SetNodeTextContent(this, mDefaultValue, true);
|
||||
}
|
||||
}
|
||||
|
||||
nsDOMTokenList*
|
||||
HTMLOutputElement::HtmlFor()
|
||||
{
|
||||
if (!mTokenList) {
|
||||
mTokenList = new nsDOMTokenList(this, nsGkAtoms::_for);
|
||||
}
|
||||
return mTokenList;
|
||||
}
|
||||
|
||||
void HTMLOutputElement::DescendantsChanged()
|
||||
{
|
||||
if (mIsDoneAddingChildren && mValueModeFlag == eModeDefault) {
|
||||
nsContentUtils::GetNodeTextContent(this, true, mDefaultValue);
|
||||
}
|
||||
}
|
||||
|
||||
// nsIMutationObserver
|
||||
|
||||
void HTMLOutputElement::CharacterDataChanged(nsIDocument* aDocument,
|
||||
nsIContent* aContent,
|
||||
CharacterDataChangeInfo* aInfo)
|
||||
{
|
||||
DescendantsChanged();
|
||||
}
|
||||
|
||||
void HTMLOutputElement::ContentAppended(nsIDocument* aDocument,
|
||||
nsIContent* aContainer,
|
||||
nsIContent* aFirstNewContent,
|
||||
int32_t aNewIndexInContainer)
|
||||
{
|
||||
DescendantsChanged();
|
||||
}
|
||||
|
||||
void HTMLOutputElement::ContentInserted(nsIDocument* aDocument,
|
||||
nsIContent* aContainer,
|
||||
nsIContent* aChild,
|
||||
int32_t aIndexInContainer)
|
||||
{
|
||||
DescendantsChanged();
|
||||
}
|
||||
|
||||
void HTMLOutputElement::ContentRemoved(nsIDocument* aDocument,
|
||||
nsIContent* aContainer,
|
||||
nsIContent* aChild,
|
||||
int32_t aIndexInContainer,
|
||||
nsIContent* aPreviousSibling)
|
||||
{
|
||||
DescendantsChanged();
|
||||
}
|
||||
|
||||
JSObject*
|
||||
HTMLOutputElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return HTMLOutputElementBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
119
dom/html/HTMLOutputElement.h
Normal file
119
dom/html/HTMLOutputElement.h
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_dom_HTMLOutputElement_h
|
||||
#define mozilla_dom_HTMLOutputElement_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsGenericHTMLElement.h"
|
||||
#include "nsStubMutationObserver.h"
|
||||
#include "nsIConstraintValidation.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class HTMLFormSubmission;
|
||||
|
||||
class HTMLOutputElement final : public nsGenericHTMLFormElement,
|
||||
public nsStubMutationObserver,
|
||||
public nsIConstraintValidation
|
||||
{
|
||||
public:
|
||||
using nsIConstraintValidation::GetValidationMessage;
|
||||
|
||||
explicit HTMLOutputElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo,
|
||||
FromParser aFromParser = NOT_FROM_PARSER);
|
||||
|
||||
// nsISupports
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
// nsIFormControl
|
||||
NS_IMETHOD_(uint32_t) GetType() const override { return NS_FORM_OUTPUT; }
|
||||
NS_IMETHOD Reset() override;
|
||||
NS_IMETHOD SubmitNamesValues(HTMLFormSubmission* aFormSubmission) override;
|
||||
|
||||
virtual bool IsDisabled() const override { return false; }
|
||||
|
||||
nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult) const override;
|
||||
|
||||
bool ParseAttribute(int32_t aNamespaceID, nsIAtom* aAttribute,
|
||||
const nsAString& aValue, nsAttrValue& aResult) override;
|
||||
|
||||
virtual void DoneAddingChildren(bool aHaveNotified) override;
|
||||
|
||||
EventStates IntrinsicState() const override;
|
||||
|
||||
virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
||||
nsIContent* aBindingParent,
|
||||
bool aCompileEventHandlers) override;
|
||||
|
||||
// This function is called when a callback function from nsIMutationObserver
|
||||
// has to be used to update the defaultValue attribute.
|
||||
void DescendantsChanged();
|
||||
|
||||
// nsIMutationObserver
|
||||
NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED
|
||||
NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
|
||||
NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
|
||||
NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
|
||||
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLOutputElement,
|
||||
nsGenericHTMLFormElement)
|
||||
|
||||
virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
// WebIDL
|
||||
nsDOMTokenList* HtmlFor();
|
||||
// nsGenericHTMLFormElement::GetForm is fine.
|
||||
void GetName(nsAString& aName)
|
||||
{
|
||||
GetHTMLAttr(nsGkAtoms::name, aName);
|
||||
}
|
||||
|
||||
void SetName(const nsAString& aName, ErrorResult& aRv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::name, aName, aRv);
|
||||
}
|
||||
|
||||
void GetType(nsAString& aType)
|
||||
{
|
||||
aType.AssignLiteral("output");
|
||||
}
|
||||
|
||||
void GetDefaultValue(nsAString& aDefaultValue)
|
||||
{
|
||||
aDefaultValue = mDefaultValue;
|
||||
}
|
||||
|
||||
void SetDefaultValue(const nsAString& aDefaultValue, ErrorResult& aRv);
|
||||
|
||||
void GetValue(nsAString& aValue);
|
||||
void SetValue(const nsAString& aValue, ErrorResult& aRv);
|
||||
|
||||
// nsIConstraintValidation::WillValidate is fine.
|
||||
// nsIConstraintValidation::Validity() is fine.
|
||||
// nsIConstraintValidation::GetValidationMessage() is fine.
|
||||
// nsIConstraintValidation::CheckValidity() is fine.
|
||||
void SetCustomValidity(const nsAString& aError);
|
||||
|
||||
protected:
|
||||
virtual ~HTMLOutputElement();
|
||||
|
||||
enum ValueModeFlag {
|
||||
eModeDefault,
|
||||
eModeValue
|
||||
};
|
||||
|
||||
ValueModeFlag mValueModeFlag;
|
||||
bool mIsDoneAddingChildren;
|
||||
nsString mDefaultValue;
|
||||
RefPtr<nsDOMTokenList> mTokenList;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_HTMLOutputElement_h
|
||||
78
dom/html/HTMLParagraphElement.cpp
Normal file
78
dom/html/HTMLParagraphElement.cpp
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
/* -*- 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/HTMLParagraphElement.h"
|
||||
#include "mozilla/dom/HTMLParagraphElementBinding.h"
|
||||
|
||||
#include "nsStyleConsts.h"
|
||||
#include "nsMappedAttributes.h"
|
||||
#include "nsRuleData.h"
|
||||
|
||||
|
||||
NS_IMPL_NS_NEW_HTML_ELEMENT(Paragraph)
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
HTMLParagraphElement::~HTMLParagraphElement()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED(HTMLParagraphElement, nsGenericHTMLElement,
|
||||
nsIDOMHTMLParagraphElement)
|
||||
|
||||
NS_IMPL_ELEMENT_CLONE(HTMLParagraphElement)
|
||||
|
||||
NS_IMPL_STRING_ATTR(HTMLParagraphElement, Align, align)
|
||||
|
||||
bool
|
||||
HTMLParagraphElement::ParseAttribute(int32_t aNamespaceID,
|
||||
nsIAtom* aAttribute,
|
||||
const nsAString& aValue,
|
||||
nsAttrValue& aResult)
|
||||
{
|
||||
if (aAttribute == nsGkAtoms::align && aNamespaceID == kNameSpaceID_None) {
|
||||
return ParseDivAlignValue(aValue, aResult);
|
||||
}
|
||||
|
||||
return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
|
||||
aResult);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLParagraphElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
|
||||
nsRuleData* aData)
|
||||
{
|
||||
nsGenericHTMLElement::MapDivAlignAttributeInto(aAttributes, aData);
|
||||
nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aData);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(bool)
|
||||
HTMLParagraphElement::IsAttributeMapped(const nsIAtom* aAttribute) const
|
||||
{
|
||||
static const MappedAttributeEntry* const map[] = {
|
||||
sDivAlignAttributeMap,
|
||||
sCommonAttributeMap,
|
||||
};
|
||||
|
||||
return FindAttributeDependence(aAttribute, map);
|
||||
}
|
||||
|
||||
|
||||
nsMapRuleToAttributesFunc
|
||||
HTMLParagraphElement::GetAttributeMappingFunction() const
|
||||
{
|
||||
return &MapAttributesIntoRule;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
HTMLParagraphElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return HTMLParagraphElementBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
62
dom/html/HTMLParagraphElement.h
Normal file
62
dom/html/HTMLParagraphElement.h
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_dom_HTMLParagraphElement_h
|
||||
#define mozilla_dom_HTMLParagraphElement_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
#include "nsIDOMHTMLParagraphElement.h"
|
||||
#include "nsGenericHTMLElement.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class HTMLParagraphElement final : public nsGenericHTMLElement,
|
||||
public nsIDOMHTMLParagraphElement
|
||||
{
|
||||
public:
|
||||
explicit HTMLParagraphElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
|
||||
: nsGenericHTMLElement(aNodeInfo)
|
||||
{
|
||||
}
|
||||
|
||||
// nsISupports
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
// nsIDOMHTMLParagraphElement
|
||||
NS_DECL_NSIDOMHTMLPARAGRAPHELEMENT
|
||||
|
||||
virtual bool ParseAttribute(int32_t aNamespaceID,
|
||||
nsIAtom* aAttribute,
|
||||
const nsAString& aValue,
|
||||
nsAttrValue& aResult) override;
|
||||
NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
|
||||
virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const override;
|
||||
|
||||
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
|
||||
|
||||
// WebIDL API
|
||||
// The XPCOM GetAlign is fine for our purposes
|
||||
void SetAlign(const nsAString& aValue, mozilla::ErrorResult& rv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::align, aValue, rv);
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual ~HTMLParagraphElement();
|
||||
|
||||
virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
private:
|
||||
static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
|
||||
nsRuleData* aData);
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_HTMLParagraphElement_h
|
||||
98
dom/html/HTMLPictureElement.cpp
Normal file
98
dom/html/HTMLPictureElement.cpp
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
/* -*- 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/HTMLPictureElement.h"
|
||||
#include "mozilla/dom/HTMLPictureElementBinding.h"
|
||||
#include "mozilla/dom/HTMLImageElement.h"
|
||||
|
||||
// Expand NS_IMPL_NS_NEW_HTML_ELEMENT(Picture) to add pref check.
|
||||
nsGenericHTMLElement*
|
||||
NS_NewHTMLPictureElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
|
||||
mozilla::dom::FromParser aFromParser)
|
||||
{
|
||||
return new mozilla::dom::HTMLPictureElement(aNodeInfo);
|
||||
}
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
HTMLPictureElement::HTMLPictureElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
|
||||
: nsGenericHTMLElement(aNodeInfo)
|
||||
{
|
||||
}
|
||||
|
||||
HTMLPictureElement::~HTMLPictureElement()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED(HTMLPictureElement, nsGenericHTMLElement,
|
||||
nsIDOMHTMLPictureElement)
|
||||
|
||||
NS_IMPL_ELEMENT_CLONE(HTMLPictureElement)
|
||||
|
||||
void
|
||||
HTMLPictureElement::RemoveChildAt(uint32_t aIndex, bool aNotify)
|
||||
{
|
||||
nsCOMPtr<nsIContent> child = GetChildAt(aIndex);
|
||||
|
||||
if (child && child->IsHTMLElement(nsGkAtoms::img)) {
|
||||
HTMLImageElement* img = HTMLImageElement::FromContent(child);
|
||||
if (img) {
|
||||
img->PictureSourceRemoved(child->AsContent());
|
||||
}
|
||||
} else if (child && child->IsHTMLElement(nsGkAtoms::source)) {
|
||||
// Find all img siblings after this <source> to notify them of its demise
|
||||
nsCOMPtr<nsIContent> nextSibling = child->GetNextSibling();
|
||||
if (nextSibling && nextSibling->GetParentNode() == this) {
|
||||
do {
|
||||
HTMLImageElement* img = HTMLImageElement::FromContent(nextSibling);
|
||||
if (img) {
|
||||
img->PictureSourceRemoved(child->AsContent());
|
||||
}
|
||||
} while ( (nextSibling = nextSibling->GetNextSibling()) );
|
||||
}
|
||||
}
|
||||
|
||||
nsGenericHTMLElement::RemoveChildAt(aIndex, aNotify);
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLPictureElement::InsertChildAt(nsIContent* aKid, uint32_t aIndex, bool aNotify)
|
||||
{
|
||||
nsresult rv = nsGenericHTMLElement::InsertChildAt(aKid, aIndex, aNotify);
|
||||
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_TRUE(aKid, rv);
|
||||
|
||||
if (aKid->IsHTMLElement(nsGkAtoms::img)) {
|
||||
HTMLImageElement* img = HTMLImageElement::FromContent(aKid);
|
||||
if (img) {
|
||||
img->PictureSourceAdded(aKid->AsContent());
|
||||
}
|
||||
} else if (aKid->IsHTMLElement(nsGkAtoms::source)) {
|
||||
// Find all img siblings after this <source> to notify them of its insertion
|
||||
nsCOMPtr<nsIContent> nextSibling = aKid->GetNextSibling();
|
||||
if (nextSibling && nextSibling->GetParentNode() == this) {
|
||||
do {
|
||||
HTMLImageElement* img = HTMLImageElement::FromContent(nextSibling);
|
||||
if (img) {
|
||||
img->PictureSourceAdded(aKid->AsContent());
|
||||
}
|
||||
} while ( (nextSibling = nextSibling->GetNextSibling()) );
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
HTMLPictureElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return HTMLPictureElementBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
42
dom/html/HTMLPictureElement.h
Normal file
42
dom/html/HTMLPictureElement.h
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_dom_HTMLPictureElement_h
|
||||
#define mozilla_dom_HTMLPictureElement_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsIDOMHTMLPictureElement.h"
|
||||
#include "nsGenericHTMLElement.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class HTMLPictureElement final : public nsGenericHTMLElement,
|
||||
public nsIDOMHTMLPictureElement
|
||||
{
|
||||
public:
|
||||
explicit HTMLPictureElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
|
||||
|
||||
// nsISupports
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
// nsIDOMHTMLPictureElement
|
||||
NS_DECL_NSIDOMHTMLPICTUREELEMENT
|
||||
|
||||
virtual nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult) const override;
|
||||
virtual void RemoveChildAt(uint32_t aIndex, bool aNotify) override;
|
||||
virtual nsresult InsertChildAt(nsIContent* aKid, uint32_t aIndex, bool aNotify) override;
|
||||
|
||||
protected:
|
||||
virtual ~HTMLPictureElement();
|
||||
|
||||
virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_HTMLPictureElement_h
|
||||
101
dom/html/HTMLPreElement.cpp
Normal file
101
dom/html/HTMLPreElement.cpp
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
/* -*- 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/HTMLPreElement.h"
|
||||
#include "mozilla/dom/HTMLPreElementBinding.h"
|
||||
|
||||
#include "nsAttrValueInlines.h"
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsStyleConsts.h"
|
||||
#include "nsMappedAttributes.h"
|
||||
#include "nsRuleData.h"
|
||||
|
||||
NS_IMPL_NS_NEW_HTML_ELEMENT(Pre)
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
HTMLPreElement::~HTMLPreElement()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED(HTMLPreElement, nsGenericHTMLElement,
|
||||
nsIDOMHTMLPreElement)
|
||||
|
||||
NS_IMPL_ELEMENT_CLONE(HTMLPreElement)
|
||||
|
||||
NS_IMPL_INT_ATTR(HTMLPreElement, Width, width)
|
||||
|
||||
bool
|
||||
HTMLPreElement::ParseAttribute(int32_t aNamespaceID,
|
||||
nsIAtom* aAttribute,
|
||||
const nsAString& aValue,
|
||||
nsAttrValue& aResult)
|
||||
{
|
||||
if (aNamespaceID == kNameSpaceID_None) {
|
||||
if (aAttribute == nsGkAtoms::width) {
|
||||
return aResult.ParseIntValue(aValue);
|
||||
}
|
||||
}
|
||||
|
||||
return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
|
||||
aResult);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLPreElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
|
||||
nsRuleData* aData)
|
||||
{
|
||||
if (aData->mSIDs & NS_STYLE_INHERIT_BIT(Text)) {
|
||||
nsCSSValue* whiteSpace = aData->ValueForWhiteSpace();
|
||||
if (whiteSpace->GetUnit() == eCSSUnit_Null) {
|
||||
// wrap: empty
|
||||
if (aAttributes->GetAttr(nsGkAtoms::wrap))
|
||||
whiteSpace->SetIntValue(NS_STYLE_WHITESPACE_PRE_WRAP, eCSSUnit_Enumerated);
|
||||
}
|
||||
}
|
||||
|
||||
nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aData);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(bool)
|
||||
HTMLPreElement::IsAttributeMapped(const nsIAtom* aAttribute) const
|
||||
{
|
||||
if (!mNodeInfo->Equals(nsGkAtoms::pre)) {
|
||||
return nsGenericHTMLElement::IsAttributeMapped(aAttribute);
|
||||
}
|
||||
|
||||
static const MappedAttributeEntry attributes[] = {
|
||||
{ &nsGkAtoms::wrap },
|
||||
{ nullptr },
|
||||
};
|
||||
|
||||
static const MappedAttributeEntry* const map[] = {
|
||||
attributes,
|
||||
sCommonAttributeMap,
|
||||
};
|
||||
|
||||
return FindAttributeDependence(aAttribute, map);
|
||||
}
|
||||
|
||||
nsMapRuleToAttributesFunc
|
||||
HTMLPreElement::GetAttributeMappingFunction() const
|
||||
{
|
||||
if (!mNodeInfo->Equals(nsGkAtoms::pre)) {
|
||||
return nsGenericHTMLElement::GetAttributeMappingFunction();
|
||||
}
|
||||
|
||||
return &MapAttributesIntoRule;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
HTMLPreElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return HTMLPreElementBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
66
dom/html/HTMLPreElement.h
Normal file
66
dom/html/HTMLPreElement.h
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_dom_HTMLPreElement_h
|
||||
#define mozilla_dom_HTMLPreElement_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
#include "nsIDOMHTMLPreElement.h"
|
||||
#include "nsGenericHTMLElement.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class HTMLPreElement final : public nsGenericHTMLElement,
|
||||
public nsIDOMHTMLPreElement
|
||||
{
|
||||
public:
|
||||
explicit HTMLPreElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
|
||||
: nsGenericHTMLElement(aNodeInfo)
|
||||
{
|
||||
}
|
||||
|
||||
// nsISupports
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
// nsIDOMHTMLPreElement
|
||||
NS_IMETHOD GetWidth(int32_t* aWidth) override;
|
||||
NS_IMETHOD SetWidth(int32_t aWidth) override;
|
||||
|
||||
virtual bool ParseAttribute(int32_t aNamespaceID,
|
||||
nsIAtom* aAttribute,
|
||||
const nsAString& aValue,
|
||||
nsAttrValue& aResult) override;
|
||||
NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
|
||||
virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const override;
|
||||
|
||||
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
|
||||
|
||||
// WebIDL API
|
||||
int32_t Width() const
|
||||
{
|
||||
return GetIntAttr(nsGkAtoms::width, 0);
|
||||
}
|
||||
void SetWidth(int32_t aWidth, mozilla::ErrorResult& rv)
|
||||
{
|
||||
rv = SetIntAttr(nsGkAtoms::width, aWidth);
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual ~HTMLPreElement();
|
||||
|
||||
virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
private:
|
||||
static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
|
||||
nsRuleData* aData);
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_HTMLPreElement_h
|
||||
109
dom/html/HTMLProgressElement.cpp
Normal file
109
dom/html/HTMLProgressElement.cpp
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
/* -*- 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/EventStates.h"
|
||||
#include "mozilla/dom/HTMLProgressElement.h"
|
||||
#include "mozilla/dom/HTMLProgressElementBinding.h"
|
||||
|
||||
NS_IMPL_NS_NEW_HTML_ELEMENT(Progress)
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
const double HTMLProgressElement::kIndeterminatePosition = -1.0;
|
||||
const double HTMLProgressElement::kDefaultValue = 0.0;
|
||||
const double HTMLProgressElement::kDefaultMax = 1.0;
|
||||
|
||||
|
||||
HTMLProgressElement::HTMLProgressElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
|
||||
: nsGenericHTMLElement(aNodeInfo)
|
||||
{
|
||||
// We start out indeterminate
|
||||
AddStatesSilently(NS_EVENT_STATE_INDETERMINATE);
|
||||
}
|
||||
|
||||
HTMLProgressElement::~HTMLProgressElement()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMPL_ELEMENT_CLONE(HTMLProgressElement)
|
||||
|
||||
|
||||
EventStates
|
||||
HTMLProgressElement::IntrinsicState() const
|
||||
{
|
||||
EventStates state = nsGenericHTMLElement::IntrinsicState();
|
||||
|
||||
if (IsIndeterminate()) {
|
||||
state |= NS_EVENT_STATE_INDETERMINATE;
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
bool
|
||||
HTMLProgressElement::ParseAttribute(int32_t aNamespaceID, nsIAtom* aAttribute,
|
||||
const nsAString& aValue, nsAttrValue& aResult)
|
||||
{
|
||||
if (aNamespaceID == kNameSpaceID_None) {
|
||||
if (aAttribute == nsGkAtoms::value || aAttribute == nsGkAtoms::max) {
|
||||
return aResult.ParseDoubleValue(aValue);
|
||||
}
|
||||
}
|
||||
|
||||
return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute,
|
||||
aValue, aResult);
|
||||
}
|
||||
|
||||
double
|
||||
HTMLProgressElement::Value() const
|
||||
{
|
||||
const nsAttrValue* attrValue = mAttrsAndChildren.GetAttr(nsGkAtoms::value);
|
||||
if (!attrValue || attrValue->Type() != nsAttrValue::eDoubleValue ||
|
||||
attrValue->GetDoubleValue() < 0.0) {
|
||||
return kDefaultValue;
|
||||
}
|
||||
|
||||
return std::min(attrValue->GetDoubleValue(), Max());
|
||||
}
|
||||
|
||||
double
|
||||
HTMLProgressElement::Max() const
|
||||
{
|
||||
const nsAttrValue* attrMax = mAttrsAndChildren.GetAttr(nsGkAtoms::max);
|
||||
if (!attrMax || attrMax->Type() != nsAttrValue::eDoubleValue ||
|
||||
attrMax->GetDoubleValue() <= 0.0) {
|
||||
return kDefaultMax;
|
||||
}
|
||||
|
||||
return attrMax->GetDoubleValue();
|
||||
}
|
||||
|
||||
double
|
||||
HTMLProgressElement::Position() const
|
||||
{
|
||||
if (IsIndeterminate()) {
|
||||
return kIndeterminatePosition;
|
||||
}
|
||||
|
||||
return Value() / Max();
|
||||
}
|
||||
|
||||
bool
|
||||
HTMLProgressElement::IsIndeterminate() const
|
||||
{
|
||||
const nsAttrValue* attrValue = mAttrsAndChildren.GetAttr(nsGkAtoms::value);
|
||||
return !attrValue || attrValue->Type() != nsAttrValue::eDoubleValue;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
HTMLProgressElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return HTMLProgressElementBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
67
dom/html/HTMLProgressElement.h
Normal file
67
dom/html/HTMLProgressElement.h
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_dom_HTMLProgressElement_h
|
||||
#define mozilla_dom_HTMLProgressElement_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsGenericHTMLElement.h"
|
||||
#include "nsAttrValue.h"
|
||||
#include "nsAttrValueInlines.h"
|
||||
#include <algorithm>
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class HTMLProgressElement final : public nsGenericHTMLElement
|
||||
{
|
||||
public:
|
||||
explicit HTMLProgressElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
|
||||
|
||||
EventStates IntrinsicState() const override;
|
||||
|
||||
nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult) const override;
|
||||
|
||||
bool ParseAttribute(int32_t aNamespaceID, nsIAtom* aAttribute,
|
||||
const nsAString& aValue, nsAttrValue& aResult) override;
|
||||
|
||||
// WebIDL
|
||||
double Value() const;
|
||||
void SetValue(double aValue, ErrorResult& aRv)
|
||||
{
|
||||
SetDoubleAttr(nsGkAtoms::value, aValue, aRv);
|
||||
}
|
||||
double Max() const;
|
||||
void SetMax(double aValue, ErrorResult& aRv)
|
||||
{
|
||||
SetDoubleAttr(nsGkAtoms::max, aValue, aRv);
|
||||
}
|
||||
double Position() const;
|
||||
|
||||
protected:
|
||||
virtual ~HTMLProgressElement();
|
||||
|
||||
virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Returns whethem the progress element is in the indeterminate state.
|
||||
* A progress element is in the indeterminate state if its value is ommited
|
||||
* or is not a floating point number..
|
||||
*
|
||||
* @return whether the progress element is in the indeterminate state.
|
||||
*/
|
||||
bool IsIndeterminate() const;
|
||||
|
||||
static const double kIndeterminatePosition;
|
||||
static const double kDefaultValue;
|
||||
static const double kDefaultMax;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_HTMLProgressElement_h
|
||||
316
dom/html/HTMLScriptElement.cpp
Normal file
316
dom/html/HTMLScriptElement.cpp
Normal file
|
|
@ -0,0 +1,316 @@
|
|||
/* -*- 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 "nsGkAtoms.h"
|
||||
#include "nsStyleConsts.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsUnicharUtils.h" // for nsCaseInsensitiveStringComparator()
|
||||
#include "nsIScriptContext.h"
|
||||
#include "nsIScriptGlobalObject.h"
|
||||
#include "nsIXPConnect.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsError.h"
|
||||
#include "nsIArray.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsDOMJSUtils.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "mozilla/dom/HTMLScriptElement.h"
|
||||
#include "mozilla/dom/HTMLScriptElementBinding.h"
|
||||
|
||||
NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER(Script)
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
JSObject*
|
||||
HTMLScriptElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return HTMLScriptElementBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
HTMLScriptElement::HTMLScriptElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo,
|
||||
FromParser aFromParser)
|
||||
: nsGenericHTMLElement(aNodeInfo)
|
||||
, nsScriptElement(aFromParser)
|
||||
{
|
||||
AddMutationObserver(this);
|
||||
}
|
||||
|
||||
HTMLScriptElement::~HTMLScriptElement()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED(HTMLScriptElement, nsGenericHTMLElement,
|
||||
nsIDOMHTMLScriptElement,
|
||||
nsIScriptLoaderObserver,
|
||||
nsIScriptElement,
|
||||
nsIMutationObserver)
|
||||
|
||||
nsresult
|
||||
HTMLScriptElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
||||
nsIContent* aBindingParent,
|
||||
bool aCompileEventHandlers)
|
||||
{
|
||||
nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent,
|
||||
aBindingParent,
|
||||
aCompileEventHandlers);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (GetComposedDoc()) {
|
||||
MaybeProcessScript();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
HTMLScriptElement::ParseAttribute(int32_t aNamespaceID,
|
||||
nsIAtom* aAttribute,
|
||||
const nsAString& aValue,
|
||||
nsAttrValue& aResult)
|
||||
{
|
||||
if (aNamespaceID == kNameSpaceID_None) {
|
||||
if (aAttribute == nsGkAtoms::crossorigin) {
|
||||
ParseCORSValue(aValue, aResult);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (aAttribute == nsGkAtoms::integrity) {
|
||||
aResult.ParseStringOrAtom(aValue);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
|
||||
aResult);
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLScriptElement::Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const
|
||||
{
|
||||
*aResult = nullptr;
|
||||
|
||||
already_AddRefed<mozilla::dom::NodeInfo> ni = RefPtr<mozilla::dom::NodeInfo>(aNodeInfo).forget();
|
||||
HTMLScriptElement* it = new HTMLScriptElement(ni, NOT_FROM_PARSER);
|
||||
|
||||
nsCOMPtr<nsINode> kungFuDeathGrip = it;
|
||||
nsresult rv = const_cast<HTMLScriptElement*>(this)->CopyInnerTo(it);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// The clone should be marked evaluated if we are.
|
||||
it->mAlreadyStarted = mAlreadyStarted;
|
||||
it->mLineNumber = mLineNumber;
|
||||
it->mMalformed = mMalformed;
|
||||
|
||||
kungFuDeathGrip.swap(*aResult);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLScriptElement::GetText(nsAString& aValue)
|
||||
{
|
||||
if (!nsContentUtils::GetNodeTextContent(this, false, aValue, fallible)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLScriptElement::SetText(const nsAString& aValue)
|
||||
{
|
||||
ErrorResult rv;
|
||||
SetText(aValue, rv);
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
|
||||
void
|
||||
HTMLScriptElement::SetText(const nsAString& aValue, ErrorResult& rv)
|
||||
{
|
||||
rv = nsContentUtils::SetNodeTextContent(this, aValue, true);
|
||||
}
|
||||
|
||||
|
||||
NS_IMPL_STRING_ATTR(HTMLScriptElement, Charset, charset)
|
||||
NS_IMPL_BOOL_ATTR(HTMLScriptElement, Defer, defer)
|
||||
// If this ever gets changed to return "" if the attr value is "" (see
|
||||
// https://github.com/whatwg/html/issues/1739 for why it might not get changed),
|
||||
// it may be worth it to use GetSrc instead of GetAttr and manual
|
||||
// NewURIWithDocumentCharset in FreezeUriAsyncDefer.
|
||||
NS_IMPL_URI_ATTR(HTMLScriptElement, Src, src)
|
||||
NS_IMPL_STRING_ATTR(HTMLScriptElement, Type, type)
|
||||
NS_IMPL_STRING_ATTR(HTMLScriptElement, HtmlFor, _for)
|
||||
NS_IMPL_STRING_ATTR(HTMLScriptElement, Event, event)
|
||||
|
||||
void
|
||||
HTMLScriptElement::SetCharset(const nsAString& aCharset, ErrorResult& rv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::charset, aCharset, rv);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLScriptElement::SetDefer(bool aDefer, ErrorResult& rv)
|
||||
{
|
||||
SetHTMLBoolAttr(nsGkAtoms::defer, aDefer, rv);
|
||||
}
|
||||
|
||||
bool
|
||||
HTMLScriptElement::Defer()
|
||||
{
|
||||
return GetBoolAttr(nsGkAtoms::defer);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLScriptElement::SetSrc(const nsAString& aSrc, ErrorResult& rv)
|
||||
{
|
||||
rv = SetAttrHelper(nsGkAtoms::src, aSrc);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLScriptElement::SetType(const nsAString& aType, ErrorResult& rv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::type, aType, rv);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLScriptElement::SetHtmlFor(const nsAString& aHtmlFor, ErrorResult& rv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::_for, aHtmlFor, rv);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLScriptElement::SetEvent(const nsAString& aEvent, ErrorResult& rv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::event, aEvent, rv);
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLScriptElement::GetAsync(bool* aValue)
|
||||
{
|
||||
*aValue = Async();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
HTMLScriptElement::Async()
|
||||
{
|
||||
return mForceAsync || GetBoolAttr(nsGkAtoms::async);
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLScriptElement::SetAsync(bool aValue)
|
||||
{
|
||||
ErrorResult rv;
|
||||
SetAsync(aValue, rv);
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
|
||||
void
|
||||
HTMLScriptElement::SetAsync(bool aValue, ErrorResult& rv)
|
||||
{
|
||||
mForceAsync = false;
|
||||
SetHTMLBoolAttr(nsGkAtoms::async, aValue, rv);
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLScriptElement::AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
|
||||
const nsAttrValue* aValue, bool aNotify)
|
||||
{
|
||||
if (nsGkAtoms::async == aName && kNameSpaceID_None == aNamespaceID) {
|
||||
mForceAsync = false;
|
||||
}
|
||||
return nsGenericHTMLElement::AfterSetAttr(aNamespaceID, aName, aValue,
|
||||
aNotify);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLScriptElement::GetInnerHTML(nsAString& aInnerHTML)
|
||||
{
|
||||
if (!nsContentUtils::GetNodeTextContent(this, false, aInnerHTML, fallible)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
HTMLScriptElement::SetInnerHTML(const nsAString& aInnerHTML,
|
||||
ErrorResult& aError)
|
||||
{
|
||||
aError = nsContentUtils::SetNodeTextContent(this, aInnerHTML, true);
|
||||
}
|
||||
|
||||
// variation of this code in nsSVGScriptElement - check if changes
|
||||
// need to be transfered when modifying
|
||||
|
||||
bool
|
||||
HTMLScriptElement::GetScriptType(nsAString& type)
|
||||
{
|
||||
return GetAttr(kNameSpaceID_None, nsGkAtoms::type, type);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLScriptElement::GetScriptText(nsAString& text)
|
||||
{
|
||||
GetText(text);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLScriptElement::GetScriptCharset(nsAString& charset)
|
||||
{
|
||||
GetCharset(charset);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLScriptElement::FreezeUriAsyncDefer()
|
||||
{
|
||||
if (mFrozen) {
|
||||
return;
|
||||
}
|
||||
|
||||
// variation of this code in nsSVGScriptElement - check if changes
|
||||
// need to be transfered when modifying. Note that we don't use GetSrc here
|
||||
// because it will return the base URL when the attr value is "".
|
||||
nsAutoString src;
|
||||
if (GetAttr(kNameSpaceID_None, nsGkAtoms::src, src)) {
|
||||
// Empty src should be treated as invalid URL.
|
||||
if (!src.IsEmpty()) {
|
||||
nsCOMPtr<nsIURI> baseURI = GetBaseURI();
|
||||
nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(mUri),
|
||||
src, OwnerDoc(), baseURI);
|
||||
}
|
||||
|
||||
// At this point mUri will be null for invalid URLs.
|
||||
mExternal = true;
|
||||
|
||||
bool defer, async;
|
||||
GetAsync(&async);
|
||||
GetDefer(&defer);
|
||||
|
||||
mDefer = !async && defer;
|
||||
mAsync = async;
|
||||
}
|
||||
|
||||
mFrozen = true;
|
||||
}
|
||||
|
||||
CORSMode
|
||||
HTMLScriptElement::GetCORSMode() const
|
||||
{
|
||||
return AttrValueToCORSMode(GetParsedAttr(nsGkAtoms::crossorigin));
|
||||
}
|
||||
|
||||
bool
|
||||
HTMLScriptElement::HasScriptContent()
|
||||
{
|
||||
return (mFrozen ? mExternal : HasAttr(kNameSpaceID_None, nsGkAtoms::src)) ||
|
||||
nsContentUtils::HasNonEmptyTextContent(this);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
104
dom/html/HTMLScriptElement.h
Normal file
104
dom/html/HTMLScriptElement.h
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_dom_HTMLScriptElement_h
|
||||
#define mozilla_dom_HTMLScriptElement_h
|
||||
|
||||
#include "nsIDOMHTMLScriptElement.h"
|
||||
#include "nsScriptElement.h"
|
||||
#include "nsGenericHTMLElement.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class HTMLScriptElement final : public nsGenericHTMLElement,
|
||||
public nsIDOMHTMLScriptElement,
|
||||
public nsScriptElement
|
||||
{
|
||||
public:
|
||||
using Element::GetText;
|
||||
using Element::SetText;
|
||||
|
||||
HTMLScriptElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo,
|
||||
FromParser aFromParser);
|
||||
|
||||
// nsISupports
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
NS_IMETHOD GetInnerHTML(nsAString& aInnerHTML) override;
|
||||
using nsGenericHTMLElement::SetInnerHTML;
|
||||
virtual void SetInnerHTML(const nsAString& aInnerHTML,
|
||||
mozilla::ErrorResult& aError) override;
|
||||
|
||||
// nsIDOMHTMLScriptElement
|
||||
NS_DECL_NSIDOMHTMLSCRIPTELEMENT
|
||||
|
||||
// nsIScriptElement
|
||||
virtual bool GetScriptType(nsAString& type) override;
|
||||
virtual void GetScriptText(nsAString& text) override;
|
||||
virtual void GetScriptCharset(nsAString& charset) override;
|
||||
virtual void FreezeUriAsyncDefer() override;
|
||||
virtual CORSMode GetCORSMode() const override;
|
||||
|
||||
// nsIContent
|
||||
virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
||||
nsIContent* aBindingParent,
|
||||
bool aCompileEventHandlers) override;
|
||||
virtual bool ParseAttribute(int32_t aNamespaceID,
|
||||
nsIAtom* aAttribute,
|
||||
const nsAString& aValue,
|
||||
nsAttrValue& aResult) override;
|
||||
|
||||
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
|
||||
|
||||
// Element
|
||||
virtual nsresult AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
|
||||
const nsAttrValue* aValue, bool aNotify) override;
|
||||
|
||||
// WebIDL
|
||||
void SetText(const nsAString& aValue, ErrorResult& rv);
|
||||
void SetCharset(const nsAString& aCharset, ErrorResult& rv);
|
||||
void SetDefer(bool aDefer, ErrorResult& rv);
|
||||
bool Defer();
|
||||
void SetSrc(const nsAString& aSrc, ErrorResult& rv);
|
||||
void SetType(const nsAString& aType, ErrorResult& rv);
|
||||
void SetHtmlFor(const nsAString& aHtmlFor, ErrorResult& rv);
|
||||
void SetEvent(const nsAString& aEvent, ErrorResult& rv);
|
||||
void GetCrossOrigin(nsAString& aResult)
|
||||
{
|
||||
// Null for both missing and invalid defaults is ok, since we
|
||||
// always parse to an enum value, so we don't need an invalid
|
||||
// default, and we _want_ the missing default to be null.
|
||||
GetEnumAttr(nsGkAtoms::crossorigin, nullptr, aResult);
|
||||
}
|
||||
void SetCrossOrigin(const nsAString& aCrossOrigin, ErrorResult& aError)
|
||||
{
|
||||
SetOrRemoveNullableStringAttr(nsGkAtoms::crossorigin, aCrossOrigin, aError);
|
||||
}
|
||||
void GetIntegrity(nsAString& aIntegrity)
|
||||
{
|
||||
GetHTMLAttr(nsGkAtoms::integrity, aIntegrity);
|
||||
}
|
||||
void SetIntegrity(const nsAString& aIntegrity, ErrorResult& rv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::integrity, aIntegrity, rv);
|
||||
}
|
||||
bool Async();
|
||||
void SetAsync(bool aValue, ErrorResult& rv);
|
||||
|
||||
protected:
|
||||
virtual ~HTMLScriptElement();
|
||||
|
||||
virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
// nsScriptElement
|
||||
virtual bool HasScriptContent() override;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_HTMLScriptElement_h
|
||||
1917
dom/html/HTMLSelectElement.cpp
Normal file
1917
dom/html/HTMLSelectElement.cpp
Normal file
File diff suppressed because it is too large
Load diff
659
dom/html/HTMLSelectElement.h
Normal file
659
dom/html/HTMLSelectElement.h
Normal file
|
|
@ -0,0 +1,659 @@
|
|||
/* -*- 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/. */
|
||||
#ifndef mozilla_dom_HTMLSelectElement_h
|
||||
#define mozilla_dom_HTMLSelectElement_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsGenericHTMLElement.h"
|
||||
#include "nsIDOMHTMLSelectElement.h"
|
||||
#include "nsIConstraintValidation.h"
|
||||
|
||||
#include "mozilla/dom/BindingDeclarations.h"
|
||||
#include "mozilla/dom/HTMLOptionsCollection.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "nsCheapSets.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsError.h"
|
||||
#include "mozilla/dom/HTMLFormElement.h"
|
||||
#include "nsContentUtils.h"
|
||||
|
||||
class nsContentList;
|
||||
class nsIDOMHTMLOptionElement;
|
||||
class nsIHTMLCollection;
|
||||
class nsISelectControlFrame;
|
||||
class nsPresState;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class EventChainPostVisitor;
|
||||
class EventChainPreVisitor;
|
||||
|
||||
namespace dom {
|
||||
|
||||
class HTMLFormSubmission;
|
||||
class HTMLSelectElement;
|
||||
|
||||
#define NS_SELECT_STATE_IID \
|
||||
{ /* 4db54c7c-d159-455f-9d8e-f60ee466dbf3 */ \
|
||||
0x4db54c7c, \
|
||||
0xd159, \
|
||||
0x455f, \
|
||||
{0x9d, 0x8e, 0xf6, 0x0e, 0xe4, 0x66, 0xdb, 0xf3} \
|
||||
}
|
||||
|
||||
/**
|
||||
* The restore state used by select
|
||||
*/
|
||||
class SelectState : public nsISupports
|
||||
{
|
||||
public:
|
||||
SelectState()
|
||||
{
|
||||
}
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_SELECT_STATE_IID)
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
void PutOption(int32_t aIndex, const nsAString& aValue)
|
||||
{
|
||||
// If the option is empty, store the index. If not, store the value.
|
||||
if (aValue.IsEmpty()) {
|
||||
mIndices.Put(aIndex);
|
||||
} else {
|
||||
mValues.Put(aValue);
|
||||
}
|
||||
}
|
||||
|
||||
bool ContainsOption(int32_t aIndex, const nsAString& aValue)
|
||||
{
|
||||
return mValues.Contains(aValue) || mIndices.Contains(aIndex);
|
||||
}
|
||||
|
||||
private:
|
||||
virtual ~SelectState()
|
||||
{
|
||||
}
|
||||
|
||||
nsCheapSet<nsStringHashKey> mValues;
|
||||
nsCheapSet<nsUint32HashKey> mIndices;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(SelectState, NS_SELECT_STATE_IID)
|
||||
|
||||
class MOZ_STACK_CLASS SafeOptionListMutation
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @param aSelect The select element which option list is being mutated.
|
||||
* Can be null.
|
||||
* @param aParent The content object which is being mutated.
|
||||
* @param aKid If not null, a new child element is being inserted to
|
||||
* aParent. Otherwise a child element will be removed.
|
||||
* @param aIndex The index of the content object in the parent.
|
||||
*/
|
||||
SafeOptionListMutation(nsIContent* aSelect, nsIContent* aParent,
|
||||
nsIContent* aKid, uint32_t aIndex, bool aNotify);
|
||||
~SafeOptionListMutation();
|
||||
void MutationFailed() { mNeedsRebuild = true; }
|
||||
private:
|
||||
static void* operator new(size_t) CPP_THROW_NEW { return 0; }
|
||||
static void operator delete(void*, size_t) {}
|
||||
/** The select element which option list is being mutated. */
|
||||
RefPtr<HTMLSelectElement> mSelect;
|
||||
/** true if the current mutation is the first one in the stack. */
|
||||
bool mTopLevelMutation;
|
||||
/** true if it is known that the option list must be recreated. */
|
||||
bool mNeedsRebuild;
|
||||
/** Option list must be recreated if more than one mutation is detected. */
|
||||
nsMutationGuard mGuard;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Implementation of <select>
|
||||
*/
|
||||
class HTMLSelectElement final : public nsGenericHTMLFormElementWithState,
|
||||
public nsIDOMHTMLSelectElement,
|
||||
public nsIConstraintValidation
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* IS_SELECTED whether to set the option(s) to true or false
|
||||
*
|
||||
* CLEAR_ALL whether to clear all other options (for example, if you
|
||||
* are normal-clicking on the current option)
|
||||
*
|
||||
* SET_DISABLED whether it is permissible to set disabled options
|
||||
* (for JavaScript)
|
||||
*
|
||||
* NOTIFY whether to notify frames and such
|
||||
*/
|
||||
enum OptionType {
|
||||
IS_SELECTED = 1 << 0,
|
||||
CLEAR_ALL = 1 << 1,
|
||||
SET_DISABLED = 1 << 2,
|
||||
NOTIFY = 1 << 3
|
||||
};
|
||||
|
||||
using nsIConstraintValidation::GetValidationMessage;
|
||||
|
||||
explicit HTMLSelectElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo,
|
||||
FromParser aFromParser = NOT_FROM_PARSER);
|
||||
|
||||
NS_IMPL_FROMCONTENT_HTML_WITH_TAG(HTMLSelectElement, select)
|
||||
|
||||
// nsISupports
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
virtual int32_t TabIndexDefault() override;
|
||||
|
||||
// Element
|
||||
virtual bool IsInteractiveHTMLContent(bool aIgnoreTabindex) const override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// nsIDOMHTMLSelectElement
|
||||
NS_DECL_NSIDOMHTMLSELECTELEMENT
|
||||
|
||||
// WebIdl HTMLSelectElement
|
||||
bool Autofocus() const
|
||||
{
|
||||
return GetBoolAttr(nsGkAtoms::autofocus);
|
||||
}
|
||||
void SetAutofocus(bool aVal, ErrorResult& aRv)
|
||||
{
|
||||
SetHTMLBoolAttr(nsGkAtoms::autofocus, aVal, aRv);
|
||||
}
|
||||
void GetAutocomplete(DOMString& aValue);
|
||||
void SetAutocomplete(const nsAString& aValue, ErrorResult& aRv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::autocomplete, aValue, aRv);
|
||||
}
|
||||
bool Disabled() const
|
||||
{
|
||||
return GetBoolAttr(nsGkAtoms::disabled);
|
||||
}
|
||||
void SetDisabled(bool aVal, ErrorResult& aRv)
|
||||
{
|
||||
SetHTMLBoolAttr(nsGkAtoms::disabled, aVal, aRv);
|
||||
}
|
||||
HTMLFormElement* GetForm() const
|
||||
{
|
||||
return nsGenericHTMLFormElementWithState::GetForm();
|
||||
}
|
||||
bool Multiple() const
|
||||
{
|
||||
return GetBoolAttr(nsGkAtoms::multiple);
|
||||
}
|
||||
void SetMultiple(bool aVal, ErrorResult& aRv)
|
||||
{
|
||||
SetHTMLBoolAttr(nsGkAtoms::multiple, aVal, aRv);
|
||||
}
|
||||
// Uses XPCOM GetName.
|
||||
void SetName(const nsAString& aName, ErrorResult& aRv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::name, aName, aRv);
|
||||
}
|
||||
bool Required() const
|
||||
{
|
||||
return GetBoolAttr(nsGkAtoms::required);
|
||||
}
|
||||
void SetRequired(bool aVal, ErrorResult& aRv)
|
||||
{
|
||||
SetHTMLBoolAttr(nsGkAtoms::required, aVal, aRv);
|
||||
}
|
||||
uint32_t Size() const
|
||||
{
|
||||
return GetUnsignedIntAttr(nsGkAtoms::size, 0);
|
||||
}
|
||||
void SetSize(uint32_t aSize, ErrorResult& aRv)
|
||||
{
|
||||
SetUnsignedIntAttr(nsGkAtoms::size, aSize, 0, aRv);
|
||||
}
|
||||
|
||||
// Uses XPCOM GetType.
|
||||
|
||||
HTMLOptionsCollection* Options() const
|
||||
{
|
||||
return mOptions;
|
||||
}
|
||||
uint32_t Length() const
|
||||
{
|
||||
return mOptions->Length();
|
||||
}
|
||||
void SetLength(uint32_t aLength, ErrorResult& aRv);
|
||||
Element* IndexedGetter(uint32_t aIdx, bool& aFound) const
|
||||
{
|
||||
return mOptions->IndexedGetter(aIdx, aFound);
|
||||
}
|
||||
HTMLOptionElement* Item(uint32_t aIdx) const
|
||||
{
|
||||
return mOptions->ItemAsOption(aIdx);
|
||||
}
|
||||
HTMLOptionElement* NamedItem(const nsAString& aName) const
|
||||
{
|
||||
return mOptions->GetNamedItem(aName);
|
||||
}
|
||||
void Add(const HTMLOptionElementOrHTMLOptGroupElement& aElement,
|
||||
const Nullable<HTMLElementOrLong>& aBefore,
|
||||
ErrorResult& aRv);
|
||||
// Uses XPCOM Remove.
|
||||
void IndexedSetter(uint32_t aIndex, HTMLOptionElement* aOption,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
mOptions->IndexedSetter(aIndex, aOption, aRv);
|
||||
}
|
||||
|
||||
static bool MatchSelectedOptions(nsIContent* aContent, int32_t, nsIAtom*,
|
||||
void*);
|
||||
|
||||
nsIHTMLCollection* SelectedOptions();
|
||||
|
||||
int32_t SelectedIndex() const
|
||||
{
|
||||
return mSelectedIndex;
|
||||
}
|
||||
void SetSelectedIndex(int32_t aIdx, ErrorResult& aRv)
|
||||
{
|
||||
aRv = SetSelectedIndexInternal(aIdx, true);
|
||||
}
|
||||
void GetValue(DOMString& aValue);
|
||||
// Uses XPCOM SetValue.
|
||||
|
||||
// nsIConstraintValidation::WillValidate is fine.
|
||||
// nsIConstraintValidation::Validity() is fine.
|
||||
// nsIConstraintValidation::GetValidationMessage() is fine.
|
||||
// nsIConstraintValidation::CheckValidity() is fine.
|
||||
using nsIConstraintValidation::CheckValidity;
|
||||
using nsIConstraintValidation::ReportValidity;
|
||||
// nsIConstraintValidation::SetCustomValidity() is fine.
|
||||
|
||||
using nsINode::Remove;
|
||||
|
||||
|
||||
// nsINode
|
||||
virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
// nsIContent
|
||||
virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override;
|
||||
virtual nsresult PostHandleEvent(
|
||||
EventChainPostVisitor& aVisitor) override;
|
||||
|
||||
virtual bool IsHTMLFocusable(bool aWithMouse, bool* aIsFocusable, int32_t* aTabIndex) override;
|
||||
virtual nsresult InsertChildAt(nsIContent* aKid, uint32_t aIndex,
|
||||
bool aNotify) override;
|
||||
virtual void RemoveChildAt(uint32_t aIndex, bool aNotify) override;
|
||||
|
||||
// Overriden nsIFormControl methods
|
||||
NS_IMETHOD_(uint32_t) GetType() const override { return NS_FORM_SELECT; }
|
||||
NS_IMETHOD Reset() override;
|
||||
NS_IMETHOD SubmitNamesValues(HTMLFormSubmission* aFormSubmission) override;
|
||||
NS_IMETHOD SaveState() override;
|
||||
virtual bool RestoreState(nsPresState* aState) override;
|
||||
virtual bool IsDisabledForEvents(EventMessage aMessage) override;
|
||||
|
||||
virtual void FieldSetDisabledChanged(bool aNotify) override;
|
||||
|
||||
EventStates IntrinsicState() const override;
|
||||
|
||||
/**
|
||||
* To be called when stuff is added under a child of the select--but *before*
|
||||
* they are actually added.
|
||||
*
|
||||
* @param aOptions the content that was added (usually just an option, but
|
||||
* could be an optgroup node with many child options)
|
||||
* @param aParent the parent the options were added to (could be an optgroup)
|
||||
* @param aContentIndex the index where the options are being added within the
|
||||
* parent (if the parent is an optgroup, the index within the optgroup)
|
||||
*/
|
||||
NS_IMETHOD WillAddOptions(nsIContent* aOptions,
|
||||
nsIContent* aParent,
|
||||
int32_t aContentIndex,
|
||||
bool aNotify);
|
||||
|
||||
/**
|
||||
* To be called when stuff is removed under a child of the select--but
|
||||
* *before* they are actually removed.
|
||||
*
|
||||
* @param aParent the parent the option(s) are being removed from
|
||||
* @param aContentIndex the index of the option(s) within the parent (if the
|
||||
* parent is an optgroup, the index within the optgroup)
|
||||
*/
|
||||
NS_IMETHOD WillRemoveOptions(nsIContent* aParent,
|
||||
int32_t aContentIndex,
|
||||
bool aNotify);
|
||||
|
||||
/**
|
||||
* Checks whether an option is disabled (even if it's part of an optgroup)
|
||||
*
|
||||
* @param aIndex the index of the option to check
|
||||
* @return whether the option is disabled
|
||||
*/
|
||||
NS_IMETHOD IsOptionDisabled(int32_t aIndex,
|
||||
bool* aIsDisabled);
|
||||
bool IsOptionDisabled(HTMLOptionElement* aOption);
|
||||
|
||||
/**
|
||||
* Sets multiple options (or just sets startIndex if select is single)
|
||||
* and handles notifications and cleanup and everything under the sun.
|
||||
* When this method exits, the select will be in a consistent state. i.e.
|
||||
* if you set the last option to false, it will select an option anyway.
|
||||
*
|
||||
* @param aStartIndex the first index to set
|
||||
* @param aEndIndex the last index to set (set same as first index for one
|
||||
* option)
|
||||
* @param aOptionsMask determines whether to set, clear all or disable
|
||||
* options and whether frames are to be notified of such.
|
||||
* @return whether any options were actually changed
|
||||
*/
|
||||
bool SetOptionsSelectedByIndex(int32_t aStartIndex,
|
||||
int32_t aEndIndex,
|
||||
uint32_t aOptionsMask);
|
||||
|
||||
/**
|
||||
* Finds the index of a given option element
|
||||
*
|
||||
* @param aOption the option to get the index of
|
||||
* @param aStartIndex the index to start looking at
|
||||
* @param aForward TRUE to look forward, FALSE to look backward
|
||||
* @return the option index
|
||||
*/
|
||||
NS_IMETHOD GetOptionIndex(nsIDOMHTMLOptionElement* aOption,
|
||||
int32_t aStartIndex,
|
||||
bool aForward,
|
||||
int32_t* aIndex);
|
||||
|
||||
/**
|
||||
* Called when an attribute is about to be changed
|
||||
*/
|
||||
virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
||||
nsIContent* aBindingParent,
|
||||
bool aCompileEventHandlers) override;
|
||||
virtual void UnbindFromTree(bool aDeep, bool aNullParent) override;
|
||||
virtual nsresult BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
nsAttrValueOrString* aValue,
|
||||
bool aNotify) override;
|
||||
virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
const nsAttrValue* aValue, bool aNotify) override;
|
||||
virtual nsresult UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
|
||||
bool aNotify) override;
|
||||
|
||||
virtual void DoneAddingChildren(bool aHaveNotified) override;
|
||||
virtual bool IsDoneAddingChildren() override {
|
||||
return mIsDoneAddingChildren;
|
||||
}
|
||||
|
||||
virtual bool ParseAttribute(int32_t aNamespaceID,
|
||||
nsIAtom* aAttribute,
|
||||
const nsAString& aValue,
|
||||
nsAttrValue& aResult) override;
|
||||
virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const override;
|
||||
virtual nsChangeHint GetAttributeChangeHint(const nsIAtom* aAttribute,
|
||||
int32_t aModType) const override;
|
||||
NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
|
||||
|
||||
virtual nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult) const override;
|
||||
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLSelectElement,
|
||||
nsGenericHTMLFormElementWithState)
|
||||
|
||||
HTMLOptionsCollection* GetOptions()
|
||||
{
|
||||
return mOptions;
|
||||
}
|
||||
|
||||
// nsIConstraintValidation
|
||||
nsresult GetValidationMessage(nsAString& aValidationMessage,
|
||||
ValidityStateType aType) override;
|
||||
|
||||
void UpdateValueMissingValidityState();
|
||||
/**
|
||||
* Insert aElement before the node given by aBefore
|
||||
*/
|
||||
void Add(nsGenericHTMLElement& aElement, nsGenericHTMLElement* aBefore,
|
||||
ErrorResult& aError);
|
||||
void Add(nsGenericHTMLElement& aElement, int32_t aIndex, ErrorResult& aError)
|
||||
{
|
||||
// If item index is out of range, insert to last.
|
||||
// (since beforeElement becomes null, it is inserted to last)
|
||||
nsIContent* beforeContent = mOptions->GetElementAt(aIndex);
|
||||
return Add(aElement, nsGenericHTMLElement::FromContentOrNull(beforeContent),
|
||||
aError);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this a combobox?
|
||||
*/
|
||||
bool IsCombobox() const
|
||||
{
|
||||
return !Multiple() && Size() <= 1;
|
||||
}
|
||||
|
||||
bool OpenInParentProcess();
|
||||
void SetOpenInParentProcess(bool aVal);
|
||||
|
||||
protected:
|
||||
virtual ~HTMLSelectElement();
|
||||
|
||||
friend class SafeOptionListMutation;
|
||||
|
||||
// Helper Methods
|
||||
/**
|
||||
* Check whether the option specified by the index is selected
|
||||
* @param aIndex the index
|
||||
* @return whether the option at the index is selected
|
||||
*/
|
||||
bool IsOptionSelectedByIndex(int32_t aIndex);
|
||||
/**
|
||||
* Starting with (and including) aStartIndex, find the first selected index
|
||||
* and set mSelectedIndex to it.
|
||||
* @param aStartIndex the index to start with
|
||||
*/
|
||||
void FindSelectedIndex(int32_t aStartIndex, bool aNotify);
|
||||
/**
|
||||
* Select some option if possible (generally the first non-disabled option).
|
||||
* @return true if something was selected, false otherwise
|
||||
*/
|
||||
bool SelectSomething(bool aNotify);
|
||||
/**
|
||||
* Call SelectSomething(), but only if nothing is selected
|
||||
* @see SelectSomething()
|
||||
* @return true if something was selected, false otherwise
|
||||
*/
|
||||
bool CheckSelectSomething(bool aNotify);
|
||||
/**
|
||||
* Called to trigger notifications of frames and fixing selected index
|
||||
*
|
||||
* @param aSelectFrame the frame for this content (could be null)
|
||||
* @param aIndex the index that was selected or deselected
|
||||
* @param aSelected whether the index was selected or deselected
|
||||
* @param aChangeOptionState if false, don't do anything to the
|
||||
* HTMLOptionElement at aIndex. If true, change
|
||||
* its selected state to aSelected.
|
||||
* @param aNotify whether to notify the style system and such
|
||||
*/
|
||||
void OnOptionSelected(nsISelectControlFrame* aSelectFrame,
|
||||
int32_t aIndex,
|
||||
bool aSelected,
|
||||
bool aChangeOptionState,
|
||||
bool aNotify);
|
||||
/**
|
||||
* Restore state to a particular state string (representing the options)
|
||||
* @param aNewSelected the state string to restore to
|
||||
*/
|
||||
void RestoreStateTo(SelectState* aNewSelected);
|
||||
|
||||
// Adding options
|
||||
/**
|
||||
* Insert option(s) into the options[] array and perform notifications
|
||||
* @param aOptions the option or optgroup being added
|
||||
* @param aListIndex the index to start adding options into the list at
|
||||
* @param aDepth the depth of aOptions (1=direct child of select ...)
|
||||
*/
|
||||
void InsertOptionsIntoList(nsIContent* aOptions,
|
||||
int32_t aListIndex,
|
||||
int32_t aDepth,
|
||||
bool aNotify);
|
||||
/**
|
||||
* Remove option(s) from the options[] array
|
||||
* @param aOptions the option or optgroup being added
|
||||
* @param aListIndex the index to start removing options from the list at
|
||||
* @param aDepth the depth of aOptions (1=direct child of select ...)
|
||||
*/
|
||||
nsresult RemoveOptionsFromList(nsIContent* aOptions,
|
||||
int32_t aListIndex,
|
||||
int32_t aDepth,
|
||||
bool aNotify);
|
||||
|
||||
// nsIConstraintValidation
|
||||
void UpdateBarredFromConstraintValidation();
|
||||
bool IsValueMissing();
|
||||
|
||||
/**
|
||||
* Get the index of the first option at, under or following the content in
|
||||
* the select, or length of options[] if none are found
|
||||
* @param aOptions the content
|
||||
* @return the index of the first option
|
||||
*/
|
||||
int32_t GetOptionIndexAt(nsIContent* aOptions);
|
||||
/**
|
||||
* Get the next option following the content in question (not at or under)
|
||||
* (this could include siblings of the current content or siblings of the
|
||||
* parent or children of siblings of the parent).
|
||||
* @param aOptions the content
|
||||
* @return the index of the next option after the content
|
||||
*/
|
||||
int32_t GetOptionIndexAfter(nsIContent* aOptions);
|
||||
/**
|
||||
* Get the first option index at or under the content in question.
|
||||
* @param aOptions the content
|
||||
* @return the index of the first option at or under the content
|
||||
*/
|
||||
int32_t GetFirstOptionIndex(nsIContent* aOptions);
|
||||
/**
|
||||
* Get the first option index under the content in question, within the
|
||||
* range specified.
|
||||
* @param aOptions the content
|
||||
* @param aStartIndex the first child to look at
|
||||
* @param aEndIndex the child *after* the last child to look at
|
||||
* @return the index of the first option at or under the content
|
||||
*/
|
||||
int32_t GetFirstChildOptionIndex(nsIContent* aOptions,
|
||||
int32_t aStartIndex,
|
||||
int32_t aEndIndex);
|
||||
|
||||
/**
|
||||
* Get the frame as an nsISelectControlFrame (MAY RETURN nullptr)
|
||||
* @return the select frame, or null
|
||||
*/
|
||||
nsISelectControlFrame* GetSelectFrame();
|
||||
|
||||
/**
|
||||
* Helper method for dispatching ContentReset notifications to list
|
||||
* and combo box frames.
|
||||
*/
|
||||
void DispatchContentReset();
|
||||
|
||||
/**
|
||||
* Rebuilds the options array from scratch as a fallback in error cases.
|
||||
*/
|
||||
void RebuildOptionsArray(bool aNotify);
|
||||
|
||||
#ifdef DEBUG
|
||||
void VerifyOptionsArray();
|
||||
#endif
|
||||
|
||||
nsresult SetSelectedIndexInternal(int32_t aIndex, bool aNotify);
|
||||
|
||||
void SetSelectionChanged(bool aValue, bool aNotify);
|
||||
|
||||
/**
|
||||
* Marks the selectedOptions list as dirty, so that it'll populate itself
|
||||
* again.
|
||||
*/
|
||||
void UpdateSelectedOptions();
|
||||
|
||||
/**
|
||||
* Return whether an element should have a validity UI.
|
||||
* (with :-moz-ui-invalid and :-moz-ui-valid pseudo-classes).
|
||||
*
|
||||
* @return Whether the element should have a validity UI.
|
||||
*/
|
||||
bool ShouldShowValidityUI() const {
|
||||
/**
|
||||
* Always show the validity UI if the form has already tried to be submitted
|
||||
* but was invalid.
|
||||
*
|
||||
* Otherwise, show the validity UI if the selection has been changed.
|
||||
*/
|
||||
if (mForm && mForm->HasEverTriedInvalidSubmit()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return mSelectionHasChanged;
|
||||
}
|
||||
|
||||
/** The options[] array */
|
||||
RefPtr<HTMLOptionsCollection> mOptions;
|
||||
nsContentUtils::AutocompleteAttrState mAutocompleteAttrState;
|
||||
/** false if the parser is in the middle of adding children. */
|
||||
bool mIsDoneAddingChildren;
|
||||
/** true if our disabled state has changed from the default **/
|
||||
bool mDisabledChanged;
|
||||
/** true if child nodes are being added or removed.
|
||||
* Used by SafeOptionListMutation.
|
||||
*/
|
||||
bool mMutating;
|
||||
/**
|
||||
* True if DoneAddingChildren will get called but shouldn't restore state.
|
||||
*/
|
||||
bool mInhibitStateRestoration;
|
||||
/**
|
||||
* True if the selection has changed since the element's creation.
|
||||
*/
|
||||
bool mSelectionHasChanged;
|
||||
/**
|
||||
* True if the default selected option has been set.
|
||||
*/
|
||||
bool mDefaultSelectionSet;
|
||||
/**
|
||||
* True if :-moz-ui-invalid can be shown.
|
||||
*/
|
||||
bool mCanShowInvalidUI;
|
||||
/**
|
||||
* True if :-moz-ui-valid can be shown.
|
||||
*/
|
||||
bool mCanShowValidUI;
|
||||
|
||||
/** The number of non-options as children of the select */
|
||||
uint32_t mNonOptionChildren;
|
||||
/** The number of optgroups anywhere under the select */
|
||||
uint32_t mOptGroupCount;
|
||||
/**
|
||||
* The current selected index for selectedIndex (will be the first selected
|
||||
* index if multiple are selected)
|
||||
*/
|
||||
int32_t mSelectedIndex;
|
||||
/**
|
||||
* The temporary restore state in case we try to restore before parser is
|
||||
* done adding options
|
||||
*/
|
||||
nsCOMPtr<SelectState> mRestoreState;
|
||||
|
||||
/**
|
||||
* The live list of selected options.
|
||||
*/
|
||||
RefPtr<nsContentList> mSelectedOptions;
|
||||
|
||||
private:
|
||||
static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
|
||||
nsRuleData* aData);
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_HTMLSelectElement_h
|
||||
373
dom/html/HTMLShadowElement.cpp
Normal file
373
dom/html/HTMLShadowElement.cpp
Normal file
|
|
@ -0,0 +1,373 @@
|
|||
/* -*- 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/ShadowRoot.h"
|
||||
|
||||
#include "ChildIterator.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsDocument.h"
|
||||
#include "mozilla/dom/HTMLShadowElement.h"
|
||||
#include "mozilla/dom/HTMLUnknownElement.h"
|
||||
#include "mozilla/dom/HTMLShadowElementBinding.h"
|
||||
|
||||
// Expand NS_IMPL_NS_NEW_HTML_ELEMENT(Shadow) to add check for web components
|
||||
// being enabled.
|
||||
nsGenericHTMLElement*
|
||||
NS_NewHTMLShadowElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
|
||||
mozilla::dom::FromParser aFromParser)
|
||||
{
|
||||
// When this check is removed, remove the nsDocument.h and
|
||||
// HTMLUnknownElement.h includes. Also remove nsINode::IsHTMLShadowElement.
|
||||
//
|
||||
// We have to jump through some hoops to be able to produce both NodeInfo* and
|
||||
// already_AddRefed<NodeInfo>& for our callees.
|
||||
RefPtr<mozilla::dom::NodeInfo> nodeInfo(aNodeInfo);
|
||||
if (!nsDocument::IsWebComponentsEnabled(nodeInfo)) {
|
||||
already_AddRefed<mozilla::dom::NodeInfo> nodeInfoArg(nodeInfo.forget());
|
||||
return new mozilla::dom::HTMLUnknownElement(nodeInfoArg);
|
||||
}
|
||||
|
||||
already_AddRefed<mozilla::dom::NodeInfo> nodeInfoArg(nodeInfo.forget());
|
||||
return new mozilla::dom::HTMLShadowElement(nodeInfoArg);
|
||||
}
|
||||
|
||||
using namespace mozilla::dom;
|
||||
|
||||
HTMLShadowElement::HTMLShadowElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
|
||||
: nsGenericHTMLElement(aNodeInfo), mIsInsertionPoint(false)
|
||||
{
|
||||
}
|
||||
|
||||
HTMLShadowElement::~HTMLShadowElement()
|
||||
{
|
||||
if (mProjectedShadow) {
|
||||
mProjectedShadow->RemoveMutationObserver(this);
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(HTMLShadowElement)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLShadowElement,
|
||||
nsGenericHTMLElement)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mProjectedShadow)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLShadowElement,
|
||||
nsGenericHTMLElement)
|
||||
if (tmp->mProjectedShadow) {
|
||||
tmp->mProjectedShadow->RemoveMutationObserver(tmp);
|
||||
tmp->mProjectedShadow = nullptr;
|
||||
}
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(HTMLShadowElement, Element)
|
||||
NS_IMPL_RELEASE_INHERITED(HTMLShadowElement, Element)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(HTMLShadowElement)
|
||||
NS_INTERFACE_MAP_END_INHERITING(nsGenericHTMLElement)
|
||||
|
||||
NS_IMPL_ELEMENT_CLONE(HTMLShadowElement)
|
||||
|
||||
JSObject*
|
||||
HTMLShadowElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return HTMLShadowElementBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLShadowElement::SetProjectedShadow(ShadowRoot* aProjectedShadow)
|
||||
{
|
||||
if (mProjectedShadow) {
|
||||
mProjectedShadow->RemoveMutationObserver(this);
|
||||
|
||||
// The currently projected ShadowRoot is going away,
|
||||
// thus the destination insertion points need to be updated.
|
||||
ExplicitChildIterator childIterator(mProjectedShadow);
|
||||
for (nsIContent* content = childIterator.GetNextChild();
|
||||
content;
|
||||
content = childIterator.GetNextChild()) {
|
||||
ShadowRoot::RemoveDestInsertionPoint(this, content->DestInsertionPoints());
|
||||
}
|
||||
}
|
||||
|
||||
mProjectedShadow = aProjectedShadow;
|
||||
if (mProjectedShadow) {
|
||||
// A new ShadowRoot is being projected, thus its explcit
|
||||
// children will be distributed to this shadow insertion point.
|
||||
ExplicitChildIterator childIterator(mProjectedShadow);
|
||||
for (nsIContent* content = childIterator.GetNextChild();
|
||||
content;
|
||||
content = childIterator.GetNextChild()) {
|
||||
content->DestInsertionPoints().AppendElement(this);
|
||||
}
|
||||
|
||||
// Watch for mutations on the projected shadow because
|
||||
// it affects the nodes that are distributed to this shadow
|
||||
// insertion point.
|
||||
mProjectedShadow->AddMutationObserver(this);
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
IsInFallbackContent(nsIContent* aContent)
|
||||
{
|
||||
nsINode* parentNode = aContent->GetParentNode();
|
||||
while (parentNode) {
|
||||
if (parentNode->IsHTMLElement(nsGkAtoms::content)) {
|
||||
return true;
|
||||
}
|
||||
parentNode = parentNode->GetParentNode();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLShadowElement::BindToTree(nsIDocument* aDocument,
|
||||
nsIContent* aParent,
|
||||
nsIContent* aBindingParent,
|
||||
bool aCompileEventHandlers)
|
||||
{
|
||||
RefPtr<ShadowRoot> oldContainingShadow = GetContainingShadow();
|
||||
|
||||
nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent,
|
||||
aBindingParent,
|
||||
aCompileEventHandlers);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
ShadowRoot* containingShadow = GetContainingShadow();
|
||||
if (containingShadow && !oldContainingShadow) {
|
||||
// Keep track of all descendant <shadow> elements in tree order so
|
||||
// that when the current shadow insertion point is removed, the next
|
||||
// one can be found quickly.
|
||||
TreeOrderComparator comparator;
|
||||
containingShadow->ShadowDescendants().InsertElementSorted(this, comparator);
|
||||
|
||||
if (containingShadow->ShadowDescendants()[0] != this) {
|
||||
// Only the first <shadow> (in tree order) of a ShadowRoot can be an insertion point.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (IsInFallbackContent(this)) {
|
||||
// If the first shadow element in tree order is invalid (in fallback content),
|
||||
// the containing ShadowRoot will not have a shadow insertion point.
|
||||
containingShadow->SetShadowElement(nullptr);
|
||||
} else {
|
||||
mIsInsertionPoint = true;
|
||||
containingShadow->SetShadowElement(this);
|
||||
}
|
||||
|
||||
containingShadow->SetInsertionPointChanged();
|
||||
}
|
||||
|
||||
if (mIsInsertionPoint && containingShadow) {
|
||||
// Propagate BindToTree calls to projected shadow root children.
|
||||
ShadowRoot* projectedShadow = containingShadow->GetOlderShadowRoot();
|
||||
if (projectedShadow) {
|
||||
projectedShadow->SetIsComposedDocParticipant(IsInComposedDoc());
|
||||
|
||||
for (nsIContent* child = projectedShadow->GetFirstChild(); child;
|
||||
child = child->GetNextSibling()) {
|
||||
rv = child->BindToTree(nullptr, projectedShadow,
|
||||
projectedShadow->GetBindingParent(),
|
||||
aCompileEventHandlers);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
HTMLShadowElement::UnbindFromTree(bool aDeep, bool aNullParent)
|
||||
{
|
||||
RefPtr<ShadowRoot> oldContainingShadow = GetContainingShadow();
|
||||
|
||||
if (mIsInsertionPoint && oldContainingShadow) {
|
||||
// Propagate UnbindFromTree call to previous projected shadow
|
||||
// root children.
|
||||
ShadowRoot* projectedShadow = oldContainingShadow->GetOlderShadowRoot();
|
||||
if (projectedShadow) {
|
||||
for (nsIContent* child = projectedShadow->GetFirstChild(); child;
|
||||
child = child->GetNextSibling()) {
|
||||
child->UnbindFromTree(true, false);
|
||||
}
|
||||
|
||||
projectedShadow->SetIsComposedDocParticipant(false);
|
||||
}
|
||||
}
|
||||
|
||||
nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
|
||||
|
||||
if (oldContainingShadow && !GetContainingShadow() && mIsInsertionPoint) {
|
||||
nsTArray<HTMLShadowElement*>& shadowDescendants =
|
||||
oldContainingShadow->ShadowDescendants();
|
||||
shadowDescendants.RemoveElement(this);
|
||||
oldContainingShadow->SetShadowElement(nullptr);
|
||||
|
||||
// Find the next shadow insertion point.
|
||||
if (shadowDescendants.Length() > 0 &&
|
||||
!IsInFallbackContent(shadowDescendants[0])) {
|
||||
oldContainingShadow->SetShadowElement(shadowDescendants[0]);
|
||||
}
|
||||
|
||||
oldContainingShadow->SetInsertionPointChanged();
|
||||
|
||||
mIsInsertionPoint = false;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
HTMLShadowElement::DistributeSingleNode(nsIContent* aContent)
|
||||
{
|
||||
if (aContent->DestInsertionPoints().Contains(this)) {
|
||||
// Node has already been distrbuted this this node,
|
||||
// we are done.
|
||||
return;
|
||||
}
|
||||
|
||||
aContent->DestInsertionPoints().AppendElement(this);
|
||||
|
||||
// Handle the case where the shadow element is a child of
|
||||
// a node with a ShadowRoot. The nodes that have been distributed to
|
||||
// this shadow insertion point will need to be reprojected into the
|
||||
// insertion points of the parent's ShadowRoot.
|
||||
ShadowRoot* parentShadowRoot = GetParent()->GetShadowRoot();
|
||||
if (parentShadowRoot) {
|
||||
parentShadowRoot->DistributeSingleNode(aContent);
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle the case where the parent of this shadow element is a ShadowRoot
|
||||
// that is projected into a shadow insertion point in the younger ShadowRoot.
|
||||
ShadowRoot* containingShadow = GetContainingShadow();
|
||||
ShadowRoot* youngerShadow = containingShadow->GetYoungerShadowRoot();
|
||||
if (youngerShadow && GetParent() == containingShadow) {
|
||||
HTMLShadowElement* youngerShadowElement = youngerShadow->GetShadowElement();
|
||||
if (youngerShadowElement) {
|
||||
youngerShadowElement->DistributeSingleNode(aContent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
HTMLShadowElement::RemoveDistributedNode(nsIContent* aContent)
|
||||
{
|
||||
ShadowRoot::RemoveDestInsertionPoint(this, aContent->DestInsertionPoints());
|
||||
|
||||
// Handle the case where the shadow element is a child of
|
||||
// a node with a ShadowRoot. The nodes that have been distributed to
|
||||
// this shadow insertion point will need to be removed from the
|
||||
// insertion points of the parent's ShadowRoot.
|
||||
ShadowRoot* parentShadowRoot = GetParent()->GetShadowRoot();
|
||||
if (parentShadowRoot) {
|
||||
parentShadowRoot->RemoveDistributedNode(aContent);
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle the case where the parent of this shadow element is a ShadowRoot
|
||||
// that is projected into a shadow insertion point in the younger ShadowRoot.
|
||||
ShadowRoot* containingShadow = GetContainingShadow();
|
||||
ShadowRoot* youngerShadow = containingShadow->GetYoungerShadowRoot();
|
||||
if (youngerShadow && GetParent() == containingShadow) {
|
||||
HTMLShadowElement* youngerShadowElement = youngerShadow->GetShadowElement();
|
||||
if (youngerShadowElement) {
|
||||
youngerShadowElement->RemoveDistributedNode(aContent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
HTMLShadowElement::DistributeAllNodes()
|
||||
{
|
||||
// All the explicit children of the projected ShadowRoot are distributed
|
||||
// into this shadow insertion point so update the destination insertion
|
||||
// points.
|
||||
ShadowRoot* containingShadow = GetContainingShadow();
|
||||
ShadowRoot* olderShadow = containingShadow->GetOlderShadowRoot();
|
||||
if (olderShadow) {
|
||||
ExplicitChildIterator childIterator(olderShadow);
|
||||
for (nsIContent* content = childIterator.GetNextChild();
|
||||
content;
|
||||
content = childIterator.GetNextChild()) {
|
||||
ShadowRoot::RemoveDestInsertionPoint(this, content->DestInsertionPoints());
|
||||
content->DestInsertionPoints().AppendElement(this);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle the case where the shadow element is a child of
|
||||
// a node with a ShadowRoot. The nodes that have been distributed to
|
||||
// this shadow insertion point will need to be reprojected into the
|
||||
// insertion points of the parent's ShadowRoot.
|
||||
ShadowRoot* parentShadowRoot = GetParent()->GetShadowRoot();
|
||||
if (parentShadowRoot) {
|
||||
parentShadowRoot->DistributeAllNodes();
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle the case where the parent of this shadow element is a ShadowRoot
|
||||
// that is projected into a shadow insertion point in the younger ShadowRoot.
|
||||
ShadowRoot* youngerShadow = containingShadow->GetYoungerShadowRoot();
|
||||
if (youngerShadow && GetParent() == containingShadow) {
|
||||
HTMLShadowElement* youngerShadowElement = youngerShadow->GetShadowElement();
|
||||
if (youngerShadowElement) {
|
||||
youngerShadowElement->DistributeAllNodes();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
HTMLShadowElement::ContentAppended(nsIDocument* aDocument,
|
||||
nsIContent* aContainer,
|
||||
nsIContent* aFirstNewContent,
|
||||
int32_t aNewIndexInContainer)
|
||||
{
|
||||
// Watch for content appended to the projected shadow (the ShadowRoot that
|
||||
// will be rendered in place of this shadow insertion point) because the
|
||||
// nodes may need to be distributed into other insertion points.
|
||||
nsIContent* currentChild = aFirstNewContent;
|
||||
while (currentChild) {
|
||||
if (ShadowRoot::IsPooledNode(currentChild, aContainer, mProjectedShadow)) {
|
||||
DistributeSingleNode(currentChild);
|
||||
}
|
||||
currentChild = currentChild->GetNextSibling();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
HTMLShadowElement::ContentInserted(nsIDocument* aDocument,
|
||||
nsIContent* aContainer,
|
||||
nsIContent* aChild,
|
||||
int32_t aIndexInContainer)
|
||||
{
|
||||
// Watch for content appended to the projected shadow (the ShadowRoot that
|
||||
// will be rendered in place of this shadow insertion point) because the
|
||||
// nodes may need to be distributed into other insertion points.
|
||||
if (!ShadowRoot::IsPooledNode(aChild, aContainer, mProjectedShadow)) {
|
||||
return;
|
||||
}
|
||||
|
||||
DistributeSingleNode(aChild);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLShadowElement::ContentRemoved(nsIDocument* aDocument,
|
||||
nsIContent* aContainer,
|
||||
nsIContent* aChild,
|
||||
int32_t aIndexInContainer,
|
||||
nsIContent* aPreviousSibling)
|
||||
{
|
||||
// Watch for content removed from the projected shadow (the ShadowRoot that
|
||||
// will be rendered in place of this shadow insertion point) because the
|
||||
// nodes may need to be removed from other insertion points.
|
||||
if (!ShadowRoot::IsPooledNode(aChild, aContainer, mProjectedShadow)) {
|
||||
return;
|
||||
}
|
||||
|
||||
RemoveDistributedNode(aChild);
|
||||
}
|
||||
|
||||
96
dom/html/HTMLShadowElement.h
Normal file
96
dom/html/HTMLShadowElement.h
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_dom_HTMLShadowElement_h__
|
||||
#define mozilla_dom_HTMLShadowElement_h__
|
||||
|
||||
#include "nsGenericHTMLElement.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class HTMLShadowElement final : public nsGenericHTMLElement,
|
||||
public nsStubMutationObserver
|
||||
{
|
||||
public:
|
||||
explicit HTMLShadowElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
|
||||
|
||||
// nsISupports
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
|
||||
NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
|
||||
NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
|
||||
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLShadowElement,
|
||||
nsGenericHTMLElement)
|
||||
|
||||
static HTMLShadowElement* FromContent(nsIContent* aContent)
|
||||
{
|
||||
if (aContent->IsHTMLShadowElement()) {
|
||||
return static_cast<HTMLShadowElement*>(aContent);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
virtual bool IsHTMLShadowElement() const override { return true; }
|
||||
|
||||
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
|
||||
|
||||
virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
||||
nsIContent* aBindingParent,
|
||||
bool aCompileEventHandlers) override;
|
||||
|
||||
virtual void UnbindFromTree(bool aDeep = true,
|
||||
bool aNullParent = true) override;
|
||||
|
||||
bool IsInsertionPoint() { return mIsInsertionPoint; }
|
||||
|
||||
/**
|
||||
* Sets the ShadowRoot that will be rendered in place of
|
||||
* this shadow insertion point.
|
||||
*/
|
||||
void SetProjectedShadow(ShadowRoot* aProjectedShadow);
|
||||
|
||||
/**
|
||||
* Distributes a single explicit child of the projected ShadowRoot
|
||||
* to relevant insertion points.
|
||||
*/
|
||||
void DistributeSingleNode(nsIContent* aContent);
|
||||
|
||||
/**
|
||||
* Removes a single explicit child of the projected ShadowRoot
|
||||
* from relevant insertion points.
|
||||
*/
|
||||
void RemoveDistributedNode(nsIContent* aContent);
|
||||
|
||||
/**
|
||||
* Distributes all the explicit children of the projected ShadowRoot
|
||||
* to the shadow insertion point in the younger ShadowRoot and
|
||||
* the content insertion point of the parent node's ShadowRoot.
|
||||
*/
|
||||
void DistributeAllNodes();
|
||||
|
||||
// WebIDL methods.
|
||||
ShadowRoot* GetOlderShadowRoot() { return mProjectedShadow; }
|
||||
|
||||
protected:
|
||||
virtual ~HTMLShadowElement();
|
||||
|
||||
virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
// The ShadowRoot that will be rendered in place of this shadow insertion point.
|
||||
RefPtr<ShadowRoot> mProjectedShadow;
|
||||
|
||||
bool mIsInsertionPoint;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_HTMLShadowElement_h__
|
||||
|
||||
360
dom/html/HTMLSharedElement.cpp
Normal file
360
dom/html/HTMLSharedElement.cpp
Normal file
|
|
@ -0,0 +1,360 @@
|
|||
/* -*- 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/HTMLSharedElement.h"
|
||||
#include "mozilla/dom/HTMLBaseElementBinding.h"
|
||||
#include "mozilla/dom/HTMLDirectoryElementBinding.h"
|
||||
#include "mozilla/dom/HTMLHeadElementBinding.h"
|
||||
#include "mozilla/dom/HTMLHtmlElementBinding.h"
|
||||
#include "mozilla/dom/HTMLParamElementBinding.h"
|
||||
#include "mozilla/dom/HTMLQuoteElementBinding.h"
|
||||
|
||||
#include "nsAttrValueInlines.h"
|
||||
#include "nsStyleConsts.h"
|
||||
#include "nsRuleData.h"
|
||||
#include "nsMappedAttributes.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsIContentSecurityPolicy.h"
|
||||
#include "nsIURI.h"
|
||||
|
||||
NS_IMPL_NS_NEW_HTML_ELEMENT(Shared)
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
extern nsAttrValue::EnumTable kListTypeTable[];
|
||||
|
||||
HTMLSharedElement::~HTMLSharedElement()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(HTMLSharedElement, Element)
|
||||
NS_IMPL_RELEASE_INHERITED(HTMLSharedElement, Element)
|
||||
|
||||
// QueryInterface implementation for HTMLSharedElement
|
||||
NS_INTERFACE_MAP_BEGIN(HTMLSharedElement)
|
||||
NS_INTERFACE_MAP_ENTRY_IF_TAG(nsIDOMHTMLBaseElement, base)
|
||||
NS_INTERFACE_MAP_ENTRY_IF_TAG(nsIDOMHTMLDirectoryElement, dir)
|
||||
NS_INTERFACE_MAP_ENTRY_IF_TAG(nsIDOMHTMLQuoteElement, q)
|
||||
NS_INTERFACE_MAP_ENTRY_IF_TAG(nsIDOMHTMLQuoteElement, blockquote)
|
||||
NS_INTERFACE_MAP_ENTRY_IF_TAG(nsIDOMHTMLHeadElement, head)
|
||||
NS_INTERFACE_MAP_ENTRY_IF_TAG(nsIDOMHTMLHtmlElement, html)
|
||||
NS_INTERFACE_MAP_END_INHERITING(nsGenericHTMLElement)
|
||||
|
||||
|
||||
NS_IMPL_ELEMENT_CLONE(HTMLSharedElement)
|
||||
|
||||
// nsIDOMHTMLQuoteElement
|
||||
NS_IMPL_URI_ATTR(HTMLSharedElement, Cite, cite)
|
||||
|
||||
// nsIDOMHTMLHeadElement
|
||||
// Empty
|
||||
|
||||
// nsIDOMHTMLHtmlElement
|
||||
NS_IMPL_STRING_ATTR(HTMLSharedElement, Version, version)
|
||||
|
||||
// nsIDOMHTMLBaseElement
|
||||
NS_IMPL_STRING_ATTR(HTMLSharedElement, Target, target)
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLSharedElement::GetHref(nsAString& aValue)
|
||||
{
|
||||
MOZ_ASSERT(mNodeInfo->Equals(nsGkAtoms::base),
|
||||
"This should only get called for <base> elements");
|
||||
nsAutoString href;
|
||||
GetAttr(kNameSpaceID_None, nsGkAtoms::href, href);
|
||||
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
nsIDocument* doc = OwnerDoc();
|
||||
nsContentUtils::NewURIWithDocumentCharset(
|
||||
getter_AddRefs(uri), href, doc, doc->GetFallbackBaseURI());
|
||||
|
||||
if (!uri) {
|
||||
aValue = href;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsAutoCString spec;
|
||||
uri->GetSpec(spec);
|
||||
CopyUTF8toUTF16(spec, aValue);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLSharedElement::SetHref(const nsAString& aValue)
|
||||
{
|
||||
return SetAttrHelper(nsGkAtoms::href, aValue);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
HTMLSharedElement::ParseAttribute(int32_t aNamespaceID,
|
||||
nsIAtom* aAttribute,
|
||||
const nsAString& aValue,
|
||||
nsAttrValue& aResult)
|
||||
{
|
||||
if (aNamespaceID == kNameSpaceID_None &&
|
||||
mNodeInfo->Equals(nsGkAtoms::dir)) {
|
||||
if (aAttribute == nsGkAtoms::type) {
|
||||
return aResult.ParseEnumValue(aValue, mozilla::dom::kListTypeTable, false);
|
||||
}
|
||||
if (aAttribute == nsGkAtoms::start) {
|
||||
return aResult.ParseIntWithBounds(aValue, 1);
|
||||
}
|
||||
}
|
||||
|
||||
return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
|
||||
aResult);
|
||||
}
|
||||
|
||||
static void
|
||||
DirectoryMapAttributesIntoRule(const nsMappedAttributes* aAttributes,
|
||||
nsRuleData* aData)
|
||||
{
|
||||
if (aData->mSIDs & NS_STYLE_INHERIT_BIT(List)) {
|
||||
nsCSSValue* listStyleType = aData->ValueForListStyleType();
|
||||
if (listStyleType->GetUnit() == eCSSUnit_Null) {
|
||||
// type: enum
|
||||
const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::type);
|
||||
if (value) {
|
||||
if (value->Type() == nsAttrValue::eEnum) {
|
||||
listStyleType->SetIntValue(value->GetEnumValue(), eCSSUnit_Enumerated);
|
||||
} else {
|
||||
listStyleType->SetIntValue(NS_STYLE_LIST_STYLE_DISC, eCSSUnit_Enumerated);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aData);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(bool)
|
||||
HTMLSharedElement::IsAttributeMapped(const nsIAtom* aAttribute) const
|
||||
{
|
||||
if (mNodeInfo->Equals(nsGkAtoms::dir)) {
|
||||
static const MappedAttributeEntry attributes[] = {
|
||||
{ &nsGkAtoms::type },
|
||||
// { &nsGkAtoms::compact }, // XXX
|
||||
{ nullptr}
|
||||
};
|
||||
|
||||
static const MappedAttributeEntry* const map[] = {
|
||||
attributes,
|
||||
sCommonAttributeMap,
|
||||
};
|
||||
|
||||
return FindAttributeDependence(aAttribute, map);
|
||||
}
|
||||
|
||||
return nsGenericHTMLElement::IsAttributeMapped(aAttribute);
|
||||
}
|
||||
|
||||
static void
|
||||
SetBaseURIUsingFirstBaseWithHref(nsIDocument* aDocument, nsIContent* aMustMatch)
|
||||
{
|
||||
NS_PRECONDITION(aDocument, "Need a document!");
|
||||
|
||||
for (nsIContent* child = aDocument->GetFirstChild(); child;
|
||||
child = child->GetNextNode()) {
|
||||
if (child->IsHTMLElement(nsGkAtoms::base) &&
|
||||
child->HasAttr(kNameSpaceID_None, nsGkAtoms::href)) {
|
||||
if (aMustMatch && child != aMustMatch) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Resolve the <base> element's href relative to our document's
|
||||
// fallback base URI.
|
||||
nsAutoString href;
|
||||
child->GetAttr(kNameSpaceID_None, nsGkAtoms::href, href);
|
||||
|
||||
nsCOMPtr<nsIURI> newBaseURI;
|
||||
nsContentUtils::NewURIWithDocumentCharset(
|
||||
getter_AddRefs(newBaseURI), href, aDocument,
|
||||
aDocument->GetFallbackBaseURI());
|
||||
|
||||
// Check if CSP allows this base-uri
|
||||
nsCOMPtr<nsIContentSecurityPolicy> csp;
|
||||
nsresult rv = aDocument->NodePrincipal()->GetCsp(getter_AddRefs(csp));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Getting CSP Failed");
|
||||
// For all the different error cases we assign a nullptr to
|
||||
// newBaseURI, so we basically call aDocument->SetBaseURI(nullptr);
|
||||
if (NS_FAILED(rv)) {
|
||||
newBaseURI = nullptr;
|
||||
}
|
||||
if (csp && newBaseURI) {
|
||||
// base-uri is only enforced if explicitly defined in the
|
||||
// policy - do *not* consult default-src, see:
|
||||
// http://www.w3.org/TR/CSP2/#directive-default-src
|
||||
bool cspPermitsBaseURI = true;
|
||||
rv = csp->Permits(newBaseURI, nsIContentSecurityPolicy::BASE_URI_DIRECTIVE,
|
||||
true, &cspPermitsBaseURI);
|
||||
if (NS_FAILED(rv) || !cspPermitsBaseURI) {
|
||||
newBaseURI = nullptr;
|
||||
}
|
||||
}
|
||||
aDocument->SetBaseURI(newBaseURI);
|
||||
aDocument->SetChromeXHRDocBaseURI(nullptr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
aDocument->SetBaseURI(nullptr);
|
||||
}
|
||||
|
||||
static void
|
||||
SetBaseTargetUsingFirstBaseWithTarget(nsIDocument* aDocument,
|
||||
nsIContent* aMustMatch)
|
||||
{
|
||||
NS_PRECONDITION(aDocument, "Need a document!");
|
||||
|
||||
for (nsIContent* child = aDocument->GetFirstChild(); child;
|
||||
child = child->GetNextNode()) {
|
||||
if (child->IsHTMLElement(nsGkAtoms::base) &&
|
||||
child->HasAttr(kNameSpaceID_None, nsGkAtoms::target)) {
|
||||
if (aMustMatch && child != aMustMatch) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsString target;
|
||||
child->GetAttr(kNameSpaceID_None, nsGkAtoms::target, target);
|
||||
aDocument->SetBaseTarget(target);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
aDocument->SetBaseTarget(EmptyString());
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLSharedElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
nsIAtom* aPrefix, const nsAString& aValue,
|
||||
bool aNotify)
|
||||
{
|
||||
nsresult rv = nsGenericHTMLElement::SetAttr(aNameSpaceID, aName, aPrefix,
|
||||
aValue, aNotify);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// If the href attribute of a <base> tag is changing, we may need to update
|
||||
// the document's base URI, which will cause all the links on the page to be
|
||||
// re-resolved given the new base. If the target attribute is changing, we
|
||||
// similarly need to change the base target.
|
||||
if (mNodeInfo->Equals(nsGkAtoms::base) &&
|
||||
aNameSpaceID == kNameSpaceID_None &&
|
||||
IsInUncomposedDoc()) {
|
||||
if (aName == nsGkAtoms::href) {
|
||||
SetBaseURIUsingFirstBaseWithHref(GetUncomposedDoc(), this);
|
||||
} else if (aName == nsGkAtoms::target) {
|
||||
SetBaseTargetUsingFirstBaseWithTarget(GetUncomposedDoc(), this);
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLSharedElement::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
bool aNotify)
|
||||
{
|
||||
nsresult rv = nsGenericHTMLElement::UnsetAttr(aNameSpaceID, aName, aNotify);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// If we're the first <base> with an href and our href attribute is being
|
||||
// unset, then we're no longer the first <base> with an href, and we need to
|
||||
// find the new one. Similar for target.
|
||||
if (mNodeInfo->Equals(nsGkAtoms::base) &&
|
||||
aNameSpaceID == kNameSpaceID_None &&
|
||||
IsInUncomposedDoc()) {
|
||||
if (aName == nsGkAtoms::href) {
|
||||
SetBaseURIUsingFirstBaseWithHref(GetUncomposedDoc(), nullptr);
|
||||
} else if (aName == nsGkAtoms::target) {
|
||||
SetBaseTargetUsingFirstBaseWithTarget(GetUncomposedDoc(), nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLSharedElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
||||
nsIContent* aBindingParent,
|
||||
bool aCompileEventHandlers)
|
||||
{
|
||||
nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent,
|
||||
aBindingParent,
|
||||
aCompileEventHandlers);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// The document stores a pointer to its base URI and base target, which we may
|
||||
// need to update here.
|
||||
if (mNodeInfo->Equals(nsGkAtoms::base) &&
|
||||
aDocument) {
|
||||
if (HasAttr(kNameSpaceID_None, nsGkAtoms::href)) {
|
||||
SetBaseURIUsingFirstBaseWithHref(aDocument, this);
|
||||
}
|
||||
if (HasAttr(kNameSpaceID_None, nsGkAtoms::target)) {
|
||||
SetBaseTargetUsingFirstBaseWithTarget(aDocument, this);
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
HTMLSharedElement::UnbindFromTree(bool aDeep, bool aNullParent)
|
||||
{
|
||||
nsIDocument* doc = GetUncomposedDoc();
|
||||
|
||||
nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
|
||||
|
||||
// If we're removing a <base> from a document, we may need to update the
|
||||
// document's base URI and base target
|
||||
if (doc && mNodeInfo->Equals(nsGkAtoms::base)) {
|
||||
if (HasAttr(kNameSpaceID_None, nsGkAtoms::href)) {
|
||||
SetBaseURIUsingFirstBaseWithHref(doc, nullptr);
|
||||
}
|
||||
if (HasAttr(kNameSpaceID_None, nsGkAtoms::target)) {
|
||||
SetBaseTargetUsingFirstBaseWithTarget(doc, nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsMapRuleToAttributesFunc
|
||||
HTMLSharedElement::GetAttributeMappingFunction() const
|
||||
{
|
||||
if (mNodeInfo->Equals(nsGkAtoms::dir)) {
|
||||
return &DirectoryMapAttributesIntoRule;
|
||||
}
|
||||
|
||||
return nsGenericHTMLElement::GetAttributeMappingFunction();
|
||||
}
|
||||
|
||||
JSObject*
|
||||
HTMLSharedElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
if (mNodeInfo->Equals(nsGkAtoms::param)) {
|
||||
return HTMLParamElementBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
if (mNodeInfo->Equals(nsGkAtoms::base)) {
|
||||
return HTMLBaseElementBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
if (mNodeInfo->Equals(nsGkAtoms::dir)) {
|
||||
return HTMLDirectoryElementBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
if (mNodeInfo->Equals(nsGkAtoms::q) ||
|
||||
mNodeInfo->Equals(nsGkAtoms::blockquote)) {
|
||||
return HTMLQuoteElementBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
if (mNodeInfo->Equals(nsGkAtoms::head)) {
|
||||
return HTMLHeadElementBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
MOZ_ASSERT(mNodeInfo->Equals(nsGkAtoms::html));
|
||||
return HTMLHtmlElementBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
189
dom/html/HTMLSharedElement.h
Normal file
189
dom/html/HTMLSharedElement.h
Normal file
|
|
@ -0,0 +1,189 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_dom_HTMLSharedElement_h
|
||||
#define mozilla_dom_HTMLSharedElement_h
|
||||
|
||||
#include "nsIDOMHTMLBaseElement.h"
|
||||
#include "nsIDOMHTMLDirectoryElement.h"
|
||||
#include "nsIDOMHTMLQuoteElement.h"
|
||||
#include "nsIDOMHTMLHeadElement.h"
|
||||
#include "nsIDOMHTMLHtmlElement.h"
|
||||
#include "nsGenericHTMLElement.h"
|
||||
|
||||
#include "nsGkAtoms.h"
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class HTMLSharedElement final : public nsGenericHTMLElement,
|
||||
public nsIDOMHTMLBaseElement,
|
||||
public nsIDOMHTMLDirectoryElement,
|
||||
public nsIDOMHTMLQuoteElement,
|
||||
public nsIDOMHTMLHeadElement,
|
||||
public nsIDOMHTMLHtmlElement
|
||||
{
|
||||
public:
|
||||
explicit HTMLSharedElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
|
||||
: nsGenericHTMLElement(aNodeInfo)
|
||||
{
|
||||
if (mNodeInfo->Equals(nsGkAtoms::head) ||
|
||||
mNodeInfo->Equals(nsGkAtoms::html)) {
|
||||
SetHasWeirdParserInsertionMode();
|
||||
}
|
||||
}
|
||||
|
||||
// nsISupports
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
// nsIDOMHTMLBaseElement
|
||||
NS_DECL_NSIDOMHTMLBASEELEMENT
|
||||
|
||||
// nsIDOMHTMLQuoteElement
|
||||
NS_DECL_NSIDOMHTMLQUOTEELEMENT
|
||||
|
||||
// nsIDOMHTMLHeadElement
|
||||
NS_DECL_NSIDOMHTMLHEADELEMENT
|
||||
|
||||
// nsIDOMHTMLHtmlElement
|
||||
NS_DECL_NSIDOMHTMLHTMLELEMENT
|
||||
|
||||
// nsIContent
|
||||
virtual bool ParseAttribute(int32_t aNamespaceID,
|
||||
nsIAtom* aAttribute,
|
||||
const nsAString& aValue,
|
||||
nsAttrValue& aResult) override;
|
||||
nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
const nsAString& aValue, bool aNotify)
|
||||
{
|
||||
return SetAttr(aNameSpaceID, aName, nullptr, aValue, aNotify);
|
||||
}
|
||||
virtual nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
nsIAtom* aPrefix, const nsAString& aValue,
|
||||
bool aNotify) override;
|
||||
|
||||
virtual nsresult UnsetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
bool aNotify) override;
|
||||
|
||||
virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
||||
nsIContent* aBindingParent,
|
||||
bool aCompileEventHandlers) override;
|
||||
|
||||
virtual void UnbindFromTree(bool aDeep = true,
|
||||
bool aNullParent = true) override;
|
||||
|
||||
virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const override;
|
||||
NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
|
||||
|
||||
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
|
||||
|
||||
// WebIDL API
|
||||
// HTMLParamElement
|
||||
void GetName(DOMString& aValue)
|
||||
{
|
||||
MOZ_ASSERT(mNodeInfo->Equals(nsGkAtoms::param));
|
||||
GetHTMLAttr(nsGkAtoms::name, aValue);
|
||||
}
|
||||
void SetName(const nsAString& aValue, ErrorResult& aResult)
|
||||
{
|
||||
MOZ_ASSERT(mNodeInfo->Equals(nsGkAtoms::param));
|
||||
SetHTMLAttr(nsGkAtoms::name, aValue, aResult);
|
||||
}
|
||||
void GetValue(DOMString& aValue)
|
||||
{
|
||||
MOZ_ASSERT(mNodeInfo->Equals(nsGkAtoms::param));
|
||||
GetHTMLAttr(nsGkAtoms::value, aValue);
|
||||
}
|
||||
void SetValue(const nsAString& aValue, ErrorResult& aResult)
|
||||
{
|
||||
MOZ_ASSERT(mNodeInfo->Equals(nsGkAtoms::param));
|
||||
SetHTMLAttr(nsGkAtoms::value, aValue, aResult);
|
||||
}
|
||||
void GetType(DOMString& aValue)
|
||||
{
|
||||
MOZ_ASSERT(mNodeInfo->Equals(nsGkAtoms::param));
|
||||
GetHTMLAttr(nsGkAtoms::type, aValue);
|
||||
}
|
||||
void SetType(const nsAString& aValue, ErrorResult& aResult)
|
||||
{
|
||||
MOZ_ASSERT(mNodeInfo->Equals(nsGkAtoms::param));
|
||||
SetHTMLAttr(nsGkAtoms::type, aValue, aResult);
|
||||
}
|
||||
void GetValueType(DOMString& aValue)
|
||||
{
|
||||
MOZ_ASSERT(mNodeInfo->Equals(nsGkAtoms::param));
|
||||
GetHTMLAttr(nsGkAtoms::valuetype, aValue);
|
||||
}
|
||||
void SetValueType(const nsAString& aValue, ErrorResult& aResult)
|
||||
{
|
||||
MOZ_ASSERT(mNodeInfo->Equals(nsGkAtoms::param));
|
||||
SetHTMLAttr(nsGkAtoms::valuetype, aValue, aResult);
|
||||
}
|
||||
|
||||
// HTMLBaseElement
|
||||
void GetTarget(DOMString& aValue)
|
||||
{
|
||||
MOZ_ASSERT(mNodeInfo->Equals(nsGkAtoms::base));
|
||||
GetHTMLAttr(nsGkAtoms::target, aValue);
|
||||
}
|
||||
void SetTarget(const nsAString& aValue, ErrorResult& aResult)
|
||||
{
|
||||
MOZ_ASSERT(mNodeInfo->Equals(nsGkAtoms::base));
|
||||
SetHTMLAttr(nsGkAtoms::target, aValue, aResult);
|
||||
}
|
||||
// The XPCOM GetHref is fine for us
|
||||
void SetHref(const nsAString& aValue, ErrorResult& aResult)
|
||||
{
|
||||
MOZ_ASSERT(mNodeInfo->Equals(nsGkAtoms::base));
|
||||
SetHTMLAttr(nsGkAtoms::href, aValue, aResult);
|
||||
}
|
||||
|
||||
// HTMLDirectoryElement
|
||||
bool Compact() const
|
||||
{
|
||||
MOZ_ASSERT(mNodeInfo->Equals(nsGkAtoms::dir));
|
||||
return GetBoolAttr(nsGkAtoms::compact);
|
||||
}
|
||||
void SetCompact(bool aCompact, ErrorResult& aResult)
|
||||
{
|
||||
MOZ_ASSERT(mNodeInfo->Equals(nsGkAtoms::dir));
|
||||
SetHTMLBoolAttr(nsGkAtoms::compact, aCompact, aResult);
|
||||
}
|
||||
|
||||
// HTMLQuoteElement
|
||||
// The XPCOM GetCite works fine for us
|
||||
void SetCite(const nsAString& aValue, ErrorResult& aResult)
|
||||
{
|
||||
MOZ_ASSERT(mNodeInfo->Equals(nsGkAtoms::q) ||
|
||||
mNodeInfo->Equals(nsGkAtoms::blockquote));
|
||||
SetHTMLAttr(nsGkAtoms::cite, aValue, aResult);
|
||||
}
|
||||
|
||||
// HTMLHtmlElement
|
||||
void GetVersion(DOMString& aValue)
|
||||
{
|
||||
MOZ_ASSERT(mNodeInfo->Equals(nsGkAtoms::html));
|
||||
GetHTMLAttr(nsGkAtoms::version, aValue);
|
||||
}
|
||||
void SetVersion(const nsAString& aValue, ErrorResult& aResult)
|
||||
{
|
||||
MOZ_ASSERT(mNodeInfo->Equals(nsGkAtoms::html));
|
||||
SetHTMLAttr(nsGkAtoms::version, aValue, aResult);
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual ~HTMLSharedElement();
|
||||
|
||||
virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_HTMLSharedElement_h
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue