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/HTMLBodyElement.h"
     32 #include "core/html/HTMLEmbedElement.h"
     33 #include "core/html/HTMLHtmlElement.h"
     34 #include "core/loader/DocumentLoader.h"
     35 #include "core/loader/FrameLoader.h"
     36 #include "core/loader/FrameLoaderClient.h"
     37 #include "core/frame/Frame.h"
     38 #include "core/frame/FrameView.h"
     39 #include "core/plugins/PluginView.h"
     40 #include "core/rendering/RenderEmbeddedObject.h"
     41 
     42 namespace WebCore {
     43 
     44 using namespace HTMLNames;
     45 
     46 // FIXME: Share more code with MediaDocumentParser.
     47 class PluginDocumentParser : public RawDataDocumentParser {
     48 public:
     49     static PassRefPtr<PluginDocumentParser> create(PluginDocument* document)
     50     {
     51         return adoptRef(new PluginDocumentParser(document));
     52     }
     53 
     54 private:
     55     PluginDocumentParser(Document* document)
     56         : RawDataDocumentParser(document)
     57         , m_embedElement(0)
     58     {
     59     }
     60 
     61     virtual void appendBytes(const char*, size_t) OVERRIDE;
     62 
     63     virtual void finish() OVERRIDE;
     64 
     65     void createDocumentStructure();
     66 
     67     PluginView* pluginView() const;
     68 
     69     RefPtr<HTMLEmbedElement> m_embedElement;
     70 };
     71 
     72 void PluginDocumentParser::createDocumentStructure()
     73 {
     74     // FIXME: Assert we have a loader to figure out why the original null checks
     75     // and assert were added for the security bug in http://trac.webkit.org/changeset/87566
     76     ASSERT(document());
     77     RELEASE_ASSERT(document()->loader());
     78 
     79     Frame* frame = document()->frame();
     80     if (!frame)
     81         return;
     82 
     83     // FIXME: Why does this check settings?
     84     if (!frame->settings() || !frame->loader().allowPlugins(NotAboutToInstantiatePlugin))
     85         return;
     86 
     87     RefPtr<HTMLHtmlElement> rootElement = HTMLHtmlElement::create(*document());
     88     rootElement->insertedByParser();
     89     document()->appendChild(rootElement);
     90     frame->loader().dispatchDocumentElementAvailable();
     91 
     92     RefPtr<HTMLBodyElement> body = HTMLBodyElement::create(*document());
     93     body->setAttribute(marginwidthAttr, "0");
     94     body->setAttribute(marginheightAttr, "0");
     95     body->setAttribute(styleAttr, "background-color: rgb(38,38,38)");
     96     rootElement->appendChild(body);
     97 
     98     m_embedElement = HTMLEmbedElement::create(*document());
     99     m_embedElement->setAttribute(widthAttr, "100%");
    100     m_embedElement->setAttribute(heightAttr, "100%");
    101     m_embedElement->setAttribute(nameAttr, "plugin");
    102     m_embedElement->setAttribute(srcAttr, AtomicString(document()->url().string()));
    103     m_embedElement->setAttribute(typeAttr, document()->loader()->mimeType());
    104     body->appendChild(m_embedElement);
    105 
    106     toPluginDocument(document())->setPluginNode(m_embedElement.get());
    107 
    108     document()->updateLayout();
    109 
    110     // We need the plugin to load synchronously so we can get the PluginView
    111     // below so flush the layout tasks now instead of waiting on the timer.
    112     frame->view()->flushAnyPendingPostLayoutTasks();
    113 
    114     if (PluginView* view = pluginView())
    115         view->didReceiveResponse(document()->loader()->response());
    116 }
    117 
    118 void PluginDocumentParser::appendBytes(const char* data, size_t length)
    119 {
    120     if (!m_embedElement)
    121         createDocumentStructure();
    122 
    123     if (!length)
    124         return;
    125     if (PluginView* view = pluginView())
    126         view->didReceiveData(data, length);
    127 }
    128 
    129 void PluginDocumentParser::finish()
    130 {
    131     if (PluginView* view = pluginView()) {
    132         const ResourceError& error = document()->loader()->mainDocumentError();
    133         if (error.isNull())
    134             view->didFinishLoading();
    135         else
    136             view->didFailLoading(error);
    137         m_embedElement = 0;
    138     }
    139     RawDataDocumentParser::finish();
    140 }
    141 
    142 PluginView* PluginDocumentParser::pluginView() const
    143 {
    144     if (Widget* widget = toPluginDocument(document())->pluginWidget()) {
    145         ASSERT_WITH_SECURITY_IMPLICATION(widget->isPluginContainer());
    146         return toPluginView(widget);
    147     }
    148     return 0;
    149 }
    150 
    151 PluginDocument::PluginDocument(const DocumentInit& initializer)
    152     : HTMLDocument(initializer, PluginDocumentClass)
    153     , m_shouldLoadPluginManually(true)
    154 {
    155     setCompatibilityMode(QuirksMode);
    156     lockCompatibilityMode();
    157 }
    158 
    159 PassRefPtr<DocumentParser> PluginDocument::createParser()
    160 {
    161     return PluginDocumentParser::create(this);
    162 }
    163 
    164 Widget* PluginDocument::pluginWidget()
    165 {
    166     if (m_pluginNode && m_pluginNode->renderer()) {
    167         ASSERT(m_pluginNode->renderer()->isEmbeddedObject());
    168         return toRenderEmbeddedObject(m_pluginNode->renderer())->widget();
    169     }
    170     return 0;
    171 }
    172 
    173 Node* PluginDocument::pluginNode()
    174 {
    175     return m_pluginNode.get();
    176 }
    177 
    178 void PluginDocument::detach(const AttachContext& context)
    179 {
    180     // Release the plugin node so that we don't have a circular reference.
    181     m_pluginNode = 0;
    182     HTMLDocument::detach(context);
    183 }
    184 
    185 void PluginDocument::cancelManualPluginLoad()
    186 {
    187     // PluginDocument::cancelManualPluginLoad should only be called once, but there are issues
    188     // with how many times we call beforeload on object elements. <rdar://problem/8441094>.
    189     if (!shouldLoadPluginManually())
    190         return;
    191 
    192     DocumentLoader* documentLoader = frame()->loader().activeDocumentLoader();
    193     documentLoader->cancelMainResourceLoad(ResourceError::cancelledError(documentLoader->request().url()));
    194     setShouldLoadPluginManually(false);
    195 }
    196 
    197 }
    198