1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "mozilla/dom/BindContext.h"
8 #include "mozilla/dom/Document.h"
9 #include "mozilla/dom/HTMLObjectElement.h"
10 #include "mozilla/dom/HTMLObjectElementBinding.h"
11 #include "mozilla/dom/ElementInlines.h"
12 #include "mozilla/dom/WindowProxyHolder.h"
13 #include "nsAttrValueInlines.h"
14 #include "nsGkAtoms.h"
16 #include "nsIContentInlines.h"
17 #include "nsIWidget.h"
18 #include "nsContentUtils.h"
20 # include "mozilla/EventDispatcher.h"
21 # include "mozilla/dom/Event.h"
22 # include "nsFocusManager.h"
25 namespace mozilla::dom
{
27 HTMLObjectElement::HTMLObjectElement(
28 already_AddRefed
<mozilla::dom::NodeInfo
>&& aNodeInfo
,
29 FromParser aFromParser
)
30 : nsGenericHTMLFormControlElement(std::move(aNodeInfo
),
31 FormControlType::Object
),
32 mIsDoneAddingChildren(!aFromParser
) {
33 RegisterActivityObserver();
34 SetIsNetworkCreated(aFromParser
== FROM_PARSER_NETWORK
);
36 // <object> is always barred from constraint validation.
37 SetBarredFromConstraintValidation(true);
39 // By default we're in the loading state
40 AddStatesSilently(ElementState::LOADING
);
43 HTMLObjectElement::~HTMLObjectElement() {
44 UnregisterActivityObserver();
45 nsImageLoadingContent::Destroy();
48 bool HTMLObjectElement::IsInteractiveHTMLContent() const {
49 return HasAttr(nsGkAtoms::usemap
) ||
50 nsGenericHTMLFormControlElement::IsInteractiveHTMLContent();
53 void HTMLObjectElement::AsyncEventRunning(AsyncEventDispatcher
* aEvent
) {
54 nsImageLoadingContent::AsyncEventRunning(aEvent
);
57 void HTMLObjectElement::DoneAddingChildren(bool aHaveNotified
) {
58 mIsDoneAddingChildren
= true;
60 // If we're already in a document, we need to trigger the load
61 // Otherwise, BindToTree takes care of that.
62 if (IsInComposedDoc()) {
63 StartObjectLoad(aHaveNotified
, false);
67 NS_IMPL_CYCLE_COLLECTION_CLASS(HTMLObjectElement
)
69 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(
70 HTMLObjectElement
, nsGenericHTMLFormControlElement
)
71 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mValidity
)
72 nsObjectLoadingContent::Traverse(tmp
, cb
);
73 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
75 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLObjectElement
,
76 nsGenericHTMLFormControlElement
)
77 NS_IMPL_CYCLE_COLLECTION_UNLINK(mValidity
)
78 nsObjectLoadingContent::Unlink(tmp
);
79 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
81 NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED(
82 HTMLObjectElement
, nsGenericHTMLFormControlElement
,
83 imgINotificationObserver
, nsIRequestObserver
, nsIStreamListener
,
84 nsFrameLoaderOwner
, nsIObjectLoadingContent
, nsIImageLoadingContent
,
85 nsIChannelEventSink
, nsIConstraintValidation
)
87 NS_IMPL_ELEMENT_CLONE(HTMLObjectElement
)
89 nsresult
HTMLObjectElement::BindToTree(BindContext
& aContext
,
91 nsresult rv
= nsGenericHTMLFormControlElement::BindToTree(aContext
, aParent
);
92 NS_ENSURE_SUCCESS(rv
, rv
);
94 rv
= nsObjectLoadingContent::BindToTree(aContext
, aParent
);
95 NS_ENSURE_SUCCESS(rv
, rv
);
97 // If we already have all the children, start the load.
98 if (IsInComposedDoc() && mIsDoneAddingChildren
) {
99 void (HTMLObjectElement::*start
)() = &HTMLObjectElement::StartObjectLoad
;
100 nsContentUtils::AddScriptRunner(
101 NewRunnableMethod("dom::HTMLObjectElement::BindToTree", this, start
));
107 void HTMLObjectElement::UnbindFromTree(bool aNullParent
) {
108 nsObjectLoadingContent::UnbindFromTree(aNullParent
);
109 nsGenericHTMLFormControlElement::UnbindFromTree(aNullParent
);
112 void HTMLObjectElement::AfterSetAttr(int32_t aNamespaceID
, nsAtom
* aName
,
113 const nsAttrValue
* aValue
,
114 const nsAttrValue
* aOldValue
,
115 nsIPrincipal
* aSubjectPrincipal
,
117 AfterMaybeChangeAttr(aNamespaceID
, aName
, aNotify
);
118 return nsGenericHTMLFormControlElement::AfterSetAttr(
119 aNamespaceID
, aName
, aValue
, aOldValue
, aSubjectPrincipal
, aNotify
);
122 void HTMLObjectElement::OnAttrSetButNotChanged(
123 int32_t aNamespaceID
, nsAtom
* aName
, const nsAttrValueOrString
& aValue
,
125 AfterMaybeChangeAttr(aNamespaceID
, aName
, aNotify
);
126 return nsGenericHTMLFormControlElement::OnAttrSetButNotChanged(
127 aNamespaceID
, aName
, aValue
, aNotify
);
130 void HTMLObjectElement::AfterMaybeChangeAttr(int32_t aNamespaceID
,
131 nsAtom
* aName
, bool aNotify
) {
132 // if aNotify is false, we are coming from the parser or some such place;
133 // we'll get bound after all the attributes have been set, so we'll do the
134 // object load from BindToTree/DoneAddingChildren.
135 // Skip the LoadObject call in that case.
136 // We also don't want to start loading the object when we're not yet in
137 // a document, just in case that the caller wants to set additional
138 // attributes before inserting the node into the document.
139 if (aNamespaceID
!= kNameSpaceID_None
|| aName
!= nsGkAtoms::data
||
140 !aNotify
|| !IsInComposedDoc() || !mIsDoneAddingChildren
||
141 BlockEmbedOrObjectContentLoading()) {
144 nsContentUtils::AddScriptRunner(NS_NewRunnableFunction(
145 "HTMLObjectElement::LoadObject",
146 [self
= RefPtr
<HTMLObjectElement
>(this), aNotify
]() {
147 if (self
->IsInComposedDoc()) {
148 self
->LoadObject(aNotify
, true);
153 bool HTMLObjectElement::IsHTMLFocusable(bool aWithMouse
, bool* aIsFocusable
,
154 int32_t* aTabIndex
) {
155 // TODO: this should probably be managed directly by IsHTMLFocusable.
157 Document
* doc
= GetComposedDoc();
158 if (!doc
|| IsInDesignMode()) {
163 *aIsFocusable
= false;
167 // Plugins that show the empty fallback should not accept focus.
168 if (Type() == eType_Fallback
) {
173 *aIsFocusable
= false;
177 const nsAttrValue
* attrVal
= mAttrs
.GetAttr(nsGkAtoms::tabindex
);
178 bool isFocusable
= attrVal
&& attrVal
->Type() == nsAttrValue::eInteger
;
180 // This method doesn't call nsGenericHTMLFormControlElement intentionally.
181 // TODO: It should probably be changed when bug 597242 will be fixed.
182 if (IsEditableRoot() || Type() == eType_Document
||
183 Type() == eType_FakePlugin
) {
185 *aTabIndex
= isFocusable
? attrVal
->GetIntegerValue() : 0;
188 *aIsFocusable
= true;
192 // TODO: this should probably be managed directly by IsHTMLFocusable.
194 if (aTabIndex
&& isFocusable
) {
195 *aTabIndex
= attrVal
->GetIntegerValue();
196 *aIsFocusable
= true;
202 int32_t HTMLObjectElement::TabIndexDefault() { return 0; }
204 Nullable
<WindowProxyHolder
> HTMLObjectElement::GetContentWindow(
205 nsIPrincipal
& aSubjectPrincipal
) {
206 Document
* doc
= GetContentDocument(aSubjectPrincipal
);
208 nsPIDOMWindowOuter
* win
= doc
->GetWindow();
210 return WindowProxyHolder(win
->GetBrowsingContext());
217 bool HTMLObjectElement::ParseAttribute(int32_t aNamespaceID
, nsAtom
* aAttribute
,
218 const nsAString
& aValue
,
219 nsIPrincipal
* aMaybeScriptedPrincipal
,
220 nsAttrValue
& aResult
) {
221 if (aNamespaceID
== kNameSpaceID_None
) {
222 if (aAttribute
== nsGkAtoms::align
) {
223 return ParseAlignValue(aValue
, aResult
);
225 if (ParseImageAttribute(aAttribute
, aValue
, aResult
)) {
230 return nsGenericHTMLFormControlElement::ParseAttribute(
231 aNamespaceID
, aAttribute
, aValue
, aMaybeScriptedPrincipal
, aResult
);
234 void HTMLObjectElement::MapAttributesIntoRule(
235 MappedDeclarationsBuilder
& aBuilder
) {
236 MapImageAlignAttributeInto(aBuilder
);
237 MapImageBorderAttributeInto(aBuilder
);
238 MapImageMarginAttributeInto(aBuilder
);
239 MapImageSizeAttributesInto(aBuilder
);
240 MapCommonAttributesInto(aBuilder
);
244 HTMLObjectElement::IsAttributeMapped(const nsAtom
* aAttribute
) const {
245 static const MappedAttributeEntry
* const map
[] = {
247 sImageMarginSizeAttributeMap
,
248 sImageBorderAttributeMap
,
249 sImageAlignAttributeMap
,
252 return FindAttributeDependence(aAttribute
, map
);
255 nsMapRuleToAttributesFunc
HTMLObjectElement::GetAttributeMappingFunction()
257 return &MapAttributesIntoRule
;
260 void HTMLObjectElement::StartObjectLoad(bool aNotify
, bool aForce
) {
261 // BindToTree can call us asynchronously, and we may be removed from the tree
263 if (!IsInComposedDoc() || !OwnerDoc()->IsActive() ||
264 BlockEmbedOrObjectContentLoading()) {
268 LoadObject(aNotify
, aForce
);
269 SetIsNetworkCreated(false);
272 ElementState
HTMLObjectElement::IntrinsicState() const {
273 return nsGenericHTMLFormControlElement::IntrinsicState() | ObjectState();
276 uint32_t HTMLObjectElement::GetCapabilities() const {
277 return nsObjectLoadingContent::GetCapabilities() | eFallbackIfClassIDPresent
;
280 void HTMLObjectElement::DestroyContent() {
281 nsObjectLoadingContent::Destroy();
282 nsGenericHTMLFormControlElement::DestroyContent();
285 nsresult
HTMLObjectElement::CopyInnerTo(Element
* aDest
) {
286 nsresult rv
= nsGenericHTMLFormControlElement::CopyInnerTo(aDest
);
287 NS_ENSURE_SUCCESS(rv
, rv
);
289 if (aDest
->OwnerDoc()->IsStaticDocument()) {
290 CreateStaticClone(static_cast<HTMLObjectElement
*>(aDest
));
296 JSObject
* HTMLObjectElement::WrapNode(JSContext
* aCx
,
297 JS::Handle
<JSObject
*> aGivenProto
) {
298 return HTMLObjectElement_Binding::Wrap(aCx
, this, aGivenProto
);
301 } // namespace mozilla::dom
303 NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER(Object
)