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