| Index: chrome/browser/ui/cocoa/tabpose_window.mm
|
| diff --git a/chrome/browser/ui/cocoa/tabpose_window.mm b/chrome/browser/ui/cocoa/tabpose_window.mm
|
| index 76865815c5d9be50e40d4a051d9b280f8be9d6b2..7f96f5945505af8b53ac6a745a1a691e3b25d859 100644
|
| --- a/chrome/browser/ui/cocoa/tabpose_window.mm
|
| +++ b/chrome/browser/ui/cocoa/tabpose_window.mm
|
| @@ -369,6 +369,17 @@ static float FitNRectsWithAspectIntoBoundingSizeWithConstantPadding(
|
|
|
| namespace tabpose {
|
|
|
| +CGFloat ScaleWithOrigin(CGFloat x, CGFloat origin, CGFloat scale) {
|
| + return (x - origin) * scale + origin;
|
| +}
|
| +
|
| +NSRect ScaleRectWithOrigin(NSRect r, NSPoint p, CGFloat scale) {
|
| + return NSMakeRect(ScaleWithOrigin(NSMinX(r), p.x, scale),
|
| + ScaleWithOrigin(NSMinY(r), p.y, scale),
|
| + NSWidth(r) * scale,
|
| + NSHeight(r) * scale);
|
| +}
|
| +
|
| // A tile is what is shown for a single tab in tabpose mode. It consists of a
|
| // title, favicon, thumbnail image, and pre- and postanimation rects.
|
| class Tile {
|
| @@ -432,7 +443,9 @@ NSRect Tile::GetStartRectRelativeTo(const Tile& tile) const {
|
|
|
| NSRect Tile::GetFaviconStartRectRelativeTo(const Tile& tile) const {
|
| NSRect thumb_start = GetStartRectRelativeTo(tile);
|
| - NSRect rect = favicon_rect_;
|
| + CGFloat scale_to_start = NSWidth(thumb_start) / NSWidth(thumb_rect_);
|
| + NSRect rect =
|
| + ScaleRectWithOrigin(favicon_rect_, thumb_rect_.origin, scale_to_start);
|
| rect.origin.x += NSMinX(thumb_start) - NSMinX(thumb_rect_);
|
| rect.origin.y += NSMinY(thumb_start) - NSMinY(thumb_rect_);
|
| return rect;
|
| @@ -449,7 +462,9 @@ SkBitmap Tile::favicon() const {
|
|
|
| NSRect Tile::GetTitleStartRectRelativeTo(const Tile& tile) const {
|
| NSRect thumb_start = GetStartRectRelativeTo(tile);
|
| - NSRect rect = title_rect_;
|
| + CGFloat scale_to_start = NSWidth(thumb_start) / NSWidth(thumb_rect_);
|
| + NSRect rect =
|
| + ScaleRectWithOrigin(title_rect_, thumb_rect_.origin, scale_to_start);
|
| rect.origin.x += NSMinX(thumb_start) - NSMinX(thumb_rect_);
|
| rect.origin.y += NSMinY(thumb_start) - NSMinY(thumb_rect_);
|
| return rect;
|
| @@ -826,8 +841,10 @@ void TileSet::MoveTileFromTo(int from_index, int to_index) {
|
|
|
| } // namespace tabpose
|
|
|
| -void AnimateCALayerFrameFromTo(
|
| - CALayer* layer, const NSRect& from, const NSRect& to,
|
| +void AnimateScaledCALayerFrameFromTo(
|
| + CALayer* layer,
|
| + const NSRect& from, CGFloat from_scale,
|
| + const NSRect& to, CGFloat to_scale,
|
| NSTimeInterval duration, id boundsAnimationDelegate) {
|
| // http://developer.apple.com/mac/library/qa/qa2008/qa1620.html
|
| CABasicAnimation* animation;
|
| @@ -852,10 +869,10 @@ void AnimateCALayerFrameFromTo(
|
| NSPoint point = to.origin;
|
|
|
| // Adapt to anchorPoint.
|
| - opoint.x += NSWidth(from) * layer.anchorPoint.x;
|
| - opoint.y += NSHeight(from) * layer.anchorPoint.y;
|
| - point.x += NSWidth(to) * layer.anchorPoint.x;
|
| - point.y += NSHeight(to) * layer.anchorPoint.y;
|
| + opoint.x += NSWidth(from) * from_scale * layer.anchorPoint.x;
|
| + opoint.y += NSHeight(from) * from_scale * layer.anchorPoint.y;
|
| + point.x += NSWidth(to) * to_scale * layer.anchorPoint.x;
|
| + point.y += NSHeight(to) * to_scale * layer.anchorPoint.y;
|
|
|
| animation = [CABasicAnimation animationWithKeyPath:@"position"];
|
| animation.fromValue = [NSValue valueWithPoint:opoint];
|
| @@ -872,6 +889,13 @@ void AnimateCALayerFrameFromTo(
|
| [layer addAnimation:animation forKey:@"position"];
|
| }
|
|
|
| +void AnimateCALayerFrameFromTo(
|
| + CALayer* layer, const NSRect& from, const NSRect& to,
|
| + NSTimeInterval duration, id boundsAnimationDelegate) {
|
| + AnimateScaledCALayerFrameFromTo(
|
| + layer, from, 1.0, to, 1.0, duration, boundsAnimationDelegate);
|
| +}
|
| +
|
| void AnimateCALayerOpacityFromTo(
|
| CALayer* layer, double from, double to, NSTimeInterval duration) {
|
| CABasicAnimation* animation;
|
| @@ -1015,15 +1039,34 @@ void AnimateCALayerOpacityFromTo(
|
| [bgLayer_ addSublayer:faviconLayer];
|
| [allFaviconLayers_ addObject:faviconLayer];
|
|
|
| + // CATextLayers can't animate their fontSize property, at least on 10.5.
|
| + // Animate transform.scale instead.
|
| +
|
| + // The scaling should have its origin in the layer's upper left corner.
|
| + // This needs to be set before |AnimateCALayerFrameFromTo()| is called.
|
| CATextLayer* titleLayer = [CATextLayer layer];
|
| + titleLayer.anchorPoint = CGPointMake(0, 1);
|
| if (showZoom) {
|
| - AnimateCALayerFrameFromTo(
|
| - titleLayer,
|
| - tile.GetTitleStartRectRelativeTo(tileSet_->selected_tile()),
|
| - tile.title_rect(),
|
| - interval,
|
| - nil);
|
| - AnimateCALayerOpacityFromTo(titleLayer, 0.0, 1.0, interval);
|
| + NSRect fromRect =
|
| + tile.GetTitleStartRectRelativeTo(tileSet_->selected_tile());
|
| + NSRect toRect = tile.title_rect();
|
| + CGFloat scale = NSWidth(fromRect) / NSWidth(toRect);
|
| + fromRect.size = toRect.size;
|
| +
|
| + // Add scale animation.
|
| + CABasicAnimation* scaleAnimation =
|
| + [CABasicAnimation animationWithKeyPath:@"transform.scale"];
|
| + scaleAnimation.fromValue = [NSNumber numberWithDouble:scale];
|
| + scaleAnimation.toValue = [NSNumber numberWithDouble:1.0];
|
| + scaleAnimation.duration = interval;
|
| + scaleAnimation.timingFunction =
|
| + [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
|
| + [titleLayer addAnimation:scaleAnimation forKey:@"transform.scale"];
|
| +
|
| + // Add the position and opacity animations.
|
| + AnimateScaledCALayerFrameFromTo(
|
| + titleLayer, fromRect, scale, toRect, 1.0, interval, nil);
|
| + AnimateCALayerOpacityFromTo(faviconLayer, 0.0, 1.0, interval);
|
| } else {
|
| titleLayer.frame = NSRectToCGRect(tile.title_rect());
|
| }
|
| @@ -1239,6 +1282,52 @@ void AnimateCALayerOpacityFromTo(
|
| return action == @selector(commandDispatch:) && tag == IDC_TABPOSE;
|
| }
|
|
|
| +- (void)fadeAwayTileAtIndex:(int)index {
|
| + const tabpose::Tile& tile = tileSet_->tile_at(index);
|
| + CALayer* layer = [allThumbnailLayers_ objectAtIndex:index];
|
| + // Add a delegate to one of the implicit animations to get a notification
|
| + // once the animations are done.
|
| + if (static_cast<int>(index) == tileSet_->selected_index()) {
|
| + CAAnimation* animation = [CAAnimation animation];
|
| + animation.delegate = self;
|
| + [animation setValue:kAnimationIdFadeOut forKey:kAnimationIdKey];
|
| + [layer addAnimation:animation forKey:@"frame"];
|
| + }
|
| +
|
| + // Thumbnail.
|
| + layer.frame = NSRectToCGRect(
|
| + tile.GetStartRectRelativeTo(tileSet_->selected_tile()));
|
| +
|
| + if (static_cast<int>(index) == tileSet_->selected_index()) {
|
| + // Redraw layer at big resolution, so that zoom-in isn't blocky.
|
| + [layer setNeedsDisplay];
|
| + }
|
| +
|
| + // Title.
|
| + CALayer* faviconLayer = [allFaviconLayers_ objectAtIndex:index];
|
| + faviconLayer.frame = NSRectToCGRect(
|
| + tile.GetFaviconStartRectRelativeTo(tileSet_->selected_tile()));
|
| + faviconLayer.opacity = 0;
|
| +
|
| + // Favicon.
|
| + // The |fontSize| cannot be animated directly, animate the layer's scale
|
| + // instead. |transform.scale| affects the rendered width, so keep the small
|
| + // bounds.
|
| + CALayer* titleLayer = [allTitleLayers_ objectAtIndex:index];
|
| + NSRect titleRect = tile.title_rect();
|
| + NSRect titleToRect =
|
| + tile.GetTitleStartRectRelativeTo(tileSet_->selected_tile());
|
| + CGFloat scale = NSWidth(titleToRect) / NSWidth(titleRect);
|
| + titleToRect.origin.x +=
|
| + NSWidth(titleRect) * scale * titleLayer.anchorPoint.x;
|
| + titleToRect.origin.y +=
|
| + NSHeight(titleRect) * scale * titleLayer.anchorPoint.y;
|
| + titleLayer.position = NSPointToCGPoint(titleToRect.origin);
|
| + [titleLayer setValue:[NSNumber numberWithDouble:scale]
|
| + forKeyPath:@"transform.scale"];
|
| + titleLayer.opacity = 0;
|
| +}
|
| +
|
| - (void)fadeAway:(BOOL)slomo {
|
| if (state_ == tabpose::kFadingOut)
|
| return;
|
| @@ -1271,35 +1360,8 @@ void AnimateCALayerOpacityFromTo(
|
| CGFloat duration =
|
| 1.3 * kDefaultAnimationDuration * (slomo ? kSlomoFactor : 1);
|
| ScopedCAActionSetDuration durationSetter(duration);
|
| - for (int i = 0; i < tabStripModel_->count(); ++i) {
|
| - const tabpose::Tile& tile = tileSet_->tile_at(i);
|
| - CALayer* layer = [allThumbnailLayers_ objectAtIndex:i];
|
| - // Add a delegate to one of the implicit animations to get a notification
|
| - // once the animations are done.
|
| - if (static_cast<int>(i) == tileSet_->selected_index()) {
|
| - CAAnimation* animation = [CAAnimation animation];
|
| - animation.delegate = self;
|
| - [animation setValue:kAnimationIdFadeOut forKey:kAnimationIdKey];
|
| - [layer addAnimation:animation forKey:@"frame"];
|
| - }
|
| -
|
| - layer.frame = NSRectToCGRect(
|
| - tile.GetStartRectRelativeTo(tileSet_->selected_tile()));
|
| -
|
| - if (static_cast<int>(i) == tileSet_->selected_index()) {
|
| - // Redraw layer at big resolution, so that zoom-in isn't blocky.
|
| - [layer setNeedsDisplay];
|
| - }
|
| -
|
| - CALayer* faviconLayer = [allFaviconLayers_ objectAtIndex:i];
|
| - faviconLayer.frame = NSRectToCGRect(
|
| - tile.GetFaviconStartRectRelativeTo(tileSet_->selected_tile()));
|
| - faviconLayer.opacity = 0;
|
| - CALayer* titleLayer = [allTitleLayers_ objectAtIndex:i];
|
| - titleLayer.frame = NSRectToCGRect(
|
| - tile.GetTitleStartRectRelativeTo(tileSet_->selected_tile()));
|
| - titleLayer.opacity = 0;
|
| - }
|
| + for (int i = 0; i < tabStripModel_->count(); ++i)
|
| + [self fadeAwayTileAtIndex:i];
|
| }
|
|
|
| - (void)animationDidStop:(CAAnimation*)animation finished:(BOOL)finished {
|
|
|