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