1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/content/html/document/src/PluginDocument.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,299 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "MediaDocument.h" 1.10 +#include "nsIPluginDocument.h" 1.11 +#include "nsGkAtoms.h" 1.12 +#include "nsIPresShell.h" 1.13 +#include "nsIObjectFrame.h" 1.14 +#include "nsNPAPIPluginInstance.h" 1.15 +#include "nsIDocumentInlines.h" 1.16 +#include "nsIDocShellTreeItem.h" 1.17 +#include "nsNodeInfoManager.h" 1.18 +#include "nsContentCreatorFunctions.h" 1.19 +#include "nsContentPolicyUtils.h" 1.20 +#include "nsIPropertyBag2.h" 1.21 +#include "mozilla/dom/Element.h" 1.22 +#include "nsObjectLoadingContent.h" 1.23 +#include "GeckoProfiler.h" 1.24 + 1.25 +namespace mozilla { 1.26 +namespace dom { 1.27 + 1.28 +class PluginDocument MOZ_FINAL : public MediaDocument 1.29 + , public nsIPluginDocument 1.30 +{ 1.31 +public: 1.32 + PluginDocument(); 1.33 + virtual ~PluginDocument(); 1.34 + 1.35 + NS_DECL_ISUPPORTS_INHERITED 1.36 + NS_DECL_NSIPLUGINDOCUMENT 1.37 + 1.38 + virtual nsresult StartDocumentLoad(const char* aCommand, 1.39 + nsIChannel* aChannel, 1.40 + nsILoadGroup* aLoadGroup, 1.41 + nsISupports* aContainer, 1.42 + nsIStreamListener** aDocListener, 1.43 + bool aReset = true, 1.44 + nsIContentSink* aSink = nullptr); 1.45 + 1.46 + virtual void SetScriptGlobalObject(nsIScriptGlobalObject* aScriptGlobalObject); 1.47 + virtual bool CanSavePresentation(nsIRequest *aNewRequest); 1.48 + 1.49 + const nsCString& GetType() const { return mMimeType; } 1.50 + Element* GetPluginContent() { return mPluginContent; } 1.51 + 1.52 + void StartLayout() { MediaDocument::StartLayout(); } 1.53 + 1.54 + NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(PluginDocument, MediaDocument) 1.55 +protected: 1.56 + nsresult CreateSyntheticPluginDocument(); 1.57 + 1.58 + nsCOMPtr<Element> mPluginContent; 1.59 + nsRefPtr<MediaDocumentStreamListener> mStreamListener; 1.60 + nsCString mMimeType; 1.61 +}; 1.62 + 1.63 +class PluginStreamListener : public MediaDocumentStreamListener 1.64 +{ 1.65 +public: 1.66 + PluginStreamListener(PluginDocument* doc) 1.67 + : MediaDocumentStreamListener(doc) 1.68 + , mPluginDoc(doc) 1.69 + {} 1.70 + NS_IMETHOD OnStartRequest(nsIRequest* request, nsISupports *ctxt); 1.71 +private: 1.72 + nsRefPtr<PluginDocument> mPluginDoc; 1.73 +}; 1.74 + 1.75 + 1.76 +NS_IMETHODIMP 1.77 +PluginStreamListener::OnStartRequest(nsIRequest* request, nsISupports *ctxt) 1.78 +{ 1.79 + PROFILER_LABEL("PluginStreamListener", "OnStartRequest"); 1.80 + 1.81 + nsCOMPtr<nsIContent> embed = mPluginDoc->GetPluginContent(); 1.82 + nsCOMPtr<nsIObjectLoadingContent> objlc = do_QueryInterface(embed); 1.83 + nsCOMPtr<nsIStreamListener> objListener = do_QueryInterface(objlc); 1.84 + 1.85 + if (!objListener) { 1.86 + NS_NOTREACHED("PluginStreamListener without appropriate content node"); 1.87 + return NS_BINDING_ABORTED; 1.88 + } 1.89 + 1.90 + SetStreamListener(objListener); 1.91 + 1.92 + // Sets up the ObjectLoadingContent tag as if it is waiting for a 1.93 + // channel, so it can proceed with a load normally once it gets OnStartRequest 1.94 + nsresult rv = objlc->InitializeFromChannel(request); 1.95 + if (NS_FAILED(rv)) { 1.96 + NS_NOTREACHED("InitializeFromChannel failed"); 1.97 + return rv; 1.98 + } 1.99 + 1.100 + // Note that because we're now hooked up to a plugin listener, this will 1.101 + // likely spawn a plugin, which may re-enter. 1.102 + return MediaDocumentStreamListener::OnStartRequest(request, ctxt); 1.103 +} 1.104 + 1.105 + // NOTE! nsDocument::operator new() zeroes out all members, so don't 1.106 + // bother initializing members to 0. 1.107 + 1.108 +PluginDocument::PluginDocument() 1.109 +{} 1.110 + 1.111 +PluginDocument::~PluginDocument() 1.112 +{} 1.113 + 1.114 + 1.115 +NS_IMPL_CYCLE_COLLECTION_INHERITED(PluginDocument, MediaDocument, 1.116 + mPluginContent) 1.117 + 1.118 +NS_IMPL_ADDREF_INHERITED(PluginDocument, MediaDocument) 1.119 +NS_IMPL_RELEASE_INHERITED(PluginDocument, MediaDocument) 1.120 + 1.121 +NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(PluginDocument) 1.122 + NS_INTERFACE_TABLE_INHERITED(PluginDocument, nsIPluginDocument) 1.123 +NS_INTERFACE_TABLE_TAIL_INHERITING(MediaDocument) 1.124 + 1.125 +void 1.126 +PluginDocument::SetScriptGlobalObject(nsIScriptGlobalObject* aScriptGlobalObject) 1.127 +{ 1.128 + // Set the script global object on the superclass before doing 1.129 + // anything that might require it.... 1.130 + MediaDocument::SetScriptGlobalObject(aScriptGlobalObject); 1.131 + 1.132 + if (aScriptGlobalObject) { 1.133 + if (!mPluginContent) { 1.134 + // Create synthetic document 1.135 +#ifdef DEBUG 1.136 + nsresult rv = 1.137 +#endif 1.138 + CreateSyntheticPluginDocument(); 1.139 + NS_ASSERTION(NS_SUCCEEDED(rv), "failed to create synthetic document"); 1.140 + } 1.141 + BecomeInteractive(); 1.142 + } else { 1.143 + mStreamListener = nullptr; 1.144 + } 1.145 +} 1.146 + 1.147 + 1.148 +bool 1.149 +PluginDocument::CanSavePresentation(nsIRequest *aNewRequest) 1.150 +{ 1.151 + // Full-page plugins cannot be cached, currently, because we don't have 1.152 + // the stream listener data to feed to the plugin instance. 1.153 + return false; 1.154 +} 1.155 + 1.156 + 1.157 +nsresult 1.158 +PluginDocument::StartDocumentLoad(const char* aCommand, 1.159 + nsIChannel* aChannel, 1.160 + nsILoadGroup* aLoadGroup, 1.161 + nsISupports* aContainer, 1.162 + nsIStreamListener** aDocListener, 1.163 + bool aReset, 1.164 + nsIContentSink* aSink) 1.165 +{ 1.166 + // do not allow message panes to host full-page plugins 1.167 + // returning an error causes helper apps to take over 1.168 + nsCOMPtr<nsIDocShellTreeItem> dsti (do_QueryInterface(aContainer)); 1.169 + if (dsti) { 1.170 + bool isMsgPane = false; 1.171 + dsti->NameEquals(MOZ_UTF16("messagepane"), &isMsgPane); 1.172 + if (isMsgPane) { 1.173 + return NS_ERROR_FAILURE; 1.174 + } 1.175 + } 1.176 + 1.177 + nsresult rv = 1.178 + MediaDocument::StartDocumentLoad(aCommand, aChannel, aLoadGroup, aContainer, 1.179 + aDocListener, aReset, aSink); 1.180 + if (NS_FAILED(rv)) { 1.181 + return rv; 1.182 + } 1.183 + 1.184 + rv = aChannel->GetContentType(mMimeType); 1.185 + if (NS_FAILED(rv)) { 1.186 + return rv; 1.187 + } 1.188 + 1.189 + MediaDocument::UpdateTitleAndCharset(mMimeType); 1.190 + 1.191 + mStreamListener = new PluginStreamListener(this); 1.192 + NS_ASSERTION(aDocListener, "null aDocListener"); 1.193 + NS_ADDREF(*aDocListener = mStreamListener); 1.194 + 1.195 + return rv; 1.196 +} 1.197 + 1.198 +nsresult 1.199 +PluginDocument::CreateSyntheticPluginDocument() 1.200 +{ 1.201 + NS_ASSERTION(!GetShell() || !GetShell()->DidInitialize(), 1.202 + "Creating synthetic plugin document content too late"); 1.203 + 1.204 + // make our generic document 1.205 + nsresult rv = MediaDocument::CreateSyntheticDocument(); 1.206 + NS_ENSURE_SUCCESS(rv, rv); 1.207 + // then attach our plugin 1.208 + 1.209 + Element* body = GetBodyElement(); 1.210 + if (!body) { 1.211 + NS_WARNING("no body on plugin document!"); 1.212 + return NS_ERROR_FAILURE; 1.213 + } 1.214 + 1.215 + // remove margins from body 1.216 + NS_NAMED_LITERAL_STRING(zero, "0"); 1.217 + body->SetAttr(kNameSpaceID_None, nsGkAtoms::marginwidth, zero, false); 1.218 + body->SetAttr(kNameSpaceID_None, nsGkAtoms::marginheight, zero, false); 1.219 + 1.220 + 1.221 + // make plugin content 1.222 + nsCOMPtr<nsINodeInfo> nodeInfo; 1.223 + nodeInfo = mNodeInfoManager->GetNodeInfo(nsGkAtoms::embed, nullptr, 1.224 + kNameSpaceID_XHTML, 1.225 + nsIDOMNode::ELEMENT_NODE); 1.226 + rv = NS_NewHTMLElement(getter_AddRefs(mPluginContent), nodeInfo.forget(), 1.227 + NOT_FROM_PARSER); 1.228 + NS_ENSURE_SUCCESS(rv, rv); 1.229 + 1.230 + // make it a named element 1.231 + mPluginContent->SetAttr(kNameSpaceID_None, nsGkAtoms::name, 1.232 + NS_LITERAL_STRING("plugin"), false); 1.233 + 1.234 + // fill viewport and auto-resize 1.235 + NS_NAMED_LITERAL_STRING(percent100, "100%"); 1.236 + mPluginContent->SetAttr(kNameSpaceID_None, nsGkAtoms::width, percent100, 1.237 + false); 1.238 + mPluginContent->SetAttr(kNameSpaceID_None, nsGkAtoms::height, percent100, 1.239 + false); 1.240 + 1.241 + // set URL 1.242 + nsAutoCString src; 1.243 + mDocumentURI->GetSpec(src); 1.244 + mPluginContent->SetAttr(kNameSpaceID_None, nsGkAtoms::src, 1.245 + NS_ConvertUTF8toUTF16(src), false); 1.246 + 1.247 + // set mime type 1.248 + mPluginContent->SetAttr(kNameSpaceID_None, nsGkAtoms::type, 1.249 + NS_ConvertUTF8toUTF16(mMimeType), false); 1.250 + 1.251 + // nsHTML(Shared)ObjectElement does not kick off a load on BindToTree if it is 1.252 + // to a PluginDocument 1.253 + body->AppendChildTo(mPluginContent, false); 1.254 + 1.255 + return NS_OK; 1.256 + 1.257 + 1.258 +} 1.259 + 1.260 +NS_IMETHODIMP 1.261 +PluginDocument::Print() 1.262 +{ 1.263 + NS_ENSURE_TRUE(mPluginContent, NS_ERROR_FAILURE); 1.264 + 1.265 + nsIObjectFrame* objectFrame = 1.266 + do_QueryFrame(mPluginContent->GetPrimaryFrame()); 1.267 + if (objectFrame) { 1.268 + nsRefPtr<nsNPAPIPluginInstance> pi; 1.269 + objectFrame->GetPluginInstance(getter_AddRefs(pi)); 1.270 + if (pi) { 1.271 + NPPrint npprint; 1.272 + npprint.mode = NP_FULL; 1.273 + npprint.print.fullPrint.pluginPrinted = false; 1.274 + npprint.print.fullPrint.printOne = false; 1.275 + npprint.print.fullPrint.platformPrint = nullptr; 1.276 + 1.277 + pi->Print(&npprint); 1.278 + } 1.279 + } 1.280 + 1.281 + return NS_OK; 1.282 +} 1.283 + 1.284 +} // namespace dom 1.285 +} // namespace mozilla 1.286 + 1.287 +nsresult 1.288 +NS_NewPluginDocument(nsIDocument** aResult) 1.289 +{ 1.290 + mozilla::dom::PluginDocument* doc = new mozilla::dom::PluginDocument(); 1.291 + 1.292 + NS_ADDREF(doc); 1.293 + nsresult rv = doc->Init(); 1.294 + 1.295 + if (NS_FAILED(rv)) { 1.296 + NS_RELEASE(doc); 1.297 + } 1.298 + 1.299 + *aResult = doc; 1.300 + 1.301 + return rv; 1.302 +}