Coverage Report

Created: 2018-09-25 14:53

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