Adds --disable-npapi as an additional build option. The default is still to build in NPAPI compatibility, but with this flag, it's finally possible to build without pulling in GTK2 on systems that don't have the package. This essentially ifdefs everything associated with NPAPI, following various Mozilla removal bugs. Ref: BZ 1682030, BZ 1251202, BZ 1217665, BZ 1687239
459 lines
14 KiB
C++
459 lines
14 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "mozilla/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"
|
|
#ifdef MOZ_ENABLE_NPAPI
|
|
#include "nsIPluginDocument.h"
|
|
#endif
|
|
#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.
|
|
#ifdef MOZ_ENABLE_NPAPI
|
|
nsCOMPtr<nsIPluginDocument> pluginDoc = do_QueryInterface(aDocument);
|
|
#else
|
|
bool pluginDoc = false;
|
|
#endif
|
|
// 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::AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
|
|
const nsAttrValue* aValue,
|
|
const nsAttrValue* aOldValue,
|
|
bool aNotify)
|
|
{
|
|
if (aValue) {
|
|
nsresult rv = AfterMaybeChangeAttr(aNamespaceID, aName, aNotify);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
}
|
|
|
|
return nsGenericHTMLElement::AfterSetAttr(aNamespaceID, aName, aValue,
|
|
aOldValue, aNotify);
|
|
}
|
|
|
|
nsresult
|
|
HTMLSharedObjectElement::OnAttrSetButNotChanged(int32_t aNamespaceID,
|
|
nsIAtom* aName,
|
|
const nsAttrValueOrString& aValue,
|
|
bool aNotify)
|
|
{
|
|
nsresult rv = AfterMaybeChangeAttr(aNamespaceID, aName, aNotify);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
return nsGenericHTMLElement::OnAttrSetButNotChanged(aNamespaceID, aName,
|
|
aValue, aNotify);
|
|
}
|
|
|
|
nsresult
|
|
HTMLSharedObjectElement::AfterMaybeChangeAttr(int32_t aNamespaceID,
|
|
nsIAtom* aName,
|
|
bool aNotify)
|
|
{
|
|
if (aNamespaceID == kNameSpaceID_None) {
|
|
if (aName == URIAttrName()) {
|
|
// 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) {
|
|
nsContentUtils::AddScriptRunner(NS_NewRunnableFunction(
|
|
[self = RefPtr<HTMLSharedObjectElement>(this), aNotify]() {
|
|
if (self->IsInComposedDoc()) {
|
|
self->LoadObject(aNotify, true);
|
|
}
|
|
}));
|
|
return NS_OK;
|
|
}
|
|
}
|
|
}
|
|
|
|
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)
|
|
{
|
|
#ifdef MOZ_ENABLE_NPAPI
|
|
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;
|
|
#else
|
|
return HTMLEmbedElementBinding::Wrap(aCx, this, aGivenProto);
|
|
#endif
|
|
}
|
|
|
|
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
|