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