| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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 #import "chrome/browser/cocoa/tab_view.h" | 5 #import "chrome/browser/cocoa/tab_view.h" |
| 6 | 6 |
| 7 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 #import "base/mac_util.h" | 8 #import "base/mac_util.h" |
| 9 #include "base/nsimage_cache_mac.h" | 9 #include "base/nsimage_cache_mac.h" |
| 10 #include "base/scoped_cftyperef.h" | 10 #include "base/scoped_cftyperef.h" |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 43 | 43 |
| 44 } // namespace | 44 } // namespace |
| 45 | 45 |
| 46 @interface TabView(Private) | 46 @interface TabView(Private) |
| 47 | 47 |
| 48 - (void)resetLastGlowUpdateTime; | 48 - (void)resetLastGlowUpdateTime; |
| 49 - (NSTimeInterval)timeElapsedSinceLastGlowUpdate; | 49 - (NSTimeInterval)timeElapsedSinceLastGlowUpdate; |
| 50 - (void)adjustGlowValue; | 50 - (void)adjustGlowValue; |
| 51 // TODO(davidben): When we stop supporting 10.5, this can be removed. | 51 // TODO(davidben): When we stop supporting 10.5, this can be removed. |
| 52 - (int)getWorkspaceID:(NSWindow*)window useCache:(BOOL)useCache; | 52 - (int)getWorkspaceID:(NSWindow*)window useCache:(BOOL)useCache; |
| 53 - (NSBezierPath*)bezierPathForRect:(NSRect)rect; |
| 53 | 54 |
| 54 @end // TabView(Private) | 55 @end // TabView(Private) |
| 55 | 56 |
| 56 @implementation TabView | 57 @implementation TabView |
| 57 | 58 |
| 58 @synthesize state = state_; | 59 @synthesize state = state_; |
| 59 @synthesize hoverAlpha = hoverAlpha_; | 60 @synthesize hoverAlpha = hoverAlpha_; |
| 60 @synthesize alertAlpha = alertAlpha_; | 61 @synthesize alertAlpha = alertAlpha_; |
| 61 @synthesize closing = closing_; | 62 @synthesize closing = closing_; |
| 62 | 63 |
| (...skipping 546 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 609 NSPoint upLocation = | 610 NSPoint upLocation = |
| 610 [[self superview] convertPoint:[theEvent locationInWindow] | 611 [[self superview] convertPoint:[theEvent locationInWindow] |
| 611 fromView:nil]; | 612 fromView:nil]; |
| 612 // If the mouse up occurred in our view or over the close button, then | 613 // If the mouse up occurred in our view or over the close button, then |
| 613 // close. | 614 // close. |
| 614 if ([self hitTest:upLocation]) | 615 if ([self hitTest:upLocation]) |
| 615 [controller_ closeTab:self]; | 616 [controller_ closeTab:self]; |
| 616 } | 617 } |
| 617 } | 618 } |
| 618 | 619 |
| 619 - (void)drawRect:(NSRect)rect { | 620 - (void)drawRect:(NSRect)dirtyRect { |
| 620 // If this tab is phantom, do not draw the tab background itself. The only UI | 621 // If this tab is phantom, do not draw the tab background itself. The only UI |
| 621 // element that will represent this tab is the favicon. | 622 // element that will represent this tab is the favicon. |
| 622 if ([controller_ phantom]) | 623 if ([controller_ phantom]) |
| 623 return; | 624 return; |
| 624 | 625 |
| 625 NSGraphicsContext* context = [NSGraphicsContext currentContext]; | 626 NSGraphicsContext* context = [NSGraphicsContext currentContext]; |
| 626 [context saveGraphicsState]; | 627 [context saveGraphicsState]; |
| 627 rect = [self bounds]; | |
| 628 BOOL active = [[self window] isKeyWindow] || [[self window] isMainWindow]; | |
| 629 BOOL selected = [self state]; | |
| 630 | |
| 631 // Outset by 0.5 in order to draw on pixels rather than on borders (which | |
| 632 // would cause blurry pixels). Subtract 1px of height to compensate, otherwise | |
| 633 // clipping will occur. | |
| 634 rect = NSInsetRect(rect, -0.5, -0.5); | |
| 635 rect.size.height -= 1.0; | |
| 636 | |
| 637 NSPoint bottomLeft = NSMakePoint(NSMinX(rect), NSMinY(rect) + 2); | |
| 638 NSPoint bottomRight = NSMakePoint(NSMaxX(rect), NSMinY(rect) + 2); | |
| 639 NSPoint topRight = | |
| 640 NSMakePoint(NSMaxX(rect) - kInsetMultiplier * NSHeight(rect), | |
| 641 NSMaxY(rect)); | |
| 642 NSPoint topLeft = | |
| 643 NSMakePoint(NSMinX(rect) + kInsetMultiplier * NSHeight(rect), | |
| 644 NSMaxY(rect)); | |
| 645 | |
| 646 CGFloat baseControlPointOutset = NSHeight(rect) * kControlPoint1Multiplier; | |
| 647 CGFloat bottomControlPointInset = NSHeight(rect) * kControlPoint2Multiplier; | |
| 648 | |
| 649 // Outset many of these values by 1 to cause the fill to bleed outside the | |
| 650 // clip area. | |
| 651 NSBezierPath* path = [NSBezierPath bezierPath]; | |
| 652 [path moveToPoint:NSMakePoint(bottomLeft.x - 1, bottomLeft.y - 2)]; | |
| 653 [path lineToPoint:NSMakePoint(bottomLeft.x - 1, bottomLeft.y)]; | |
| 654 [path lineToPoint:bottomLeft]; | |
| 655 [path curveToPoint:topLeft | |
| 656 controlPoint1:NSMakePoint(bottomLeft.x + baseControlPointOutset, | |
| 657 bottomLeft.y) | |
| 658 controlPoint2:NSMakePoint(topLeft.x - bottomControlPointInset, | |
| 659 topLeft.y)]; | |
| 660 [path lineToPoint:topRight]; | |
| 661 [path curveToPoint:bottomRight | |
| 662 controlPoint1:NSMakePoint(topRight.x + bottomControlPointInset, | |
| 663 topRight.y) | |
| 664 controlPoint2:NSMakePoint(bottomRight.x - baseControlPointOutset, | |
| 665 bottomRight.y)]; | |
| 666 [path lineToPoint:NSMakePoint(bottomRight.x + 1, bottomRight.y)]; | |
| 667 [path lineToPoint:NSMakePoint(bottomRight.x + 1, bottomRight.y - 2)]; | |
| 668 | 628 |
| 669 ThemeProvider* themeProvider = [[self window] themeProvider]; | 629 ThemeProvider* themeProvider = [[self window] themeProvider]; |
| 630 [context setPatternPhase:[[self window] themePatternPhase]]; |
| 670 | 631 |
| 671 // Set the pattern phase. | 632 NSRect rect = [self bounds]; |
| 672 NSPoint phase = [[self window] themePatternPhase]; | 633 NSBezierPath* path = [self bezierPathForRect:rect]; |
| 673 [context setPatternPhase:phase]; | |
| 674 | 634 |
| 635 BOOL selected = [self state]; |
| 675 // Don't draw the window/tab bar background when selected, since the tab | 636 // Don't draw the window/tab bar background when selected, since the tab |
| 676 // background overlay drawn over it (see below) will be fully opaque. | 637 // background overlay drawn over it (see below) will be fully opaque. |
| 677 BOOL hasBackgroundImage = NO; | 638 BOOL hasBackgroundImage = NO; |
| 678 if (!selected) { | 639 if (!selected) { |
| 679 // ThemeProvider::HasCustomImage is true only if the theme provides the | 640 // ThemeProvider::HasCustomImage is true only if the theme provides the |
| 680 // image. However, even if the theme doesn't provide a tab background, the | 641 // image. However, even if the theme doesn't provide a tab background, the |
| 681 // theme machinery will make one if given a frame image. See | 642 // theme machinery will make one if given a frame image. See |
| 682 // BrowserThemePack::GenerateTabBackgroundImages for details. | 643 // BrowserThemePack::GenerateTabBackgroundImages for details. |
| 683 hasBackgroundImage = themeProvider && | 644 hasBackgroundImage = themeProvider && |
| 684 (themeProvider->HasCustomImage(IDR_THEME_TAB_BACKGROUND) || | 645 (themeProvider->HasCustomImage(IDR_THEME_TAB_BACKGROUND) || |
| 685 themeProvider->HasCustomImage(IDR_THEME_FRAME)); | 646 themeProvider->HasCustomImage(IDR_THEME_FRAME)); |
| 686 | 647 |
| 687 NSColor* backgroundImageColor = | 648 NSColor* backgroundImageColor = hasBackgroundImage ? |
| 688 hasBackgroundImage ? | 649 themeProvider->GetNSImageColorNamed(IDR_THEME_TAB_BACKGROUND, true) : |
| 689 themeProvider->GetNSImageColorNamed(IDR_THEME_TAB_BACKGROUND, true) : | 650 nil; |
| 690 nil; | 651 |
| 691 if (backgroundImageColor) { | 652 if (backgroundImageColor) { |
| 692 [backgroundImageColor set]; | 653 [backgroundImageColor set]; |
| 693 [path fill]; | 654 [path fill]; |
| 694 } else { | 655 } else { |
| 695 // Use the window's background color rather than |[NSColor | 656 // Use the window's background color rather than |[NSColor |
| 696 // windowBackgroundColor]|, which gets confused by the fullscreen window. | 657 // windowBackgroundColor]|, which gets confused by the fullscreen window. |
| 697 // (The result is the same for normal, non-fullscreen windows.) | 658 // (The result is the same for normal, non-fullscreen windows.) |
| 698 [[[self window] backgroundColor] set]; | 659 [[[self window] backgroundColor] set]; |
| 699 [path fill]; | 660 [path fill]; |
| 700 [[NSColor colorWithCalibratedWhite:1.0 alpha:0.3] set]; | 661 [[NSColor colorWithCalibratedWhite:1.0 alpha:0.3] set]; |
| 701 [path fill]; | 662 [path fill]; |
| 702 } | 663 } |
| 703 } | 664 } |
| 704 | 665 |
| 705 [context saveGraphicsState]; | 666 [context saveGraphicsState]; |
| 706 [path addClip]; | 667 [path addClip]; |
| 707 | 668 |
| 708 // Use the same overlay for the selected state and for hover and alert glows; | 669 // Use the same overlay for the selected state and for hover and alert glows; |
| 709 // for the selected state, it's fully opaque. | 670 // for the selected state, it's fully opaque. |
| 710 CGFloat hoverAlpha = [self hoverAlpha]; | 671 CGFloat hoverAlpha = [self hoverAlpha]; |
| 711 CGFloat alertAlpha = [self alertAlpha]; | 672 CGFloat alertAlpha = [self alertAlpha]; |
| 712 if (selected || hoverAlpha > 0 || alertAlpha > 0) { | 673 if (selected || hoverAlpha > 0 || alertAlpha > 0) { |
| 713 // Draw the selected background / glow overlay. | 674 // Draw the selected background / glow overlay. |
| 714 [context saveGraphicsState]; | 675 [context saveGraphicsState]; |
| 715 CGContextRef cgContext = | 676 CGContextRef cgContext = static_cast<CGContextRef>([context graphicsPort]); |
| 716 (CGContextRef)([context graphicsPort]); | |
| 717 CGContextBeginTransparencyLayer(cgContext, 0); | 677 CGContextBeginTransparencyLayer(cgContext, 0); |
| 718 if (!selected) { | 678 if (!selected) { |
| 719 // The alert glow overlay is like the selected state but at most at most | 679 // The alert glow overlay is like the selected state but at most at most |
| 720 // 80% opaque. The hover glow brings up the overlay's opacity at most 50%. | 680 // 80% opaque. The hover glow brings up the overlay's opacity at most 50%. |
| 721 CGFloat backgroundAlpha = 0.8 * alertAlpha; | 681 CGFloat backgroundAlpha = 0.8 * alertAlpha; |
| 722 backgroundAlpha += (1 - backgroundAlpha) * 0.5 * hoverAlpha; | 682 backgroundAlpha += (1 - backgroundAlpha) * 0.5 * hoverAlpha; |
| 723 CGContextSetAlpha(cgContext, backgroundAlpha); | 683 CGContextSetAlpha(cgContext, backgroundAlpha); |
| 724 } | 684 } |
| 725 [path addClip]; | 685 [path addClip]; |
| 726 [context saveGraphicsState]; | 686 [context saveGraphicsState]; |
| 727 [super drawBackground]; | 687 [super drawBackground]; |
| 728 [context restoreGraphicsState]; | 688 [context restoreGraphicsState]; |
| 729 | 689 |
| 730 // Draw a mouse hover gradient for the default themes. | 690 // Draw a mouse hover gradient for the default themes. |
| 731 if (!selected && hoverAlpha > 0) { | 691 if (!selected && hoverAlpha > 0) { |
| 732 if (themeProvider && !hasBackgroundImage) { | 692 if (themeProvider && !hasBackgroundImage) { |
| 733 scoped_nsobject<NSGradient> glow([NSGradient alloc]); | 693 scoped_nsobject<NSGradient> glow([NSGradient alloc]); |
| 734 [glow initWithStartingColor:[NSColor colorWithCalibratedWhite:1.0 | 694 [glow initWithStartingColor:[NSColor colorWithCalibratedWhite:1.0 |
| 735 alpha:1.0 * hoverAlpha] | 695 alpha:1.0 * hoverAlpha] |
| 736 endingColor:[NSColor colorWithCalibratedWhite:1.0 | 696 endingColor:[NSColor colorWithCalibratedWhite:1.0 |
| 737 alpha:0.0]]; | 697 alpha:0.0]]; |
| 738 | 698 |
| 739 NSPoint point = hoverPoint_; | 699 NSPoint point = hoverPoint_; |
| 740 point.y = NSHeight(rect); | 700 point.y = NSHeight(rect); |
| 741 [glow drawFromCenter:point | 701 [glow drawFromCenter:point |
| 742 radius:0 | 702 radius:0.0 |
| 743 toCenter:point | 703 toCenter:point |
| 744 radius:NSWidth(rect)/3 | 704 radius:NSWidth(rect) / 3.0 |
| 745 options:NSGradientDrawsBeforeStartingLocation]; | 705 options:NSGradientDrawsBeforeStartingLocation]; |
| 746 | 706 |
| 747 [glow drawInBezierPath:path relativeCenterPosition:hoverPoint_]; | 707 [glow drawInBezierPath:path relativeCenterPosition:hoverPoint_]; |
| 748 } | 708 } |
| 749 } | 709 } |
| 750 | 710 |
| 751 CGContextEndTransparencyLayer(cgContext); | 711 CGContextEndTransparencyLayer(cgContext); |
| 752 [context restoreGraphicsState]; | 712 [context restoreGraphicsState]; |
| 753 } | 713 } |
| 754 | 714 |
| 755 // Draw the top inner highlight. | 715 BOOL active = [[self window] isKeyWindow] || [[self window] isMainWindow]; |
| 756 NSAffineTransform* highlightTransform = [NSAffineTransform transform]; | 716 CGFloat borderAlpha = selected ? (active ? 0.3 : 0.2) : 0.2; |
| 757 [highlightTransform translateXBy:1 yBy:-1]; | 717 NSColor* borderColor = [NSColor colorWithDeviceWhite:0.0 alpha:borderAlpha]; |
| 758 scoped_nsobject<NSBezierPath> highlightPath([path copy]); | 718 NSColor* highlightColor = [NSColor colorWithCalibratedWhite:0.96 alpha:1.0]; |
| 759 [highlightPath transformUsingAffineTransform:highlightTransform]; | 719 |
| 760 [[NSColor colorWithCalibratedWhite:1.0 alpha:0.2 + 0.3 * hoverAlpha] | 720 // Draw the top inner highlight within the currently selected tab. |
| 761 setStroke]; | 721 if (selected) { |
| 762 [highlightPath stroke]; | 722 NSAffineTransform* highlightTransform = [NSAffineTransform transform]; |
| 723 [highlightTransform translateXBy:1.0 yBy:-1.0]; |
| 724 scoped_nsobject<NSBezierPath> highlightPath([path copy]); |
| 725 [highlightPath transformUsingAffineTransform:highlightTransform]; |
| 726 [highlightColor setStroke]; |
| 727 [highlightPath setLineWidth:1.0]; |
| 728 [highlightPath stroke]; |
| 729 highlightTransform = [NSAffineTransform transform]; |
| 730 [highlightTransform translateXBy:-2.0 yBy:0.0]; |
| 731 [highlightPath transformUsingAffineTransform:highlightTransform]; |
| 732 [highlightPath stroke]; |
| 733 } |
| 763 | 734 |
| 764 [context restoreGraphicsState]; | 735 [context restoreGraphicsState]; |
| 765 | 736 |
| 766 // Draw the top stroke. | 737 // Draw the top stroke. |
| 767 [context saveGraphicsState]; | 738 [context saveGraphicsState]; |
| 768 if (selected) { | 739 [borderColor set]; |
| 769 [[NSColor colorWithDeviceWhite:0.0 alpha:active ? 0.3 : 0.15] set]; | |
| 770 } else { | |
| 771 [[NSColor colorWithDeviceWhite:0.0 alpha:active ? 0.2 : 0.15] set]; | |
| 772 [[NSBezierPath bezierPathWithRect:NSOffsetRect(rect, 0, 2.5)] addClip]; | |
| 773 } | |
| 774 [path setLineWidth:1.0]; | 740 [path setLineWidth:1.0]; |
| 775 [path stroke]; | 741 [path stroke]; |
| 776 [context restoreGraphicsState]; | 742 [context restoreGraphicsState]; |
| 777 | 743 |
| 778 // Mimic the tab strip's bottom border, which consists of a dark border | 744 // Mimic the tab strip's bottom border, which consists of a dark border |
| 779 // and light highlight. | 745 // and light highlight. |
| 780 if (!selected) { | 746 if (!selected) { |
| 781 [path addClip]; | 747 [path addClip]; |
| 782 NSRect borderRect = rect; | 748 NSRect borderRect = rect; |
| 783 borderRect.origin.y = 1; | 749 borderRect.origin.y = 1; |
| 784 borderRect.size.height = 1; | 750 borderRect.size.height = 1; |
| 785 [[NSColor colorWithDeviceWhite:0.0 alpha:active ? 0.2 : 0.15] set]; | 751 [borderColor set]; |
| 786 NSRectFillUsingOperation(borderRect, NSCompositeSourceOver); | 752 NSRectFillUsingOperation(borderRect, NSCompositeSourceOver); |
| 787 | 753 |
| 788 borderRect.origin.y = 0; | 754 borderRect.origin.y = 0; |
| 789 [[NSColor colorWithCalibratedWhite:0.96 alpha:1.0] set]; | 755 [highlightColor set]; |
| 790 NSRectFillUsingOperation(borderRect, NSCompositeSourceOver); | 756 NSRectFillUsingOperation(borderRect, NSCompositeSourceOver); |
| 791 } | 757 } |
| 792 | 758 |
| 793 [context restoreGraphicsState]; | 759 [context restoreGraphicsState]; |
| 794 } | 760 } |
| 795 | 761 |
| 796 - (void)viewDidMoveToWindow { | 762 - (void)viewDidMoveToWindow { |
| 797 [super viewDidMoveToWindow]; | 763 [super viewDidMoveToWindow]; |
| 798 if ([self window]) { | 764 if ([self window]) { |
| 799 [controller_ updateTitleColor]; | 765 [controller_ updateTitleColor]; |
| (...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1023 } else { | 989 } else { |
| 1024 NOTREACHED(); | 990 NOTREACHED(); |
| 1025 } | 991 } |
| 1026 } | 992 } |
| 1027 if (useCache) { | 993 if (useCache) { |
| 1028 workspaceIDCache_[windowID] = workspace; | 994 workspaceIDCache_[windowID] = workspace; |
| 1029 } | 995 } |
| 1030 return workspace; | 996 return workspace; |
| 1031 } | 997 } |
| 1032 | 998 |
| 999 // Returns the bezier path used to draw the tab given the bounds to draw it in. |
| 1000 - (NSBezierPath*)bezierPathForRect:(NSRect)rect { |
| 1001 // Outset by 0.5 in order to draw on pixels rather than on borders (which |
| 1002 // would cause blurry pixels). Subtract 1px of height to compensate, otherwise |
| 1003 // clipping will occur. |
| 1004 rect = NSInsetRect(rect, -0.5, -0.5); |
| 1005 rect.size.height -= 1.0; |
| 1006 |
| 1007 NSPoint bottomLeft = NSMakePoint(NSMinX(rect), NSMinY(rect) + 2); |
| 1008 NSPoint bottomRight = NSMakePoint(NSMaxX(rect), NSMinY(rect) + 2); |
| 1009 NSPoint topRight = |
| 1010 NSMakePoint(NSMaxX(rect) - kInsetMultiplier * NSHeight(rect), |
| 1011 NSMaxY(rect)); |
| 1012 NSPoint topLeft = |
| 1013 NSMakePoint(NSMinX(rect) + kInsetMultiplier * NSHeight(rect), |
| 1014 NSMaxY(rect)); |
| 1015 |
| 1016 CGFloat baseControlPointOutset = NSHeight(rect) * kControlPoint1Multiplier; |
| 1017 CGFloat bottomControlPointInset = NSHeight(rect) * kControlPoint2Multiplier; |
| 1018 |
| 1019 // Outset many of these values by 1 to cause the fill to bleed outside the |
| 1020 // clip area. |
| 1021 NSBezierPath* path = [NSBezierPath bezierPath]; |
| 1022 [path moveToPoint:NSMakePoint(bottomLeft.x - 1, bottomLeft.y - 2)]; |
| 1023 [path lineToPoint:NSMakePoint(bottomLeft.x - 1, bottomLeft.y)]; |
| 1024 [path lineToPoint:bottomLeft]; |
| 1025 [path curveToPoint:topLeft |
| 1026 controlPoint1:NSMakePoint(bottomLeft.x + baseControlPointOutset, |
| 1027 bottomLeft.y) |
| 1028 controlPoint2:NSMakePoint(topLeft.x - bottomControlPointInset, |
| 1029 topLeft.y)]; |
| 1030 [path lineToPoint:topRight]; |
| 1031 [path curveToPoint:bottomRight |
| 1032 controlPoint1:NSMakePoint(topRight.x + bottomControlPointInset, |
| 1033 topRight.y) |
| 1034 controlPoint2:NSMakePoint(bottomRight.x - baseControlPointOutset, |
| 1035 bottomRight.y)]; |
| 1036 [path lineToPoint:NSMakePoint(bottomRight.x + 1, bottomRight.y)]; |
| 1037 [path lineToPoint:NSMakePoint(bottomRight.x + 1, bottomRight.y - 2)]; |
| 1038 return path; |
| 1039 } |
| 1040 |
| 1033 @end // @implementation TabView(Private) | 1041 @end // @implementation TabView(Private) |
| OLD | NEW |