Home | History | Annotate | Download | only in html
      1 /*
      2  * Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  * 1. Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  * 2. Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
     14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
     17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     19  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     20  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     22  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     23  */
     24 
     25 #include "config.h"
     26 #include "core/html/PluginDocument.h"
     27 
     28 #include "HTMLNames.h"
     29 #include "bindings/v8/ExceptionStatePlaceholder.h"
     30 #include "core/dom/RawDataDocumentParser.h"
     31 #include "core/html/HTMLEmbedElement.h"
     32 #include "core/html/HTMLHtmlElement.h"
     33 #include "core/loader/DocumentLoader.h"
     34 #include "core/loader/FrameLoader.h"
     35 #include "core/loader/FrameLoaderClient.h"
     36 #include "core/page/Frame.h"
     37 #include "core/page/FrameView.h"
     38 #include "core/plugins/PluginView.h"
     39 #include "core/rendering/RenderEmbeddedObject.h"
     40 
     41 namespace WebCore {
     42 
     43 using namespace HTMLNames;
     44 
     45 // FIXME: Share more code with MediaDocumentParser.
     46 class PluginDocumentParser : public RawDataDocumentParser {
     47 public:
     48     static PassRefPtr<PluginDocumentParser> create(PluginDocument* document)
     49     {
     50         return adoptRef(new PluginDocumentParser(document));
     51     }
     52 
     53 private:
     54     PluginDocumentParser(Document* document)
     55         : RawDataDocumentParser(document)
     56         , m_embedElement(0)
     57     {
     58     }
     59 
     60     virtual size_t appendBytes(const char*, size_t) OVERRIDE;
     61 
     62     virtual void finish() OVERRIDE;
     63 
     64     void createDocumentStructure();
     65 
     66     PluginView* pluginView() const;
     67 
     68     HTMLEmbedElement* m_embedElement;
     69 };
     70 
     71 void PluginDocumentParser::createDocumentStructure()
     72 {
     73     RefPtr<Element> rootElement = document()->createElement(htmlTag, false);
     74     document()->appendChild(rootElement, IGNORE_EXCEPTION);
     75     toHTMLHtmlElement(rootElement.get())->insertedByParser();
     76 
     77     if (document()->frame() && document()->frame()->loader())
     78         document()->frame()->loader()->dispatchDocumentElementAvailable();
     79 
     80     RefPtr<Element> body = document()->createElement(bodyTag, false);
     81     body->setAttribute(marginwidthAttr, "0");
     82     body->setAttribute(marginheightAttr, "0");
     83     body->setAttribute(styleAttr, "background-color: rgb(38,38,38)");
     84 
     85     rootElement->appendChild(body, IGNORE_EXCEPTION);
     86 
     87     RefPtr<Element> embedElement = document()->createElement(embedTag, false);
     88 
     89     m_embedElement = static_cast<HTMLEmbedElement*>(embedElement.get());
     90     m_embedElement->setAttribute(widthAttr, "100%");
     91     m_embedElement->setAttribute(heightAttr, "100%");
     92 
     93     m_embedElement->setAttribute(nameAttr, "plugin");
     94     m_embedElement->setAttribute(srcAttr, document()->url().string());
     95 
     96     DocumentLoader* loader = document()->loader();
     97     ASSERT(loader);
     98     if (loader)
     99         m_embedElement->setAttribute(typeAttr, loader->mimeType());
    100 
    101     toPluginDocument(document())->setPluginNode(m_embedElement);
    102 
    103     body->appendChild(embedElement, IGNORE_EXCEPTION);
    104 
    105     Frame* frame = document()->frame();
    106     if (!frame)
    107         return;
    108     Settings* settings = frame->settings();
    109     if (!settings || !frame->loader()->allowPlugins(NotAboutToInstantiatePlugin))
    110         return;
    111 
    112     document()->updateLayout();
    113 
    114     // Below we assume that renderer->widget() to have been created by
    115     // document()->updateLayout(). However, in some cases, updateLayout() will
    116     // recurse too many times and delay its post-layout tasks (such as creating
    117     // the widget). Here we kick off the pending post-layout tasks so that we
    118     // can synchronously redirect data to the plugin.
    119     frame->view()->flushAnyPendingPostLayoutTasks();
    120 
    121     if (PluginView* view = pluginView())
    122         view->didReceiveResponse(document()->loader()->response());
    123 }
    124 
    125 size_t PluginDocumentParser::appendBytes(const char* data, size_t length)
    126 {
    127     if (!m_embedElement)
    128         createDocumentStructure();
    129 
    130     if (!length)
    131         return 0;
    132     if (PluginView* view = pluginView())
    133         view->didReceiveData(data, length);
    134 
    135     return 0;
    136 }
    137 
    138 void PluginDocumentParser::finish()
    139 {
    140     if (PluginView* view = pluginView()) {
    141         const ResourceError& error = document()->loader()->mainDocumentError();
    142         if (error.isNull())
    143             view->didFinishLoading();
    144         else
    145             view->didFailLoading(error);
    146     }
    147     RawDataDocumentParser::finish();
    148 }
    149 
    150 PluginView* PluginDocumentParser::pluginView() const
    151 {
    152     if (Widget* widget = static_cast<PluginDocument*>(document())->pluginWidget()) {
    153         ASSERT_WITH_SECURITY_IMPLICATION(widget->isPluginContainer());
    154         return static_cast<PluginView*>(widget);
    155     }
    156     return 0;
    157 }
    158 
    159 PluginDocument::PluginDocument(const DocumentInit& initializer)
    160     : HTMLDocument(initializer, PluginDocumentClass)
    161     , m_shouldLoadPluginManually(true)
    162 {
    163     setCompatibilityMode(QuirksMode);
    164     lockCompatibilityMode();
    165 }
    166 
    167 PassRefPtr<DocumentParser> PluginDocument::createParser()
    168 {
    169     return PluginDocumentParser::create(this);
    170 }
    171 
    172 Widget* PluginDocument::pluginWidget()
    173 {
    174     if (m_pluginNode && m_pluginNode->renderer()) {
    175         ASSERT(m_pluginNode->renderer()->isEmbeddedObject());
    176         return toRenderEmbeddedObject(m_pluginNode->renderer())->widget();
    177     }
    178     return 0;
    179 }
    180 
    181 Node* PluginDocument::pluginNode()
    182 {
    183     return m_pluginNode.get();
    184 }
    185 
    186 void PluginDocument::detach(const AttachContext& context)
    187 {
    188     // Release the plugin node so that we don't have a circular reference.
    189     m_pluginNode = 0;
    190     HTMLDocument::detach(context);
    191 }
    192 
    193 void PluginDocument::cancelManualPluginLoad()
    194 {
    195     // PluginDocument::cancelManualPluginLoad should only be called once, but there are issues
    196     // with how many times we call beforeload on object elements. <rdar://problem/8441094>.
    197     if (!shouldLoadPluginManually())
    198         return;
    199 
    200     DocumentLoader* documentLoader = frame()->loader()->activeDocumentLoader();
    201     documentLoader->cancelMainResourceLoad(ResourceError::cancelledError(documentLoader->request().url()));
    202     setShouldLoadPluginManually(false);
    203 }
    204 
    205 }
    206