| /* |
| * 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 "core/html/PluginDocument.h" |
| |
| #include "bindings/core/v8/ExceptionStatePlaceholder.h" |
| #include "core/HTMLNames.h" |
| #include "core/dom/RawDataDocumentParser.h" |
| #include "core/frame/FrameView.h" |
| #include "core/frame/LocalFrame.h" |
| #include "core/frame/UseCounter.h" |
| #include "core/html/HTMLBodyElement.h" |
| #include "core/html/HTMLEmbedElement.h" |
| #include "core/html/HTMLHtmlElement.h" |
| #include "core/layout/LayoutEmbeddedObject.h" |
| #include "core/loader/DocumentLoader.h" |
| #include "core/loader/FrameLoader.h" |
| #include "core/loader/FrameLoaderClient.h" |
| #include "core/plugins/PluginView.h" |
| |
| namespace blink { |
| |
| using namespace HTMLNames; |
| |
| // FIXME: Share more code with MediaDocumentParser. |
| class PluginDocumentParser : public RawDataDocumentParser { |
| public: |
| static PluginDocumentParser* create(PluginDocument* document) { |
| return new PluginDocumentParser(document); |
| } |
| |
| DEFINE_INLINE_VIRTUAL_TRACE() { |
| visitor->trace(m_embedElement); |
| RawDataDocumentParser::trace(visitor); |
| } |
| |
| private: |
| PluginDocumentParser(Document* document) |
| : RawDataDocumentParser(document), m_embedElement(nullptr) {} |
| |
| void appendBytes(const char*, size_t) override; |
| |
| void finish() override; |
| |
| void createDocumentStructure(); |
| |
| PluginView* pluginView() const; |
| |
| Member<HTMLEmbedElement> m_embedElement; |
| }; |
| |
| void PluginDocumentParser::createDocumentStructure() { |
| // 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(document()); |
| RELEASE_ASSERT(document()->loader()); |
| |
| LocalFrame* frame = document()->frame(); |
| if (!frame) |
| return; |
| |
| // FIXME: Why does this check settings? |
| if (!frame->settings() || |
| !frame->loader().allowPlugins(NotAboutToInstantiatePlugin)) |
| return; |
| |
| HTMLHtmlElement* rootElement = HTMLHtmlElement::create(*document()); |
| document()->appendChild(rootElement); |
| rootElement->insertedByParser(); |
| if (isStopped()) |
| return; // runScriptsAtDocumentElementAvailable can detach the frame. |
| |
| HTMLBodyElement* body = HTMLBodyElement::create(*document()); |
| body->setAttribute(styleAttr, |
| "background-color: rgb(38,38,38); height: 100%; width: " |
| "100%; overflow: hidden; margin: 0"); |
| rootElement->appendChild(body); |
| if (isStopped()) { |
| // Possibly detached by a mutation event listener installed in |
| // runScriptsAtDocumentElementAvailable. |
| return; |
| } |
| |
| m_embedElement = HTMLEmbedElement::create(*document()); |
| m_embedElement->setAttribute(widthAttr, "100%"); |
| m_embedElement->setAttribute(heightAttr, "100%"); |
| m_embedElement->setAttribute(nameAttr, "plugin"); |
| m_embedElement->setAttribute(idAttr, "plugin"); |
| m_embedElement->setAttribute(srcAttr, |
| AtomicString(document()->url().getString())); |
| m_embedElement->setAttribute(typeAttr, document()->loader()->mimeType()); |
| body->appendChild(m_embedElement); |
| if (isStopped()) { |
| // Possibly detached by a mutation event listener installed in |
| // runScriptsAtDocumentElementAvailable. |
| return; |
| } |
| |
| toPluginDocument(document())->setPluginNode(m_embedElement.get()); |
| |
| document()->updateStyleAndLayout(); |
| |
| // We need the plugin to load synchronously so we can get the PluginView |
| // 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()) { |
| m_embedElement->focus(); |
| if (isStopped()) { |
| // Possibly detached by a mutation event listener installed in |
| // runScriptsAtDocumentElementAvailable. |
| return; |
| } |
| } |
| |
| if (PluginView* view = pluginView()) |
| view->didReceiveResponse(document()->loader()->response()); |
| } |
| |
| void PluginDocumentParser::appendBytes(const char* data, size_t length) { |
| if (!m_embedElement) { |
| createDocumentStructure(); |
| if (isStopped()) |
| return; |
| } |
| |
| if (!length) |
| return; |
| if (PluginView* view = pluginView()) |
| view->didReceiveData(data, length); |
| } |
| |
| void PluginDocumentParser::finish() { |
| m_embedElement = nullptr; |
| RawDataDocumentParser::finish(); |
| } |
| |
| PluginView* PluginDocumentParser::pluginView() const { |
| if (Widget* widget = toPluginDocument(document())->pluginWidget()) { |
| SECURITY_DCHECK(widget->isPluginContainer()); |
| return toPluginView(widget); |
| } |
| return 0; |
| } |
| |
| PluginDocument::PluginDocument(const DocumentInit& initializer) |
| : HTMLDocument(initializer, PluginDocumentClass) { |
| setCompatibilityMode(QuirksMode); |
| lockCompatibilityMode(); |
| UseCounter::count(*this, UseCounter::PluginDocument); |
| if (!isInMainFrame()) |
| UseCounter::count(*this, UseCounter::PluginDocumentInFrame); |
| } |
| |
| DocumentParser* PluginDocument::createParser() { |
| return PluginDocumentParser::create(this); |
| } |
| |
| Widget* PluginDocument::pluginWidget() { |
| if (m_pluginNode && m_pluginNode->layoutObject()) { |
| CHECK(m_pluginNode->layoutObject()->isEmbeddedObject()); |
| Widget* widget = |
| toLayoutEmbeddedObject(m_pluginNode->layoutObject())->widget(); |
| if (!widget || !widget->isPluginContainer()) |
| return nullptr; |
| return widget; |
| } |
| return 0; |
| } |
| |
| Node* PluginDocument::pluginNode() { |
| return m_pluginNode.get(); |
| } |
| |
| void PluginDocument::shutdown() { |
| // Release the plugin node so that we don't have a circular reference. |
| m_pluginNode = nullptr; |
| HTMLDocument::shutdown(); |
| } |
| |
| DEFINE_TRACE(PluginDocument) { |
| visitor->trace(m_pluginNode); |
| HTMLDocument::trace(visitor); |
| } |
| |
| } // namespace blink |