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/. */
6
7 #include "mozilla/EventStates.h"
8 #include "mozilla/dom/BindContext.h"
9 #include "mozilla/dom/Document.h"
10 #include "mozilla/dom/HTMLObjectElement.h"
11 #include "mozilla/dom/HTMLObjectElementBinding.h"
12 #include "mozilla/dom/ElementInlines.h"
13 #include "mozilla/dom/WindowProxyHolder.h"
14 #include "nsAttrValueInlines.h"
15 #include "nsGkAtoms.h"
16 #include "nsError.h"
17 #include "nsIContentInlines.h"
18 #include "nsIWidget.h"
19 #include "nsContentUtils.h"
20 #ifdef XP_MACOSX
21 # include "mozilla/EventDispatcher.h"
22 # include "mozilla/dom/Event.h"
23 # include "nsFocusManager.h"
24 #endif
25
26 namespace mozilla::dom {
27
HTMLObjectElement(already_AddRefed<mozilla::dom::NodeInfo> && aNodeInfo,FromParser aFromParser)28 HTMLObjectElement::HTMLObjectElement(
29 already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
30 FromParser aFromParser)
31 : nsGenericHTMLFormControlElement(std::move(aNodeInfo),
32 FormControlType::Object),
33 mIsDoneAddingChildren(!aFromParser) {
34 RegisterActivityObserver();
35 SetIsNetworkCreated(aFromParser == FROM_PARSER_NETWORK);
36
37 // <object> is always barred from constraint validation.
38 SetBarredFromConstraintValidation(true);
39
40 // By default we're in the loading state
41 AddStatesSilently(NS_EVENT_STATE_LOADING);
42 }
43
~HTMLObjectElement()44 HTMLObjectElement::~HTMLObjectElement() {
45 UnregisterActivityObserver();
46 nsImageLoadingContent::Destroy();
47 }
48
IsInteractiveHTMLContent() const49 bool HTMLObjectElement::IsInteractiveHTMLContent() const {
50 return HasAttr(kNameSpaceID_None, nsGkAtoms::usemap) ||
51 nsGenericHTMLFormControlElement::IsInteractiveHTMLContent();
52 }
53
AsyncEventRunning(AsyncEventDispatcher * aEvent)54 void HTMLObjectElement::AsyncEventRunning(AsyncEventDispatcher* aEvent) {
55 nsImageLoadingContent::AsyncEventRunning(aEvent);
56 }
57
IsDoneAddingChildren()58 bool HTMLObjectElement::IsDoneAddingChildren() { return mIsDoneAddingChildren; }
59
DoneAddingChildren(bool aHaveNotified)60 void HTMLObjectElement::DoneAddingChildren(bool aHaveNotified) {
61 mIsDoneAddingChildren = true;
62
63 // If we're already in a document, we need to trigger the load
64 // Otherwise, BindToTree takes care of that.
65 if (IsInComposedDoc()) {
66 StartObjectLoad(aHaveNotified, false);
67 }
68 }
69
70 NS_IMPL_CYCLE_COLLECTION_CLASS(HTMLObjectElement)
71
72 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(
73 HTMLObjectElement, nsGenericHTMLFormControlElement)
74 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mValidity)
75 nsObjectLoadingContent::Traverse(tmp, cb);
76 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
77
78 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLObjectElement,
79 nsGenericHTMLFormControlElement)
80 NS_IMPL_CYCLE_COLLECTION_UNLINK(mValidity)
81 nsObjectLoadingContent::Unlink(tmp);
82 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
83
NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED(HTMLObjectElement,nsGenericHTMLFormControlElement,imgINotificationObserver,nsIRequestObserver,nsIStreamListener,nsFrameLoaderOwner,nsIObjectLoadingContent,nsIImageLoadingContent,nsIChannelEventSink,nsIConstraintValidation)84 NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED(
85 HTMLObjectElement, nsGenericHTMLFormControlElement,
86 imgINotificationObserver, nsIRequestObserver, nsIStreamListener,
87 nsFrameLoaderOwner, nsIObjectLoadingContent, nsIImageLoadingContent,
88 nsIChannelEventSink, nsIConstraintValidation)
89
90 NS_IMPL_ELEMENT_CLONE(HTMLObjectElement)
91
92 nsresult HTMLObjectElement::BindToTree(BindContext& aContext,
93 nsINode& aParent) {
94 nsresult rv = nsGenericHTMLFormControlElement::BindToTree(aContext, aParent);
95 NS_ENSURE_SUCCESS(rv, rv);
96
97 rv = nsObjectLoadingContent::BindToTree(aContext, aParent);
98 NS_ENSURE_SUCCESS(rv, rv);
99
100 // If we already have all the children, start the load.
101 if (IsInComposedDoc() && mIsDoneAddingChildren) {
102 void (HTMLObjectElement::*start)() = &HTMLObjectElement::StartObjectLoad;
103 nsContentUtils::AddScriptRunner(
104 NewRunnableMethod("dom::HTMLObjectElement::BindToTree", this, start));
105 }
106
107 return NS_OK;
108 }
109
UnbindFromTree(bool aNullParent)110 void HTMLObjectElement::UnbindFromTree(bool aNullParent) {
111 nsObjectLoadingContent::UnbindFromTree(aNullParent);
112 nsGenericHTMLFormControlElement::UnbindFromTree(aNullParent);
113 }
114
AfterSetAttr(int32_t aNamespaceID,nsAtom * aName,const nsAttrValue * aValue,const nsAttrValue * aOldValue,nsIPrincipal * aSubjectPrincipal,bool aNotify)115 nsresult HTMLObjectElement::AfterSetAttr(int32_t aNamespaceID, nsAtom* aName,
116 const nsAttrValue* aValue,
117 const nsAttrValue* aOldValue,
118 nsIPrincipal* aSubjectPrincipal,
119 bool aNotify) {
120 nsresult rv = AfterMaybeChangeAttr(aNamespaceID, aName, aNotify);
121 NS_ENSURE_SUCCESS(rv, rv);
122
123 return nsGenericHTMLFormControlElement::AfterSetAttr(
124 aNamespaceID, aName, aValue, aOldValue, aSubjectPrincipal, aNotify);
125 }
126
OnAttrSetButNotChanged(int32_t aNamespaceID,nsAtom * aName,const nsAttrValueOrString & aValue,bool aNotify)127 nsresult HTMLObjectElement::OnAttrSetButNotChanged(
128 int32_t aNamespaceID, nsAtom* aName, const nsAttrValueOrString& aValue,
129 bool aNotify) {
130 nsresult rv = AfterMaybeChangeAttr(aNamespaceID, aName, aNotify);
131 NS_ENSURE_SUCCESS(rv, rv);
132
133 return nsGenericHTMLFormControlElement::OnAttrSetButNotChanged(
134 aNamespaceID, aName, aValue, aNotify);
135 }
136
AfterMaybeChangeAttr(int32_t aNamespaceID,nsAtom * aName,bool aNotify)137 nsresult HTMLObjectElement::AfterMaybeChangeAttr(int32_t aNamespaceID,
138 nsAtom* aName, bool aNotify) {
139 if (aNamespaceID == kNameSpaceID_None) {
140 // if aNotify is false, we are coming from the parser or some such place;
141 // we'll get bound after all the attributes have been set, so we'll do the
142 // object load from BindToTree/DoneAddingChildren.
143 // Skip the LoadObject call in that case.
144 // We also don't want to start loading the object when we're not yet in
145 // a document, just in case that the caller wants to set additional
146 // attributes before inserting the node into the document.
147 if (aNotify && IsInComposedDoc() && mIsDoneAddingChildren &&
148 aName == nsGkAtoms::data && !BlockEmbedOrObjectContentLoading()) {
149 nsContentUtils::AddScriptRunner(NS_NewRunnableFunction(
150 "HTMLObjectElement::LoadObject",
151 [self = RefPtr<HTMLObjectElement>(this), aNotify]() {
152 if (self->IsInComposedDoc()) {
153 self->LoadObject(aNotify, true);
154 }
155 }));
156 return NS_OK;
157 }
158 }
159
160 return NS_OK;
161 }
162
IsHTMLFocusable(bool aWithMouse,bool * aIsFocusable,int32_t * aTabIndex)163 bool HTMLObjectElement::IsHTMLFocusable(bool aWithMouse, bool* aIsFocusable,
164 int32_t* aTabIndex) {
165 // TODO: this should probably be managed directly by IsHTMLFocusable.
166 // See bug 597242.
167 Document* doc = GetComposedDoc();
168 if (!doc || IsInDesignMode()) {
169 if (aTabIndex) {
170 *aTabIndex = -1;
171 }
172
173 *aIsFocusable = false;
174 return false;
175 }
176
177 // Plugins that show the empty fallback should not accept focus.
178 if (Type() == eType_Fallback) {
179 if (aTabIndex) {
180 *aTabIndex = -1;
181 }
182
183 *aIsFocusable = false;
184 return false;
185 }
186
187 const nsAttrValue* attrVal = mAttrs.GetAttr(nsGkAtoms::tabindex);
188 bool isFocusable = attrVal && attrVal->Type() == nsAttrValue::eInteger;
189
190 // This method doesn't call nsGenericHTMLFormControlElement intentionally.
191 // TODO: It should probably be changed when bug 597242 will be fixed.
192 if (IsEditableRoot() ||
193 ((Type() == eType_Document || Type() == eType_FakePlugin) &&
194 nsContentUtils::IsSubDocumentTabbable(this))) {
195 if (aTabIndex) {
196 *aTabIndex = isFocusable ? attrVal->GetIntegerValue() : 0;
197 }
198
199 *aIsFocusable = true;
200 return false;
201 }
202
203 // TODO: this should probably be managed directly by IsHTMLFocusable.
204 // See bug 597242.
205 if (aTabIndex && isFocusable) {
206 *aTabIndex = attrVal->GetIntegerValue();
207 *aIsFocusable = true;
208 }
209
210 return false;
211 }
212
TabIndexDefault()213 int32_t HTMLObjectElement::TabIndexDefault() { return 0; }
214
GetContentWindow(nsIPrincipal & aSubjectPrincipal)215 Nullable<WindowProxyHolder> HTMLObjectElement::GetContentWindow(
216 nsIPrincipal& aSubjectPrincipal) {
217 Document* doc = GetContentDocument(aSubjectPrincipal);
218 if (doc) {
219 nsPIDOMWindowOuter* win = doc->GetWindow();
220 if (win) {
221 return WindowProxyHolder(win->GetBrowsingContext());
222 }
223 }
224
225 return nullptr;
226 }
227
ParseAttribute(int32_t aNamespaceID,nsAtom * aAttribute,const nsAString & aValue,nsIPrincipal * aMaybeScriptedPrincipal,nsAttrValue & aResult)228 bool HTMLObjectElement::ParseAttribute(int32_t aNamespaceID, nsAtom* aAttribute,
229 const nsAString& aValue,
230 nsIPrincipal* aMaybeScriptedPrincipal,
231 nsAttrValue& aResult) {
232 if (aNamespaceID == kNameSpaceID_None) {
233 if (aAttribute == nsGkAtoms::align) {
234 return ParseAlignValue(aValue, aResult);
235 }
236 if (ParseImageAttribute(aAttribute, aValue, aResult)) {
237 return true;
238 }
239 }
240
241 return nsGenericHTMLFormControlElement::ParseAttribute(
242 aNamespaceID, aAttribute, aValue, aMaybeScriptedPrincipal, aResult);
243 }
244
MapAttributesIntoRule(const nsMappedAttributes * aAttributes,MappedDeclarations & aDecls)245 void HTMLObjectElement::MapAttributesIntoRule(
246 const nsMappedAttributes* aAttributes, MappedDeclarations& aDecls) {
247 nsGenericHTMLFormControlElement::MapImageAlignAttributeInto(aAttributes,
248 aDecls);
249 nsGenericHTMLFormControlElement::MapImageBorderAttributeInto(aAttributes,
250 aDecls);
251 nsGenericHTMLFormControlElement::MapImageMarginAttributeInto(aAttributes,
252 aDecls);
253 nsGenericHTMLFormControlElement::MapImageSizeAttributesInto(aAttributes,
254 aDecls);
255 nsGenericHTMLFormControlElement::MapCommonAttributesInto(aAttributes, aDecls);
256 }
257
NS_IMETHODIMP_(bool)258 NS_IMETHODIMP_(bool)
259 HTMLObjectElement::IsAttributeMapped(const nsAtom* aAttribute) const {
260 static const MappedAttributeEntry* const map[] = {
261 sCommonAttributeMap,
262 sImageMarginSizeAttributeMap,
263 sImageBorderAttributeMap,
264 sImageAlignAttributeMap,
265 };
266
267 return FindAttributeDependence(aAttribute, map);
268 }
269
GetAttributeMappingFunction() const270 nsMapRuleToAttributesFunc HTMLObjectElement::GetAttributeMappingFunction()
271 const {
272 return &MapAttributesIntoRule;
273 }
274
StartObjectLoad(bool aNotify,bool aForce)275 void HTMLObjectElement::StartObjectLoad(bool aNotify, bool aForce) {
276 // BindToTree can call us asynchronously, and we may be removed from the tree
277 // in the interim
278 if (!IsInComposedDoc() || !OwnerDoc()->IsActive() ||
279 BlockEmbedOrObjectContentLoading()) {
280 return;
281 }
282
283 LoadObject(aNotify, aForce);
284 SetIsNetworkCreated(false);
285 }
286
IntrinsicState() const287 EventStates HTMLObjectElement::IntrinsicState() const {
288 return nsGenericHTMLFormControlElement::IntrinsicState() | ObjectState();
289 }
290
GetCapabilities() const291 uint32_t HTMLObjectElement::GetCapabilities() const {
292 return nsObjectLoadingContent::GetCapabilities() | eFallbackIfClassIDPresent;
293 }
294
DestroyContent()295 void HTMLObjectElement::DestroyContent() {
296 nsObjectLoadingContent::Destroy();
297 nsGenericHTMLFormControlElement::DestroyContent();
298 }
299
CopyInnerTo(Element * aDest)300 nsresult HTMLObjectElement::CopyInnerTo(Element* aDest) {
301 nsresult rv = nsGenericHTMLFormControlElement::CopyInnerTo(aDest);
302 NS_ENSURE_SUCCESS(rv, rv);
303
304 if (aDest->OwnerDoc()->IsStaticDocument()) {
305 CreateStaticClone(static_cast<HTMLObjectElement*>(aDest));
306 }
307
308 return rv;
309 }
310
WrapNode(JSContext * aCx,JS::Handle<JSObject * > aGivenProto)311 JSObject* HTMLObjectElement::WrapNode(JSContext* aCx,
312 JS::Handle<JSObject*> aGivenProto) {
313 return HTMLObjectElement_Binding::Wrap(aCx, this, aGivenProto);
314 }
315
316 } // namespace mozilla::dom
317
318 NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER(Object)
319