@@ -718,10 +718,10 @@ index 5de630a1db847a09651b310928bb7bc4d4f66f29..0268bc2bdfb3bfda2ef6e01a5dd24209
718
718
nsCOMPtr<nsIPrincipal> principal =
719
719
diff --git a/juggler/BrowserContextManager.js b/juggler/BrowserContextManager.js
720
720
new file mode 100644
721
- index 0000000000000000000000000000000000000000..3365aa618718308ffdf05d9f196d792fc7b58677
721
+ index 0000000000000000000000000000000000000000..bd57d338c279f5ab31102e6644f43e133b7f4e25
722
722
--- /dev/null
723
723
+++ b/juggler/BrowserContextManager.js
724
- @@ -0,0 +1,229 @@
724
+ @@ -0,0 +1,235 @@
725
725
+ "use strict";
726
726
+
727
727
+ const {ContextualIdentityService} = ChromeUtils.import("resource://gre/modules/ContextualIdentityService.jsm");
@@ -807,6 +807,7 @@ index 0000000000000000000000000000000000000000..3365aa618718308ffdf05d9f196d792f
807
807
+ this._manager._userContextIdToBrowserContext.set(this.userContextId, this);
808
808
+ this.options = options || {};
809
809
+ this.options.scriptsToEvaluateOnNewDocument = [];
810
+ + this.options.bindings = [];
810
811
+ this.pages = new Set();
811
812
+ }
812
813
+
@@ -824,6 +825,11 @@ index 0000000000000000000000000000000000000000..3365aa618718308ffdf05d9f196d792f
824
825
+ await Promise.all(Array.from(this.pages).map(page => page.addScriptToEvaluateOnNewDocument(script)));
825
826
+ }
826
827
+
828
+ + async addBinding(name, script) {
829
+ + this.options.bindings.push({ name, script });
830
+ + await Promise.all(Array.from(this.pages).map(page => page.addBinding(name, script)));
831
+ + }
832
+ +
827
833
+ async setGeolocationOverride(geolocation) {
828
834
+ this.options.geolocation = geolocation;
829
835
+ await Promise.all(Array.from(this.pages).map(page => page.setGeolocationOverride(geolocation)));
@@ -1929,10 +1935,10 @@ index 0000000000000000000000000000000000000000..ba34976ad05e7f5f1a99777f76ac08b1
1929
1935
+ this.SimpleChannel = SimpleChannel;
1930
1936
diff --git a/juggler/TargetRegistry.js b/juggler/TargetRegistry.js
1931
1937
new file mode 100644
1932
- index 0000000000000000000000000000000000000000..75ea79a8fa493f0d8f2f88244aaf397af17833d4
1938
+ index 0000000000000000000000000000000000000000..e624e3c21a20dd324e0d135598e2a2402c8b62bf
1933
1939
--- /dev/null
1934
1940
+++ b/juggler/TargetRegistry.js
1935
- @@ -0,0 +1,273 @@
1941
+ @@ -0,0 +1,277 @@
1936
1942
+ const {EventEmitter} = ChromeUtils.import('resource://gre/modules/EventEmitter.jsm');
1937
1943
+ const {Helper} = ChromeUtils.import('chrome://juggler/content/Helper.js');
1938
1944
+ const {SimpleChannel} = ChromeUtils.import('chrome://juggler/content/SimpleChannel.js');
@@ -2169,6 +2175,10 @@ index 0000000000000000000000000000000000000000..75ea79a8fa493f0d8f2f88244aaf397a
2169
2175
+ await this._channel.connect('').send('addScriptToEvaluateOnNewDocument', script).catch(e => void e);
2170
2176
+ }
2171
2177
+
2178
+ + async addBinding(name, script) {
2179
+ + await this._channel.connect('').send('addBinding', { name, script }).catch(e => void e);
2180
+ + }
2181
+ +
2172
2182
+ async setGeolocationOverride(geolocation) {
2173
2183
+ await this._channel.connect('').send('setGeolocationOverride', geolocation).catch(e => void e);
2174
2184
+ }
@@ -2354,10 +2364,10 @@ index 0000000000000000000000000000000000000000..268fbc361d8053182bb6c27f626e853d
2354
2364
+
2355
2365
diff --git a/juggler/content/FrameTree.js b/juggler/content/FrameTree.js
2356
2366
new file mode 100644
2357
- index 0000000000000000000000000000000000000000..13c3cd817b369ed012326b97d03ba6e123b84740
2367
+ index 0000000000000000000000000000000000000000..679b5851c427064c636bd1f7793358cc45b0de67
2358
2368
--- /dev/null
2359
2369
+++ b/juggler/content/FrameTree.js
2360
- @@ -0,0 +1,376 @@
2370
+ @@ -0,0 +1,411 @@
2361
2371
+ "use strict";
2362
2372
+ const Ci = Components.interfaces;
2363
2373
+ const Cr = Components.results;
@@ -2378,6 +2388,7 @@ index 0000000000000000000000000000000000000000..13c3cd817b369ed012326b97d03ba6e1
2378
2388
+ this._browsingContextGroup.__jugglerFrameTrees = new Set();
2379
2389
+ this._browsingContextGroup.__jugglerFrameTrees.add(this);
2380
2390
+
2391
+ + this._bindings = new Map();
2381
2392
+ this._workers = new Map();
2382
2393
+ this._docShellToFrame = new Map();
2383
2394
+ this._frameIdToFrame = new Map();
@@ -2408,6 +2419,7 @@ index 0000000000000000000000000000000000000000..13c3cd817b369ed012326b97d03ba6e1
2408
2419
+ this._eventListeners = [
2409
2420
+ helper.addObserver(subject => this._onDocShellCreated(subject.QueryInterface(Ci.nsIDocShell)), 'webnavigation-create'),
2410
2421
+ helper.addObserver(subject => this._onDocShellDestroyed(subject.QueryInterface(Ci.nsIDocShell)), 'webnavigation-destroy'),
2422
+ + helper.addObserver(window => this._onDOMWindowCreated(window), 'content-document-global-created'),
2411
2423
+ helper.addProgressListener(webProgress, this, flags),
2412
2424
+ ];
2413
2425
+ }
@@ -2471,6 +2483,25 @@ index 0000000000000000000000000000000000000000..13c3cd817b369ed012326b97d03ba6e1
2471
2483
+ return this._scriptsToEvaluateOnNewDocument;
2472
2484
+ }
2473
2485
+
2486
+ + addBinding(name, script) {
2487
+ + this._bindings.set(name, script);
2488
+ + for (const frame of this.frames())
2489
+ + this._addBindingToFrame(frame, name, script);
2490
+ + }
2491
+ +
2492
+ + _addBindingToFrame(frame, name, script) {
2493
+ + Cu.exportFunction((...args) => {
2494
+ + this.emit(FrameTree.Events.BindingCalled, {
2495
+ + frame,
2496
+ + name,
2497
+ + payload: args[0]
2498
+ + });
2499
+ + }, frame.domWindow(), {
2500
+ + defineAs: name,
2501
+ + });
2502
+ + frame.domWindow().eval(script);
2503
+ + }
2504
+ +
2474
2505
+ frameForDocShell(docShell) {
2475
2506
+ return this._docShellToFrame.get(docShell) || null;
2476
2507
+ }
@@ -2578,6 +2609,8 @@ index 0000000000000000000000000000000000000000..13c3cd817b369ed012326b97d03ba6e1
2578
2609
+ const frame = new Frame(this, docShell, parentFrame);
2579
2610
+ this._docShellToFrame.set(docShell, frame);
2580
2611
+ this._frameIdToFrame.set(frame.id(), frame);
2612
+ + for (const [name, script] of this._bindings)
2613
+ + this._addBindingToFrame(frame, name, script);
2581
2614
+ this.emit(FrameTree.Events.FrameAttached, frame);
2582
2615
+ return frame;
2583
2616
+ }
@@ -2588,6 +2621,16 @@ index 0000000000000000000000000000000000000000..13c3cd817b369ed012326b97d03ba6e1
2588
2621
+ this._detachFrame(frame);
2589
2622
+ }
2590
2623
+
2624
+ + _onDOMWindowCreated(window) {
2625
+ + const docShell = window.docShell;
2626
+ + const frame = this.frameForDocShell(docShell);
2627
+ + if (!frame)
2628
+ + return;
2629
+ + for (const [name, script] of this._bindings)
2630
+ + this._addBindingToFrame(frame, name, script);
2631
+ + this.emit(FrameTree.Events.GlobalObjectCreated, { frame, window });
2632
+ + }
2633
+ +
2591
2634
+ _detachFrame(frame) {
2592
2635
+ // Detach all children first
2593
2636
+ for (const subframe of frame._children)
@@ -2602,8 +2645,10 @@ index 0000000000000000000000000000000000000000..13c3cd817b369ed012326b97d03ba6e1
2602
2645
+ }
2603
2646
+
2604
2647
+ FrameTree.Events = {
2648
+ + BindingCalled: 'bindingcalled',
2605
2649
+ FrameAttached: 'frameattached',
2606
2650
+ FrameDetached: 'framedetached',
2651
+ + GlobalObjectCreated: 'globalobjectcreated',
2607
2652
+ WorkerCreated: 'workercreated',
2608
2653
+ WorkerDestroyed: 'workerdestroyed',
2609
2654
+ NavigationStarted: 'navigationstarted',
@@ -2804,10 +2849,10 @@ index 0000000000000000000000000000000000000000..be70ea364f9534bb3b344f64970366c3
2804
2849
+
2805
2850
diff --git a/juggler/content/PageAgent.js b/juggler/content/PageAgent.js
2806
2851
new file mode 100644
2807
- index 0000000000000000000000000000000000000000..3dd06f27d071a1ca70609d63a12b1ff690d99371
2852
+ index 0000000000000000000000000000000000000000..6a001d9f51c819edd3981e090172ac87d6f85840
2808
2853
--- /dev/null
2809
2854
+++ b/juggler/content/PageAgent.js
2810
- @@ -0,0 +1,938 @@
2855
+ @@ -0,0 +1,921 @@
2811
2856
+ "use strict";
2812
2857
+ const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
2813
2858
+ const Ci = Components.interfaces;
@@ -2873,8 +2918,6 @@ index 0000000000000000000000000000000000000000..3dd06f27d071a1ca70609d63a12b1ff6
2873
2918
+ name: '',
2874
2919
+ });
2875
2920
+
2876
- + for (const bindingName of this._agent._bindingsToAdd.values())
2877
- + this.exposeFunction(bindingName);
2878
2921
+ for (const script of this._agent._frameTree.scriptsToEvaluateOnNewDocument()) {
2879
2922
+ // TODO: this should actually be handled in FrameTree, but first we have to move
2880
2923
+ // execution contexts there.
@@ -2896,18 +2939,6 @@ index 0000000000000000000000000000000000000000..3dd06f27d071a1ca70609d63a12b1ff6
2896
2939
+ }
2897
2940
+ }
2898
2941
+
2899
- + exposeFunction(name) {
2900
- + Cu.exportFunction((...args) => {
2901
- + this._agent._browserPage.emit('pageBindingCalled', {
2902
- + executionContextId: this.mainContext.id(),
2903
- + name,
2904
- + payload: args[0]
2905
- + });
2906
- + }, this._frame.domWindow(), {
2907
- + defineAs: name,
2908
- + });
2909
- + }
2910
- +
2911
2942
+ createIsolatedWorld(name) {
2912
2943
+ const principal = [this._frame.domWindow()]; // extended principal
2913
2944
+ const sandbox = Cu.Sandbox(principal, {
@@ -2954,11 +2985,10 @@ index 0000000000000000000000000000000000000000..3dd06f27d071a1ca70609d63a12b1ff6
2954
2985
+ this._frameData = new Map();
2955
2986
+ this._workerData = new Map();
2956
2987
+ this._scriptsToEvaluateOnNewDocument = new Map();
2957
- + this._bindingsToAdd = new Set();
2958
2988
+
2959
2989
+ this._eventListeners = [
2960
2990
+ browserChannel.register(sessionId + 'page', {
2961
- + addBinding: this._addBinding.bind(this ),
2991
+ + addBinding: ({ name, script }) => this._frameTree.addBinding(name, script ),
2962
2992
+ addScriptToEvaluateOnNewDocument: this._addScriptToEvaluateOnNewDocument.bind(this),
2963
2993
+ adoptNode: this._adoptNode.bind(this),
2964
2994
+ awaitViewportDimensions: this._awaitViewportDimensions.bind(this),
@@ -3080,13 +3110,14 @@ index 0000000000000000000000000000000000000000..3dd06f27d071a1ca70609d63a12b1ff6
3080
3110
+ helper.addObserver(this._linkClicked.bind(this, false), 'juggler-link-click'),
3081
3111
+ helper.addObserver(this._linkClicked.bind(this, true), 'juggler-link-click-sync'),
3082
3112
+ helper.addObserver(this._filePickerShown.bind(this), 'juggler-file-picker-shown'),
3083
- + helper.addObserver(this._onDOMWindowCreated.bind(this), 'content-document-global-created'),
3084
3113
+ helper.addEventListener(this._messageManager, 'DOMContentLoaded', this._onDOMContentLoaded.bind(this)),
3085
3114
+ helper.addEventListener(this._messageManager, 'pageshow', this._onLoad.bind(this)),
3086
3115
+ helper.addObserver(this._onDocumentOpenLoad.bind(this), 'juggler-document-open-loaded'),
3087
3116
+ helper.addEventListener(this._messageManager, 'error', this._onError.bind(this)),
3117
+ + helper.on(this._frameTree, 'bindingcalled', this._onBindingCalled.bind(this)),
3088
3118
+ helper.on(this._frameTree, 'frameattached', this._onFrameAttached.bind(this)),
3089
3119
+ helper.on(this._frameTree, 'framedetached', this._onFrameDetached.bind(this)),
3120
+ + helper.on(this._frameTree, 'globalobjectcreated', this._onGlobalObjectCreated.bind(this)),
3090
3121
+ helper.on(this._frameTree, 'navigationstarted', this._onNavigationStarted.bind(this)),
3091
3122
+ helper.on(this._frameTree, 'navigationcommitted', this._onNavigationCommitted.bind(this)),
3092
3123
+ helper.on(this._frameTree, 'navigationaborted', this._onNavigationAborted.bind(this)),
@@ -3244,11 +3275,7 @@ index 0000000000000000000000000000000000000000..3dd06f27d071a1ca70609d63a12b1ff6
3244
3275
+ });
3245
3276
+ }
3246
3277
+
3247
- + _onDOMWindowCreated(window) {
3248
- + const docShell = window.docShell;
3249
- + const frame = this._frameTree.frameForDocShell(docShell);
3250
- + if (!frame)
3251
- + return;
3278
+ + _onGlobalObjectCreated({ frame }) {
3252
3279
+ this._frameData.get(frame).reset();
3253
3280
+ }
3254
3281
+
@@ -3267,6 +3294,15 @@ index 0000000000000000000000000000000000000000..3dd06f27d071a1ca70609d63a12b1ff6
3267
3294
+ });
3268
3295
+ }
3269
3296
+
3297
+ + _onBindingCalled({frame, name, payload}) {
3298
+ + const frameData = this._frameData.get(frame);
3299
+ + this._browserPage.emit('pageBindingCalled', {
3300
+ + executionContextId: frameData.mainContext.id(),
3301
+ + name,
3302
+ + payload
3303
+ + });
3304
+ + }
3305
+ +
3270
3306
+ dispose() {
3271
3307
+ for (const workerData of this._workerData.values())
3272
3308
+ workerData.dispose();
@@ -3334,14 +3370,6 @@ index 0000000000000000000000000000000000000000..3dd06f27d071a1ca70609d63a12b1ff6
3334
3370
+ return {navigationId: frame.pendingNavigationId(), navigationURL: frame.pendingNavigationURL()};
3335
3371
+ }
3336
3372
+
3337
- + _addBinding({name}) {
3338
- + if (this._bindingsToAdd.has(name))
3339
- + throw new Error(`Binding with name ${name} already exists`);
3340
- + this._bindingsToAdd.add(name);
3341
- + for (const frameData of this._frameData.values())
3342
- + frameData.exposeFunction(name);
3343
- + }
3344
- +
3345
3373
+ async _adoptNode({frameId, objectId, executionContextId}) {
3346
3374
+ const frame = this._frameTree.frame(frameId);
3347
3375
+ if (!frame)
@@ -4511,10 +4539,10 @@ index 0000000000000000000000000000000000000000..3a386425d3796d0a6786dea193b3402d
4511
4539
+
4512
4540
diff --git a/juggler/content/main.js b/juggler/content/main.js
4513
4541
new file mode 100644
4514
- index 0000000000000000000000000000000000000000..56472e8515cb84d66bd0ec89e5ca1984bb360f5a
4542
+ index 0000000000000000000000000000000000000000..9bb5c2bff8eb3e350203b56a3445e9b200747f8b
4515
4543
--- /dev/null
4516
4544
+++ b/juggler/content/main.js
4517
- @@ -0,0 +1,172 @@
4545
+ @@ -0,0 +1,178 @@
4518
4546
+ const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
4519
4547
+ const {Helper} = ChromeUtils.import('chrome://juggler/content/Helper.js');
4520
4548
+ const {FrameTree} = ChromeUtils.import('chrome://juggler/content/content/FrameTree.js');
@@ -4590,7 +4618,7 @@ index 0000000000000000000000000000000000000000..56472e8515cb84d66bd0ec89e5ca1984
4590
4618
+ response = { sessionIds: [], browserContextOptions: {}, waitForInitialNavigation: false };
4591
4619
+
4592
4620
+ const { sessionIds, browserContextOptions, waitForInitialNavigation } = response;
4593
- + const { userAgent, bypassCSP, javaScriptDisabled, viewport, scriptsToEvaluateOnNewDocument, locale, geolocation, onlineOverride } = browserContextOptions;
4621
+ + const { userAgent, bypassCSP, javaScriptDisabled, viewport, scriptsToEvaluateOnNewDocument, bindings, locale, geolocation, onlineOverride } = browserContextOptions;
4594
4622
+
4595
4623
+ if (userAgent !== undefined)
4596
4624
+ docShell.customUserAgent = userAgent;
@@ -4614,6 +4642,8 @@ index 0000000000000000000000000000000000000000..56472e8515cb84d66bd0ec89e5ca1984
4614
4642
+ frameTree = new FrameTree(docShell, waitForInitialNavigation);
4615
4643
+ for (const script of scriptsToEvaluateOnNewDocument || [])
4616
4644
+ frameTree.addScriptToEvaluateOnNewDocument(script);
4645
+ + for (const { name, script } of bindings || [])
4646
+ + frameTree.addBinding(name, script);
4617
4647
+ networkMonitor = new NetworkMonitor(docShell, frameTree);
4618
4648
+
4619
4649
+ const channel = SimpleChannel.createForMessageManager('content::page', messageManager);
@@ -4634,6 +4664,10 @@ index 0000000000000000000000000000000000000000..56472e8515cb84d66bd0ec89e5ca1984
4634
4664
+ frameTree.addScriptToEvaluateOnNewDocument(script);
4635
4665
+ },
4636
4666
+
4667
+ + addBinding(name, script) {
4668
+ + frameTree.addBinding(name, script);
4669
+ + },
4670
+ +
4637
4671
+ setGeolocationOverride(geolocation) {
4638
4672
+ setGeolocationOverrideInDocShell(geolocation);
4639
4673
+ },
@@ -4768,10 +4802,10 @@ index 0000000000000000000000000000000000000000..2f2b7ca247f6b6dff396fb4b644654de
4768
4802
+ this.AccessibilityHandler = AccessibilityHandler;
4769
4803
diff --git a/juggler/protocol/BrowserHandler.js b/juggler/protocol/BrowserHandler.js
4770
4804
new file mode 100644
4771
- index 0000000000000000000000000000000000000000..b3a7b47765d69f9ba48c74e23aaae4e2a40498e5
4805
+ index 0000000000000000000000000000000000000000..e225fc81c62bbfac4d071ab1a9d83a754dda46bb
4772
4806
--- /dev/null
4773
4807
+++ b/juggler/protocol/BrowserHandler.js
4774
- @@ -0,0 +1,174 @@
4808
+ @@ -0,0 +1,178 @@
4775
4809
+ "use strict";
4776
4810
+
4777
4811
+ const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
@@ -4920,6 +4954,10 @@ index 0000000000000000000000000000000000000000..b3a7b47765d69f9ba48c74e23aaae4e2
4920
4954
+ await this._contextManager.browserContextForId(browserContextId).addScriptToEvaluateOnNewDocument(script);
4921
4955
+ }
4922
4956
+
4957
+ + async addBinding({browserContextId, name, script}) {
4958
+ + await this._contextManager.browserContextForId(browserContextId).addBinding(name, script);
4959
+ + }
4960
+ +
4923
4961
+ setCookies({browserContextId, cookies}) {
4924
4962
+ this._contextManager.browserContextForId(browserContextId).setCookies(cookies);
4925
4963
+ }
@@ -5817,10 +5855,10 @@ index 0000000000000000000000000000000000000000..78b6601b91d0b7fcda61114e6846aa07
5817
5855
+ this.EXPORTED_SYMBOLS = ['t', 'checkScheme'];
5818
5856
diff --git a/juggler/protocol/Protocol.js b/juggler/protocol/Protocol.js
5819
5857
new file mode 100644
5820
- index 0000000000000000000000000000000000000000..390e68d71c0034748ae90132d9d1defaa67de772
5858
+ index 0000000000000000000000000000000000000000..67df4d5592d66e0db3c7c120ad12f9b360b9c45d
5821
5859
--- /dev/null
5822
5860
+++ b/juggler/protocol/Protocol.js
5823
- @@ -0,0 +1,770 @@
5861
+ @@ -0,0 +1,778 @@
5824
5862
+ const {t, checkScheme} = ChromeUtils.import('chrome://juggler/content/protocol/PrimitiveTypes.js');
5825
5863
+
5826
5864
+ // Protocol-specific types.
@@ -6096,6 +6134,13 @@ index 0000000000000000000000000000000000000000..390e68d71c0034748ae90132d9d1defa
6096
6134
+ script: t.String,
6097
6135
+ }
6098
6136
+ },
6137
+ + 'addBinding': {
6138
+ + params: {
6139
+ + browserContextId: t.Optional(t.String),
6140
+ + name: t.String,
6141
+ + script: t.String,
6142
+ + },
6143
+ + },
6099
6144
+ 'grantPermissions': {
6100
6145
+ params: {
6101
6146
+ origin: t.String,
@@ -6382,6 +6427,7 @@ index 0000000000000000000000000000000000000000..390e68d71c0034748ae90132d9d1defa
6382
6427
+ 'addBinding': {
6383
6428
+ params: {
6384
6429
+ name: t.String,
6430
+ + script: t.String,
6385
6431
+ },
6386
6432
+ },
6387
6433
+ 'setViewportSize': {
0 commit comments