1/* 2 * Copyright (C) 2006, 2008, 2013 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 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 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 "ExceptionCodePlaceholder.h" 30#include "Frame.h" 31#include "FrameLoader.h" 32#include "FrameLoaderClient.h" 33#include "FrameView.h" 34#include "HTMLEmbedElement.h" 35#include "HTMLHtmlElement.h" 36#include "HTMLNames.h" 37#include "Page.h" 38#include "RawDataDocumentParser.h" 39#include "RenderEmbeddedObject.h" 40#include "Settings.h" 41 42namespace WebCore { 43 44using namespace HTMLNames; 45 46// FIXME: Share more code with MediaDocumentParser. 47class PluginDocumentParser final : public RawDataDocumentParser { 48public: 49 static PassRefPtr<PluginDocumentParser> create(PluginDocument& document) 50 { 51 return adoptRef(new PluginDocumentParser(document)); 52 } 53 54private: 55 PluginDocumentParser(Document& document) 56 : RawDataDocumentParser(document) 57 , m_embedElement(0) 58 { 59 } 60 61 virtual void appendBytes(DocumentWriter&, const char*, size_t) override; 62 63 void createDocumentStructure(); 64 65 HTMLEmbedElement* m_embedElement; 66}; 67 68void PluginDocumentParser::createDocumentStructure() 69{ 70 RefPtr<Element> rootElement = document()->createElement(htmlTag, false); 71 document()->appendChild(rootElement, IGNORE_EXCEPTION); 72 toHTMLHtmlElement(rootElement.get())->insertedByParser(); 73 74 if (document()->frame()) 75 document()->frame()->injectUserScripts(InjectAtDocumentStart); 76 77#if PLATFORM(IOS) 78 // Should not be able to zoom into standalone plug-in documents. 79 document()->processViewport(ASCIILiteral("user-scalable=no"), ViewportArguments::PluginDocument); 80#endif 81 82 RefPtr<Element> body = document()->createElement(bodyTag, false); 83 body->setAttribute(marginwidthAttr, AtomicString("0", AtomicString::ConstructFromLiteral)); 84 body->setAttribute(marginheightAttr, AtomicString("0", AtomicString::ConstructFromLiteral)); 85#if PLATFORM(IOS) 86 body->setAttribute(styleAttr, AtomicString("background-color: rgb(217,224,233)", AtomicString::ConstructFromLiteral)); 87#else 88 body->setAttribute(styleAttr, AtomicString("background-color: rgb(38,38,38)", AtomicString::ConstructFromLiteral)); 89#endif 90 91 rootElement->appendChild(body, IGNORE_EXCEPTION); 92 93 RefPtr<Element> embedElement = document()->createElement(embedTag, false); 94 95 m_embedElement = toHTMLEmbedElement(embedElement.get()); 96 m_embedElement->setAttribute(widthAttr, "100%"); 97 m_embedElement->setAttribute(heightAttr, "100%"); 98 99 m_embedElement->setAttribute(nameAttr, "plugin"); 100 m_embedElement->setAttribute(srcAttr, document()->url().string()); 101 102 DocumentLoader* loader = document()->loader(); 103 ASSERT(loader); 104 if (loader) 105 m_embedElement->setAttribute(typeAttr, loader->writer().mimeType()); 106 107 toPluginDocument(document())->setPluginElement(m_embedElement); 108 109 body->appendChild(embedElement, IGNORE_EXCEPTION); 110} 111 112void PluginDocumentParser::appendBytes(DocumentWriter&, const char*, size_t) 113{ 114 if (m_embedElement) 115 return; 116 117 createDocumentStructure(); 118 119 Frame* frame = document()->frame(); 120 if (!frame) 121 return; 122 123 document()->updateLayout(); 124 125 // Below we assume that renderer->widget() to have been created by 126 // document()->updateLayout(). However, in some cases, updateLayout() will 127 // recurse too many times and delay its post-layout tasks (such as creating 128 // the widget). Here we kick off the pending post-layout tasks so that we 129 // can synchronously redirect data to the plugin. 130 frame->view()->flushAnyPendingPostLayoutTasks(); 131 132 if (RenderWidget* renderer = m_embedElement->renderWidget()) { 133 if (Widget* widget = renderer->widget()) { 134 frame->loader().client().redirectDataToPlugin(widget); 135 // In a plugin document, the main resource is the plugin. If we have a null widget, that means 136 // the loading of the plugin was cancelled, which gives us a null mainResourceLoader(), so we 137 // need to have this call in a null check of the widget or of mainResourceLoader(). 138 frame->loader().activeDocumentLoader()->setMainResourceDataBufferingPolicy(DoNotBufferData); 139 } 140 } 141} 142 143PluginDocument::PluginDocument(Frame* frame, const URL& url) 144 : HTMLDocument(frame, url, PluginDocumentClass) 145 , m_shouldLoadPluginManually(true) 146{ 147 setCompatibilityMode(DocumentCompatibilityMode::QuirksMode); 148 lockCompatibilityMode(); 149} 150 151PassRefPtr<DocumentParser> PluginDocument::createParser() 152{ 153 return PluginDocumentParser::create(*this); 154} 155 156Widget* PluginDocument::pluginWidget() 157{ 158 if (m_pluginElement && m_pluginElement->renderer()) { 159 ASSERT(m_pluginElement->renderer()->isEmbeddedObject()); 160 return toRenderEmbeddedObject(m_pluginElement->renderer())->widget(); 161 } 162 return 0; 163} 164 165void PluginDocument::setPluginElement(PassRefPtr<HTMLPlugInElement> element) 166{ 167 m_pluginElement = element; 168} 169 170void PluginDocument::detachFromPluginElement() 171{ 172 // Release the plugin Element so that we don't have a circular reference. 173 m_pluginElement = 0; 174 frame()->loader().client().redirectDataToPlugin(0); 175} 176 177void 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 DocumentLoader* documentLoader = frame()->loader().activeDocumentLoader(); 185 documentLoader->cancelMainResourceLoad(frame()->loader().cancelledError(documentLoader->request())); 186 setShouldLoadPluginManually(false); 187} 188 189} 190