Keep auxilliary media objects on the heap always.
[chromium-blink-merge.git] / third_party / WebKit / Source / core / html / HTMLPlugInElement.cpp
blobcde57a859cdcdc7988fd99d701bf3571e05cf17c
1 /**
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * (C) 2000 Stefan Schimanski (1Stein@gmx.de)
5 * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc.
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public License
18 * along with this library; see the file COPYING.LIB. If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
23 #include "config.h"
24 #include "core/html/HTMLPlugInElement.h"
26 #include "bindings/core/v8/ScriptController.h"
27 #include "bindings/core/v8/npruntime_impl.h"
28 #include "core/CSSPropertyNames.h"
29 #include "core/HTMLNames.h"
30 #include "core/dom/Document.h"
31 #include "core/dom/Node.h"
32 #include "core/dom/shadow/ShadowRoot.h"
33 #include "core/events/Event.h"
34 #include "core/frame/FrameView.h"
35 #include "core/frame/LocalFrame.h"
36 #include "core/frame/Settings.h"
37 #include "core/frame/csp/ContentSecurityPolicy.h"
38 #include "core/html/HTMLContentElement.h"
39 #include "core/html/HTMLImageLoader.h"
40 #include "core/html/PluginDocument.h"
41 #include "core/input/EventHandler.h"
42 #include "core/layout/LayoutBlockFlow.h"
43 #include "core/layout/LayoutEmbeddedObject.h"
44 #include "core/layout/LayoutImage.h"
45 #include "core/layout/LayoutPart.h"
46 #include "core/loader/FrameLoaderClient.h"
47 #include "core/loader/MixedContentChecker.h"
48 #include "core/page/Page.h"
49 #include "core/page/scrolling/ScrollingCoordinator.h"
50 #include "core/plugins/PluginPlaceholder.h"
51 #include "core/plugins/PluginView.h"
52 #include "platform/Logging.h"
53 #include "platform/MIMETypeFromURL.h"
54 #include "platform/MIMETypeRegistry.h"
55 #include "platform/Widget.h"
56 #include "platform/plugins/PluginData.h"
57 #include "public/platform/WebURLRequest.h"
59 namespace blink {
61 using namespace HTMLNames;
63 HTMLPlugInElement::HTMLPlugInElement(const QualifiedName& tagName, Document& doc, bool createdByParser, PreferPlugInsForImagesOption preferPlugInsForImagesOption)
64 : HTMLFrameOwnerElement(tagName, doc)
65 , m_isDelayingLoadEvent(false)
66 , m_NPObject(0)
67 // m_needsWidgetUpdate(!createdByParser) allows HTMLObjectElement to delay
68 // widget updates until after all children are parsed. For HTMLEmbedElement
69 // this delay is unnecessary, but it is simpler to make both classes share
70 // the same codepath in this class.
71 , m_needsWidgetUpdate(!createdByParser)
72 , m_shouldPreferPlugInsForImages(preferPlugInsForImagesOption == ShouldPreferPlugInsForImages)
76 HTMLPlugInElement::~HTMLPlugInElement()
78 ASSERT(!m_pluginWrapper); // cleared in detach()
79 ASSERT(!m_isDelayingLoadEvent);
81 if (m_NPObject) {
82 _NPN_ReleaseObject(m_NPObject);
83 m_NPObject = 0;
87 DEFINE_TRACE(HTMLPlugInElement)
89 visitor->trace(m_imageLoader);
90 visitor->trace(m_placeholder);
91 visitor->trace(m_persistedPluginWidget);
92 HTMLFrameOwnerElement::trace(visitor);
95 #if ENABLE(OILPAN)
96 void HTMLPlugInElement::disconnectContentFrame()
98 if (m_persistedPluginWidget) {
99 m_persistedPluginWidget->dispose();
100 m_persistedPluginWidget = nullptr;
102 HTMLFrameOwnerElement::disconnectContentFrame();
105 void HTMLPlugInElement::shouldDisposePlugin()
107 if (m_persistedPluginWidget && m_persistedPluginWidget->isPluginView())
108 toPluginView(m_persistedPluginWidget.get())->shouldDisposePlugin();
110 #endif
112 void HTMLPlugInElement::setPersistedPluginWidget(Widget* widget)
114 if (m_persistedPluginWidget == widget)
115 return;
116 #if ENABLE(OILPAN)
117 if (m_persistedPluginWidget && m_persistedPluginWidget->isPluginView()) {
118 LocalFrame* frame = toPluginView(m_persistedPluginWidget.get())->pluginFrame();
119 ASSERT(frame);
120 frame->unregisterPluginElement(this);
122 if (widget && widget->isPluginView()) {
123 LocalFrame* frame = toPluginView(widget)->pluginFrame();
124 ASSERT(frame);
125 frame->registerPluginElement(this);
127 #endif
128 m_persistedPluginWidget = widget;
131 bool HTMLPlugInElement::canProcessDrag() const
133 if (Widget* widget = existingPluginWidget())
134 return widget->isPluginView() && toPluginView(widget)->canProcessDrag();
135 return false;
138 bool HTMLPlugInElement::willRespondToMouseClickEvents()
140 if (isDisabledFormControl())
141 return false;
142 LayoutObject* r = layoutObject();
143 return r && (r->isEmbeddedObject() || r->isLayoutPart());
146 void HTMLPlugInElement::removeAllEventListeners()
148 HTMLFrameOwnerElement::removeAllEventListeners();
149 if (LayoutPart* layoutObject = existingLayoutPart()) {
150 if (Widget* widget = layoutObject->widget())
151 widget->eventListenersRemoved();
155 void HTMLPlugInElement::didMoveToNewDocument(Document& oldDocument)
157 if (m_imageLoader)
158 m_imageLoader->elementDidMoveToNewDocument();
159 HTMLFrameOwnerElement::didMoveToNewDocument(oldDocument);
162 void HTMLPlugInElement::attach(const AttachContext& context)
164 HTMLFrameOwnerElement::attach(context);
166 if (!layoutObject() || useFallbackContent())
167 return;
169 if (isImageType()) {
170 if (!m_imageLoader)
171 m_imageLoader = HTMLImageLoader::create(this);
172 m_imageLoader->updateFromElement();
173 } else if (needsWidgetUpdate()
174 && layoutEmbeddedObject()
175 && !layoutEmbeddedObject()->showsUnavailablePluginIndicator()
176 && !wouldLoadAsNetscapePlugin(m_url, m_serviceType)
177 && !m_isDelayingLoadEvent) {
178 m_isDelayingLoadEvent = true;
179 document().incrementLoadEventDelayCount();
180 document().loadPluginsSoon();
184 void HTMLPlugInElement::updateWidget()
186 RefPtrWillBeRawPtr<HTMLPlugInElement> protector(this);
187 updateWidgetInternal();
188 if (m_isDelayingLoadEvent) {
189 m_isDelayingLoadEvent = false;
190 document().decrementLoadEventDelayCount();
194 void HTMLPlugInElement::requestPluginCreationWithoutLayoutObjectIfPossible()
196 if (m_serviceType.isEmpty())
197 return;
199 if (!document().frame()
200 || !document().frame()->loader().client()->canCreatePluginWithoutRenderer(m_serviceType))
201 return;
203 if (layoutObject() && layoutObject()->isLayoutPart())
204 return;
206 createPluginWithoutLayoutObject();
209 void HTMLPlugInElement::createPluginWithoutLayoutObject()
211 ASSERT(document().frame()->loader().client()->canCreatePluginWithoutRenderer(m_serviceType));
213 KURL url;
214 Vector<String> paramNames;
215 Vector<String> paramValues;
217 paramNames.append("type");
218 paramValues.append(m_serviceType);
220 bool useFallback = false;
221 loadPlugin(url, m_serviceType, paramNames, paramValues, useFallback, false);
224 bool HTMLPlugInElement::shouldAccelerate() const
226 if (Widget* widget = ownedWidget())
227 return widget->isPluginView() && toPluginView(widget)->platformLayer();
228 return false;
231 void HTMLPlugInElement::detach(const AttachContext& context)
233 // Update the widget the next time we attach (detaching destroys the plugin).
234 // FIXME: None of this "needsWidgetUpdate" related code looks right.
235 if (layoutObject() && !useFallbackContent())
236 setNeedsWidgetUpdate(true);
237 if (m_isDelayingLoadEvent) {
238 m_isDelayingLoadEvent = false;
239 document().decrementLoadEventDelayCount();
242 // Only try to persist a plugin widget we actually own.
243 Widget* plugin = ownedWidget();
244 if (plugin && plugin->pluginShouldPersist())
245 setPersistedPluginWidget(plugin);
247 resetInstance();
248 // Clear the widget; will trigger disposal of it with Oilpan.
249 setWidget(nullptr);
251 if (m_NPObject) {
252 _NPN_ReleaseObject(m_NPObject);
253 m_NPObject = 0;
256 HTMLFrameOwnerElement::detach(context);
259 LayoutObject* HTMLPlugInElement::createLayoutObject(const ComputedStyle& style)
261 // Fallback content breaks the DOM->layoutObject class relationship of this
262 // class and all superclasses because createObject won't necessarily return
263 // a LayoutEmbeddedObject or LayoutPart.
264 if (useFallbackContent())
265 return LayoutObject::createObject(this, style);
267 if (isImageType()) {
268 LayoutImage* image = new LayoutImage(this);
269 image->setImageResource(LayoutImageResource::create());
270 return image;
273 if (usePlaceholderContent())
274 return new LayoutBlockFlow(this);
276 return new LayoutEmbeddedObject(this);
279 void HTMLPlugInElement::finishParsingChildren()
281 HTMLFrameOwnerElement::finishParsingChildren();
282 if (useFallbackContent())
283 return;
285 setNeedsWidgetUpdate(true);
286 if (inDocument())
287 lazyReattachIfNeeded();
290 void HTMLPlugInElement::resetInstance()
292 m_pluginWrapper.clear();
295 SharedPersistent<v8::Object>* HTMLPlugInElement::pluginWrapper()
297 LocalFrame* frame = document().frame();
298 if (!frame)
299 return nullptr;
301 // If the host dynamically turns off JavaScript (or Java) we will still
302 // return the cached allocated Bindings::Instance. Not supporting this
303 // edge-case is OK.
304 if (!m_pluginWrapper) {
305 Widget* plugin;
307 if (m_persistedPluginWidget)
308 plugin = m_persistedPluginWidget.get();
309 else
310 plugin = pluginWidgetForJSBindings();
312 if (plugin)
313 m_pluginWrapper = frame->script().createPluginWrapper(plugin);
315 return m_pluginWrapper.get();
318 Widget* HTMLPlugInElement::existingPluginWidget() const
320 if (LayoutPart* layoutPart = existingLayoutPart())
321 return layoutPart->widget();
322 return nullptr;
325 Widget* HTMLPlugInElement::pluginWidgetForJSBindings()
327 if (LayoutPart* layoutPart = layoutPartForJSBindings())
328 return layoutPart->widget();
329 return nullptr;
332 bool HTMLPlugInElement::isPresentationAttribute(const QualifiedName& name) const
334 if (name == widthAttr || name == heightAttr || name == vspaceAttr || name == hspaceAttr || name == alignAttr)
335 return true;
336 return HTMLFrameOwnerElement::isPresentationAttribute(name);
339 void HTMLPlugInElement::collectStyleForPresentationAttribute(const QualifiedName& name, const AtomicString& value, MutableStylePropertySet* style)
341 if (name == widthAttr) {
342 addHTMLLengthToStyle(style, CSSPropertyWidth, value);
343 } else if (name == heightAttr) {
344 addHTMLLengthToStyle(style, CSSPropertyHeight, value);
345 } else if (name == vspaceAttr) {
346 addHTMLLengthToStyle(style, CSSPropertyMarginTop, value);
347 addHTMLLengthToStyle(style, CSSPropertyMarginBottom, value);
348 } else if (name == hspaceAttr) {
349 addHTMLLengthToStyle(style, CSSPropertyMarginLeft, value);
350 addHTMLLengthToStyle(style, CSSPropertyMarginRight, value);
351 } else if (name == alignAttr) {
352 applyAlignmentAttributeToStyle(value, style);
353 } else {
354 HTMLFrameOwnerElement::collectStyleForPresentationAttribute(name, value, style);
358 void HTMLPlugInElement::defaultEventHandler(Event* event)
360 // Firefox seems to use a fake event listener to dispatch events to plugin
361 // (tested with mouse events only). This is observable via different order
362 // of events - in Firefox, event listeners specified in HTML attributes
363 // fires first, then an event gets dispatched to plugin, and only then
364 // other event listeners fire. Hopefully, this difference does not matter in
365 // practice.
367 // FIXME: Mouse down and scroll events are passed down to plugin via custom
368 // code in EventHandler; these code paths should be united.
370 LayoutObject* r = layoutObject();
371 if (!r || !r->isLayoutPart())
372 return;
373 if (r->isEmbeddedObject()) {
374 if (toLayoutEmbeddedObject(r)->showsUnavailablePluginIndicator())
375 return;
377 RefPtrWillBeRawPtr<Widget> widget = toLayoutPart(r)->widget();
378 if (!widget)
379 return;
380 widget->handleEvent(event);
381 if (event->defaultHandled())
382 return;
383 HTMLFrameOwnerElement::defaultEventHandler(event);
386 LayoutPart* HTMLPlugInElement::layoutPartForJSBindings() const
388 // Needs to load the plugin immediatedly because this function is called
389 // when JavaScript code accesses the plugin.
390 // FIXME: Check if dispatching events here is safe.
391 document().updateLayoutIgnorePendingStylesheets(Document::RunPostLayoutTasksSynchronously);
392 return existingLayoutPart();
395 bool HTMLPlugInElement::isKeyboardFocusable() const
397 if (useFallbackContent() || usePlaceholderContent())
398 return HTMLElement::isKeyboardFocusable();
400 if (!document().isActive())
401 return false;
403 if (Widget* widget = existingPluginWidget())
404 return widget->isPluginView() && toPluginView(widget)->supportsKeyboardFocus();
406 return false;
409 bool HTMLPlugInElement::hasCustomFocusLogic() const
411 return !useFallbackContent() && !usePlaceholderContent();
414 bool HTMLPlugInElement::isPluginElement() const
416 return true;
419 bool HTMLPlugInElement::layoutObjectIsFocusable() const
421 if (HTMLFrameOwnerElement::supportsFocus() && HTMLFrameOwnerElement::layoutObjectIsFocusable())
422 return true;
424 if (useFallbackContent() || !layoutObject() || !layoutObject()->isEmbeddedObject())
425 return false;
426 return !toLayoutEmbeddedObject(layoutObject())->showsUnavailablePluginIndicator();
429 NPObject* HTMLPlugInElement::getNPObject()
431 ASSERT(document().frame());
432 if (!m_NPObject)
433 m_NPObject = document().frame()->script().createScriptObjectForPluginElement(this);
434 return m_NPObject;
437 void HTMLPlugInElement::setPluginFocus(bool focused)
439 Widget* focusedWidget = existingPluginWidget();
440 // NPAPI flash requires to receive messages when web contents focus changes.
441 if (getNPObject() && focusedWidget)
442 focusedWidget->setFocus(focused, WebFocusTypeNone);
445 bool HTMLPlugInElement::isImageType()
447 if (m_serviceType.isEmpty() && protocolIs(m_url, "data"))
448 m_serviceType = mimeTypeFromDataURL(m_url);
450 if (LocalFrame* frame = document().frame()) {
451 KURL completedURL = document().completeURL(m_url);
452 return frame->loader().client()->objectContentType(completedURL, m_serviceType, shouldPreferPlugInsForImages()) == ObjectContentImage;
455 return Image::supportsType(m_serviceType);
458 LayoutEmbeddedObject* HTMLPlugInElement::layoutEmbeddedObject() const
460 // HTMLObjectElement and HTMLEmbedElement may return arbitrary layoutObjects
461 // when using fallback content.
462 if (!layoutObject() || !layoutObject()->isEmbeddedObject())
463 return nullptr;
464 return toLayoutEmbeddedObject(layoutObject());
467 // We don't use m_url, as it may not be the final URL that the object loads,
468 // depending on <param> values.
469 bool HTMLPlugInElement::allowedToLoadFrameURL(const String& url)
471 KURL completeURL = document().completeURL(url);
472 if (contentFrame() && protocolIsJavaScript(completeURL)
473 && !document().securityOrigin()->canAccess(contentFrame()->securityContext()->securityOrigin()))
474 return false;
475 return document().frame()->isURLAllowed(completeURL);
478 // We don't use m_url, or m_serviceType as they may not be the final values
479 // that <object> uses depending on <param> values.
480 bool HTMLPlugInElement::wouldLoadAsNetscapePlugin(const String& url, const String& serviceType)
482 ASSERT(document().frame());
483 KURL completedURL;
484 if (!url.isEmpty())
485 completedURL = document().completeURL(url);
486 return document().frame()->loader().client()->objectContentType(completedURL, serviceType, shouldPreferPlugInsForImages()) == ObjectContentNetscapePlugin;
489 bool HTMLPlugInElement::requestObject(const String& url, const String& mimeType, const Vector<String>& paramNames, const Vector<String>& paramValues)
491 if (url.isEmpty() && mimeType.isEmpty())
492 return false;
494 if (protocolIsJavaScript(url))
495 return false;
497 KURL completedURL = url.isEmpty() ? KURL() : document().completeURL(url);
498 if (!pluginIsLoadable(completedURL, mimeType))
499 return false;
501 bool useFallback;
502 if (shouldUsePlugin(completedURL, mimeType, hasFallbackContent(), useFallback))
503 return loadPlugin(completedURL, mimeType, paramNames, paramValues, useFallback, true);
505 // If the plugin element already contains a subframe,
506 // loadOrRedirectSubframe will re-use it. Otherwise, it will create a new
507 // frame and set it as the LayoutPart's widget, causing what was previously
508 // in the widget to be torn down.
509 return loadOrRedirectSubframe(completedURL, getNameAttribute(), true);
512 bool HTMLPlugInElement::loadPlugin(const KURL& url, const String& mimeType, const Vector<String>& paramNames, const Vector<String>& paramValues, bool useFallback, bool requireLayoutObject)
514 LocalFrame* frame = document().frame();
516 if (!frame->loader().allowPlugins(AboutToInstantiatePlugin))
517 return false;
519 LayoutEmbeddedObject* layoutObject = layoutEmbeddedObject();
520 // FIXME: This code should not depend on layoutObject!
521 if ((!layoutObject && requireLayoutObject) || useFallback)
522 return false;
524 WTF_LOG(Plugins, "%p Plugin URL: %s", this, m_url.utf8().data());
525 WTF_LOG(Plugins, " Loaded URL: %s", url.string().utf8().data());
526 m_loadedUrl = url;
528 OwnPtrWillBeRawPtr<PluginPlaceholder> placeholder = nullptr;
529 RefPtrWillBeRawPtr<Widget> widget = m_persistedPluginWidget;
530 if (!widget) {
531 bool loadManually = document().isPluginDocument() && !document().containsPlugins();
532 placeholder = frame->loader().client()->createPluginPlaceholder(document(), url, paramNames, paramValues, mimeType, loadManually);
533 if (!placeholder) {
534 FrameLoaderClient::DetachedPluginPolicy policy = requireLayoutObject ? FrameLoaderClient::FailOnDetachedPlugin : FrameLoaderClient::AllowDetachedPlugin;
535 widget = frame->loader().client()->createPlugin(this, url, paramNames, paramValues, mimeType, loadManually, policy);
539 if (!placeholder && !widget) {
540 if (layoutObject && !layoutObject->showsUnavailablePluginIndicator())
541 layoutObject->setPluginUnavailabilityReason(LayoutEmbeddedObject::PluginMissing);
542 setPlaceholder(nullptr);
543 return false;
546 if (placeholder) {
547 setPlaceholder(placeholder.release());
548 return true;
551 if (layoutObject) {
552 setWidget(widget);
553 setPersistedPluginWidget(nullptr);
554 } else {
555 setPersistedPluginWidget(widget.get());
557 setPlaceholder(nullptr);
558 document().setContainsPlugins();
559 // TODO(esprehn): WebPluginContainerImpl::setWebLayer also schedules a compositing update, do we need both?
560 setNeedsCompositingUpdate();
561 // Make sure any input event handlers introduced by the plugin are taken into account.
562 if (Page* page = document().frame()->page()) {
563 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
564 scrollingCoordinator->notifyLayoutUpdated();
566 return true;
569 bool HTMLPlugInElement::shouldUsePlugin(const KURL& url, const String& mimeType, bool hasFallback, bool& useFallback)
571 // Allow other plugins to win over QuickTime because if the user has
572 // installed a plugin that can handle TIFF (which QuickTime can also
573 // handle) they probably intended to override QT.
574 if (document().frame()->page() && (mimeType == "image/tiff" || mimeType == "image/tif" || mimeType == "image/x-tiff")) {
575 const PluginData* pluginData = document().frame()->page()->pluginData();
576 String pluginName = pluginData ? pluginData->pluginNameForMimeType(mimeType) : String();
577 if (!pluginName.isEmpty() && !pluginName.contains("QuickTime", TextCaseInsensitive))
578 return true;
581 ObjectContentType objectType = document().frame()->loader().client()->objectContentType(url, mimeType, shouldPreferPlugInsForImages());
582 // If an object's content can't be handled and it has no fallback, let
583 // it be handled as a plugin to show the broken plugin icon.
584 useFallback = objectType == ObjectContentNone && hasFallback;
585 return objectType == ObjectContentNone || objectType == ObjectContentNetscapePlugin || objectType == ObjectContentOtherPlugin;
588 void HTMLPlugInElement::setPlaceholder(PassOwnPtrWillBeRawPtr<PluginPlaceholder> placeholder)
590 bool needsLazyReattach = (!placeholder) != (!m_placeholder);
591 if (placeholder) {
592 placeholder->loadIntoContainer(ensureUserAgentShadowRoot());
593 m_placeholder = placeholder;
594 } else {
595 ShadowRoot& shadowRoot = ensureUserAgentShadowRoot();
596 shadowRoot.removeChildren();
597 shadowRoot.appendChild(HTMLContentElement::create(document()));
598 m_placeholder.clear();
600 if (needsLazyReattach)
601 lazyReattachIfAttached();
604 void HTMLPlugInElement::dispatchErrorEvent()
606 if (document().isPluginDocument() && document().ownerElement())
607 document().ownerElement()->dispatchEvent(Event::create(EventTypeNames::error));
608 else
609 dispatchEvent(Event::create(EventTypeNames::error));
612 bool HTMLPlugInElement::pluginIsLoadable(const KURL& url, const String& mimeType)
614 if (url.isEmpty() && mimeType.isEmpty())
615 return false;
617 LocalFrame* frame = document().frame();
618 Settings* settings = frame->settings();
619 if (!settings)
620 return false;
622 if (MIMETypeRegistry::isJavaAppletMIMEType(mimeType) && !settings->javaEnabled())
623 return false;
625 if (document().isSandboxed(SandboxPlugins))
626 return false;
628 if (!document().securityOrigin()->canDisplay(url)) {
629 FrameLoader::reportLocalLoadFailed(frame, url.string());
630 return false;
633 AtomicString declaredMimeType = document().isPluginDocument() && document().ownerElement() ?
634 document().ownerElement()->fastGetAttribute(HTMLNames::typeAttr) :
635 fastGetAttribute(HTMLNames::typeAttr);
636 if (!document().contentSecurityPolicy()->allowObjectFromSource(url)
637 || !document().contentSecurityPolicy()->allowPluginTypeForDocument(document(), mimeType, declaredMimeType, url)) {
638 layoutEmbeddedObject()->setPluginUnavailabilityReason(LayoutEmbeddedObject::PluginBlockedByContentSecurityPolicy);
639 return false;
642 return (!mimeType.isEmpty() && url.isEmpty()) || !MixedContentChecker::shouldBlockFetch(frame, WebURLRequest::RequestContextObject, WebURLRequest::FrameTypeNone, url);
645 void HTMLPlugInElement::didAddUserAgentShadowRoot(ShadowRoot&)
647 userAgentShadowRoot()->appendChild(HTMLContentElement::create(document()));
650 void HTMLPlugInElement::willAddFirstAuthorShadowRoot()
652 lazyReattachIfAttached();
655 bool HTMLPlugInElement::hasFallbackContent() const
657 return false;
660 bool HTMLPlugInElement::useFallbackContent() const
662 return openShadowRoot();
665 void HTMLPlugInElement::lazyReattachIfNeeded()
667 if (!useFallbackContent() && !usePlaceholderContent() && needsWidgetUpdate() && layoutObject() && !isImageType())
668 lazyReattachIfAttached();