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/HTMLEmbedElement.h"
9 #include "mozilla/dom/HTMLEmbedElementBinding.h"
10 #include "mozilla/dom/ElementInlines.h"
11 
12 #include "nsIDocument.h"
13 #include "nsIPluginDocument.h"
14 #include "nsIDOMDocument.h"
15 #include "nsThreadUtils.h"
16 #include "nsIScriptError.h"
17 #include "nsIWidget.h"
18 #include "nsContentUtils.h"
19 #ifdef XP_MACOSX
20 #include "mozilla/EventDispatcher.h"
21 #include "mozilla/dom/Event.h"
22 #endif
23 #include "mozilla/dom/HTMLObjectElement.h"
24 
25 NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER(Embed)
26 
27 namespace mozilla {
28 namespace dom {
29 
HTMLEmbedElement(already_AddRefed<mozilla::dom::NodeInfo> & aNodeInfo,FromParser aFromParser)30 HTMLEmbedElement::HTMLEmbedElement(
31     already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo, FromParser aFromParser)
32     : nsGenericHTMLElement(aNodeInfo) {
33   RegisterActivityObserver();
34   SetIsNetworkCreated(aFromParser == FROM_PARSER_NETWORK);
35 
36   // By default we're in the loading state
37   AddStatesSilently(NS_EVENT_STATE_LOADING);
38 }
39 
~HTMLEmbedElement()40 HTMLEmbedElement::~HTMLEmbedElement() {
41 #ifdef XP_MACOSX
42   HTMLObjectElement::OnFocusBlurPlugin(this, false);
43 #endif
44   UnregisterActivityObserver();
45   DestroyImageLoadingContent();
46 }
47 
48 NS_IMPL_CYCLE_COLLECTION_CLASS(HTMLEmbedElement)
49 
50 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLEmbedElement,
51                                                   nsGenericHTMLElement)
52   nsObjectLoadingContent::Traverse(tmp, cb);
53 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
54 
NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED(HTMLEmbedElement,nsGenericHTMLElement,nsIRequestObserver,nsIStreamListener,nsIFrameLoaderOwner,nsIObjectLoadingContent,imgINotificationObserver,nsIImageLoadingContent,nsIChannelEventSink)55 NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED(
56     HTMLEmbedElement, nsGenericHTMLElement, nsIRequestObserver,
57     nsIStreamListener, nsIFrameLoaderOwner, nsIObjectLoadingContent,
58     imgINotificationObserver, nsIImageLoadingContent, nsIChannelEventSink)
59 
60 NS_IMPL_ELEMENT_CLONE(HTMLEmbedElement)
61 
62 #ifdef XP_MACOSX
63 
64 NS_IMETHODIMP
65 HTMLEmbedElement::PostHandleEvent(EventChainPostVisitor& aVisitor) {
66   HTMLObjectElement::HandleFocusBlurPlugin(this, aVisitor.mEvent);
67   return NS_OK;
68 }
69 
70 #endif  // #ifdef XP_MACOSX
71 
AsyncEventRunning(AsyncEventDispatcher * aEvent)72 void HTMLEmbedElement::AsyncEventRunning(AsyncEventDispatcher* aEvent) {
73   nsImageLoadingContent::AsyncEventRunning(aEvent);
74 }
75 
BindToTree(nsIDocument * aDocument,nsIContent * aParent,nsIContent * aBindingParent,bool aCompileEventHandlers)76 nsresult HTMLEmbedElement::BindToTree(nsIDocument* aDocument,
77                                       nsIContent* aParent,
78                                       nsIContent* aBindingParent,
79                                       bool aCompileEventHandlers) {
80   nsresult rv = nsGenericHTMLElement::BindToTree(
81       aDocument, aParent, aBindingParent, aCompileEventHandlers);
82   NS_ENSURE_SUCCESS(rv, rv);
83 
84   rv = nsObjectLoadingContent::BindToTree(aDocument, aParent, aBindingParent,
85                                           aCompileEventHandlers);
86   NS_ENSURE_SUCCESS(rv, rv);
87 
88   // Don't kick off load from being bound to a plugin document - the plugin
89   // document will call nsObjectLoadingContent::InitializeFromChannel() for the
90   // initial load.
91   nsCOMPtr<nsIPluginDocument> pluginDoc = do_QueryInterface(aDocument);
92 
93   if (!pluginDoc) {
94     void (HTMLEmbedElement::*start)() = &HTMLEmbedElement::StartObjectLoad;
95     nsContentUtils::AddScriptRunner(
96         NewRunnableMethod("dom::HTMLEmbedElement::BindToTree", this, start));
97   }
98 
99   return NS_OK;
100 }
101 
UnbindFromTree(bool aDeep,bool aNullParent)102 void HTMLEmbedElement::UnbindFromTree(bool aDeep, bool aNullParent) {
103 #ifdef XP_MACOSX
104   // When a page is reloaded (when an nsIDocument's content is removed), the
105   // focused element isn't necessarily sent an eBlur event. See
106   // nsFocusManager::ContentRemoved(). This means that a widget may think it
107   // still contains a focused plugin when it doesn't -- which in turn can
108   // disable text input in the browser window. See bug 1137229.
109   HTMLObjectElement::OnFocusBlurPlugin(this, false);
110 #endif
111   nsObjectLoadingContent::UnbindFromTree(aDeep, aNullParent);
112   nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
113 }
114 
AfterSetAttr(int32_t aNamespaceID,nsAtom * aName,const nsAttrValue * aValue,const nsAttrValue * aOldValue,nsIPrincipal * aSubjectPrincipal,bool aNotify)115 nsresult HTMLEmbedElement::AfterSetAttr(int32_t aNamespaceID, nsAtom* aName,
116                                         const nsAttrValue* aValue,
117                                         const nsAttrValue* aOldValue,
118                                         nsIPrincipal* aSubjectPrincipal,
119                                         bool aNotify) {
120   if (aValue) {
121     nsresult rv = AfterMaybeChangeAttr(aNamespaceID, aName, aNotify);
122     NS_ENSURE_SUCCESS(rv, rv);
123   }
124 
125   return nsGenericHTMLElement::AfterSetAttr(
126       aNamespaceID, aName, aValue, aOldValue, aSubjectPrincipal, aNotify);
127 }
128 
OnAttrSetButNotChanged(int32_t aNamespaceID,nsAtom * aName,const nsAttrValueOrString & aValue,bool aNotify)129 nsresult HTMLEmbedElement::OnAttrSetButNotChanged(
130     int32_t aNamespaceID, nsAtom* aName, const nsAttrValueOrString& aValue,
131     bool aNotify) {
132   nsresult rv = AfterMaybeChangeAttr(aNamespaceID, aName, aNotify);
133   NS_ENSURE_SUCCESS(rv, rv);
134 
135   return nsGenericHTMLElement::OnAttrSetButNotChanged(aNamespaceID, aName,
136                                                       aValue, aNotify);
137 }
138 
AfterMaybeChangeAttr(int32_t aNamespaceID,nsAtom * aName,bool aNotify)139 nsresult HTMLEmbedElement::AfterMaybeChangeAttr(int32_t aNamespaceID,
140                                                 nsAtom* aName, bool aNotify) {
141   if (aNamespaceID == kNameSpaceID_None) {
142     if (aName == nsGkAtoms::src) {
143       // If aNotify is false, we are coming from the parser or some such place;
144       // we'll get bound after all the attributes have been set, so we'll do the
145       // object load from BindToTree.
146       // Skip the LoadObject call in that case.
147       // We also don't want to start loading the object when we're not yet in
148       // a document, just in case that the caller wants to set additional
149       // attributes before inserting the node into the document.
150       if (aNotify && IsInComposedDoc() && !BlockEmbedOrObjectContentLoading()) {
151         nsresult rv = LoadObject(aNotify, true);
152         NS_ENSURE_SUCCESS(rv, rv);
153       }
154     }
155   }
156 
157   return NS_OK;
158 }
159 
IsHTMLFocusable(bool aWithMouse,bool * aIsFocusable,int32_t * aTabIndex)160 bool HTMLEmbedElement::IsHTMLFocusable(bool aWithMouse, bool* aIsFocusable,
161                                        int32_t* aTabIndex) {
162   // Has plugin content: let the plugin decide what to do in terms of
163   // internal focus from mouse clicks
164   if (aTabIndex) {
165     *aTabIndex = TabIndex();
166   }
167 
168   *aIsFocusable = true;
169 
170   // Let the plugin decide, so override.
171   return true;
172 }
173 
GetDesiredIMEState()174 nsIContent::IMEState HTMLEmbedElement::GetDesiredIMEState() {
175   if (Type() == eType_Plugin) {
176     return IMEState(IMEState::PLUGIN);
177   }
178 
179   return nsGenericHTMLElement::GetDesiredIMEState();
180 }
181 
TabIndexDefault()182 int32_t HTMLEmbedElement::TabIndexDefault() { return -1; }
183 
ParseAttribute(int32_t aNamespaceID,nsAtom * aAttribute,const nsAString & aValue,nsIPrincipal * aMaybeScriptedPrincipal,nsAttrValue & aResult)184 bool HTMLEmbedElement::ParseAttribute(int32_t aNamespaceID, nsAtom* aAttribute,
185                                       const nsAString& aValue,
186                                       nsIPrincipal* aMaybeScriptedPrincipal,
187                                       nsAttrValue& aResult) {
188   if (aNamespaceID == kNameSpaceID_None) {
189     if (aAttribute == nsGkAtoms::align) {
190       return ParseAlignValue(aValue, aResult);
191     }
192     if (ParseImageAttribute(aAttribute, aValue, aResult)) {
193       return true;
194     }
195   }
196 
197   return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
198                                               aMaybeScriptedPrincipal, aResult);
199 }
200 
MapAttributesIntoRuleBase(const nsMappedAttributes * aAttributes,GenericSpecifiedValues * aData)201 static void MapAttributesIntoRuleBase(const nsMappedAttributes* aAttributes,
202                                       GenericSpecifiedValues* aData) {
203   nsGenericHTMLElement::MapImageBorderAttributeInto(aAttributes, aData);
204   nsGenericHTMLElement::MapImageMarginAttributeInto(aAttributes, aData);
205   nsGenericHTMLElement::MapImageSizeAttributesInto(aAttributes, aData);
206   nsGenericHTMLElement::MapImageAlignAttributeInto(aAttributes, aData);
207 }
208 
MapAttributesIntoRuleExceptHidden(const nsMappedAttributes * aAttributes,GenericSpecifiedValues * aData)209 static void MapAttributesIntoRuleExceptHidden(
210     const nsMappedAttributes* aAttributes, GenericSpecifiedValues* aData) {
211   MapAttributesIntoRuleBase(aAttributes, aData);
212   nsGenericHTMLElement::MapCommonAttributesIntoExceptHidden(aAttributes, aData);
213 }
214 
MapAttributesIntoRule(const nsMappedAttributes * aAttributes,GenericSpecifiedValues * aData)215 void HTMLEmbedElement::MapAttributesIntoRule(
216     const nsMappedAttributes* aAttributes, GenericSpecifiedValues* aData) {
217   MapAttributesIntoRuleBase(aAttributes, aData);
218   nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aData);
219 }
220 
NS_IMETHODIMP_(bool)221 NS_IMETHODIMP_(bool)
222 HTMLEmbedElement::IsAttributeMapped(const nsAtom* aAttribute) const {
223   static const MappedAttributeEntry* const map[] = {
224       sCommonAttributeMap,
225       sImageMarginSizeAttributeMap,
226       sImageBorderAttributeMap,
227       sImageAlignAttributeMap,
228   };
229 
230   return FindAttributeDependence(aAttribute, map);
231 }
232 
GetAttributeMappingFunction() const233 nsMapRuleToAttributesFunc HTMLEmbedElement::GetAttributeMappingFunction()
234     const {
235   return &MapAttributesIntoRuleExceptHidden;
236 }
237 
StartObjectLoad(bool aNotify,bool aForceLoad)238 void HTMLEmbedElement::StartObjectLoad(bool aNotify, bool aForceLoad) {
239   // BindToTree can call us asynchronously, and we may be removed from the tree
240   // in the interim
241   if (!IsInComposedDoc() || !OwnerDoc()->IsActive() ||
242       BlockEmbedOrObjectContentLoading()) {
243     return;
244   }
245 
246   LoadObject(aNotify, aForceLoad);
247   SetIsNetworkCreated(false);
248 }
249 
IntrinsicState() const250 EventStates HTMLEmbedElement::IntrinsicState() const {
251   return nsGenericHTMLElement::IntrinsicState() | ObjectState();
252 }
253 
GetCapabilities() const254 uint32_t HTMLEmbedElement::GetCapabilities() const {
255   return eSupportPlugins | eAllowPluginSkipChannel | eSupportImages |
256          eSupportDocuments;
257 }
258 
DestroyContent()259 void HTMLEmbedElement::DestroyContent() {
260   nsObjectLoadingContent::DestroyContent();
261   nsGenericHTMLElement::DestroyContent();
262 }
263 
CopyInnerTo(Element * aDest,bool aPreallocateChildren)264 nsresult HTMLEmbedElement::CopyInnerTo(Element* aDest,
265                                        bool aPreallocateChildren) {
266   nsresult rv = nsGenericHTMLElement::CopyInnerTo(aDest, aPreallocateChildren);
267   NS_ENSURE_SUCCESS(rv, rv);
268 
269   if (aDest->OwnerDoc()->IsStaticDocument()) {
270     CreateStaticClone(static_cast<HTMLEmbedElement*>(aDest));
271   }
272 
273   return rv;
274 }
275 
WrapNode(JSContext * aCx,JS::Handle<JSObject * > aGivenProto)276 JSObject* HTMLEmbedElement::WrapNode(JSContext* aCx,
277                                      JS::Handle<JSObject*> aGivenProto) {
278   JSObject* obj;
279   obj = HTMLEmbedElementBinding::Wrap(aCx, this, aGivenProto);
280 
281   if (!obj) {
282     return nullptr;
283   }
284   JS::Rooted<JSObject*> rootedObj(aCx, obj);
285   SetupProtoChain(aCx, rootedObj);
286   return rootedObj;
287 }
288 
GetContentPolicyType() const289 nsContentPolicyType HTMLEmbedElement::GetContentPolicyType() const {
290   return nsIContentPolicy::TYPE_INTERNAL_EMBED;
291 }
292 
293 }  // namespace dom
294 }  // namespace mozilla
295