Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
michael@0 | 1 | /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
michael@0 | 2 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 5 | |
michael@0 | 6 | #include "MediaDocument.h" |
michael@0 | 7 | #include "nsIPluginDocument.h" |
michael@0 | 8 | #include "nsGkAtoms.h" |
michael@0 | 9 | #include "nsIPresShell.h" |
michael@0 | 10 | #include "nsIObjectFrame.h" |
michael@0 | 11 | #include "nsNPAPIPluginInstance.h" |
michael@0 | 12 | #include "nsIDocumentInlines.h" |
michael@0 | 13 | #include "nsIDocShellTreeItem.h" |
michael@0 | 14 | #include "nsNodeInfoManager.h" |
michael@0 | 15 | #include "nsContentCreatorFunctions.h" |
michael@0 | 16 | #include "nsContentPolicyUtils.h" |
michael@0 | 17 | #include "nsIPropertyBag2.h" |
michael@0 | 18 | #include "mozilla/dom/Element.h" |
michael@0 | 19 | #include "nsObjectLoadingContent.h" |
michael@0 | 20 | #include "GeckoProfiler.h" |
michael@0 | 21 | |
michael@0 | 22 | namespace mozilla { |
michael@0 | 23 | namespace dom { |
michael@0 | 24 | |
michael@0 | 25 | class PluginDocument MOZ_FINAL : public MediaDocument |
michael@0 | 26 | , public nsIPluginDocument |
michael@0 | 27 | { |
michael@0 | 28 | public: |
michael@0 | 29 | PluginDocument(); |
michael@0 | 30 | virtual ~PluginDocument(); |
michael@0 | 31 | |
michael@0 | 32 | NS_DECL_ISUPPORTS_INHERITED |
michael@0 | 33 | NS_DECL_NSIPLUGINDOCUMENT |
michael@0 | 34 | |
michael@0 | 35 | virtual nsresult StartDocumentLoad(const char* aCommand, |
michael@0 | 36 | nsIChannel* aChannel, |
michael@0 | 37 | nsILoadGroup* aLoadGroup, |
michael@0 | 38 | nsISupports* aContainer, |
michael@0 | 39 | nsIStreamListener** aDocListener, |
michael@0 | 40 | bool aReset = true, |
michael@0 | 41 | nsIContentSink* aSink = nullptr); |
michael@0 | 42 | |
michael@0 | 43 | virtual void SetScriptGlobalObject(nsIScriptGlobalObject* aScriptGlobalObject); |
michael@0 | 44 | virtual bool CanSavePresentation(nsIRequest *aNewRequest); |
michael@0 | 45 | |
michael@0 | 46 | const nsCString& GetType() const { return mMimeType; } |
michael@0 | 47 | Element* GetPluginContent() { return mPluginContent; } |
michael@0 | 48 | |
michael@0 | 49 | void StartLayout() { MediaDocument::StartLayout(); } |
michael@0 | 50 | |
michael@0 | 51 | NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(PluginDocument, MediaDocument) |
michael@0 | 52 | protected: |
michael@0 | 53 | nsresult CreateSyntheticPluginDocument(); |
michael@0 | 54 | |
michael@0 | 55 | nsCOMPtr<Element> mPluginContent; |
michael@0 | 56 | nsRefPtr<MediaDocumentStreamListener> mStreamListener; |
michael@0 | 57 | nsCString mMimeType; |
michael@0 | 58 | }; |
michael@0 | 59 | |
michael@0 | 60 | class PluginStreamListener : public MediaDocumentStreamListener |
michael@0 | 61 | { |
michael@0 | 62 | public: |
michael@0 | 63 | PluginStreamListener(PluginDocument* doc) |
michael@0 | 64 | : MediaDocumentStreamListener(doc) |
michael@0 | 65 | , mPluginDoc(doc) |
michael@0 | 66 | {} |
michael@0 | 67 | NS_IMETHOD OnStartRequest(nsIRequest* request, nsISupports *ctxt); |
michael@0 | 68 | private: |
michael@0 | 69 | nsRefPtr<PluginDocument> mPluginDoc; |
michael@0 | 70 | }; |
michael@0 | 71 | |
michael@0 | 72 | |
michael@0 | 73 | NS_IMETHODIMP |
michael@0 | 74 | PluginStreamListener::OnStartRequest(nsIRequest* request, nsISupports *ctxt) |
michael@0 | 75 | { |
michael@0 | 76 | PROFILER_LABEL("PluginStreamListener", "OnStartRequest"); |
michael@0 | 77 | |
michael@0 | 78 | nsCOMPtr<nsIContent> embed = mPluginDoc->GetPluginContent(); |
michael@0 | 79 | nsCOMPtr<nsIObjectLoadingContent> objlc = do_QueryInterface(embed); |
michael@0 | 80 | nsCOMPtr<nsIStreamListener> objListener = do_QueryInterface(objlc); |
michael@0 | 81 | |
michael@0 | 82 | if (!objListener) { |
michael@0 | 83 | NS_NOTREACHED("PluginStreamListener without appropriate content node"); |
michael@0 | 84 | return NS_BINDING_ABORTED; |
michael@0 | 85 | } |
michael@0 | 86 | |
michael@0 | 87 | SetStreamListener(objListener); |
michael@0 | 88 | |
michael@0 | 89 | // Sets up the ObjectLoadingContent tag as if it is waiting for a |
michael@0 | 90 | // channel, so it can proceed with a load normally once it gets OnStartRequest |
michael@0 | 91 | nsresult rv = objlc->InitializeFromChannel(request); |
michael@0 | 92 | if (NS_FAILED(rv)) { |
michael@0 | 93 | NS_NOTREACHED("InitializeFromChannel failed"); |
michael@0 | 94 | return rv; |
michael@0 | 95 | } |
michael@0 | 96 | |
michael@0 | 97 | // Note that because we're now hooked up to a plugin listener, this will |
michael@0 | 98 | // likely spawn a plugin, which may re-enter. |
michael@0 | 99 | return MediaDocumentStreamListener::OnStartRequest(request, ctxt); |
michael@0 | 100 | } |
michael@0 | 101 | |
michael@0 | 102 | // NOTE! nsDocument::operator new() zeroes out all members, so don't |
michael@0 | 103 | // bother initializing members to 0. |
michael@0 | 104 | |
michael@0 | 105 | PluginDocument::PluginDocument() |
michael@0 | 106 | {} |
michael@0 | 107 | |
michael@0 | 108 | PluginDocument::~PluginDocument() |
michael@0 | 109 | {} |
michael@0 | 110 | |
michael@0 | 111 | |
michael@0 | 112 | NS_IMPL_CYCLE_COLLECTION_INHERITED(PluginDocument, MediaDocument, |
michael@0 | 113 | mPluginContent) |
michael@0 | 114 | |
michael@0 | 115 | NS_IMPL_ADDREF_INHERITED(PluginDocument, MediaDocument) |
michael@0 | 116 | NS_IMPL_RELEASE_INHERITED(PluginDocument, MediaDocument) |
michael@0 | 117 | |
michael@0 | 118 | NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(PluginDocument) |
michael@0 | 119 | NS_INTERFACE_TABLE_INHERITED(PluginDocument, nsIPluginDocument) |
michael@0 | 120 | NS_INTERFACE_TABLE_TAIL_INHERITING(MediaDocument) |
michael@0 | 121 | |
michael@0 | 122 | void |
michael@0 | 123 | PluginDocument::SetScriptGlobalObject(nsIScriptGlobalObject* aScriptGlobalObject) |
michael@0 | 124 | { |
michael@0 | 125 | // Set the script global object on the superclass before doing |
michael@0 | 126 | // anything that might require it.... |
michael@0 | 127 | MediaDocument::SetScriptGlobalObject(aScriptGlobalObject); |
michael@0 | 128 | |
michael@0 | 129 | if (aScriptGlobalObject) { |
michael@0 | 130 | if (!mPluginContent) { |
michael@0 | 131 | // Create synthetic document |
michael@0 | 132 | #ifdef DEBUG |
michael@0 | 133 | nsresult rv = |
michael@0 | 134 | #endif |
michael@0 | 135 | CreateSyntheticPluginDocument(); |
michael@0 | 136 | NS_ASSERTION(NS_SUCCEEDED(rv), "failed to create synthetic document"); |
michael@0 | 137 | } |
michael@0 | 138 | BecomeInteractive(); |
michael@0 | 139 | } else { |
michael@0 | 140 | mStreamListener = nullptr; |
michael@0 | 141 | } |
michael@0 | 142 | } |
michael@0 | 143 | |
michael@0 | 144 | |
michael@0 | 145 | bool |
michael@0 | 146 | PluginDocument::CanSavePresentation(nsIRequest *aNewRequest) |
michael@0 | 147 | { |
michael@0 | 148 | // Full-page plugins cannot be cached, currently, because we don't have |
michael@0 | 149 | // the stream listener data to feed to the plugin instance. |
michael@0 | 150 | return false; |
michael@0 | 151 | } |
michael@0 | 152 | |
michael@0 | 153 | |
michael@0 | 154 | nsresult |
michael@0 | 155 | PluginDocument::StartDocumentLoad(const char* aCommand, |
michael@0 | 156 | nsIChannel* aChannel, |
michael@0 | 157 | nsILoadGroup* aLoadGroup, |
michael@0 | 158 | nsISupports* aContainer, |
michael@0 | 159 | nsIStreamListener** aDocListener, |
michael@0 | 160 | bool aReset, |
michael@0 | 161 | nsIContentSink* aSink) |
michael@0 | 162 | { |
michael@0 | 163 | // do not allow message panes to host full-page plugins |
michael@0 | 164 | // returning an error causes helper apps to take over |
michael@0 | 165 | nsCOMPtr<nsIDocShellTreeItem> dsti (do_QueryInterface(aContainer)); |
michael@0 | 166 | if (dsti) { |
michael@0 | 167 | bool isMsgPane = false; |
michael@0 | 168 | dsti->NameEquals(MOZ_UTF16("messagepane"), &isMsgPane); |
michael@0 | 169 | if (isMsgPane) { |
michael@0 | 170 | return NS_ERROR_FAILURE; |
michael@0 | 171 | } |
michael@0 | 172 | } |
michael@0 | 173 | |
michael@0 | 174 | nsresult rv = |
michael@0 | 175 | MediaDocument::StartDocumentLoad(aCommand, aChannel, aLoadGroup, aContainer, |
michael@0 | 176 | aDocListener, aReset, aSink); |
michael@0 | 177 | if (NS_FAILED(rv)) { |
michael@0 | 178 | return rv; |
michael@0 | 179 | } |
michael@0 | 180 | |
michael@0 | 181 | rv = aChannel->GetContentType(mMimeType); |
michael@0 | 182 | if (NS_FAILED(rv)) { |
michael@0 | 183 | return rv; |
michael@0 | 184 | } |
michael@0 | 185 | |
michael@0 | 186 | MediaDocument::UpdateTitleAndCharset(mMimeType); |
michael@0 | 187 | |
michael@0 | 188 | mStreamListener = new PluginStreamListener(this); |
michael@0 | 189 | NS_ASSERTION(aDocListener, "null aDocListener"); |
michael@0 | 190 | NS_ADDREF(*aDocListener = mStreamListener); |
michael@0 | 191 | |
michael@0 | 192 | return rv; |
michael@0 | 193 | } |
michael@0 | 194 | |
michael@0 | 195 | nsresult |
michael@0 | 196 | PluginDocument::CreateSyntheticPluginDocument() |
michael@0 | 197 | { |
michael@0 | 198 | NS_ASSERTION(!GetShell() || !GetShell()->DidInitialize(), |
michael@0 | 199 | "Creating synthetic plugin document content too late"); |
michael@0 | 200 | |
michael@0 | 201 | // make our generic document |
michael@0 | 202 | nsresult rv = MediaDocument::CreateSyntheticDocument(); |
michael@0 | 203 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 204 | // then attach our plugin |
michael@0 | 205 | |
michael@0 | 206 | Element* body = GetBodyElement(); |
michael@0 | 207 | if (!body) { |
michael@0 | 208 | NS_WARNING("no body on plugin document!"); |
michael@0 | 209 | return NS_ERROR_FAILURE; |
michael@0 | 210 | } |
michael@0 | 211 | |
michael@0 | 212 | // remove margins from body |
michael@0 | 213 | NS_NAMED_LITERAL_STRING(zero, "0"); |
michael@0 | 214 | body->SetAttr(kNameSpaceID_None, nsGkAtoms::marginwidth, zero, false); |
michael@0 | 215 | body->SetAttr(kNameSpaceID_None, nsGkAtoms::marginheight, zero, false); |
michael@0 | 216 | |
michael@0 | 217 | |
michael@0 | 218 | // make plugin content |
michael@0 | 219 | nsCOMPtr<nsINodeInfo> nodeInfo; |
michael@0 | 220 | nodeInfo = mNodeInfoManager->GetNodeInfo(nsGkAtoms::embed, nullptr, |
michael@0 | 221 | kNameSpaceID_XHTML, |
michael@0 | 222 | nsIDOMNode::ELEMENT_NODE); |
michael@0 | 223 | rv = NS_NewHTMLElement(getter_AddRefs(mPluginContent), nodeInfo.forget(), |
michael@0 | 224 | NOT_FROM_PARSER); |
michael@0 | 225 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 226 | |
michael@0 | 227 | // make it a named element |
michael@0 | 228 | mPluginContent->SetAttr(kNameSpaceID_None, nsGkAtoms::name, |
michael@0 | 229 | NS_LITERAL_STRING("plugin"), false); |
michael@0 | 230 | |
michael@0 | 231 | // fill viewport and auto-resize |
michael@0 | 232 | NS_NAMED_LITERAL_STRING(percent100, "100%"); |
michael@0 | 233 | mPluginContent->SetAttr(kNameSpaceID_None, nsGkAtoms::width, percent100, |
michael@0 | 234 | false); |
michael@0 | 235 | mPluginContent->SetAttr(kNameSpaceID_None, nsGkAtoms::height, percent100, |
michael@0 | 236 | false); |
michael@0 | 237 | |
michael@0 | 238 | // set URL |
michael@0 | 239 | nsAutoCString src; |
michael@0 | 240 | mDocumentURI->GetSpec(src); |
michael@0 | 241 | mPluginContent->SetAttr(kNameSpaceID_None, nsGkAtoms::src, |
michael@0 | 242 | NS_ConvertUTF8toUTF16(src), false); |
michael@0 | 243 | |
michael@0 | 244 | // set mime type |
michael@0 | 245 | mPluginContent->SetAttr(kNameSpaceID_None, nsGkAtoms::type, |
michael@0 | 246 | NS_ConvertUTF8toUTF16(mMimeType), false); |
michael@0 | 247 | |
michael@0 | 248 | // nsHTML(Shared)ObjectElement does not kick off a load on BindToTree if it is |
michael@0 | 249 | // to a PluginDocument |
michael@0 | 250 | body->AppendChildTo(mPluginContent, false); |
michael@0 | 251 | |
michael@0 | 252 | return NS_OK; |
michael@0 | 253 | |
michael@0 | 254 | |
michael@0 | 255 | } |
michael@0 | 256 | |
michael@0 | 257 | NS_IMETHODIMP |
michael@0 | 258 | PluginDocument::Print() |
michael@0 | 259 | { |
michael@0 | 260 | NS_ENSURE_TRUE(mPluginContent, NS_ERROR_FAILURE); |
michael@0 | 261 | |
michael@0 | 262 | nsIObjectFrame* objectFrame = |
michael@0 | 263 | do_QueryFrame(mPluginContent->GetPrimaryFrame()); |
michael@0 | 264 | if (objectFrame) { |
michael@0 | 265 | nsRefPtr<nsNPAPIPluginInstance> pi; |
michael@0 | 266 | objectFrame->GetPluginInstance(getter_AddRefs(pi)); |
michael@0 | 267 | if (pi) { |
michael@0 | 268 | NPPrint npprint; |
michael@0 | 269 | npprint.mode = NP_FULL; |
michael@0 | 270 | npprint.print.fullPrint.pluginPrinted = false; |
michael@0 | 271 | npprint.print.fullPrint.printOne = false; |
michael@0 | 272 | npprint.print.fullPrint.platformPrint = nullptr; |
michael@0 | 273 | |
michael@0 | 274 | pi->Print(&npprint); |
michael@0 | 275 | } |
michael@0 | 276 | } |
michael@0 | 277 | |
michael@0 | 278 | return NS_OK; |
michael@0 | 279 | } |
michael@0 | 280 | |
michael@0 | 281 | } // namespace dom |
michael@0 | 282 | } // namespace mozilla |
michael@0 | 283 | |
michael@0 | 284 | nsresult |
michael@0 | 285 | NS_NewPluginDocument(nsIDocument** aResult) |
michael@0 | 286 | { |
michael@0 | 287 | mozilla::dom::PluginDocument* doc = new mozilla::dom::PluginDocument(); |
michael@0 | 288 | |
michael@0 | 289 | NS_ADDREF(doc); |
michael@0 | 290 | nsresult rv = doc->Init(); |
michael@0 | 291 | |
michael@0 | 292 | if (NS_FAILED(rv)) { |
michael@0 | 293 | NS_RELEASE(doc); |
michael@0 | 294 | } |
michael@0 | 295 | |
michael@0 | 296 | *aResult = doc; |
michael@0 | 297 | |
michael@0 | 298 | return rv; |
michael@0 | 299 | } |