diff options
Diffstat (limited to 'dom/html/HTMLSharedObjectElement.cpp')
-rw-r--r-- | dom/html/HTMLSharedObjectElement.cpp | 419 |
1 files changed, 419 insertions, 0 deletions
diff --git a/dom/html/HTMLSharedObjectElement.cpp b/dom/html/HTMLSharedObjectElement.cpp new file mode 100644 index 000000000..889fd5aef --- /dev/null +++ b/dom/html/HTMLSharedObjectElement.cpp @@ -0,0 +1,419 @@ +/* -*- 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/HTMLSharedObjectElement.h" +#include "mozilla/dom/HTMLEmbedElementBinding.h" +#include "mozilla/dom/HTMLAppletElementBinding.h" +#include "mozilla/dom/ElementInlines.h" + +#include "nsIDocument.h" +#include "nsIPluginDocument.h" +#include "nsIDOMDocument.h" +#include "nsThreadUtils.h" +#include "nsIScriptError.h" +#include "nsIWidget.h" +#include "nsContentUtils.h" +#ifdef XP_MACOSX +#include "mozilla/EventDispatcher.h" +#include "mozilla/dom/Event.h" +#endif +#include "mozilla/dom/HTMLObjectElement.h" + + +NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER(SharedObject) + +namespace mozilla { +namespace dom { + +HTMLSharedObjectElement::HTMLSharedObjectElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo, + FromParser aFromParser) + : nsGenericHTMLElement(aNodeInfo), + mIsDoneAddingChildren(mNodeInfo->Equals(nsGkAtoms::embed) || !aFromParser) +{ + RegisterActivityObserver(); + SetIsNetworkCreated(aFromParser == FROM_PARSER_NETWORK); + + // By default we're in the loading state + AddStatesSilently(NS_EVENT_STATE_LOADING); +} + +HTMLSharedObjectElement::~HTMLSharedObjectElement() +{ +#ifdef XP_MACOSX + HTMLObjectElement::OnFocusBlurPlugin(this, false); +#endif + UnregisterActivityObserver(); + DestroyImageLoadingContent(); +} + +bool +HTMLSharedObjectElement::IsDoneAddingChildren() +{ + return mIsDoneAddingChildren; +} + +void +HTMLSharedObjectElement::DoneAddingChildren(bool aHaveNotified) +{ + if (!mIsDoneAddingChildren) { + 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, false); + } + } +} + +NS_IMPL_CYCLE_COLLECTION_CLASS(HTMLSharedObjectElement) + +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLSharedObjectElement, + nsGenericHTMLElement) + nsObjectLoadingContent::Traverse(tmp, cb); +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END + +NS_IMPL_ADDREF_INHERITED(HTMLSharedObjectElement, Element) +NS_IMPL_RELEASE_INHERITED(HTMLSharedObjectElement, Element) + +NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(HTMLSharedObjectElement) + NS_INTERFACE_TABLE_INHERITED(HTMLSharedObjectElement, + nsIRequestObserver, + nsIStreamListener, + nsIFrameLoaderOwner, + nsIObjectLoadingContent, + imgINotificationObserver, + nsIImageLoadingContent, + imgIOnloadBlocker, + nsIChannelEventSink) + NS_INTERFACE_TABLE_TO_MAP_SEGUE + NS_INTERFACE_MAP_ENTRY_IF_TAG(nsIDOMHTMLAppletElement, applet) + NS_INTERFACE_MAP_ENTRY_IF_TAG(nsIDOMHTMLEmbedElement, embed) +NS_INTERFACE_MAP_END_INHERITING(nsGenericHTMLElement) + +NS_IMPL_ELEMENT_CLONE(HTMLSharedObjectElement) + +#ifdef XP_MACOSX + +NS_IMETHODIMP +HTMLSharedObjectElement::PostHandleEvent(EventChainPostVisitor& aVisitor) +{ + HTMLObjectElement::HandleFocusBlurPlugin(this, aVisitor.mEvent); + return NS_OK; +} + +#endif // #ifdef XP_MACOSX + +void +HTMLSharedObjectElement::AsyncEventRunning(AsyncEventDispatcher* aEvent) +{ + nsImageLoadingContent::AsyncEventRunning(aEvent); +} + +nsresult +HTMLSharedObjectElement::BindToTree(nsIDocument *aDocument, + nsIContent *aParent, + nsIContent *aBindingParent, + bool aCompileEventHandlers) +{ + nsresult rv = nsGenericHTMLElement::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 (HTMLSharedObjectElement::*start)() = + &HTMLSharedObjectElement::StartObjectLoad; + nsContentUtils::AddScriptRunner(NewRunnableMethod(this, start)); + } + + return NS_OK; +} + +void +HTMLSharedObjectElement::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. + HTMLObjectElement::OnFocusBlurPlugin(this, false); +#endif + nsObjectLoadingContent::UnbindFromTree(aDeep, aNullParent); + nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent); +} + + +nsresult +HTMLSharedObjectElement::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 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 == URIAttrName() + && !BlockEmbedContentLoading()) { + return LoadObject(aNotify, true); + } + + return NS_OK; +} + +bool +HTMLSharedObjectElement::IsHTMLFocusable(bool aWithMouse, + bool *aIsFocusable, + int32_t *aTabIndex) +{ + if (mNodeInfo->Equals(nsGkAtoms::embed) || Type() == eType_Plugin) { + // Has plugin content: let the plugin decide what to do in terms of + // internal focus from mouse clicks + if (aTabIndex) { + GetTabIndex(aTabIndex); + } + + *aIsFocusable = true; + + // Let the plugin decide, so override. + return true; + } + + return nsGenericHTMLElement::IsHTMLFocusable(aWithMouse, aIsFocusable, aTabIndex); +} + +nsIContent::IMEState +HTMLSharedObjectElement::GetDesiredIMEState() +{ + if (Type() == eType_Plugin) { + return IMEState(IMEState::PLUGIN); + } + + return nsGenericHTMLElement::GetDesiredIMEState(); +} + +NS_IMPL_STRING_ATTR(HTMLSharedObjectElement, Align, align) +NS_IMPL_STRING_ATTR(HTMLSharedObjectElement, Alt, alt) +NS_IMPL_STRING_ATTR(HTMLSharedObjectElement, Archive, archive) +NS_IMPL_STRING_ATTR(HTMLSharedObjectElement, Code, code) +NS_IMPL_URI_ATTR(HTMLSharedObjectElement, CodeBase, codebase) +NS_IMPL_STRING_ATTR(HTMLSharedObjectElement, Height, height) +NS_IMPL_INT_ATTR(HTMLSharedObjectElement, Hspace, hspace) +NS_IMPL_STRING_ATTR(HTMLSharedObjectElement, Name, name) +NS_IMPL_URI_ATTR_WITH_BASE(HTMLSharedObjectElement, Object, object, codebase) +NS_IMPL_URI_ATTR(HTMLSharedObjectElement, Src, src) +NS_IMPL_STRING_ATTR(HTMLSharedObjectElement, Type, type) +NS_IMPL_INT_ATTR(HTMLSharedObjectElement, Vspace, vspace) +NS_IMPL_STRING_ATTR(HTMLSharedObjectElement, Width, width) + +int32_t +HTMLSharedObjectElement::TabIndexDefault() +{ + return -1; +} + +bool +HTMLSharedObjectElement::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 nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue, + aResult); +} + +static void +MapAttributesIntoRuleBase(const nsMappedAttributes *aAttributes, + nsRuleData *aData) +{ + nsGenericHTMLElement::MapImageBorderAttributeInto(aAttributes, aData); + nsGenericHTMLElement::MapImageMarginAttributeInto(aAttributes, aData); + nsGenericHTMLElement::MapImageSizeAttributesInto(aAttributes, aData); + nsGenericHTMLElement::MapImageAlignAttributeInto(aAttributes, aData); +} + +static void +MapAttributesIntoRuleExceptHidden(const nsMappedAttributes *aAttributes, + nsRuleData *aData) +{ + MapAttributesIntoRuleBase(aAttributes, aData); + nsGenericHTMLElement::MapCommonAttributesIntoExceptHidden(aAttributes, aData); +} + +void +HTMLSharedObjectElement::MapAttributesIntoRule(const nsMappedAttributes *aAttributes, + nsRuleData *aData) +{ + MapAttributesIntoRuleBase(aAttributes, aData); + nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aData); +} + +NS_IMETHODIMP_(bool) +HTMLSharedObjectElement::IsAttributeMapped(const nsIAtom *aAttribute) const +{ + static const MappedAttributeEntry* const map[] = { + sCommonAttributeMap, + sImageMarginSizeAttributeMap, + sImageBorderAttributeMap, + sImageAlignAttributeMap, + }; + + return FindAttributeDependence(aAttribute, map); +} + + +nsMapRuleToAttributesFunc +HTMLSharedObjectElement::GetAttributeMappingFunction() const +{ + if (mNodeInfo->Equals(nsGkAtoms::embed)) { + return &MapAttributesIntoRuleExceptHidden; + } + + return &MapAttributesIntoRule; +} + +void +HTMLSharedObjectElement::StartObjectLoad(bool aNotify, bool aForceLoad) +{ + // BindToTree can call us asynchronously, and we may be removed from the tree + // in the interim + if (!IsInComposedDoc() || !OwnerDoc()->IsActive() || + BlockEmbedContentLoading()) { + return; + } + + LoadObject(aNotify, aForceLoad); + SetIsNetworkCreated(false); +} + +EventStates +HTMLSharedObjectElement::IntrinsicState() const +{ + return nsGenericHTMLElement::IntrinsicState() | ObjectState(); +} + +uint32_t +HTMLSharedObjectElement::GetCapabilities() const +{ + uint32_t capabilities = eSupportPlugins | eAllowPluginSkipChannel; + if (mNodeInfo->Equals(nsGkAtoms::embed)) { + capabilities |= eSupportImages | eSupportDocuments; + } + + return capabilities; +} + +void +HTMLSharedObjectElement::DestroyContent() +{ + nsObjectLoadingContent::DestroyContent(); + nsGenericHTMLElement::DestroyContent(); +} + +nsresult +HTMLSharedObjectElement::CopyInnerTo(Element* aDest) +{ + nsresult rv = nsGenericHTMLElement::CopyInnerTo(aDest); + NS_ENSURE_SUCCESS(rv, rv); + + if (aDest->OwnerDoc()->IsStaticDocument()) { + CreateStaticClone(static_cast<HTMLSharedObjectElement*>(aDest)); + } + + return rv; +} + +JSObject* +HTMLSharedObjectElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) +{ + JSObject* obj; + if (mNodeInfo->Equals(nsGkAtoms::applet)) { + obj = HTMLAppletElementBinding::Wrap(aCx, this, aGivenProto); + } else { + MOZ_ASSERT(mNodeInfo->Equals(nsGkAtoms::embed)); + obj = HTMLEmbedElementBinding::Wrap(aCx, this, aGivenProto); + } + if (!obj) { + return nullptr; + } + JS::Rooted<JSObject*> rootedObj(aCx, obj); + SetupProtoChain(aCx, rootedObj); + return rootedObj; +} + +nsContentPolicyType +HTMLSharedObjectElement::GetContentPolicyType() const +{ + if (mNodeInfo->Equals(nsGkAtoms::applet)) { + // We use TYPE_INTERNAL_OBJECT for applet too, since it is not exposed + // through RequestContext yet. + return nsIContentPolicy::TYPE_INTERNAL_OBJECT; + } else { + MOZ_ASSERT(mNodeInfo->Equals(nsGkAtoms::embed)); + return nsIContentPolicy::TYPE_INTERNAL_EMBED; + } +} + +bool +HTMLSharedObjectElement::BlockEmbedContentLoading() +{ + // Only check on embed elements + if (!IsHTMLElement(nsGkAtoms::embed)) { + return false; + } + // Traverse up the node tree to see if we have any ancestors that may block us + // from loading + for (nsIContent* parent = GetParent(); parent; parent = parent->GetParent()) { + if (parent->IsAnyOfHTMLElements(nsGkAtoms::video, nsGkAtoms::audio)) { + return true; + } + // If we have an ancestor that is an object with a source, it'll have an + // associated displayed type. If that type is not null, don't load content + // for the embed. + if (HTMLObjectElement* object = HTMLObjectElement::FromContent(parent)) { + uint32_t type = object->DisplayedType(); + if (type != eType_Null) { + return true; + } + } + } + return false; +} + +} // namespace dom +} // namespace mozilla |