Bug 624931 - Use -moz-transform for Panorama zoom. r=iangilman a=sdwilsh

This commit is contained in:
Patrick Walton 2011-01-31 16:41:05 -08:00
parent ce990249cb
commit c7d0f009c3
6 changed files with 155 additions and 100 deletions

View File

@ -2356,10 +2356,8 @@ let GroupItems = {
if (shouldUpdateTabBar)
this._updateTabBar();
else if (shouldShowTabView) {
tab._tabViewTabItem.setZoomPrep(false);
else if (shouldShowTabView)
UI.showTabView();
}
},
// ----------

View File

@ -94,7 +94,6 @@ function TabItem(tab, options) {
this.defaultSize = new Point(TabItems.tabWidth, TabItems.tabHeight);
this._hidden = false;
this.isATabItem = true;
this._zoomPrep = false;
this.sizeExtra = new Point();
this.keepProportional = true;
this._hasBeenDrawn = false;
@ -428,9 +427,6 @@ TabItem.prototype = Utils.extend(new Item(), new Subscribable(), {
let rect = new Rect(inRect.left, inRect.top,
validSize.x, validSize.y);
if (this._zoomPrep)
this.bounds.copy(rect);
else {
var css = {};
if (rect.left != this.bounds.left || options.force)
@ -520,7 +516,6 @@ TabItem.prototype = Utils.extend(new Item(), new Subscribable(), {
}
this._hasBeenDrawn = true;
}
UI.clearShouldResizeItems();
@ -625,17 +620,22 @@ TabItem.prototype = Utils.extend(new Item(), new Subscribable(), {
return;
var self = this;
var $tabEl = this.$container;
var $tabEl = this.$container, $canvas = this.$canvas;
var childHitResult = { shouldZoom: true };
if (this.parent)
childHitResult = this.parent.childHit(this);
this.shouldHideCachedData = true;
TabItems._update(this.tab);
if (childHitResult.shouldZoom) {
// Zoom in!
var tab = this.tab;
var orig = $tabEl.bounds();
function onZoomDone() {
$canvas.css({ '-moz-transform': null });
$tabEl.removeClass("front");
UI.goToTab(tab);
// tab might not be selected because hideTabView() is invoked after
@ -652,9 +652,13 @@ TabItem.prototype = Utils.extend(new Item(), new Subscribable(), {
let animateZoom = gPrefBranch.getBoolPref("animate_zoom");
if (animateZoom) {
let transform = this.getZoomTransform();
TabItems.pausePainting();
$tabEl.addClass("front")
.animate(this.getZoomRect(), {
$tabEl.addClass("front");
$canvas
.css({ '-moz-transform-origin': transform.transformOrigin })
.animate({ '-moz-transform': transform.transform }, {
duration: 230,
easing: 'fast',
complete: function() {
@ -662,10 +666,6 @@ TabItem.prototype = Utils.extend(new Item(), new Subscribable(), {
setTimeout(function() {
TabItems.resumePainting();
$tabEl
.css(orig)
.removeClass("front");
}, 0);
}
});
@ -683,34 +683,35 @@ TabItem.prototype = Utils.extend(new Item(), new Subscribable(), {
// Parameters:
// complete - a function to call after the zoom down animation
zoomOut: function TabItem_zoomOut(complete) {
var $tab = this.$container;
let $tab = this.$container, $canvas = this.$canvas;
var self = this;
let onZoomDone = function onZoomDone() {
self.setZoomPrep(false);
$tab.removeClass("front");
$canvas.css("-moz-transform", null);
GroupItems.setActiveOrphanTab(null);
if (typeof complete == "function")
complete();
};
this.shouldHideCachedData = true;
TabItems._update(this.tab);
$tab.addClass("front");
let animateZoom = gPrefBranch.getBoolPref("animate_zoom");
if (animateZoom) {
let box = this.getBounds();
box.width -= this.sizeExtra.x;
if (!this.isStacked)
box.height -= this.sizeExtra.y + TabItems.fontSizeRange.max;
else
box.height -= this.sizeExtra.y;
TabItems.pausePainting();
$tab.animate({
left: box.left,
top: box.top,
width: box.width,
height: box.height
}, {
// The scaleCheat of 2 here is a clever way to speed up the zoom-out
// code. See getZoomTransform() below.
let transform = this.getZoomTransform(2);
$canvas.css({
'-moz-transform': transform.transform,
'-moz-transform-origin': transform.transformOrigin
});
$canvas.animate({ "-moz-transform": "scale(1.0)" }, {
duration: 300,
easing: 'cubic-bezier', // note that this is legal easing, even without parameters
complete: function() {
@ -724,65 +725,42 @@ TabItem.prototype = Utils.extend(new Item(), new Subscribable(), {
},
// ----------
// Function: getZoomRect
// Returns a faux rect (just an object with top, left, width, height)
// which represents the maximum bounds of the tab thumbnail in the zoom
// animation. Note that this is not just the rect of the window itself,
// due to scaleCheat.
getZoomRect: function TabItem_getZoomRect(scaleCheat) {
let $tabEl = iQ(this.container);
let orig = $tabEl.bounds();
// Function: getZoomTransform
// Returns the transform function which represents the maximum bounds of the
// tab thumbnail in the zoom animation.
getZoomTransform: function TabItem_getZoomTransform(scaleCheat) {
// Taking the bounds of the container (as opposed to the canvas) makes us
// immune to any transformations applied to the canvas.
let { left, top, width, height, right, bottom } = this.$container.bounds();
let { innerWidth: windowWidth, innerHeight: windowHeight } = window;
// The scaleCheat is a clever way to speed up the zoom-in code.
// Because image scaling is slowest on big images, we cheat and stop
// the image at scaled-down size and placed accordingly. Because the
// animation is fast, you can't see the difference but it feels a lot
// zippier. The only trick is choosing the right animation function so
// that you don't see a change in percieved animation speed.
// that you don't see a change in percieved animation speed from frame #1
// (the tab) to frame #2 (the half-size image) to frame #3 (the first frame
// of real animation). Choosing an animation that starts fast is key.
if (!scaleCheat)
scaleCheat = 1.7;
let zoomWidth = orig.width + (window.innerWidth - orig.width) / scaleCheat;
let zoomWidth = width + (window.innerWidth - width) / scaleCheat;
let zoomScaleFactor = zoomWidth / width;
let zoomHeight = height * zoomScaleFactor;
let zoomTop = top * (1 - 1/scaleCheat);
let zoomLeft = left * (1 - 1/scaleCheat);
let xOrigin = (left - zoomLeft) / ((left - zoomLeft) + (zoomLeft + zoomWidth - right)) * 100;
let yOrigin = (top - zoomTop) / ((top - zoomTop) + (zoomTop + zoomHeight - bottom)) * 100;
return {
top: orig.top * (1 - 1/scaleCheat),
left: orig.left * (1 - 1/scaleCheat),
width: zoomWidth,
height: (orig.width ? orig.height * zoomWidth / orig.width : 0)
transformOrigin: xOrigin + "% " + yOrigin + "%",
transform: "scale(" + zoomScaleFactor + ")"
};
},
// ----------
// Function: setZoomPrep
// Either go into or return from (depending on <value>) "zoom prep" mode,
// where the tab fills a large portion of the screen in anticipation of
// the zoom out animation.
setZoomPrep: function TabItem_setZoomPrep(value) {
let animateZoom = gPrefBranch.getBoolPref("animate_zoom");
var $div = this.$container;
if (value && animateZoom) {
this._zoomPrep = true;
// The scaleCheat of 2 here is a clever way to speed up the zoom-out code.
// Because image scaling is slowest on big images, we cheat and start the image
// at half-size and placed accordingly. Because the animation is fast, you can't
// see the difference but it feels a lot zippier. The only trick is choosing the
// right animation function so that you don't see a change in percieved
// animation speed from frame #1 (the tab) to frame #2 (the half-size image) to
// frame #3 (the first frame of real animation). Choosing an animation that starts
// fast is key.
$div
.addClass('front')
.css(this.getZoomRect(2));
} else {
let box = this.getBounds();
this._zoomPrep = false;
$div.removeClass('front');
this.setBounds(box, true, {force: true});
}
}
});

View File

@ -86,12 +86,14 @@ body {
.front {
z-index: 999999 !important;
border-radius: 0 !important;
box-shadow: none !important;
-moz-transform: none !important;
image-rendering: -moz-crisp-edges;
}
.front canvas {
border: none !important;
padding: 1px !important;
}
/* Groups
----------------------------------*/

View File

@ -515,9 +515,6 @@ let UI = {
TabItems.resumePainting();
});
} else {
if (currentTab && currentTab._tabViewTabItem)
currentTab._tabViewTabItem.setZoomPrep(false);
self.setActiveTab(null);
dispatchEvent(event);
@ -744,9 +741,6 @@ let UI = {
if (closingLastOfGroup || closingUnnamedGroup) {
// for the tab focus event to pick up.
self._closedLastVisibleTab = true;
// remove the zoom prep.
if (tab && tab._tabViewTabItem)
tab._tabViewTabItem.setZoomPrep(false);
self.showTabView();
}
}
@ -886,15 +880,6 @@ let UI = {
if (GroupItems.getActiveGroupItem() || GroupItems.getActiveOrphanTab())
GroupItems._updateTabBar();
}
// ___ prepare for when we return to TabView
if (newItem != oldItem) {
if (oldItem)
oldItem.setZoomPrep(false);
if (newItem)
newItem.setZoomPrep(true);
} else if (oldItem)
oldItem.setZoomPrep(true);
},
// ----------

View File

@ -89,6 +89,7 @@ _BROWSER_FILES = \
browser_tabview_bug622835.js \
browser_tabview_bug622872.js \
browser_tabview_bug624265.js \
browser_tabview_bug624931.js \
browser_tabview_bug624727.js \
browser_tabview_bug624953.js \
browser_tabview_bug625269.js \

View File

@ -0,0 +1,91 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Tests that there is a transform being applied to the tabs as they zoom in
// and out.
let tab, frontChanged, transformChanged;
function test() {
waitForExplicitFinish();
window.addEventListener("tabviewshown", onTabViewWindowLoaded, false);
TabView.toggle();
}
function onTabViewWindowLoaded() {
window.removeEventListener("tabviewshown", onTabViewWindowLoaded, false);
let contentWindow = document.getElementById("tab-view").contentWindow;
tab = contentWindow.UI.getActiveTab();
ok(tab, "We have an active tab");
frontChanged = transformChanged = false;
tab.$container[0].addEventListener("DOMAttrModified", checkForFrontAddition,
false);
tab.$canvas[0].addEventListener("DOMAttrModified", checkForTransformAddition,
false);
window.addEventListener("tabviewhidden", onTabViewHidden, false);
TabView.toggle();
}
function checkForFrontAddition(aEvent) {
if (aEvent.attrName == "class" &&
aEvent.target.classList.contains("front")) {
frontChanged = true;
}
}
function checkForTransformAddition(aEvent) {
if (aEvent.attrName == "style" && aEvent.target.style.MozTransform) {
transformChanged = true;
}
}
function onTabViewHidden() {
window.removeEventListener("tabviewhidden", onTabViewHidden, false);
ok(frontChanged, "the CSS class 'front' was added while zooming in");
ok(transformChanged, "the CSS class '-moz-transform' was modified while " +
"zooming in");
frontChanged = transformChanged = false;
tab.$container[0].removeEventListener("DOMAttrModified",
checkForFrontAddition, false);
tab.$container[0].addEventListener("DOMAttrModified", checkForFrontRemoval,
false);
window.addEventListener("tabviewshown", onTabViewShownAgain, false);
TabView.toggle();
}
function checkForFrontRemoval(aEvent) {
if (aEvent.attrName == "class" &&
!aEvent.target.classList.contains("front")) {
frontChanged = true;
}
}
function onTabViewShownAgain() {
window.removeEventListener("tabviewshown", onTabViewShownAgain, false);
ok(frontChanged, "the CSS class 'front' was removed while zooming out");
ok(transformChanged, "the CSS class 'transform' was removed while zooming " +
"out");
tab.$container[0].removeEventListener("DOMAttrModified",
checkForFrontRemoval, false);
tab.$canvas[0].removeEventListener("DOMAttrModified",
checkForTransformAddition, false);
window.addEventListener("tabviewhidden", onTabViewHiddenAgain, false);
TabView.toggle();
}
function onTabViewHiddenAgain() {
window.removeEventListener("tabviewhidden", onTabViewHiddenAgain, false);
finish();
}