HTMLEmbedElement.cpp (8975B)
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/dom/HTMLEmbedElement.h" 8 9 #include "mozilla/dom/BindContext.h" 10 #include "mozilla/dom/Document.h" 11 #include "mozilla/dom/ElementInlines.h" 12 #include "mozilla/dom/HTMLEmbedElementBinding.h" 13 #include "nsContentUtils.h" 14 #include "nsFrameLoader.h" 15 #include "nsIWidget.h" 16 #include "nsObjectLoadingContent.h" 17 #include "nsThreadUtils.h" 18 #ifdef XP_MACOSX 19 # include "mozilla/EventDispatcher.h" 20 # include "mozilla/dom/Event.h" 21 #endif 22 23 NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER(Embed) 24 25 namespace mozilla::dom { 26 27 HTMLEmbedElement::HTMLEmbedElement( 28 already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo, 29 FromParser aFromParser) 30 : nsGenericHTMLElement(std::move(aNodeInfo)) { 31 SetIsNetworkCreated(aFromParser == FROM_PARSER_NETWORK); 32 } 33 34 HTMLEmbedElement::~HTMLEmbedElement() = default; 35 36 NS_IMPL_CYCLE_COLLECTION_CLASS(HTMLEmbedElement) 37 38 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLEmbedElement, 39 nsGenericHTMLElement) 40 nsObjectLoadingContent::Traverse(tmp, cb); 41 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END 42 43 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLEmbedElement, 44 nsGenericHTMLElement) 45 nsObjectLoadingContent::Unlink(tmp); 46 NS_IMPL_CYCLE_COLLECTION_UNLINK_END 47 48 NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED( 49 HTMLEmbedElement, nsGenericHTMLElement, nsIRequestObserver, 50 nsIStreamListener, nsFrameLoaderOwner, nsIObjectLoadingContent, 51 nsIChannelEventSink) 52 53 NS_IMPL_ELEMENT_CLONE(HTMLEmbedElement) 54 55 nsresult HTMLEmbedElement::BindToTree(BindContext& aContext, nsINode& aParent) { 56 nsresult rv = nsGenericHTMLElement::BindToTree(aContext, aParent); 57 NS_ENSURE_SUCCESS(rv, rv); 58 59 if (IsInComposedDoc()) { 60 void (HTMLEmbedElement::*start)() = &HTMLEmbedElement::StartObjectLoad; 61 nsContentUtils::AddScriptRunner( 62 NewRunnableMethod("dom::HTMLEmbedElement::BindToTree", this, start)); 63 } 64 65 return NS_OK; 66 } 67 68 void HTMLEmbedElement::UnbindFromTree(UnbindContext& aContext) { 69 nsObjectLoadingContent::UnbindFromTree(); 70 nsGenericHTMLElement::UnbindFromTree(aContext); 71 } 72 73 void HTMLEmbedElement::AfterSetAttr(int32_t aNamespaceID, nsAtom* aName, 74 const nsAttrValue* aValue, 75 const nsAttrValue* aOldValue, 76 nsIPrincipal* aSubjectPrincipal, 77 bool aNotify) { 78 if (aValue) { 79 AfterMaybeChangeAttr(aNamespaceID, aName, aNotify); 80 } 81 82 if (aName == nsGkAtoms::src) { 83 RefreshFeaturePolicy(); 84 } 85 86 if (aNamespaceID == kNameSpaceID_None && 87 aName == nsGkAtoms::allowfullscreen && mFrameLoader) { 88 if (auto* bc = mFrameLoader->GetExtantBrowsingContext()) { 89 MOZ_ALWAYS_SUCCEEDS(bc->SetFullscreenAllowedByOwner(AllowFullscreen())); 90 } 91 } 92 93 return nsGenericHTMLElement::AfterSetAttr( 94 aNamespaceID, aName, aValue, aOldValue, aSubjectPrincipal, aNotify); 95 } 96 97 void HTMLEmbedElement::OnAttrSetButNotChanged(int32_t aNamespaceID, 98 nsAtom* aName, 99 const nsAttrValueOrString& aValue, 100 bool aNotify) { 101 AfterMaybeChangeAttr(aNamespaceID, aName, aNotify); 102 return nsGenericHTMLElement::OnAttrSetButNotChanged(aNamespaceID, aName, 103 aValue, aNotify); 104 } 105 106 void HTMLEmbedElement::AfterMaybeChangeAttr(int32_t aNamespaceID, nsAtom* aName, 107 bool aNotify) { 108 if (aNamespaceID != kNameSpaceID_None || aName != nsGkAtoms::src) { 109 return; 110 } 111 // If aNotify is false, we are coming from the parser or some such place; 112 // we'll get bound after all the attributes have been set, so we'll do the 113 // object load from BindToTree. 114 // Skip the LoadObject call in that case. 115 // We also don't want to start loading the object when we're not yet in 116 // a document, just in case that the caller wants to set additional 117 // attributes before inserting the node into the document. 118 if (!aNotify || !IsInComposedDoc() || BlockEmbedOrObjectContentLoading()) { 119 return; 120 } 121 nsContentUtils::AddScriptRunner(NS_NewRunnableFunction( 122 "HTMLEmbedElement::LoadObject", 123 [self = RefPtr<HTMLEmbedElement>(this), aNotify]() { 124 if (self->IsInComposedDoc()) { 125 self->LoadObject(aNotify, true); 126 } 127 })); 128 } 129 130 int32_t HTMLEmbedElement::TabIndexDefault() { 131 // Only when we loaded a sub-document, <embed> should be tabbable by default 132 // because it's a navigable containers mentioned in 6.6.3 The tabindex 133 // attribute in the standard (see "If the value is null" section). 134 // https://html.spec.whatwg.org/#the-tabindex-attribute 135 // Otherwise, the default tab-index of <embed> is expected as -1 in a WPT: 136 // https://searchfox.org/mozilla-central/rev/7d98e651953f3135d91e98fa6d33efa131aec7ea/testing/web-platform/tests/html/interaction/focus/sequential-focus-navigation-and-the-tabindex-attribute/tabindex-getter.html#63 137 return Type() == ObjectType::Document ? 0 : -1; 138 } 139 140 bool HTMLEmbedElement::IsHTMLFocusable(IsFocusableFlags aFlags, 141 bool* aIsFocusable, int32_t* aTabIndex) { 142 // Has non-plugin content: let the plugin decide what to do in terms of 143 // internal focus from mouse clicks 144 if (aTabIndex) { 145 *aTabIndex = TabIndex(); 146 } 147 148 *aIsFocusable = true; 149 150 // Let the plugin decide, so override. 151 return true; 152 } 153 154 bool HTMLEmbedElement::ParseAttribute(int32_t aNamespaceID, nsAtom* aAttribute, 155 const nsAString& aValue, 156 nsIPrincipal* aMaybeScriptedPrincipal, 157 nsAttrValue& aResult) { 158 if (aNamespaceID == kNameSpaceID_None) { 159 if (aAttribute == nsGkAtoms::align) { 160 return ParseAlignValue(aValue, aResult); 161 } 162 if (aAttribute == nsGkAtoms::width || aAttribute == nsGkAtoms::height || 163 aAttribute == nsGkAtoms::hspace || aAttribute == nsGkAtoms::vspace) { 164 return aResult.ParseHTMLDimension(aValue); 165 } 166 } 167 168 return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue, 169 aMaybeScriptedPrincipal, aResult); 170 } 171 172 static void MapAttributesIntoRuleBase(MappedDeclarationsBuilder& aBuilder) { 173 nsGenericHTMLElement::MapImageMarginAttributeInto(aBuilder); 174 nsGenericHTMLElement::MapImageSizeAttributesInto(aBuilder); 175 nsGenericHTMLElement::MapImageAlignAttributeInto(aBuilder); 176 } 177 178 static void MapAttributesIntoRuleExceptHidden( 179 MappedDeclarationsBuilder& aBuilder) { 180 MapAttributesIntoRuleBase(aBuilder); 181 nsGenericHTMLElement::MapCommonAttributesIntoExceptHidden(aBuilder); 182 } 183 184 void HTMLEmbedElement::MapAttributesIntoRule( 185 MappedDeclarationsBuilder& aBuilder) { 186 MapAttributesIntoRuleBase(aBuilder); 187 nsGenericHTMLElement::MapCommonAttributesInto(aBuilder); 188 } 189 190 NS_IMETHODIMP_(bool) 191 HTMLEmbedElement::IsAttributeMapped(const nsAtom* aAttribute) const { 192 static const MappedAttributeEntry* const map[] = { 193 sCommonAttributeMap, 194 sImageMarginSizeAttributeMap, 195 sImageBorderAttributeMap, 196 sImageAlignAttributeMap, 197 }; 198 199 return FindAttributeDependence(aAttribute, map); 200 } 201 202 nsMapRuleToAttributesFunc HTMLEmbedElement::GetAttributeMappingFunction() 203 const { 204 return &MapAttributesIntoRuleExceptHidden; 205 } 206 207 void HTMLEmbedElement::StartObjectLoad(bool aNotify, bool aForceLoad) { 208 // BindToTree can call us asynchronously, and we may be removed from the tree 209 // in the interim 210 if (!IsInComposedDoc() || !OwnerDoc()->IsActive() || 211 BlockEmbedOrObjectContentLoading()) { 212 return; 213 } 214 215 LoadObject(aNotify, aForceLoad); 216 SetIsNetworkCreated(false); 217 } 218 219 uint32_t HTMLEmbedElement::GetCapabilities() const { 220 return eAllowPluginSkipChannel | eSupportImages | eSupportDocuments; 221 } 222 223 void HTMLEmbedElement::DestroyContent() { 224 nsObjectLoadingContent::Destroy(); 225 nsGenericHTMLElement::DestroyContent(); 226 } 227 228 nsresult HTMLEmbedElement::CopyInnerTo(HTMLEmbedElement* aDest) { 229 nsresult rv = nsGenericHTMLElement::CopyInnerTo(aDest); 230 NS_ENSURE_SUCCESS(rv, rv); 231 232 if (aDest->OwnerDoc()->IsStaticDocument()) { 233 CreateStaticClone(aDest); 234 } 235 236 return rv; 237 } 238 239 JSObject* HTMLEmbedElement::WrapNode(JSContext* aCx, 240 JS::Handle<JSObject*> aGivenProto) { 241 return HTMLEmbedElement_Binding::Wrap(aCx, this, aGivenProto); 242 } 243 244 nsContentPolicyType HTMLEmbedElement::GetContentPolicyType() const { 245 return nsIContentPolicy::TYPE_INTERNAL_EMBED; 246 } 247 248 } // namespace mozilla::dom