summaryrefslogtreecommitdiff
path: root/browser/base/content/test/browser_pluginplaypreview.js
blob: d1d8a53fb113df6fe4858033d5824f23257b5f3d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

var rootDir = getRootDirectory(gTestPath);
const gTestRoot = rootDir;

var gTestBrowser = null;
var gNextTest = null;
var gNextTestSkip = 0;
var gPlayPreviewPluginActualEvents = 0;
var gPlayPreviewPluginExpectedEvents = 1;

var gPlayPreviewRegistration = null;

function registerPlayPreview(mimeType, targetUrl) {

  function StreamConverterFactory() {}
  StreamConverterFactory.prototype = {
    QueryInterface: XPCOMUtils.generateQI([Ci.nsIFactory]),
    _targetConstructor: null,

    register: function register(targetConstructor) {
      this._targetConstructor = targetConstructor;
      var proto = targetConstructor.prototype;
      var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
      registrar.registerFactory(proto.classID, proto.classDescription,
                                proto.contractID, this);
    },

    unregister: function unregister() {
      var proto = this._targetConstructor.prototype;
      var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
      registrar.unregisterFactory(proto.classID, this);
      this._targetConstructor = null;
    },

    // nsIFactory
    createInstance: function createInstance(aOuter, iid) {
      if (aOuter !== null)
        throw Cr.NS_ERROR_NO_AGGREGATION;
      return (new (this._targetConstructor)).QueryInterface(iid);
    },

    // nsIFactory
    lockFactory: function lockFactory(lock) {
      // No longer used as of gecko 1.7.
      throw Cr.NS_ERROR_NOT_IMPLEMENTED;
    }
  };

  function OverlayStreamConverter() {}
  OverlayStreamConverter.prototype = {
    QueryInterface: XPCOMUtils.generateQI([
        Ci.nsISupports,
        Ci.nsIStreamConverter,
        Ci.nsIStreamListener,
        Ci.nsIRequestObserver
    ]),

    classID: Components.ID('{4c6030f7-e20a-264f-0f9b-ada3a9e97384}'),
    classDescription: 'overlay-test-data Component',
    contractID: '@mozilla.org/streamconv;1?from=application/x-moz-playpreview&to=*/*',

    // nsIStreamConverter::convert
    convert: function(aFromStream, aFromType, aToType, aCtxt) {
      throw Cr.NS_ERROR_NOT_IMPLEMENTED;
    },

    // nsIStreamConverter::asyncConvertData
    asyncConvertData: function(aFromType, aToType, aListener, aCtxt) {
      var isValidRequest = false;
      try {
        var request = aCtxt;
        request.QueryInterface(Ci.nsIChannel);
        var spec = request.URI.spec;
        var expectedSpec = 'data:application/x-moz-playpreview;,' + mimeType;
        isValidRequest = (spec == expectedSpec);
      } catch (e) { }
      if (!isValidRequest)
        throw Cr.NS_ERROR_NOT_IMPLEMENTED;

      // Store the listener passed to us
      this.listener = aListener;
    },

    // nsIStreamListener::onDataAvailable
    onDataAvailable: function(aRequest, aContext, aInputStream, aOffset, aCount) {
      // Do nothing since all the data loading is handled by the viewer.
      ok(false, "onDataAvailable should not be called");
    },

    // nsIRequestObserver::onStartRequest
    onStartRequest: function(aRequest, aContext) {

      // Setup the request so we can use it below.
      aRequest.QueryInterface(Ci.nsIChannel);
      // Cancel the request so the viewer can handle it.
      aRequest.cancel(Cr.NS_BINDING_ABORTED);

      // Create a new channel that is viewer loaded as a resource.
      var ioService = Services.io;
      var channel = ioService.newChannel(targetUrl, null, null);
      channel.asyncOpen(this.listener, aContext);
    },

    // nsIRequestObserver::onStopRequest
    onStopRequest: function(aRequest, aContext, aStatusCode) {
      // Do nothing.
    }
  };

  var ph = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
  ph.registerPlayPreviewMimeType(mimeType, true); // ignoring CTP rules

  var factory = new StreamConverterFactory();
  factory.register(OverlayStreamConverter);

  return (gPlayPreviewRegistration = {
    unregister: function() {
      ph.unregisterPlayPreviewMimeType(mimeType);
      factory.unregister();
      gPlayPreviewRegistration = null;
    }
  });
}

function unregisterPlayPreview() {
  gPlayPreviewRegistration.unregister();
}

Components.utils.import('resource://gre/modules/XPCOMUtils.jsm');
Components.utils.import("resource://gre/modules/Services.jsm");


function test() {
  waitForExplicitFinish();
  registerCleanupFunction(function() {
    if (gPlayPreviewRegistration)
      gPlayPreviewRegistration.unregister();
    Services.prefs.clearUserPref("plugins.click_to_play");
    var plugin = getTestPlugin();
    plugin.enabledState = Ci.nsIPluginTag.STATE_ENABLED;
  });

  var newTab = gBrowser.addTab();
  gBrowser.selectedTab = newTab;
  gTestBrowser = gBrowser.selectedBrowser;
  gTestBrowser.addEventListener("load", pageLoad, true);
  gTestBrowser.addEventListener("PluginBindingAttached", handleBindingAttached, true, true);

  registerPlayPreview('application/x-test', 'about:');
  prepareTest(test1a, gTestRoot + "plugin_test.html", 1);
}

function finishTest() {
  gTestBrowser.removeEventListener("load", pageLoad, true);
  gTestBrowser.removeEventListener("PluginBindingAttached", handleBindingAttached, true, true);
  gBrowser.removeCurrentTab();
  window.focus();
  finish();
}

function handleBindingAttached(evt) {
  if (evt.target instanceof Ci.nsIObjectLoadingContent &&
      evt.target.pluginFallbackType == Ci.nsIObjectLoadingContent.PLUGIN_PLAY_PREVIEW)
    gPlayPreviewPluginActualEvents++;
}

function pageLoad() {
  // The plugin events are async dispatched and can come after the load event
  // This just allows the events to fire before we then go on to test the states

  // iframe might triggers load event as well, making sure we skip some to let
  // all iframes on the page be loaded as well
  if (gNextTestSkip) {
    gNextTestSkip--;
    return;
  }
  executeSoon(gNextTest);
}

function prepareTest(nextTest, url, skip) {
  gNextTest = nextTest;
  gNextTestSkip = skip;
  gTestBrowser.contentWindow.location = url;
}

// Tests a page with normal play preview registration (1/2)
function test1a() {
  var notificationBox = gBrowser.getNotificationBox(gTestBrowser);
  ok(!notificationBox.getNotificationWithValue("missing-plugins"), "Test 1a, Should not have displayed the missing plugin notification");
  ok(!notificationBox.getNotificationWithValue("blocked-plugins"), "Test 1a, Should not have displayed the blocked plugin notification");

  var pluginInfo = getTestPlugin();
  ok(pluginInfo, "Should have a test plugin");

  var doc = gTestBrowser.contentDocument;
  var plugin = doc.getElementById("test");
  var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
  is(objLoadingContent.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_PLAY_PREVIEW, "Test 1a, plugin fallback type should be PLUGIN_PLAY_PREVIEW");
  ok(!objLoadingContent.activated, "Test 1a, Plugin should not be activated");

  var overlay = doc.getAnonymousElementByAttribute(plugin, "class", "previewPluginContent");
  ok(overlay, "Test 1a, the overlay div is expected");

  var iframe = overlay.getElementsByClassName("previewPluginContentFrame")[0];
  ok(iframe && iframe.localName == "iframe", "Test 1a, the overlay iframe is expected");
  var iframeHref = iframe.contentWindow.location.href;
  ok(iframeHref == "about:", "Test 1a, the overlay about: content is expected");

  var rect = iframe.getBoundingClientRect();
  ok(rect.width == 200, "Test 1a, Plugin with id=" + plugin.id + " overlay rect should have 200px width before being replaced by actual plugin");
  ok(rect.height == 200, "Test 1a, Plugin with id=" + plugin.id + " overlay rect should have 200px height before being replaced by actual plugin");

  var e = overlay.ownerDocument.createEvent("CustomEvent");
  e.initCustomEvent("MozPlayPlugin", true, true, null);
  overlay.dispatchEvent(e);
  var condition = function() objLoadingContent.activated;
  waitForCondition(condition, test1b, "Test 1a, Waited too long for plugin to stop play preview");
}

// Tests that activating via MozPlayPlugin through the notification works (part 2/2)
function test1b() {
  var plugin = gTestBrowser.contentDocument.getElementById("test");
  var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
  ok(objLoadingContent.activated, "Test 1b, Plugin should be activated");

  is(gPlayPreviewPluginActualEvents, gPlayPreviewPluginExpectedEvents,
     "There should be exactly one PluginPlayPreview event");

  unregisterPlayPreview();

  prepareTest(test2, gTestRoot + "plugin_test.html");
}

// Tests a page with a working plugin in it -- the mime type was just unregistered.
function test2() {
  var plugin = gTestBrowser.contentDocument.getElementById("test");
  var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
  ok(objLoadingContent.activated, "Test 2, Plugin should be activated");

  registerPlayPreview('application/x-unknown', 'about:');

  prepareTest(test3, gTestRoot + "plugin_test.html");
}

// Tests a page with a working plugin in it -- diffent play preview type is reserved.
function test3() {
  var plugin = gTestBrowser.contentDocument.getElementById("test");
  var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
  ok(objLoadingContent.activated, "Test 3, Plugin should be activated");

  unregisterPlayPreview();

  registerPlayPreview('application/x-test', 'about:');
  Services.prefs.setBoolPref("plugins.click_to_play", true);
  var plugin = getTestPlugin();
  plugin.enabledState = Ci.nsIPluginTag.STATE_CLICKTOPLAY;
  prepareTest(test4a, gTestRoot + "plugin_test.html", 1);
}

// Test a fallback to the click-to-play
function test4a() {
  var doc = gTestBrowser.contentDocument;
  var plugin = doc.getElementById("test");
  var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
  is(objLoadingContent.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_PLAY_PREVIEW, "Test 4a, plugin fallback type should be PLUGIN_PLAY_PREVIEW");
  ok(!objLoadingContent.activated, "Test 4a, Plugin should not be activated");

  var overlay = doc.getAnonymousElementByAttribute(plugin, "class", "previewPluginContent");
  ok(overlay, "Test 4a, the overlay div is expected");

  var e = overlay.ownerDocument.createEvent("CustomEvent");
  e.initCustomEvent("MozPlayPlugin", true, true, true);
  overlay.dispatchEvent(e);
  var condition = function() objLoadingContent.pluginFallbackType == Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY;
  waitForCondition(condition, test4b, "Test 4a, Waited too long for plugin to stop play preview");
}

function test4b() {
  var doc = gTestBrowser.contentDocument;
  var plugin = doc.getElementById("test");
  var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
  ok(objLoadingContent.pluginFallbackType != Ci.nsIObjectLoadingContent.PLUGIN_PLAY_PREVIEW, "Test 4b, plugin fallback type should not be PLUGIN_PLAY_PREVIEW");
  ok(!objLoadingContent.activated, "Test 4b, Plugin should not be activated");

  prepareTest(test5a, gTestRoot + "plugin_test.html", 1);
}

// Test a bypass of the click-to-play
function test5a() {
  var doc = gTestBrowser.contentDocument;
  var plugin = doc.getElementById("test");
  var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
  is(objLoadingContent.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_PLAY_PREVIEW, "Test 5a, plugin fallback type should be PLUGIN_PLAY_PREVIEW");
  ok(!objLoadingContent.activated, "Test 5a, Plugin should not be activated");

  var overlay = doc.getAnonymousElementByAttribute(plugin, "class", "previewPluginContent");
  ok(overlay, "Test 5a, the overlay div is expected");

  var e = overlay.ownerDocument.createEvent("CustomEvent");
  e.initCustomEvent("MozPlayPlugin", true, true, false);
  overlay.dispatchEvent(e);
  var condition = function() objLoadingContent.activated;
  waitForCondition(condition, test5b, "Test 5a, Waited too long for plugin to stop play preview");
}

function test5b() {
  var doc = gTestBrowser.contentDocument;
  var plugin = doc.getElementById("test");
  var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
  ok(objLoadingContent.activated, "Test 5b, Plugin should be activated");

  finishTest();
}