blob: 5a7167660432f77b004b4c3505995e30b3a23a6f [file] [log] [blame]
/*
* Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "third_party/blink/renderer/core/html/plugin_document.h"
#include "third_party/blink/renderer/core/css/css_color_value.h"
#include "third_party/blink/renderer/core/dom/events/event.h"
#include "third_party/blink/renderer/core/dom/events/native_event_listener.h"
#include "third_party/blink/renderer/core/dom/raw_data_document_parser.h"
#include "third_party/blink/renderer/core/events/before_unload_event.h"
#include "third_party/blink/renderer/core/exported/web_plugin_container_impl.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/local_frame_client.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
#include "third_party/blink/renderer/core/frame/use_counter.h"
#include "third_party/blink/renderer/core/html/html_body_element.h"
#include "third_party/blink/renderer/core/html/html_embed_element.h"
#include "third_party/blink/renderer/core/html/html_html_element.h"
#include "third_party/blink/renderer/core/html/html_plugin_element.h"
#include "third_party/blink/renderer/core/html_names.h"
#include "third_party/blink/renderer/core/layout/layout_embedded_object.h"
#include "third_party/blink/renderer/core/loader/document_loader.h"
#include "third_party/blink/renderer/core/loader/frame_loader.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
namespace blink {
using namespace html_names;
class PluginDocument::BeforeUnloadEventListener : public NativeEventListener {
public:
static BeforeUnloadEventListener* Create(PluginDocument* document) {
return MakeGarbageCollected<BeforeUnloadEventListener>(document);
}
explicit BeforeUnloadEventListener(PluginDocument* document)
: doc_(document) {}
void SetShowBeforeUnloadDialog(bool show_dialog) {
show_dialog_ = show_dialog;
}
void Trace(Visitor* visitor) override {
visitor->Trace(doc_);
NativeEventListener::Trace(visitor);
}
private:
void Invoke(ExecutionContext*, Event* event) override {
DCHECK_EQ(event->type(), event_type_names::kBeforeunload);
if (show_dialog_)
ToBeforeUnloadEvent(event)->setReturnValue(g_empty_string);
}
Member<PluginDocument> doc_;
bool show_dialog_;
};
// FIXME: Share more code with MediaDocumentParser.
class PluginDocumentParser : public RawDataDocumentParser {
public:
static PluginDocumentParser* Create(PluginDocument* document,
Color background_color) {
return MakeGarbageCollected<PluginDocumentParser>(document,
background_color);
}
PluginDocumentParser(Document* document, Color background_color)
: RawDataDocumentParser(document),
embed_element_(nullptr),
background_color_(background_color) {}
void Trace(Visitor* visitor) override {
visitor->Trace(embed_element_);
RawDataDocumentParser::Trace(visitor);
}
private:
void AppendBytes(const char*, size_t) override;
void Finish() override;
void StopParsing() override;
void CreateDocumentStructure();
WebPluginContainerImpl* GetPluginView() const;
Member<HTMLEmbedElement> embed_element_;
const Color background_color_;
};
void PluginDocumentParser::CreateDocumentStructure() {
if (embed_element_)
return;
// FIXME: Assert we have a loader to figure out why the original null checks
// and assert were added for the security bug in
// http://trac.webkit.org/changeset/87566
DCHECK(GetDocument());
CHECK(GetDocument()->Loader());
LocalFrame* frame = GetDocument()->GetFrame();
if (!frame)
return;
// FIXME: Why does this check settings?
if (!frame->GetSettings() ||
!frame->Loader().AllowPlugins(kNotAboutToInstantiatePlugin))
return;
HTMLHtmlElement* root_element = HTMLHtmlElement::Create(*GetDocument());
GetDocument()->AppendChild(root_element);
root_element->InsertedByParser();
if (IsStopped())
return; // runScriptsAtDocumentElementAvailable can detach the frame.
HTMLBodyElement* body = HTMLBodyElement::Create(*GetDocument());
body->setAttribute(kStyleAttr,
"height: 100%; width: 100%; overflow: hidden; margin: 0");
body->SetInlineStyleProperty(
CSSPropertyBackgroundColor,
*cssvalue::CSSColorValue::Create(background_color_.Rgb()));
root_element->AppendChild(body);
if (IsStopped()) {
// Possibly detached by a mutation event listener installed in
// runScriptsAtDocumentElementAvailable.
return;
}
embed_element_ = HTMLEmbedElement::Create(*GetDocument());
embed_element_->setAttribute(kWidthAttr, "100%");
embed_element_->setAttribute(kHeightAttr, "100%");
embed_element_->setAttribute(kNameAttr, "plugin");
embed_element_->setAttribute(kIdAttr, "plugin");
embed_element_->setAttribute(kSrcAttr,
AtomicString(GetDocument()->Url().GetString()));
embed_element_->setAttribute(kTypeAttr, GetDocument()->Loader()->MimeType());
body->AppendChild(embed_element_);
if (IsStopped()) {
// Possibly detached by a mutation event listener installed in
// runScriptsAtDocumentElementAvailable.
return;
}
ToPluginDocument(GetDocument())->SetPluginNode(embed_element_);
GetDocument()->UpdateStyleAndLayout();
// We need the plugin to load synchronously so we can get the
// WebPluginContainerImpl below so flush the layout tasks now instead of
// waiting on the timer.
frame->View()->FlushAnyPendingPostLayoutTasks();
// Focus the plugin here, as the line above is where the plugin is created.
if (frame->IsMainFrame()) {
embed_element_->focus();
if (IsStopped()) {
// Possibly detached by a mutation event listener installed in
// runScriptsAtDocumentElementAvailable.
return;
}
}
if (WebPluginContainerImpl* view = GetPluginView())
view->DidReceiveResponse(GetDocument()->Loader()->GetResponse());
}
void PluginDocumentParser::AppendBytes(const char* data, size_t length) {
CreateDocumentStructure();
if (IsStopped())
return;
if (!length)
return;
if (WebPluginContainerImpl* view = GetPluginView())
view->DidReceiveData(data, length);
}
void PluginDocumentParser::Finish() {
CreateDocumentStructure();
embed_element_ = nullptr;
RawDataDocumentParser::Finish();
}
void PluginDocumentParser::StopParsing() {
CreateDocumentStructure();
RawDataDocumentParser::StopParsing();
}
WebPluginContainerImpl* PluginDocumentParser::GetPluginView() const {
return ToPluginDocument(GetDocument())->GetPluginView();
}
PluginDocument::PluginDocument(const DocumentInit& initializer,
Color background_color)
: HTMLDocument(initializer, kPluginDocumentClass),
background_color_(background_color) {
SetCompatibilityMode(kQuirksMode);
LockCompatibilityMode();
}
DocumentParser* PluginDocument::CreateParser() {
return PluginDocumentParser::Create(this, background_color_);
}
WebPluginContainerImpl* PluginDocument::GetPluginView() {
return plugin_node_ ? plugin_node_->OwnedPlugin() : nullptr;
}
void PluginDocument::SetShowBeforeUnloadDialog(bool show_dialog) {
if (!before_unload_event_listener_) {
if (!show_dialog)
return;
before_unload_event_listener_ = BeforeUnloadEventListener::Create(this);
domWindow()->addEventListener(event_type_names::kBeforeunload,
before_unload_event_listener_, false);
}
before_unload_event_listener_->SetShowBeforeUnloadDialog(show_dialog);
}
void PluginDocument::Shutdown() {
// Release the plugin node so that we don't have a circular reference.
plugin_node_ = nullptr;
before_unload_event_listener_ = nullptr;
HTMLDocument::Shutdown();
}
void PluginDocument::Trace(Visitor* visitor) {
visitor->Trace(plugin_node_);
visitor->Trace(before_unload_event_listener_);
HTMLDocument::Trace(visitor);
}
} // namespace blink