df6dca00bab69b3b8dc1f15c0c4b9fe6810f823d
[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 #include <wtf/IsoMallocInlines.h>
40
41 namespace WebCore {
42
43 WTF_MAKE_ISO_ALLOCATED_IMPL(PluginDocument);
44
45 using namespace HTMLNames;
46
47 // FIXME: Share more code with MediaDocumentParser.
48 class PluginDocumentParser final : public RawDataDocumentParser {
49 public:
50     static Ref<PluginDocumentParser> create(PluginDocument& document)
51     {
52         return adoptRef(*new PluginDocumentParser(document));
53     }
54
55 private:
56     PluginDocumentParser(Document& document)
57         : RawDataDocumentParser(document)
58     {
59     }
60
61     void appendBytes(DocumentWriter&, const char*, size_t) final;
62     void createDocumentStructure();
63
64     HTMLEmbedElement* m_embedElement { nullptr };
65 };
66
67 void PluginDocumentParser::createDocumentStructure()
68 {
69     auto& document = downcast<PluginDocument>(*this->document());
70
71     auto rootElement = HTMLHtmlElement::create(document);
72     document.appendChild(rootElement);
73     rootElement->insertedByParser();
74
75     if (document.frame())
76         document.frame()->injectUserScripts(InjectAtDocumentStart);
77
78 #if PLATFORM(IOS)
79     // Should not be able to zoom into standalone plug-in documents.
80     document.processViewport("user-scalable=no"_s, ViewportArguments::PluginDocument);
81 #endif
82
83     auto body = HTMLBodyElement::create(document);
84     body->setAttributeWithoutSynchronization(marginwidthAttr, AtomicString("0", AtomicString::ConstructFromLiteral));
85     body->setAttributeWithoutSynchronization(marginheightAttr, AtomicString("0", AtomicString::ConstructFromLiteral));
86 #if PLATFORM(IOS)
87     body->setAttribute(styleAttr, AtomicString("background-color: rgb(217,224,233)", AtomicString::ConstructFromLiteral));
88 #else
89     body->setAttribute(styleAttr, AtomicString("background-color: rgb(38,38,38)", AtomicString::ConstructFromLiteral));
90 #endif
91
92     rootElement->appendChild(body);
93         
94     auto embedElement = HTMLEmbedElement::create(document);
95         
96     m_embedElement = embedElement.ptr();
97     embedElement->setAttributeWithoutSynchronization(widthAttr, AtomicString("100%", AtomicString::ConstructFromLiteral));
98     embedElement->setAttributeWithoutSynchronization(heightAttr, AtomicString("100%", AtomicString::ConstructFromLiteral));
99     
100     embedElement->setAttributeWithoutSynchronization(nameAttr, AtomicString("plugin", AtomicString::ConstructFromLiteral));
101     embedElement->setAttributeWithoutSynchronization(srcAttr, document.url().string());
102     
103     ASSERT(document.loader());
104     if (auto loader = makeRefPtr(document.loader()))
105         m_embedElement->setAttributeWithoutSynchronization(typeAttr, loader->writer().mimeType());
106
107     document.setPluginElement(*m_embedElement);
108
109     body->appendChild(embedElement);
110 }
111
112 void PluginDocumentParser::appendBytes(DocumentWriter&, const char*, size_t)
113 {
114     if (m_embedElement)
115         return;
116
117     createDocumentStructure();
118
119     auto frame = makeRefPtr(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 (RefPtr<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
143 PluginDocument::PluginDocument(Frame* frame, const URL& url)
144     : HTMLDocument(frame, url, PluginDocumentClass)
145 {
146     setCompatibilityMode(DocumentCompatibilityMode::QuirksMode);
147     lockCompatibilityMode();
148 }
149
150 Ref<DocumentParser> PluginDocument::createParser()
151 {
152     return PluginDocumentParser::create(*this);
153 }
154
155 Widget* PluginDocument::pluginWidget()
156 {
157     if (!m_pluginElement)
158         return nullptr;
159     auto* renderer = m_pluginElement->renderer();
160     if (!renderer)
161         return nullptr;
162     return downcast<RenderEmbeddedObject>(*m_pluginElement->renderer()).widget();
163 }
164
165 void PluginDocument::setPluginElement(HTMLPlugInElement& element)
166 {
167     m_pluginElement = &element;
168 }
169
170 void PluginDocument::detachFromPluginElement()
171 {
172     // Release the plugin Element so that we don't have a circular reference.
173     m_pluginElement = nullptr;
174 }
175
176 void PluginDocument::cancelManualPluginLoad()
177 {
178     // PluginDocument::cancelManualPluginLoad should only be called once, but there are issues
179     // with how many times we call beforeload on object elements. <rdar://problem/8441094>.
180     if (!shouldLoadPluginManually())
181         return;
182
183     auto& frameLoader = frame()->loader();
184     auto& documentLoader = *frameLoader.activeDocumentLoader();
185     documentLoader.cancelMainResourceLoad(frameLoader.cancelledError(documentLoader.request()));
186     m_shouldLoadPluginManually = false;
187 }
188
189 }