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