OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 /** | 5 /** |
6 * @fileoverview | 6 * @fileoverview |
7 * Class that wraps low-level details of interacting with the client plugin. | 7 * Class that wraps low-level details of interacting with the client plugin. |
8 * | 8 * |
9 * This abstracts a <embed> element and controls the plugin which does | 9 * This abstracts a <embed> element and controls the plugin which does |
10 * the actual remoting work. It also handles differences between | 10 * the actual remoting work. It also handles differences between |
(...skipping 17 matching lines...) Expand all Loading... |
28 /** | 28 /** |
29 * @param {Element} container The container for the embed element. | 29 * @param {Element} container The container for the embed element. |
30 * @param {function(string, string):boolean} onExtensionMessage The handler for | 30 * @param {function(string, string):boolean} onExtensionMessage The handler for |
31 * protocol extension messages. Returns true if a message is recognized; | 31 * protocol extension messages. Returns true if a message is recognized; |
32 * false otherwise. | 32 * false otherwise. |
33 * @param {Array.<string>} requiredCapabilities The set of capabilties that the | 33 * @param {Array.<string>} requiredCapabilities The set of capabilties that the |
34 * session must support for this application. | 34 * session must support for this application. |
35 * @constructor | 35 * @constructor |
36 * @implements {remoting.ClientPlugin} | 36 * @implements {remoting.ClientPlugin} |
37 */ | 37 */ |
38 remoting.ClientPluginImpl = function(container, onExtensionMessage, | 38 remoting.ClientPluginImpl = function(container, |
| 39 onExtensionMessage, |
39 requiredCapabilities) { | 40 requiredCapabilities) { |
40 this.plugin_ = remoting.ClientPluginImpl.createPluginElement_(); | 41 this.plugin_ = remoting.ClientPluginImpl.createPluginElement_(); |
41 this.plugin_.id = 'session-client-plugin'; | 42 this.plugin_.id = 'session-client-plugin'; |
42 container.appendChild(this.plugin_); | 43 container.appendChild(this.plugin_); |
43 | 44 |
44 this.onExtensionMessage_ = onExtensionMessage; | 45 this.onExtensionMessage_ = onExtensionMessage; |
45 /** | 46 /** |
46 * @type {Array.<string>} | 47 * @type {Array.<string>} |
47 * @private | 48 * @private |
48 */ | 49 */ |
49 this.requiredCapabilities_ = requiredCapabilities; | 50 this.requiredCapabilities_ = requiredCapabilities; |
50 | 51 |
51 /** @private */ | |
52 this.desktopWidth_ = 0; | |
53 /** @private */ | |
54 this.desktopHeight_ = 0; | |
55 /** @private */ | |
56 this.desktopXDpi_ = 96; | |
57 /** @private */ | |
58 this.desktopYDpi_ = 96; | |
59 | |
60 /** | 52 /** |
61 * @param {string} iq The Iq stanza received from the host. | 53 * @param {string} iq The Iq stanza received from the host. |
62 * @private | 54 * @private |
63 */ | 55 */ |
64 this.onOutgoingIqHandler_ = function (iq) {}; | 56 this.onOutgoingIqHandler_ = function (iq) {}; |
65 /** | 57 /** |
66 * @param {string} message Log message. | 58 * @param {string} message Log message. |
67 * @private | 59 * @private |
68 */ | 60 */ |
69 this.onDebugMessageHandler_ = function (message) {}; | 61 this.onDebugMessageHandler_ = function (message) {}; |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
173 var that = this; | 165 var that = this; |
174 /** @param {Event} event Message event from the plugin. */ | 166 /** @param {Event} event Message event from the plugin. */ |
175 this.plugin_.addEventListener('message', function(event) { | 167 this.plugin_.addEventListener('message', function(event) { |
176 that.handleMessage_( | 168 that.handleMessage_( |
177 /** @type {remoting.ClientPluginMessage} */ (event.data)); | 169 /** @type {remoting.ClientPluginMessage} */ (event.data)); |
178 }, false); | 170 }, false); |
179 | 171 |
180 if (remoting.settings.CLIENT_PLUGIN_TYPE == 'native') { | 172 if (remoting.settings.CLIENT_PLUGIN_TYPE == 'native') { |
181 window.setTimeout(this.showPluginForClickToPlay_.bind(this), 500); | 173 window.setTimeout(this.showPluginForClickToPlay_.bind(this), 500); |
182 } | 174 } |
| 175 |
| 176 this.hostDesktop_ = new remoting.ClientPlugin.HostDesktopImpl( |
| 177 this, this.postMessage_.bind(this)); |
183 }; | 178 }; |
184 | 179 |
185 /** | 180 /** |
186 * Creates plugin element without adding it to a container. | 181 * Creates plugin element without adding it to a container. |
187 * | 182 * |
188 * @return {HTMLEmbedElement} Plugin element | 183 * @return {HTMLEmbedElement} Plugin element |
189 */ | 184 */ |
190 remoting.ClientPluginImpl.createPluginElement_ = function() { | 185 remoting.ClientPluginImpl.createPluginElement_ = function() { |
191 var plugin = | 186 var plugin = |
192 /** @type {HTMLEmbedElement} */ (document.createElement('embed')); | 187 /** @type {HTMLEmbedElement} */ (document.createElement('embed')); |
(...skipping 225 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
418 var error = remoting.ClientSession.ConnectionError.fromString( | 413 var error = remoting.ClientSession.ConnectionError.fromString( |
419 getStringAttr(message.data, 'error')); | 414 getStringAttr(message.data, 'error')); |
420 this.onConnectionStatusUpdateHandler_(state, error); | 415 this.onConnectionStatusUpdateHandler_(state, error); |
421 | 416 |
422 } else if (message.method == 'onRouteChanged') { | 417 } else if (message.method == 'onRouteChanged') { |
423 var channel = getStringAttr(message.data, 'channel'); | 418 var channel = getStringAttr(message.data, 'channel'); |
424 var connectionType = getStringAttr(message.data, 'connectionType'); | 419 var connectionType = getStringAttr(message.data, 'connectionType'); |
425 this.onRouteChangedHandler_(channel, connectionType); | 420 this.onRouteChangedHandler_(channel, connectionType); |
426 | 421 |
427 } else if (message.method == 'onDesktopSize') { | 422 } else if (message.method == 'onDesktopSize') { |
428 this.desktopWidth_ = getNumberAttr(message.data, 'width'); | 423 this.hostDesktop_.onSizeUpdated(message); |
429 this.desktopHeight_ = getNumberAttr(message.data, 'height'); | |
430 this.desktopXDpi_ = getNumberAttr(message.data, 'x_dpi', 96); | |
431 this.desktopYDpi_ = getNumberAttr(message.data, 'y_dpi', 96); | |
432 this.onDesktopSizeUpdateHandler_(); | 424 this.onDesktopSizeUpdateHandler_(); |
433 | 425 |
434 } else if (message.method == 'onDesktopShape') { | 426 } else if (message.method == 'onDesktopShape') { |
435 var rects = getArrayAttr(message.data, 'rects'); | 427 var rects = this.hostDesktop_.onShapeUpdated(message); |
436 for (var i = 0; i < rects.length; ++i) { | |
437 /** @type {Array.<number>} */ | |
438 var rect = rects[i]; | |
439 if (typeof rect != 'object' || rect.length != 4) { | |
440 throw 'Received invalid onDesktopShape message'; | |
441 } | |
442 } | |
443 this.onDesktopShapeUpdateHandler_(rects); | 428 this.onDesktopShapeUpdateHandler_(rects); |
444 | 429 |
445 } else if (message.method == 'onPerfStats') { | 430 } else if (message.method == 'onPerfStats') { |
446 // Return value is ignored. These calls will throw an error if the value | 431 // Return value is ignored. These calls will throw an error if the value |
447 // is not a number. | 432 // is not a number. |
448 getNumberAttr(message.data, 'videoBandwidth'); | 433 getNumberAttr(message.data, 'videoBandwidth'); |
449 getNumberAttr(message.data, 'videoFrameRate'); | 434 getNumberAttr(message.data, 'videoFrameRate'); |
450 getNumberAttr(message.data, 'captureLatency'); | 435 getNumberAttr(message.data, 'captureLatency'); |
451 getNumberAttr(message.data, 'encodeLatency'); | 436 getNumberAttr(message.data, 'encodeLatency'); |
452 getNumberAttr(message.data, 'decodeLatency'); | 437 getNumberAttr(message.data, 'decodeLatency'); |
(...skipping 22 matching lines...) Expand all Loading... |
475 // The pairingSupported value in the dictionary indicates whether both | 460 // The pairingSupported value in the dictionary indicates whether both |
476 // client and host support pairing. If the client doesn't support pairing, | 461 // client and host support pairing. If the client doesn't support pairing, |
477 // then the value won't be there at all, so give it a default of false. | 462 // then the value won't be there at all, so give it a default of false. |
478 var pairingSupported = getBooleanAttr(message.data, 'pairingSupported', | 463 var pairingSupported = getBooleanAttr(message.data, 'pairingSupported', |
479 false) | 464 false) |
480 this.fetchPinHandler_(pairingSupported); | 465 this.fetchPinHandler_(pairingSupported); |
481 | 466 |
482 } else if (message.method == 'setCapabilities') { | 467 } else if (message.method == 'setCapabilities') { |
483 /** @type {!Array.<string>} */ | 468 /** @type {!Array.<string>} */ |
484 var capabilities = tokenize(getStringAttr(message.data, 'capabilities')); | 469 var capabilities = tokenize(getStringAttr(message.data, 'capabilities')); |
| 470 this.hostDesktop_.onSetCapabilities(capabilities); |
485 this.onSetCapabilitiesHandler_(capabilities); | 471 this.onSetCapabilitiesHandler_(capabilities); |
486 | 472 |
487 } else if (message.method == 'fetchThirdPartyToken') { | 473 } else if (message.method == 'fetchThirdPartyToken') { |
488 var tokenUrl = getStringAttr(message.data, 'tokenUrl'); | 474 var tokenUrl = getStringAttr(message.data, 'tokenUrl'); |
489 var hostPublicKey = getStringAttr(message.data, 'hostPublicKey'); | 475 var hostPublicKey = getStringAttr(message.data, 'hostPublicKey'); |
490 var scope = getStringAttr(message.data, 'scope'); | 476 var scope = getStringAttr(message.data, 'scope'); |
491 this.fetchThirdPartyTokenHandler_(tokenUrl, hostPublicKey, scope); | 477 this.fetchThirdPartyTokenHandler_(tokenUrl, hostPublicKey, scope); |
492 | 478 |
493 } else if (message.method == 'pairingResponse') { | 479 } else if (message.method == 'pairingResponse') { |
494 var clientId = getStringAttr(message.data, 'clientId'); | 480 var clientId = getStringAttr(message.data, 'clientId'); |
(...skipping 256 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
751 | 737 |
752 /** | 738 /** |
753 * Notifies the host that the client has the specified size and pixel density. | 739 * Notifies the host that the client has the specified size and pixel density. |
754 * | 740 * |
755 * @param {number} width The available client width in DIPs. | 741 * @param {number} width The available client width in DIPs. |
756 * @param {number} height The available client height in DIPs. | 742 * @param {number} height The available client height in DIPs. |
757 * @param {number} device_scale The number of device pixels per DIP. | 743 * @param {number} device_scale The number of device pixels per DIP. |
758 */ | 744 */ |
759 remoting.ClientPluginImpl.prototype.notifyClientResolution = | 745 remoting.ClientPluginImpl.prototype.notifyClientResolution = |
760 function(width, height, device_scale) { | 746 function(width, height, device_scale) { |
761 if (this.hasFeature(remoting.ClientPlugin.Feature.NOTIFY_CLIENT_RESOLUTION)) { | 747 this.hostDesktop_.resize(width, height, device_scale); |
762 var dpi = Math.floor(device_scale * 96); | |
763 this.plugin_.postMessage(JSON.stringify( | |
764 { method: 'notifyClientResolution', | |
765 data: { width: Math.floor(width * device_scale), | |
766 height: Math.floor(height * device_scale), | |
767 x_dpi: dpi, y_dpi: dpi }})); | |
768 } | |
769 }; | 748 }; |
770 | 749 |
771 /** | 750 /** |
772 * Requests that the host pause or resume sending video updates. | 751 * Requests that the host pause or resume sending video updates. |
773 * | 752 * |
774 * @param {boolean} pause True to suspend video updates, false otherwise. | 753 * @param {boolean} pause True to suspend video updates, false otherwise. |
775 */ | 754 */ |
776 remoting.ClientPluginImpl.prototype.pauseVideo = | 755 remoting.ClientPluginImpl.prototype.pauseVideo = |
777 function(pause) { | 756 function(pause) { |
778 if (this.hasFeature(remoting.ClientPlugin.Feature.VIDEO_CONTROL)) { | 757 if (this.hasFeature(remoting.ClientPlugin.Feature.VIDEO_CONTROL)) { |
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
900 function(type, message) { | 879 function(type, message) { |
901 if (!this.hasFeature(remoting.ClientPlugin.Feature.EXTENSION_MESSAGE)) { | 880 if (!this.hasFeature(remoting.ClientPlugin.Feature.EXTENSION_MESSAGE)) { |
902 return; | 881 return; |
903 } | 882 } |
904 this.plugin_.postMessage(JSON.stringify( | 883 this.plugin_.postMessage(JSON.stringify( |
905 { method: 'extensionMessage', | 884 { method: 'extensionMessage', |
906 data: { type: type, data: message } })); | 885 data: { type: type, data: message } })); |
907 | 886 |
908 }; | 887 }; |
909 | 888 |
| 889 remoting.ClientPluginImpl.prototype.hostDesktop = function() { |
| 890 return this.hostDesktop_; |
| 891 }; |
| 892 |
| 893 // TODO(kelvinp): Fix all call sites to use ClientPlugin.HostDesktop and remove |
| 894 // the four methods below. |
910 remoting.ClientPluginImpl.prototype.getDesktopWidth = function() { | 895 remoting.ClientPluginImpl.prototype.getDesktopWidth = function() { |
911 return this.desktopWidth_; | 896 return this.hostDesktop_.getDimensions().width; |
912 } | 897 }; |
913 | 898 |
914 remoting.ClientPluginImpl.prototype.getDesktopHeight = function() { | 899 remoting.ClientPluginImpl.prototype.getDesktopHeight = function() { |
915 return this.desktopHeight_; | 900 return this.hostDesktop_.getDimensions().height; |
916 } | 901 }; |
917 | 902 |
918 remoting.ClientPluginImpl.prototype.getDesktopXDpi = function() { | 903 remoting.ClientPluginImpl.prototype.getDesktopXDpi = function() { |
919 return this.desktopXDpi_; | 904 return this.hostDesktop_.getDimensions().xDpi; |
920 } | 905 }; |
921 | 906 |
922 remoting.ClientPluginImpl.prototype.getDesktopYDpi = function() { | 907 remoting.ClientPluginImpl.prototype.getDesktopYDpi = function() { |
923 return this.desktopYDpi_; | 908 return this.hostDesktop_.getDimensions().yDpi; |
924 } | 909 }; |
925 | 910 |
926 /** | 911 /** |
927 * If we haven't yet received a "hello" message from the plugin, change its | 912 * If we haven't yet received a "hello" message from the plugin, change its |
928 * size so that the user can confirm it if click-to-play is enabled, or can | 913 * size so that the user can confirm it if click-to-play is enabled, or can |
929 * see the "this plugin is disabled" message if it is actually disabled. | 914 * see the "this plugin is disabled" message if it is actually disabled. |
930 * @private | 915 * @private |
931 */ | 916 */ |
932 remoting.ClientPluginImpl.prototype.showPluginForClickToPlay_ = function() { | 917 remoting.ClientPluginImpl.prototype.showPluginForClickToPlay_ = function() { |
933 if (!this.helloReceived_) { | 918 if (!this.helloReceived_) { |
934 var width = 200; | 919 var width = 200; |
(...skipping 14 matching lines...) Expand all Loading... |
949 * @private | 934 * @private |
950 */ | 935 */ |
951 remoting.ClientPluginImpl.prototype.hidePluginForClickToPlay_ = function() { | 936 remoting.ClientPluginImpl.prototype.hidePluginForClickToPlay_ = function() { |
952 this.plugin_.style.width = ''; | 937 this.plugin_.style.width = ''; |
953 this.plugin_.style.height = ''; | 938 this.plugin_.style.height = ''; |
954 this.plugin_.style.top = ''; | 939 this.plugin_.style.top = ''; |
955 this.plugin_.style.left = ''; | 940 this.plugin_.style.left = ''; |
956 this.plugin_.style.position = ''; | 941 this.plugin_.style.position = ''; |
957 }; | 942 }; |
958 | 943 |
| 944 /** |
| 945 * Callback passed to submodules to post a message to the plugin. |
| 946 * |
| 947 * @param {Object} objectLiteral |
| 948 * @private |
| 949 */ |
| 950 remoting.ClientPluginImpl.prototype.postMessage_ = function(objectLiteral) { |
| 951 if (this.plugin_ && this.plugin_.postMessage) { |
| 952 this.plugin_.postMessage(JSON.stringify(objectLiteral)); |
| 953 } |
| 954 }; |
959 | 955 |
960 /** | 956 /** |
961 * @constructor | 957 * @constructor |
962 * @implements {remoting.ClientPluginFactory} | 958 * @implements {remoting.ClientPluginFactory} |
963 */ | 959 */ |
964 remoting.DefaultClientPluginFactory = function() {}; | 960 remoting.DefaultClientPluginFactory = function() {}; |
965 | 961 |
966 /** | 962 /** |
967 * @param {Element} container | 963 * @param {Element} container |
968 * @param {function(string, string):boolean} onExtensionMessage | 964 * @param {function(string, string):boolean} onExtensionMessage |
969 * @param {Array.<string>} requiredCapabilities | 965 * @param {Array.<string>} requiredCapabilities |
970 * @return {remoting.ClientPlugin} | 966 * @return {remoting.ClientPlugin} |
971 */ | 967 */ |
972 remoting.DefaultClientPluginFactory.prototype.createPlugin = | 968 remoting.DefaultClientPluginFactory.prototype.createPlugin = |
973 function(container, onExtensionMessage, requiredCapabilities) { | 969 function(container, onExtensionMessage, requiredCapabilities) { |
974 return new remoting.ClientPluginImpl(container, onExtensionMessage, | 970 return new remoting.ClientPluginImpl(container, onExtensionMessage, |
975 requiredCapabilities); | 971 requiredCapabilities); |
976 }; | 972 }; |
977 | 973 |
978 remoting.DefaultClientPluginFactory.prototype.preloadPlugin = function() { | 974 remoting.DefaultClientPluginFactory.prototype.preloadPlugin = function() { |
979 if (remoting.settings.CLIENT_PLUGIN_TYPE != 'pnacl') { | 975 if (remoting.settings.CLIENT_PLUGIN_TYPE != 'pnacl') { |
980 return; | 976 return; |
981 } | 977 } |
982 | 978 |
983 var plugin = remoting.ClientPluginImpl.createPluginElement_(); | 979 var plugin = remoting.ClientPluginImpl.createPluginElement_(); |
984 plugin.addEventListener( | 980 plugin.addEventListener( |
985 'loadend', function() { document.body.removeChild(plugin); }, false); | 981 'loadend', function() { document.body.removeChild(plugin); }, false); |
986 document.body.appendChild(plugin); | 982 document.body.appendChild(plugin); |
987 }; | 983 }; |
OLD | NEW |