Commit 4c32d7e3 authored by jbroman@chromium.org's avatar jbroman@chromium.org

Allow HTMLPlugInElement to host UA shadow DOM.

When in "use placeholder content" mode, the element will
create an ordinary RenderBlockFlow as its renderer, and
so will be laid out as a block or inline-block.

A rule was added to StyleAdjuster to ensure that the
default width/height rules for replaced elements are
applied in this case. Since plugins have no intrinsic
ratio, this should be equivalent to mapping 'auto' to
the appropriate defaults.

Finally, a hook in Internals was added to allow layout
tests to trigger this mode, and two layout tests using
this were added.

BUG=364716

Review URL: https://codereview.chromium.org/369893006

git-svn-id: svn://svn.chromium.org/blink/trunk@180487 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent 8563ede3
<!DOCTYPE html>
<style>
div { margin: 10px; width: 300px; height: 150px; background: green; }
</style>
<div></div>
<div></div>
<div></div>
<!DOCTYPE html>
<style>
div { margin: 10px; width: 300px; height: 150px; background: green; }
</style>
<div style="width: 200px"></div>
<div style="height: 100px"></div>
<div style="width: 200px; height: 100px"></div>
<!DOCTYPE html>
<style>
applet, embed, object { display: block; margin: 10px; }
</style>
<!-- These should appear as green blocks of various sizes (200x150, 300x100, 200x100). -->
<applet code="DoesNotExist.class" width="200"></applet>
<embed type="application/x-fake-plugin" height="100"></embed>
<object type="application/x-fake-plugin" width="200" height="100"></object>
<script>
internals.settings.setJavaEnabled(true);
var placeholderHTML =
'<style>:host { overflow: hidden }</style>' +
'<div style="margin: 0; padding: 0; width: 100%; height: 100%; background-color: green;"></div>';
Array.prototype.forEach.call(document.querySelectorAll("applet, embed, object"), function(plugin) {
internals.forcePluginPlaceholder(plugin, placeholderHTML);
});
</script>
<!DOCTYPE html>
<style>
applet, embed, object { display: block; margin: 10px; }
</style>
<!-- These should all appear as 300x150 green blocks. -->
<applet code="DoesNotExist.class"></applet>
<embed type="application/x-fake-plugin"></embed>
<object type="application/x-fake-plugin"></object>
<script>
internals.settings.setJavaEnabled(true);
var placeholderHTML =
'<style>:host { overflow: hidden }</style>' +
'<div style="margin: 0; padding: 0; width: 100%; height: 100%; background-color: green;"></div>';
Array.prototype.forEach.call(document.querySelectorAll("applet, embed, object"), function(plugin) {
internals.forcePluginPlaceholder(plugin, placeholderHTML);
});
</script>
......@@ -42,6 +42,7 @@
#include "core/html/HTMLTextAreaElement.h"
#include "core/frame/FrameView.h"
#include "core/frame/Settings.h"
#include "core/rendering/RenderReplaced.h"
#include "core/rendering/RenderTheme.h"
#include "core/rendering/style/GridPosition.h"
#include "core/rendering/style/RenderStyle.h"
......@@ -383,6 +384,16 @@ void StyleAdjuster::adjustStyleForTagName(RenderStyle* style, RenderStyle* paren
if (isHTMLPlugInElement(element)) {
style->setRequiresAcceleratedCompositingForExternalReasons(toHTMLPlugInElement(element).shouldAccelerate());
// Plugins should get the standard replaced width/height instead of 'auto'.
// Replaced renderers get this for free, and fallback content doesn't count.
if (toHTMLPlugInElement(element).usePlaceholderContent()) {
if (style->width().isAuto())
style->setWidth(Length(RenderReplaced::defaultWidth, Fixed));
if (style->height().isAuto())
style->setHeight(Length(RenderReplaced::defaultHeight, Fixed));
}
return;
}
}
......
......@@ -34,6 +34,7 @@
#include "core/frame/Settings.h"
#include "core/frame/csp/ContentSecurityPolicy.h"
#include "core/rendering/RenderApplet.h"
#include "core/rendering/RenderBlockFlow.h"
#include "platform/Widget.h"
#include "platform/weborigin/KURL.h"
#include "platform/weborigin/SecurityOrigin.h"
......@@ -95,6 +96,9 @@ RenderObject* HTMLAppletElement::createRenderer(RenderStyle* style)
if (!canEmbedJava() || hasAuthorShadowRoot())
return RenderObject::createObject(this, style);
if (usePlaceholderContent())
return new RenderBlockFlow(this);
return new RenderApplet(this);
}
......
......@@ -42,6 +42,7 @@
#include "core/page/EventHandler.h"
#include "core/page/Page.h"
#include "core/plugins/PluginView.h"
#include "core/rendering/RenderBlockFlow.h"
#include "core/rendering/RenderEmbeddedObject.h"
#include "core/rendering/RenderImage.h"
#include "core/rendering/RenderWidget.h"
......@@ -66,6 +67,7 @@ HTMLPlugInElement::HTMLPlugInElement(const QualifiedName& tagName, Document& doc
// the same codepath in this class.
, m_needsWidgetUpdate(!createdByParser)
, m_shouldPreferPlugInsForImages(preferPlugInsForImagesOption == ShouldPreferPlugInsForImages)
, m_usePlaceholderContent(false)
{
setHasCustomStyleCallbacks();
}
......@@ -236,13 +238,16 @@ RenderObject* HTMLPlugInElement::createRenderer(RenderStyle* style)
return image;
}
if (usePlaceholderContent())
return new RenderBlockFlow(this);
return new RenderEmbeddedObject(this);
}
void HTMLPlugInElement::willRecalcStyle(StyleRecalcChange)
{
// FIXME: Why is this necessary? Manual re-attach is almost always wrong.
if (!useFallbackContent() && needsWidgetUpdate() && renderer() && !isImageType())
if (!useFallbackContent() && !usePlaceholderContent() && needsWidgetUpdate() && renderer() && !isImageType())
reattach();
}
......@@ -579,4 +584,12 @@ bool HTMLPlugInElement::useFallbackContent() const
return hasAuthorShadowRoot();
}
void HTMLPlugInElement::setUsePlaceholderContent(bool use)
{
if (use != m_usePlaceholderContent) {
m_usePlaceholderContent = use;
lazyReattachIfAttached();
}
}
}
......@@ -63,6 +63,9 @@ public:
void requestPluginCreationWithoutRendererIfPossible();
void createPluginWithoutRenderer();
bool usePlaceholderContent() { return m_usePlaceholderContent; }
void setUsePlaceholderContent(bool);
protected:
HTMLPlugInElement(const QualifiedName& tagName, Document&, bool createdByParser, PreferPlugInsForImagesOption);
......@@ -133,6 +136,7 @@ private:
bool m_isCapturingMouseEvents;
bool m_needsWidgetUpdate;
bool m_shouldPreferPlugInsForImages;
bool m_usePlaceholderContent;
// Normally the Widget is stored in HTMLFrameOwnerElement::m_widget.
// However, plugins can persist even when not rendered. In order to
......
......@@ -36,12 +36,12 @@
namespace blink {
const int cDefaultWidth = 300;
const int cDefaultHeight = 150;
const int RenderReplaced::defaultWidth = 300;
const int RenderReplaced::defaultHeight = 150;
RenderReplaced::RenderReplaced(Element* element)
: RenderBox(element)
, m_intrinsicSize(cDefaultWidth, cDefaultHeight)
, m_intrinsicSize(defaultWidth, defaultHeight)
{
setReplaced(true);
}
......@@ -94,8 +94,8 @@ void RenderReplaced::layout()
void RenderReplaced::intrinsicSizeChanged()
{
int scaledWidth = static_cast<int>(cDefaultWidth * style()->effectiveZoom());
int scaledHeight = static_cast<int>(cDefaultHeight * style()->effectiveZoom());
int scaledWidth = static_cast<int>(defaultWidth * style()->effectiveZoom());
int scaledHeight = static_cast<int>(defaultHeight * style()->effectiveZoom());
m_intrinsicSize = IntSize(scaledWidth, scaledHeight);
setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation();
}
......
......@@ -40,6 +40,11 @@ public:
virtual bool needsPreferredWidthsRecalculation() const OVERRIDE;
// These values are specified to be 300 and 150 pixels in the CSS 2.1 spec.
// http://www.w3.org/TR/CSS2/visudet.html#inline-replaced-width
static const int defaultWidth;
static const int defaultHeight;
protected:
virtual void willBeDestroyed() OVERRIDE;
......
......@@ -53,11 +53,7 @@ RenderVideo::~RenderVideo()
IntSize RenderVideo::defaultSize()
{
// These values are specified in the spec.
static const int cDefaultWidth = 300;
static const int cDefaultHeight = 150;
return IntSize(cDefaultWidth, cDefaultHeight);
return IntSize(defaultWidth, defaultHeight);
}
void RenderVideo::intrinsicSizeChanged()
......
......@@ -77,6 +77,7 @@
#include "core/html/HTMLIFrameElement.h"
#include "core/html/HTMLInputElement.h"
#include "core/html/HTMLMediaElement.h"
#include "core/html/HTMLPlugInElement.h"
#include "core/html/HTMLSelectElement.h"
#include "core/html/HTMLTextAreaElement.h"
#include "core/html/canvas/CanvasRenderingContext2D.h"
......@@ -2226,4 +2227,18 @@ void Internals::hideAllTransitionElements()
frame()->document()->hideTransitionElements(AtomicString(iter->selector));
}
void Internals::forcePluginPlaceholder(HTMLElement* element, const String& htmlSource, ExceptionState& exceptionState)
{
if (!element) {
exceptionState.throwDOMException(InvalidAccessError, ExceptionMessages::argumentNullOrIncorrectType(1, "HTMLElement"));
return;
}
if (!element->isPluginElement()) {
exceptionState.throwDOMException(InvalidNodeTypeError, "The element provided is not a plugin.");
return;
}
element->ensureUserAgentShadowRoot().setInnerHTML(htmlSource, exceptionState);
toHTMLPlugInElement(element)->setUsePlaceholderContent(true);
}
} // namespace blink
......@@ -54,6 +54,7 @@ class Element;
class ExceptionState;
class ExecutionContext;
class GCObservation;
class HTMLElement;
class HTMLMediaElement;
class InternalProfilers;
class InternalRuntimeFlags;
......@@ -315,6 +316,8 @@ public:
unsigned countHitRegions(CanvasRenderingContext2D*);
void forcePluginPlaceholder(HTMLElement* plugin, const String& htmlSource, ExceptionState&);
private:
explicit Internals(Document*);
Document* contextDocument() const;
......
......@@ -278,4 +278,6 @@
DOMString serializeNavigationMarkup();
void hideAllTransitionElements();
[RaisesException] void forcePluginPlaceholder(HTMLElement plugin, DOMString htmlSource);
};
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment