Bug 712472 - click-and-drag in Tilt becomes wonky after you do full-page-zoom (Ctrl +). r=robcee

This commit is contained in:
Victor Porof 2011-12-21 14:39:29 +02:00
parent b2a9cfa61e
commit d41f125f14
9 changed files with 220 additions and 45 deletions

View File

@ -514,7 +514,7 @@ TiltGL.Renderer.prototype = {
*/
scale: function TGLR_scale(x, y, z)
{
mat4.scale(this.mvMatrix, [x, y, z || 0]);
mat4.scale(this.mvMatrix, [x, y, z || 1]);
},
/**

View File

@ -650,12 +650,25 @@ TiltUtils.getWindowId = function TU_getWindowId(aWindow)
.currentInnerWindowID;
};
/**
* Gets the markup document viewer zoom for the currently selected browser.
*
* @return {Number} the zoom ammount
*/
TiltUtils.getDocumentZoom = function TU_getDocumentZoom() {
let browserWindow = Cc["@mozilla.org/appshell/window-mediator;1"]
.getService(Ci.nsIWindowMediator)
.getMostRecentWindow("navigator:browser");
return browserWindow.gBrowser.selectedBrowser.markupDocumentViewer.fullZoom;
};
/**
* Performs a garbage collection.
*/
TiltUtils.gc = function TU_gc()
{
var browserWindow = Cc["@mozilla.org/appshell/window-mediator;1"]
let browserWindow = Cc["@mozilla.org/appshell/window-mediator;1"]
.getService(Ci.nsIWindowMediator)
.getMostRecentWindow("navigator:browser");

View File

@ -221,6 +221,7 @@ TiltVisualizer.Presenter = function TV_Presenter(
* Modified by events in the controller through delegate functions.
*/
this.transforms = {
zoom: TiltUtils.getDocumentZoom(),
offset: vec3.create(), // mesh offset, aligned to the viewport center
translation: vec3.create(), // scene translation, on the [x, y, z] axis
rotation: quat4.create() // scene rotation, expressed as a quaternion
@ -338,6 +339,8 @@ TiltVisualizer.Presenter.prototype = {
renderer.translate(transforms.offset[0],
transforms.offset[1] + transforms.translation[1], 0);
renderer.scale(transforms.zoom, transforms.zoom);
// draw the visualization mesh
renderer.strokeWeight(2);
renderer.depthTest(true);
@ -492,12 +495,13 @@ TiltVisualizer.Presenter.prototype = {
this.highlightNode(this.inspectorUI.selection);
}
let width = renderer.width;
let height = renderer.height;
let zoom = TiltUtils.getDocumentZoom();
let width = Math.min(aData.meshWidth * zoom, renderer.width);
let height = Math.min(aData.meshHeight * zoom, renderer.height);
// set the necessary mesh offsets
this.transforms.offset[0] = -Math.min(aData.meshWidth, width) * 0.5;
this.transforms.offset[1] = -Math.min(aData.meshHeight, height) * 0.5;
this.transforms.offset[0] = -width * 0.5;
this.transforms.offset[1] = -height * 0.5;
// make sure the canvas is opaque now that the initialization is finished
this.canvas.style.background = TiltVisualizerStyle.canvas.background;
@ -559,8 +563,9 @@ TiltVisualizer.Presenter.prototype = {
*/
onResize: function TVP_onResize(e)
{
let width = e.target.innerWidth;
let height = e.target.innerHeight;
let zoom = TiltUtils.getDocumentZoom();
let width = e.target.innerWidth * zoom;
let height = e.target.innerHeight * zoom;
// handle aspect ratio changes to update the projection matrix
this.renderer.width = width;
@ -703,9 +708,12 @@ TiltVisualizer.Presenter.prototype = {
}
}, false);
let width = this.renderer.width;
let height = this.renderer.height;
let zoom = TiltUtils.getDocumentZoom();
let width = this.renderer.width * zoom;
let height = this.renderer.height * zoom;
let mesh = this.meshStacks;
x *= zoom;
y *= zoom;
// create a ray following the mouse direction from the near clipping plane
// to the far clipping plane, to check for intersections with the mesh,
@ -988,7 +996,11 @@ TiltVisualizer.Controller.prototype = {
e.preventDefault();
e.stopPropagation();
}
this.arcball.keyDown(code);
if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) {
this.arcball.cancelKeyEvents();
} else {
this.arcball.keyDown(code);
}
},
/**
@ -1013,7 +1025,7 @@ TiltVisualizer.Controller.prototype = {
* Called when the canvas looses focus.
*/
onBlur: function TVC_onBlur(e) {
this.arcball._keyCode = {};
this.arcball.cancelKeyEvents();
},
/**
@ -1021,8 +1033,9 @@ TiltVisualizer.Controller.prototype = {
*/
onResize: function TVC_onResize(e)
{
let width = e.target.innerWidth;
let height = e.target.innerHeight;
let zoom = TiltUtils.getDocumentZoom();
let width = e.target.innerWidth * zoom;
let height = e.target.innerHeight * zoom;
this.arcball.resize(width, height);
},
@ -1468,6 +1481,13 @@ TiltVisualizer.Arcball.prototype = {
}
},
/**
* Cancels all pending transformations caused by key events.
*/
cancelKeyEvents: function TVA_cancelKeyEvents() {
this._keyCode = {};
},
/**
* Resize this implementation to use different bounds.
* This function is automatically called when the arcball is created.

View File

@ -76,6 +76,7 @@ _BROWSER_TEST_FILES = \
browser_tilt_utils05.js \
browser_tilt_utils06.js \
browser_tilt_visualizer.js \
browser_tilt_zoom.js \
$(NULL)
libs:: $(_BROWSER_TEST_FILES)

View File

@ -45,36 +45,55 @@ function test() {
"At init, the rotation should be zero.");
EventUtils.synthesizeKey("VK_A", { type: "keydown" });
EventUtils.synthesizeKey("VK_LEFT", { type: "keydown" });
instance.controller.update();
ok(!isEqualVec(tran(), prev_tran),
"After a translation key is pressed, the vector should change.");
ok(!isEqualVec(rot(), prev_rot),
"After a rotation key is pressed, the quaternion should change.");
save();
gBrowser.selectedBrowser.contentWindow.focus();
instance.controller.update();
ok(!isEqualVec(tran(), prev_tran),
"Even if the canvas lost focus, the vector has some inertia.");
ok(!isEqualVec(rot(), prev_rot),
"Even if the canvas lost focus, the quaternion has some inertia.");
save();
while (!isEqualVec(tran(), prev_tran) || !isEqualVec(rot(), prev_rot)) {
function testEventCancel(cancellingEvent) {
EventUtils.synthesizeKey("VK_A", { type: "keydown" });
EventUtils.synthesizeKey("VK_LEFT", { type: "keydown" });
instance.controller.update();
ok(!isEqualVec(tran(), prev_tran),
"After a translation key is pressed, the vector should change.");
ok(!isEqualVec(rot(), prev_rot),
"After a rotation key is pressed, the quaternion should change.");
save();
cancellingEvent();
instance.controller.update();
ok(!isEqualVec(tran(), prev_tran),
"Even if the canvas lost focus, the vector has some inertia.");
ok(!isEqualVec(rot(), prev_rot),
"Even if the canvas lost focus, the quaternion has some inertia.");
save();
while (!isEqualVec(tran(), prev_tran) ||
!isEqualVec(rot(), prev_rot)) {
instance.controller.update();
save();
}
ok(isEqualVec(tran(), prev_tran) && isEqualVec(rot(), prev_rot),
"After focus lost, the transforms inertia eventually stops.");
}
ok(isEqualVec(tran(), prev_tran) && isEqualVec(rot(), prev_rot),
"After the focus is lost, the transforms inertia eventually stops.");
testEventCancel(function() {
EventUtils.synthesizeKey("T", { type: "keydown", altKey: 1 });
});
testEventCancel(function() {
EventUtils.synthesizeKey("I", { type: "keydown", ctrlKey: 1 });
});
testEventCancel(function() {
EventUtils.synthesizeKey("L", { type: "keydown", metaKey: 1 });
});
testEventCancel(function() {
EventUtils.synthesizeKey("T", { type: "keydown", shiftKey: 1 });
});
testEventCancel(function() {
gBrowser.selectedBrowser.contentWindow.focus();
});
},
onEnd: function()
{

View File

@ -113,4 +113,14 @@ function test() {
ok(isApproxVec(renderer.mvMatrix, [
1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1
]), "The origin wasn't reset to identity correctly.");
renderer.translate(1, 2);
ok(isApproxVec(renderer.mvMatrix, [
1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 2, 0, 1
]), "The second translation transformation wasn't applied correctly.");
renderer.scale(3, 4);
ok(isApproxVec(renderer.mvMatrix, [
3, 0, 0, 0, 0, 4, 0, 0, 0, 0, 1, 0, 1, 2, 0, 1
]), "The second scale transformation wasn't applied correctly.");
}

View File

@ -99,6 +99,8 @@ function testPresenter(presenter) {
"The presenter highlight fourth vertex should be initially zeroed.");
ok(presenter.transforms,
"The presenter transforms wasn't initialized properly.");
ok(isApproxVec(presenter.transforms.zoom, 1),
"The presenter transforms zoom should be initially 1.");
ok(isApproxVec(presenter.transforms.offset, [0, 0, 0]),
"The presenter transforms offset should be initially zeroed.");
ok(isApproxVec(presenter.transforms.translation, [0, 0, 0]),

View File

@ -0,0 +1,98 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/*global ok, is, info, waitForExplicitFinish, finish, executeSoon, gBrowser */
/*global isApprox, isTiltEnabled, isWebGLSupported, createTab, createTilt */
/*global Services, EventUtils, TiltUtils, InspectorUI, TILT_DESTROYED */
"use strict";
const ZOOM = 2;
const RESIZE = 50;
function setZoom(value) {
gBrowser.selectedBrowser.markupDocumentViewer.fullZoom = value;
}
function getZoom() {
return gBrowser.selectedBrowser.markupDocumentViewer.fullZoom;
}
function test() {
setZoom(Math.random());
is(getZoom(), TiltUtils.getDocumentZoom(),
"The getDocumentZoom utility function didn't return the expected results.");
if (!isTiltEnabled()) {
info("Skipping controller test because Tilt isn't enabled.");
return;
}
if (!isWebGLSupported()) {
info("Skipping controller test because WebGL isn't supported.");
return;
}
waitForExplicitFinish();
createTab(function() {
createTilt({
onInspectorOpen: function()
{
setZoom(ZOOM);
},
onTiltOpen: function(instance)
{
ok(isApprox(instance.presenter.transforms.zoom, ZOOM),
"The presenter transforms zoom wasn't initially set correctly.");
let contentWindow = gBrowser.selectedBrowser.contentWindow;
let initialWidth = contentWindow.innerWidth;
let initialHeight = contentWindow.innerHeight;
let renderer = instance.presenter.renderer;
let arcball = instance.controller.arcball;
ok(isApprox(contentWindow.innerWidth * ZOOM, renderer.width, 1),
"The renderer width wasn't set correctly.");
ok(isApprox(contentWindow.innerHeight * ZOOM, renderer.height, 1),
"The renderer height wasn't set correctly.");
ok(isApprox(contentWindow.innerWidth * ZOOM, arcball.width, 1),
"The arcball width wasn't set correctly.");
ok(isApprox(contentWindow.innerHeight * ZOOM, arcball.height, 1),
"The arcball height wasn't set correctly.");
window.resizeBy(-RESIZE * ZOOM, -RESIZE * ZOOM);
executeSoon(function() {
ok(isApprox(contentWindow.innerWidth + RESIZE, initialWidth, 1),
"The content window width wasn't set correctly.");
ok(isApprox(contentWindow.innerHeight + RESIZE, initialHeight, 1),
"The content window height wasn't set correctly.");
ok(isApprox(contentWindow.innerWidth * ZOOM, renderer.width, 1),
"The renderer width wasn't set correctly.");
ok(isApprox(contentWindow.innerHeight * ZOOM, renderer.height, 1),
"The renderer height wasn't set correctly.");
ok(isApprox(contentWindow.innerWidth * ZOOM, arcball.width, 1),
"The arcball width wasn't set correctly.");
ok(isApprox(contentWindow.innerHeight * ZOOM, arcball.height, 1),
"The arcball height wasn't set correctly.");
window.resizeBy(RESIZE * ZOOM, RESIZE * ZOOM);
Services.obs.addObserver(cleanup, TILT_DESTROYED, false);
InspectorUI.closeInspectorUI();
});
},
});
});
}
function cleanup() {
Services.obs.removeObserver(cleanup, TILT_DESTROYED);
gBrowser.removeCurrentTab();
finish();
}

View File

@ -1,7 +1,7 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/*global Services, Components, gBrowser, executeSoon */
/*global Services, Components, gBrowser, executeSoon, info */
/*global InspectorUI, Tilt, TiltGL, EPSILON */
"use strict";
@ -53,16 +53,24 @@ function isWebGLSupported() {
return TiltGL.isWebGLSupported() && TiltGL.create3DContext(createCanvas());
}
function isApprox(num1, num2) {
return Math.abs(num1 - num2) < EPSILON;
function isApprox(num1, num2, delta) {
if (Math.abs(num1 - num2) > (delta || EPSILON)) {
info("isApprox expected " + num1 + ", got " + num2 + " instead.");
return false;
}
return true;
}
function isApproxVec(vec1, vec2) {
function isApproxVec(vec1, vec2, delta) {
vec1 = Array.prototype.slice.call(vec1);
vec2 = Array.prototype.slice.call(vec2);
if (vec1.length !== vec2.length) {
return false;
}
for (let i = 0, len = vec1.length; i < len; i++) {
if (!isApprox(vec1[i], vec2[i])) {
if (!isApprox(vec1[i], vec2[i], delta)) {
info("isApproxVec expected [" + vec1 + "], got [" + vec2 + "] instead.");
return false;
}
}
@ -70,11 +78,15 @@ function isApproxVec(vec1, vec2) {
}
function isEqualVec(vec1, vec2) {
vec1 = Array.prototype.slice.call(vec1);
vec2 = Array.prototype.slice.call(vec2);
if (vec1.length !== vec2.length) {
return false;
}
for (let i = 0, len = vec1.length; i < len; i++) {
if (vec1[i] !== vec2[i]) {
info("isEqualVec expected [" + vec1 + "], got [" + vec2 + "] instead.");
return false;
}
}