Bug 1655413 [wpt PR 24763] - Make CSP default-src without 'unsafe-eval' block eval...
[gecko.git] / dom / html / HTMLObjectElement.cpp
blob3f1ded40b9b76bbc45cb223a4a016465509dabfa
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/EventStates.h"
8 #include "mozilla/dom/BindContext.h"
9 #include "mozilla/dom/HTMLFormSubmission.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 "mozilla/dom/Document.h"
18 #include "nsIPluginDocument.h"
19 #include "nsIObjectFrame.h"
20 #include "nsNPAPIPluginInstance.h"
21 #include "nsIWidget.h"
22 #include "nsContentUtils.h"
23 #ifdef XP_MACOSX
24 # include "mozilla/EventDispatcher.h"
25 # include "mozilla/dom/Event.h"
26 # include "nsFocusManager.h"
27 #endif
29 namespace mozilla {
30 namespace dom {
32 HTMLObjectElement::HTMLObjectElement(
33 already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
34 FromParser aFromParser)
35 : nsGenericHTMLFormElement(std::move(aNodeInfo), NS_FORM_OBJECT),
36 mIsDoneAddingChildren(!aFromParser) {
37 RegisterActivityObserver();
38 SetIsNetworkCreated(aFromParser == FROM_PARSER_NETWORK);
40 // <object> is always barred from constraint validation.
41 SetBarredFromConstraintValidation(true);
43 // By default we're in the loading state
44 AddStatesSilently(NS_EVENT_STATE_LOADING);
47 HTMLObjectElement::~HTMLObjectElement() {
48 #ifdef XP_MACOSX
49 OnFocusBlurPlugin(this, false);
50 #endif
51 UnregisterActivityObserver();
52 nsImageLoadingContent::Destroy();
55 bool HTMLObjectElement::IsInteractiveHTMLContent() const {
56 return HasAttr(kNameSpaceID_None, nsGkAtoms::usemap) ||
57 nsGenericHTMLFormElement::IsInteractiveHTMLContent();
60 void HTMLObjectElement::AsyncEventRunning(AsyncEventDispatcher* aEvent) {
61 nsImageLoadingContent::AsyncEventRunning(aEvent);
64 bool HTMLObjectElement::IsDoneAddingChildren() { return mIsDoneAddingChildren; }
66 void HTMLObjectElement::DoneAddingChildren(bool aHaveNotified) {
67 mIsDoneAddingChildren = true;
69 // If we're already in a document, we need to trigger the load
70 // Otherwise, BindToTree takes care of that.
71 if (IsInComposedDoc()) {
72 StartObjectLoad(aHaveNotified, false);
76 NS_IMPL_CYCLE_COLLECTION_CLASS(HTMLObjectElement)
78 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLObjectElement,
79 nsGenericHTMLFormElement)
80 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mValidity)
81 nsObjectLoadingContent::Traverse(tmp, cb);
82 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
84 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLObjectElement,
85 nsGenericHTMLFormElement)
86 NS_IMPL_CYCLE_COLLECTION_UNLINK(mValidity)
87 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
89 NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED(
90 HTMLObjectElement, nsGenericHTMLFormElement, imgINotificationObserver,
91 nsIRequestObserver, nsIStreamListener, nsFrameLoaderOwner,
92 nsIObjectLoadingContent, nsIImageLoadingContent, nsIChannelEventSink,
93 nsIConstraintValidation)
95 NS_IMPL_ELEMENT_CLONE(HTMLObjectElement)
97 #ifdef XP_MACOSX
99 static nsIWidget* GetWidget(Element* aElement) {
100 return nsContentUtils::WidgetForDocument(aElement->OwnerDoc());
103 Element* HTMLObjectElement::sLastFocused = nullptr; // Weak
105 class PluginFocusSetter : public Runnable {
106 public:
107 PluginFocusSetter(nsIWidget* aWidget, Element* aElement)
108 : Runnable("PluginFocusSetter"), mWidget(aWidget), mElement(aElement) {}
110 NS_IMETHOD Run() override {
111 if (mElement) {
112 HTMLObjectElement::sLastFocused = mElement;
113 bool value = true;
114 mWidget->SetPluginFocused(value);
115 } else if (!HTMLObjectElement::sLastFocused) {
116 bool value = false;
117 mWidget->SetPluginFocused(value);
120 return NS_OK;
123 private:
124 nsCOMPtr<nsIWidget> mWidget;
125 nsCOMPtr<Element> mElement;
128 void HTMLObjectElement::OnFocusBlurPlugin(Element* aElement, bool aFocus) {
129 // In general we don't want to call nsIWidget::SetPluginFocused() for any
130 // Element that doesn't have a plugin running. But if SetPluginFocused(true)
131 // was just called for aElement while it had a plugin running, we want to
132 // make sure nsIWidget::SetPluginFocused(false) gets called for it now, even
133 // if aFocus is true.
134 if (aFocus) {
135 nsCOMPtr<nsIObjectLoadingContent> olc = do_QueryInterface(aElement);
136 bool hasRunningPlugin = false;
137 if (olc) {
138 hasRunningPlugin =
139 static_cast<nsObjectLoadingContent*>(olc.get())->HasRunningPlugin();
141 if (!hasRunningPlugin) {
142 aFocus = false;
146 if (aFocus || aElement == sLastFocused) {
147 if (!aFocus) {
148 sLastFocused = nullptr;
150 nsIWidget* widget = GetWidget(aElement);
151 if (widget) {
152 nsContentUtils::AddScriptRunner(
153 new PluginFocusSetter(widget, aFocus ? aElement : nullptr));
158 void HTMLObjectElement::HandlePluginCrashed(Element* aElement) {
159 OnFocusBlurPlugin(aElement, false);
162 void HTMLObjectElement::HandlePluginInstantiated(Element* aElement) {
163 // If aElement is already focused when a plugin is instantiated, we need
164 // to initiate a call to nsIWidget::SetPluginFocused(true). Otherwise
165 // keyboard input won't work in a click-to-play plugin until aElement
166 // loses focus and regains it.
167 nsFocusManager* fm = nsFocusManager::GetFocusManager();
168 if (fm && fm->GetFocusedElement() == aElement) {
169 OnFocusBlurPlugin(aElement, true);
173 void HTMLObjectElement::HandleFocusBlurPlugin(Element* aElement,
174 WidgetEvent* aEvent) {
175 if (!aEvent->IsTrusted()) {
176 return;
178 switch (aEvent->mMessage) {
179 case eFocus: {
180 OnFocusBlurPlugin(aElement, true);
181 break;
183 case eBlur: {
184 OnFocusBlurPlugin(aElement, false);
185 break;
187 default:
188 break;
192 NS_IMETHODIMP
193 HTMLObjectElement::PostHandleEvent(EventChainPostVisitor& aVisitor) {
194 HandleFocusBlurPlugin(this, aVisitor.mEvent);
195 return NS_OK;
198 #endif // #ifdef XP_MACOSX
200 nsresult HTMLObjectElement::BindToTree(BindContext& aContext,
201 nsINode& aParent) {
202 nsresult rv = nsGenericHTMLFormElement::BindToTree(aContext, aParent);
203 NS_ENSURE_SUCCESS(rv, rv);
205 rv = nsObjectLoadingContent::BindToTree(aContext, aParent);
206 NS_ENSURE_SUCCESS(rv, rv);
208 // Don't kick off load from being bound to a plugin document - the plugin
209 // document will call nsObjectLoadingContent::InitializeFromChannel() for the
210 // initial load.
211 if (IsInComposedDoc()) {
212 nsCOMPtr<nsIPluginDocument> pluginDoc =
213 do_QueryInterface(&aContext.OwnerDoc());
214 // If we already have all the children, start the load.
215 if (mIsDoneAddingChildren && !pluginDoc) {
216 void (HTMLObjectElement::*start)() = &HTMLObjectElement::StartObjectLoad;
217 nsContentUtils::AddScriptRunner(
218 NewRunnableMethod("dom::HTMLObjectElement::BindToTree", this, start));
222 return NS_OK;
225 void HTMLObjectElement::UnbindFromTree(bool aNullParent) {
226 #ifdef XP_MACOSX
227 // When a page is reloaded (when an Document's content is removed), the
228 // focused element isn't necessarily sent an eBlur event. See
229 // nsFocusManager::ContentRemoved(). This means that a widget may think it
230 // still contains a focused plugin when it doesn't -- which in turn can
231 // disable text input in the browser window. See bug 1137229.
232 OnFocusBlurPlugin(this, false);
233 #endif
234 nsObjectLoadingContent::UnbindFromTree(aNullParent);
235 nsGenericHTMLFormElement::UnbindFromTree(aNullParent);
238 nsresult HTMLObjectElement::AfterSetAttr(int32_t aNamespaceID, nsAtom* aName,
239 const nsAttrValue* aValue,
240 const nsAttrValue* aOldValue,
241 nsIPrincipal* aSubjectPrincipal,
242 bool aNotify) {
243 nsresult rv = AfterMaybeChangeAttr(aNamespaceID, aName, aNotify);
244 NS_ENSURE_SUCCESS(rv, rv);
246 return nsGenericHTMLFormElement::AfterSetAttr(
247 aNamespaceID, aName, aValue, aOldValue, aSubjectPrincipal, aNotify);
250 nsresult HTMLObjectElement::OnAttrSetButNotChanged(
251 int32_t aNamespaceID, nsAtom* aName, const nsAttrValueOrString& aValue,
252 bool aNotify) {
253 nsresult rv = AfterMaybeChangeAttr(aNamespaceID, aName, aNotify);
254 NS_ENSURE_SUCCESS(rv, rv);
256 return nsGenericHTMLFormElement::OnAttrSetButNotChanged(aNamespaceID, aName,
257 aValue, aNotify);
260 nsresult HTMLObjectElement::AfterMaybeChangeAttr(int32_t aNamespaceID,
261 nsAtom* aName, bool aNotify) {
262 if (aNamespaceID == kNameSpaceID_None) {
263 // if aNotify is false, we are coming from the parser or some such place;
264 // we'll get bound after all the attributes have been set, so we'll do the
265 // object load from BindToTree/DoneAddingChildren.
266 // Skip the LoadObject call in that case.
267 // We also don't want to start loading the object when we're not yet in
268 // a document, just in case that the caller wants to set additional
269 // attributes before inserting the node into the document.
270 if (aNotify && IsInComposedDoc() && mIsDoneAddingChildren &&
271 aName == nsGkAtoms::data && !BlockEmbedOrObjectContentLoading()) {
272 return LoadObject(aNotify, true);
276 return NS_OK;
279 bool HTMLObjectElement::IsHTMLFocusable(bool aWithMouse, bool* aIsFocusable,
280 int32_t* aTabIndex) {
281 // TODO: this should probably be managed directly by IsHTMLFocusable.
282 // See bug 597242.
283 Document* doc = GetComposedDoc();
284 if (!doc || doc->HasFlag(NODE_IS_EDITABLE)) {
285 if (aTabIndex) {
286 *aTabIndex = -1;
289 *aIsFocusable = false;
290 return false;
293 const nsAttrValue* attrVal = mAttrs.GetAttr(nsGkAtoms::tabindex);
294 bool isFocusable = attrVal && attrVal->Type() == nsAttrValue::eInteger;
296 // Has plugin content: let the plugin decide what to do in terms of
297 // internal focus from mouse clicks
298 if (Type() == eType_Plugin) {
299 if (aTabIndex) {
300 *aTabIndex = isFocusable ? attrVal->GetIntegerValue() : -1;
303 *aIsFocusable = true;
304 return false;
307 // This method doesn't call nsGenericHTMLFormElement intentionally.
308 // TODO: It should probably be changed when bug 597242 will be fixed.
309 if (IsEditableRoot() ||
310 ((Type() == eType_Document || Type() == eType_FakePlugin) &&
311 nsContentUtils::IsSubDocumentTabbable(this))) {
312 if (aTabIndex) {
313 *aTabIndex = isFocusable ? attrVal->GetIntegerValue() : 0;
316 *aIsFocusable = true;
317 return false;
320 // TODO: this should probably be managed directly by IsHTMLFocusable.
321 // See bug 597242.
322 if (aTabIndex && isFocusable) {
323 *aTabIndex = attrVal->GetIntegerValue();
324 *aIsFocusable = true;
327 return false;
330 nsIContent::IMEState HTMLObjectElement::GetDesiredIMEState() {
331 if (Type() == eType_Plugin) {
332 return IMEState(IMEState::PLUGIN);
335 return nsGenericHTMLFormElement::GetDesiredIMEState();
338 NS_IMETHODIMP
339 HTMLObjectElement::Reset() { return NS_OK; }
341 NS_IMETHODIMP
342 HTMLObjectElement::SubmitNamesValues(HTMLFormSubmission* aFormSubmission) {
343 nsAutoString name;
344 if (!GetAttr(kNameSpaceID_None, nsGkAtoms::name, name)) {
345 // No name, don't submit.
347 return NS_OK;
350 nsIFrame* frame = GetPrimaryFrame();
352 nsIObjectFrame* objFrame = do_QueryFrame(frame);
353 if (!objFrame) {
354 // No frame, nothing to submit.
356 return NS_OK;
359 RefPtr<nsNPAPIPluginInstance> pi = objFrame->GetPluginInstance();
360 if (!pi) {
361 return NS_OK;
364 nsAutoString value;
365 nsresult rv = pi->GetFormValue(value);
366 NS_ENSURE_SUCCESS(rv, rv);
368 return aFormSubmission->AddNameValuePair(name, value);
371 int32_t HTMLObjectElement::TabIndexDefault() { return 0; }
373 Nullable<WindowProxyHolder> HTMLObjectElement::GetContentWindow(
374 nsIPrincipal& aSubjectPrincipal) {
375 Document* doc = GetContentDocument(aSubjectPrincipal);
376 if (doc) {
377 nsPIDOMWindowOuter* win = doc->GetWindow();
378 if (win) {
379 return WindowProxyHolder(win->GetBrowsingContext());
383 return nullptr;
386 bool HTMLObjectElement::ParseAttribute(int32_t aNamespaceID, nsAtom* aAttribute,
387 const nsAString& aValue,
388 nsIPrincipal* aMaybeScriptedPrincipal,
389 nsAttrValue& aResult) {
390 if (aNamespaceID == kNameSpaceID_None) {
391 if (aAttribute == nsGkAtoms::align) {
392 return ParseAlignValue(aValue, aResult);
394 if (ParseImageAttribute(aAttribute, aValue, aResult)) {
395 return true;
399 return nsGenericHTMLFormElement::ParseAttribute(
400 aNamespaceID, aAttribute, aValue, aMaybeScriptedPrincipal, aResult);
403 void HTMLObjectElement::MapAttributesIntoRule(
404 const nsMappedAttributes* aAttributes, MappedDeclarations& aDecls) {
405 nsGenericHTMLFormElement::MapImageAlignAttributeInto(aAttributes, aDecls);
406 nsGenericHTMLFormElement::MapImageBorderAttributeInto(aAttributes, aDecls);
407 nsGenericHTMLFormElement::MapImageMarginAttributeInto(aAttributes, aDecls);
408 nsGenericHTMLFormElement::MapImageSizeAttributesInto(aAttributes, aDecls);
409 nsGenericHTMLFormElement::MapCommonAttributesInto(aAttributes, aDecls);
412 NS_IMETHODIMP_(bool)
413 HTMLObjectElement::IsAttributeMapped(const nsAtom* aAttribute) const {
414 static const MappedAttributeEntry* const map[] = {
415 sCommonAttributeMap,
416 sImageMarginSizeAttributeMap,
417 sImageBorderAttributeMap,
418 sImageAlignAttributeMap,
421 return FindAttributeDependence(aAttribute, map);
424 nsMapRuleToAttributesFunc HTMLObjectElement::GetAttributeMappingFunction()
425 const {
426 return &MapAttributesIntoRule;
429 void HTMLObjectElement::StartObjectLoad(bool aNotify, bool aForce) {
430 // BindToTree can call us asynchronously, and we may be removed from the tree
431 // in the interim
432 if (!IsInComposedDoc() || !OwnerDoc()->IsActive() ||
433 BlockEmbedOrObjectContentLoading()) {
434 return;
437 LoadObject(aNotify, aForce);
438 SetIsNetworkCreated(false);
441 EventStates HTMLObjectElement::IntrinsicState() const {
442 return nsGenericHTMLFormElement::IntrinsicState() | ObjectState();
445 uint32_t HTMLObjectElement::GetCapabilities() const {
446 return nsObjectLoadingContent::GetCapabilities() | eFallbackIfClassIDPresent;
449 void HTMLObjectElement::DestroyContent() {
450 nsObjectLoadingContent::Destroy();
451 nsGenericHTMLFormElement::DestroyContent();
454 nsresult HTMLObjectElement::CopyInnerTo(Element* aDest) {
455 nsresult rv = nsGenericHTMLFormElement::CopyInnerTo(aDest);
456 NS_ENSURE_SUCCESS(rv, rv);
458 if (aDest->OwnerDoc()->IsStaticDocument()) {
459 CreateStaticClone(static_cast<HTMLObjectElement*>(aDest));
462 return rv;
465 JSObject* HTMLObjectElement::WrapNode(JSContext* aCx,
466 JS::Handle<JSObject*> aGivenProto) {
467 JS::Rooted<JSObject*> obj(
468 aCx, HTMLObjectElement_Binding::Wrap(aCx, this, aGivenProto));
469 if (!obj) {
470 return nullptr;
472 SetupProtoChain(aCx, obj);
473 return obj;
476 } // namespace dom
477 } // namespace mozilla
479 NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER(Object)