Commit ace70167 authored by jbroman@chromium.org's avatar jbroman@chromium.org

Add a custom element to own structure of shadow DOM plugin placeholders.

This creates PluginPlaceholderElement, which manages a subtree of
elements which represent plugin placeholder content and exposes an
interface to manipulate this content. It is expected that this interface
will grow to encompass more than a single string in the future.

This change also adds an Internals method which uses this, so that its
appearance can be covered by layout tests, and adds one such layout test.

Ultimately, this class will be manipulated by a glue class which controls
this content on behalf of the embedder.

BUG=364716

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

git-svn-id: svn://svn.chromium.org/blink/trunk@182014 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent 99fbb7c8
Ensures that the private PluginPlaceholderElement interface is not exposed.
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
PASS window.PluginPlaceholderElement is undefined.
PASS PluginPlaceholderElement threw exception ReferenceError: PluginPlaceholderElement is not defined.
PASS PluginPlaceholderElement.prototype threw exception ReferenceError: PluginPlaceholderElement is not defined.
PASS successfullyParsed is true
TEST COMPLETE
<!DOCTYPE html>
<script src="../../resources/js-test.js"></script>
<script>
description('Ensures that the private PluginPlaceholderElement interface is not exposed.');
shouldBeUndefined('window.PluginPlaceholderElement');
shouldThrow('PluginPlaceholderElement');
shouldThrow('PluginPlaceholderElement.prototype');
</script>
<!DOCTYPE html>
<style>
.plugin {
display: block;
width: 300px;
height: 150px;
}
.plugin-placeholder {
width: 100%;
height: 100%;
overflow: hidden;
display: flex;
align-items: center;
background-color: gray;
font: 12px -webkit-control;
}
.plugin-placeholder-content {
text-align: center;
margin: auto;
}
</style>
<div class="plugin">
<div class="plugin-placeholder">
<div class="plugin-placeholder-content">
<div class="plugin-placeholder-message">
Sorry, but your plugin couldn't be loaded.
</div>
</div>
</div>
</div>
<!DOCTYPE html>
<!-- The message inserted below should be shown with some suitable style. -->
<object type="application/x-fake-plugin"></object>
<script>
var plugin = document.querySelector("object");
internals.forcePluginPlaceholder(plugin, { message: "Sorry, but your plugin couldn't be loaded." });
</script>
...@@ -917,6 +917,7 @@ action("make_core_generated_private_script") { ...@@ -917,6 +917,7 @@ action("make_core_generated_private_script") {
inputs = [ inputs = [
"../bindings/core/v8/PrivateScriptRunner.js", "../bindings/core/v8/PrivateScriptRunner.js",
"html/HTMLMarqueeElement.js", "html/HTMLMarqueeElement.js",
"html/shadow/PluginPlaceholderElement.js",
"xml/DocumentXMLTreeViewer.js", "xml/DocumentXMLTreeViewer.js",
] ]
outputs = [ outputs = [
......
...@@ -267,6 +267,7 @@ ...@@ -267,6 +267,7 @@
'html/canvas/WebGLUniformLocation.idl', 'html/canvas/WebGLUniformLocation.idl',
'html/canvas/WebGLVertexArrayObjectOES.idl', 'html/canvas/WebGLVertexArrayObjectOES.idl',
'html/ime/InputMethodContext.idl', 'html/ime/InputMethodContext.idl',
'html/shadow/PluginPlaceholderElement.idl',
'html/track/AudioTrack.idl', 'html/track/AudioTrack.idl',
'html/track/AudioTrackList.idl', 'html/track/AudioTrackList.idl',
'html/track/TextTrack.idl', 'html/track/TextTrack.idl',
...@@ -2831,6 +2832,8 @@ ...@@ -2831,6 +2832,8 @@
'html/shadow/MeterShadowElement.h', 'html/shadow/MeterShadowElement.h',
'html/shadow/PickerIndicatorElement.cpp', 'html/shadow/PickerIndicatorElement.cpp',
'html/shadow/PickerIndicatorElement.h', 'html/shadow/PickerIndicatorElement.h',
'html/shadow/PluginPlaceholderElement.cpp',
'html/shadow/PluginPlaceholderElement.h',
'html/shadow/ProgressShadowElement.cpp', 'html/shadow/ProgressShadowElement.cpp',
'html/shadow/ProgressShadowElement.h', 'html/shadow/ProgressShadowElement.h',
'html/shadow/ShadowElementNames.cpp', 'html/shadow/ShadowElementNames.cpp',
......
...@@ -151,6 +151,7 @@ ...@@ -151,6 +151,7 @@
'private_script_files': [ 'private_script_files': [
'../bindings/core/v8/PrivateScriptRunner.js', '../bindings/core/v8/PrivateScriptRunner.js',
'html/HTMLMarqueeElement.js', 'html/HTMLMarqueeElement.js',
'html/shadow/PluginPlaceholderElement.js',
'xml/DocumentXMLTreeViewer.js', 'xml/DocumentXMLTreeViewer.js',
], ],
'inputs': [ 'inputs': [
......
...@@ -63,7 +63,7 @@ public: ...@@ -63,7 +63,7 @@ public:
void requestPluginCreationWithoutRendererIfPossible(); void requestPluginCreationWithoutRendererIfPossible();
void createPluginWithoutRenderer(); void createPluginWithoutRenderer();
bool usePlaceholderContent() { return m_usePlaceholderContent; } bool usePlaceholderContent() const { return m_usePlaceholderContent; }
void setUsePlaceholderContent(bool); void setUsePlaceholderContent(bool);
protected: protected:
......
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "config.h"
#include "core/html/shadow/PluginPlaceholderElement.h"
#include "bindings/core/v8/V8PluginPlaceholderElement.h"
#include "core/dom/Document.h"
#include "wtf/Assertions.h"
namespace blink {
PluginPlaceholderElement::PluginPlaceholderElement(Document& document)
: HTMLDivElement(document)
{
}
PassRefPtrWillBeRawPtr<PluginPlaceholderElement> PluginPlaceholderElement::create(Document& document)
{
RefPtrWillBeRawPtr<PluginPlaceholderElement> element = adoptRefWillBeNoop(new PluginPlaceholderElement(document));
bool success = V8PluginPlaceholderElement::PrivateScript::createdCallbackMethod(document.frame(), element.get());
ASSERT_UNUSED(success, success);
return element.release();
}
void PluginPlaceholderElement::setMessage(const String& message)
{
bool success = V8PluginPlaceholderElement::PrivateScript::messageAttributeSetter(document().frame(), this, message);
ASSERT_UNUSED(success, success);
}
} // namespace blink
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef PluginPlaceholderElement_h
#define PluginPlaceholderElement_h
#include "core/dom/Element.h"
#include "core/html/HTMLDivElement.h"
namespace blink {
class PluginPlaceholderElement FINAL : public HTMLDivElement {
DEFINE_WRAPPERTYPEINFO();
public:
static PassRefPtrWillBeRawPtr<PluginPlaceholderElement> create(Document&);
void setMessage(const String&);
private:
explicit PluginPlaceholderElement(Document&);
};
} // namespace blink
#endif // PluginPlaceholderElement_h
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
[
NoInterfaceObject
] interface PluginPlaceholderElement : HTMLDivElement {
[ImplementedInPrivateScript, OnlyExposedToPrivateScript] attribute DOMString message;
[ImplementedInPrivateScript, OnlyExposedToPrivateScript] void createdCallback();
};
/** // Copyright 2014 The Chromium Authors. All rights reserved.
* This is a placeholder to create the // Use of this source code is governed by a BSD-style license that can be
* IDR_PRIVATE_SCRIPT_PLUGINPLACEHOLDERELEMENT_JS resource. // found in the LICENSE file.
*
* It will be replaced by a complete file in: 'use strict';
* https://codereview.chromium.org/522783002/
*/ installClass('PluginPlaceholderElement', function(PluginPlaceholderElementPrototype) {
PluginPlaceholderElementPrototype.createdCallback = function() {
// FIXME: Move style out of script and into CSS.
this.id = 'plugin-placeholder';
this.style.width = '100%';
this.style.height = '100%';
this.style.overflow = 'hidden';
this.style.display = 'flex';
this.style.alignItems = 'center';
this.style.backgroundColor = 'gray';
this.style.font = '12px -webkit-control';
var contentElement = document.createElement('div');
contentElement.id = 'plugin-placeholder-content';
contentElement.style.textAlign = 'center';
contentElement.style.margin = 'auto';
var messageElement = document.createElement('div');
messageElement.id = 'plugin-placeholder-message';
contentElement.appendChild(messageElement);
this.appendChild(contentElement);
this.messageElement = messageElement;
};
Object.defineProperty(PluginPlaceholderElementPrototype, 'message', {
get: function() { return this.messageElement.textContent; },
set: function(message) { this.messageElement.textContent = message; },
});
});
...@@ -84,6 +84,7 @@ ...@@ -84,6 +84,7 @@
#include "core/html/HTMLTextAreaElement.h" #include "core/html/HTMLTextAreaElement.h"
#include "core/html/canvas/CanvasRenderingContext2D.h" #include "core/html/canvas/CanvasRenderingContext2D.h"
#include "core/html/forms/FormController.h" #include "core/html/forms/FormController.h"
#include "core/html/shadow/PluginPlaceholderElement.h"
#include "core/html/shadow/ShadowElementNames.h" #include "core/html/shadow/ShadowElementNames.h"
#include "core/html/shadow/TextControlInnerElements.h" #include "core/html/shadow/TextControlInnerElements.h"
#include "core/inspector/ConsoleMessageStorage.h" #include "core/inspector/ConsoleMessageStorage.h"
...@@ -2247,15 +2248,36 @@ void Internals::hideAllTransitionElements() ...@@ -2247,15 +2248,36 @@ void Internals::hideAllTransitionElements()
void Internals::forcePluginPlaceholder(HTMLElement* element, const String& htmlSource, ExceptionState& exceptionState) void Internals::forcePluginPlaceholder(HTMLElement* element, const String& htmlSource, ExceptionState& exceptionState)
{ {
if (!element) { if (!element->isPluginElement()) {
exceptionState.throwDOMException(InvalidAccessError, ExceptionMessages::argumentNullOrIncorrectType(1, "HTMLElement")); exceptionState.throwDOMException(InvalidNodeTypeError, "The element provided is not a plugin.");
return; return;
} }
element->ensureUserAgentShadowRoot().setInnerHTML(htmlSource, exceptionState);
if (exceptionState.hadException())
return;
toHTMLPlugInElement(element)->setUsePlaceholderContent(true);
}
void Internals::forcePluginPlaceholder(HTMLElement* element, const Dictionary& options, ExceptionState& exceptionState)
{
if (!element->isPluginElement()) { if (!element->isPluginElement()) {
exceptionState.throwDOMException(InvalidNodeTypeError, "The element provided is not a plugin."); exceptionState.throwDOMException(InvalidNodeTypeError, "The element provided is not a plugin.");
return; return;
} }
element->ensureUserAgentShadowRoot().setInnerHTML(htmlSource, exceptionState);
RefPtrWillBeRawPtr<PluginPlaceholderElement> placeholder = PluginPlaceholderElement::create(element->document());
String stringValue;
if (DictionaryHelper::get(options, "message", stringValue))
placeholder->setMessage(stringValue);
ShadowRoot& shadowRoot = element->ensureUserAgentShadowRoot();
shadowRoot.removeChildren();
shadowRoot.appendChild(placeholder.release(), exceptionState);
if (exceptionState.hadException())
return;
toHTMLPlugInElement(element)->setUsePlaceholderContent(true); toHTMLPlugInElement(element)->setUsePlaceholderContent(true);
} }
......
...@@ -318,6 +318,7 @@ public: ...@@ -318,6 +318,7 @@ public:
unsigned countHitRegions(CanvasRenderingContext2D*); unsigned countHitRegions(CanvasRenderingContext2D*);
void forcePluginPlaceholder(HTMLElement* plugin, const String& htmlSource, ExceptionState&); void forcePluginPlaceholder(HTMLElement* plugin, const String& htmlSource, ExceptionState&);
void forcePluginPlaceholder(HTMLElement* plugin, const Dictionary& options, ExceptionState&);
Iterator* iterator(ScriptState*, ExceptionState&); Iterator* iterator(ScriptState*, ExceptionState&);
......
...@@ -277,7 +277,8 @@ ...@@ -277,7 +277,8 @@
DOMString serializeNavigationMarkup(); DOMString serializeNavigationMarkup();
void hideAllTransitionElements(); void hideAllTransitionElements();
[RaisesException] void forcePluginPlaceholder(HTMLElement plugin, DOMString htmlSource); [RaisesException, TypeChecking=Interface] void forcePluginPlaceholder(HTMLElement plugin, DOMString htmlSource);
[RaisesException, TypeChecking=Interface] void forcePluginPlaceholder(HTMLElement plugin, Dictionary options);
DictionaryTest dictionaryTest(); DictionaryTest dictionaryTest();
}; };
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