blob: d2459fc420e2cc9c64e0f50d73db1c6238c81873 [file] [log] [blame]
/*
* Copyright (C) 2013 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @constructor
* @extends {WebInspector.View}
*/
WebInspector.ScreencastView = function()
{
WebInspector.View.call(this);
this.registerRequiredCSS("screencastView.css");
this.element.addStyleClass("fill");
this.element.addStyleClass("screencast");
this._isCasting = false;
this._imageElement = this.element.createChild("img", "screencast-frame");
this._imageElement.tabIndex = 1;
this._imageElement.addEventListener("mousedown", this._handleMouseEvent.bind(this), false);
this._imageElement.addEventListener("mouseup", this._handleMouseEvent.bind(this), false);
this._imageElement.addEventListener("mousemove", this._handleMouseEvent.bind(this), false);
this._imageElement.addEventListener("mousewheel", this._handleMouseEvent.bind(this), false);
this._imageElement.addEventListener("click", this._handleMouseEvent.bind(this), false);
this._imageElement.addEventListener("contextmenu", this._handleContextMenuEvent.bind(this), false);
this._imageElement.addEventListener("keydown", this._handleKeyEvent.bind(this), false);
this._imageElement.addEventListener("keyup", this._handleKeyEvent.bind(this), false);
this._imageElement.addEventListener("keypress", this._handleKeyEvent.bind(this), false);
this._scale = 0.7;
WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.ScreencastFrame, this._screencastFrame, this);
}
WebInspector.ScreencastView.prototype = {
wasShown: function()
{
this.startCasting();
},
willHide: function()
{
this.stopCasting();
},
startCasting: function()
{
if (this._isCasting)
return;
this._isCasting = true;
PageAgent.startScreencast("jpeg", 80, this._scale);
},
stopCasting: function()
{
if (!this._isCasting)
return;
this._isCasting = false;
PageAgent.stopScreencast();
},
/**
* @param {WebInspector.Event} event
*/
_screencastFrame: function(event)
{
var base64Data = /** type {string} */(event.data);
var previousWidth = this._imageElement.naturalWidth;
var previousHeight = this._imageElement.naturalHeight;
this._imageElement.src = "data:image/jpg;base64," + base64Data;
if (previousWidth !== this._imageElement.naturalWidth || previousHeight !== this._imageElement.naturalHeight)
this.onResize();
},
/**
* @param {Event} event
*/
_handleMouseEvent: function(event)
{
if (!WebInspector.inspectElementModeController.enabled()) {
this._simulateTouchGestureForMouseEvent(event);
event.consume(true);
return;
}
var type;
switch (event.type) {
case "mousedown": type = "mousePressed"; break;
case "mouseup": type = "mouseReleased"; break;
case "mousemove": type = "mouseMoved"; break;
default: return;
}
var button;
switch (event.which) {
case 0: button = "none"; break;
case 1: button = "left"; break;
case 2: button = "middle"; break;
case 3: button = "right"; break;
default: return;
}
var position = this._convertIntoScreenSpace(event);
InputAgent.dispatchMouseEvent(type, position.x, position.y, this._modifiersForEvent(event), event.timeStamp / 1000, button, event.detail, true);
this.element.focus();
event.consume(true);
},
/**
* @param {Event} event
*/
_handleKeyEvent: function(event)
{
var type;
switch (event.type) {
case "keydown": type = "keyDown"; break;
case "keyup": type = "keyUp"; break;
case "keypress": type = "char"; break;
default: return;
}
var text = event.type === "keypress" ? String.fromCharCode(event.charCode) : undefined;
InputAgent.dispatchKeyEvent(type, this._modifiersForEvent(event), event.timeStamp / 1000, text, text ? text.toLowerCase() : undefined,
event.keyIdentifier, event.keyCode /* windowsVirtualKeyCode */, event.keyCode /* nativeVirtualKeyCode */, undefined /* macCharCode */, false, false, false);
this.element.focus();
event.consume(true);
},
/**
* @param {Event} event
*/
_handleContextMenuEvent: function(event)
{
event.consume(true);
},
/**
* @param {Event} event
*/
_simulateTouchGestureForMouseEvent: function(event)
{
var position = this._convertIntoScreenSpace(event);
var timeStamp = event.timeStamp / 1000;
var x = position.x;
var y = position.y;
switch (event.which) {
case 1: // Left
if (event.type === "mousedown") {
InputAgent.dispatchGestureEvent("scrollBegin", x, y, timeStamp);
} else if (event.type === "mousemove") {
var dx = this._lastScrollPosition ? position.x - this._lastScrollPosition.x : 0;
var dy = this._lastScrollPosition ? position.y - this._lastScrollPosition.y : 0;
if (dx || dy)
InputAgent.dispatchGestureEvent("scrollUpdate", x, y, timeStamp, dx, dy);
} else if (event.type === "mouseup") {
InputAgent.dispatchGestureEvent("scrollEnd", x, y, timeStamp);
} else if (event.type === "mousewheel") {
InputAgent.dispatchGestureEvent("scrollBegin", x, y, timeStamp);
InputAgent.dispatchGestureEvent("scrollUpdate", x, y, timeStamp, event.wheelDeltaX, event.wheelDeltaY);
InputAgent.dispatchGestureEvent("scrollEnd", x, y, timeStamp);
} else if (event.type === "click") {
InputAgent.dispatchGestureEvent("tapDown", x, y, timeStamp);
InputAgent.dispatchGestureEvent("tap", x, y, timeStamp);
}
this._lastScrollPosition = position;
break;
case 2: // Middle
if (event.type === "mousedown") {
InputAgent.dispatchGestureEvent("tapDown", x, y, timeStamp);
} else if (event.type === "mouseup") {
InputAgent.dispatchGestureEvent("tap", x, y, timeStamp);
}
break;
case 3: // Right
if (event.type === "mousedown") {
this._pinchStart = position;
InputAgent.dispatchGestureEvent("pinchBegin", x, y, timeStamp);
} else if (event.type === "mousemove") {
var dx = this._pinchStart ? position.x - this._pinchStart.x : 0;
var dy = this._pinchStart ? position.y - this._pinchStart.y : 0;
if (dx || dy) {
var scale = Math.pow(dy < 0 ? 0.999 : 1.001, Math.abs(dy));
InputAgent.dispatchGestureEvent("pinchUpdate", this._pinchStart.x, this._pinchStart.y, timeStamp, 0, 0, scale);
}
} else if (event.type === "mouseup") {
InputAgent.dispatchGestureEvent("pinchEnd", x, y, timeStamp);
}
break;
case 0: // None
default:
}
},
/**
* @param {Event} event
* @return {{x: number, y: number}}
*/
_convertIntoScreenSpace: function(event)
{
var position = {};
const gutterSize = 40;
position.x = Math.round((event.x - gutterSize) / this._scale / this._zoom);
position.y = Math.round((event.y - gutterSize) / this._scale / this._zoom);
return position;
},
/**
* @param {Event} event
* @return number
*/
_modifiersForEvent: function(event)
{
var modifiers = 0;
if (event.altKey)
modifiers = 1;
if (event.ctrlKey)
modifiers += 2;
if (event.metaKey)
modifiers += 4;
if (event.shiftKey)
modifiers += 8;
return modifiers;
},
onResize: function()
{
if (!this._imageElement.naturalWidth)
return;
const gutterSize = 30;
const bordersSize = 60;
var ratio = this._imageElement.naturalWidth / this._imageElement.naturalHeight;
var maxWidth = this.element.offsetWidth - bordersSize - gutterSize;
var maxHeight = this.element.offsetHeight - bordersSize - gutterSize;
if (maxWidth > ratio * maxHeight) {
this._imageElement.style.width = (ratio * maxHeight) + bordersSize + "px";
this._imageElement.style.height = (maxHeight + bordersSize) + "px";
} else {
this._imageElement.style.width = (maxWidth + bordersSize) + "px";
this._imageElement.style.height = maxWidth / ratio + bordersSize + "px";
}
this._zoom = (this._imageElement.offsetWidth - bordersSize) / this._imageElement.naturalWidth;
},
__proto__: WebInspector.View.prototype
}