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 "PluginDocument.h" 27 28 #include "DocumentLoader.h" 29 #include "Frame.h" 30 #include "FrameLoaderClient.h" 31 #include "FrameView.h" 32 #include "HTMLEmbedElement.h" 33 #include "HTMLHtmlElement.h" 34 #include "HTMLNames.h" 35 #include "MainResourceLoader.h" 36 #include "NodeList.h" 37 #include "Page.h" 38 #include "RawDataDocumentParser.h" 39 #include "RenderEmbeddedObject.h" 40 #include "Settings.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(DocumentWriter*, const char*, int, bool); 62 63 void createDocumentStructure(); 64 65 HTMLEmbedElement* m_embedElement; 66 }; 67 68 void PluginDocumentParser::createDocumentStructure() 69 { 70 ExceptionCode ec; 71 RefPtr<Element> rootElement = document()->createElement(htmlTag, false); 72 document()->appendChild(rootElement, ec); 73 #if ENABLE(OFFLINE_WEB_APPLICATIONS) 74 static_cast<HTMLHtmlElement*>(rootElement.get())->insertedByParser(); 75 #endif 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(bgcolorAttr, "rgb(38,38,38)"); 84 85 rootElement->appendChild(body, ec); 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->writer()->mimeType()); 100 101 static_cast<PluginDocument*>(document())->setPluginNode(m_embedElement); 102 103 body->appendChild(embedElement, ec); 104 } 105 106 void PluginDocumentParser::appendBytes(DocumentWriter*, const char*, int, bool) 107 { 108 ASSERT(!m_embedElement); 109 if (m_embedElement) 110 return; 111 112 createDocumentStructure(); 113 114 Frame* frame = document()->frame(); 115 if (!frame) 116 return; 117 Settings* settings = frame->settings(); 118 if (!settings || !frame->loader()->subframeLoader()->allowPlugins(NotAboutToInstantiatePlugin)) 119 return; 120 121 document()->updateLayout(); 122 123 // Below we assume that renderer->widget() to have been created by 124 // document()->updateLayout(). However, in some cases, updateLayout() will 125 // recurse too many times and delay its post-layout tasks (such as creating 126 // the widget). Here we kick off the pending post-layout tasks so that we 127 // can synchronously redirect data to the plugin. 128 frame->view()->flushAnyPendingPostLayoutTasks(); 129 130 if (RenderPart* renderer = m_embedElement->renderPart()) { 131 if (Widget* widget = renderer->widget()) { 132 frame->loader()->client()->redirectDataToPlugin(widget); 133 // In a plugin document, the main resource is the plugin. If we have a null widget, that means 134 // the loading of the plugin was cancelled, which gives us a null mainResourceLoader(), so we 135 // need to have this call in a null check of the widget or of mainResourceLoader(). 136 frame->loader()->activeDocumentLoader()->mainResourceLoader()->setShouldBufferData(false); 137 } 138 } 139 140 finish(); 141 } 142 143 PluginDocument::PluginDocument(Frame* frame, const KURL& url) 144 : HTMLDocument(frame, url) 145 , m_shouldLoadPluginManually(true) 146 { 147 setCompatibilityMode(QuirksMode); 148 lockCompatibilityMode(); 149 } 150 151 PassRefPtr<DocumentParser> PluginDocument::createParser() 152 { 153 return PluginDocumentParser::create(this); 154 } 155 156 Widget* PluginDocument::pluginWidget() 157 { 158 if (m_pluginNode && m_pluginNode->renderer()) { 159 ASSERT(m_pluginNode->renderer()->isEmbeddedObject()); 160 return toRenderEmbeddedObject(m_pluginNode->renderer())->widget(); 161 } 162 return 0; 163 } 164 165 Node* PluginDocument::pluginNode() 166 { 167 return m_pluginNode.get(); 168 } 169 170 void PluginDocument::detach() 171 { 172 // Release the plugin node so that we don't have a circular reference. 173 m_pluginNode = 0; 174 HTMLDocument::detach(); 175 } 176 177 void PluginDocument::cancelManualPluginLoad() 178 { 179 // PluginDocument::cancelManualPluginLoad should only be called once, but there are issues 180 // with how many times we call beforeload on object elements. <rdar://problem/8441094>. 181 if (!shouldLoadPluginManually()) 182 return; 183 184 frame()->loader()->activeDocumentLoader()->mainResourceLoader()->cancel(); 185 setShouldLoadPluginManually(false); 186 } 187 188 } 189