OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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/ui/cocoa/tabs/tab_strip_controller.h" | 5 #import "chrome/browser/ui/cocoa/tabs/tab_strip_controller.h" |
6 | 6 |
7 #import <QuartzCore/QuartzCore.h> | 7 #import <QuartzCore/QuartzCore.h> |
8 | 8 |
| 9 #include <cmath> |
9 #include <limits> | 10 #include <limits> |
10 #include <string> | 11 #include <string> |
11 | 12 |
12 #include "base/command_line.h" | 13 #include "base/command_line.h" |
13 #include "base/mac/mac_util.h" | 14 #include "base/mac/mac_util.h" |
14 #include "base/sys_string_conversions.h" | 15 #include "base/sys_string_conversions.h" |
15 #include "chrome/app/chrome_command_ids.h" | 16 #include "chrome/app/chrome_command_ids.h" |
16 #include "chrome/browser/autocomplete/autocomplete.h" | 17 #include "chrome/browser/autocomplete/autocomplete.h" |
17 #include "chrome/browser/autocomplete/autocomplete_classifier.h" | 18 #include "chrome/browser/autocomplete/autocomplete_classifier.h" |
18 #include "chrome/browser/autocomplete/autocomplete_match.h" | 19 #include "chrome/browser/autocomplete/autocomplete_match.h" |
(...skipping 825 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
844 // This may be negative, but that's okay (taken care of by |MAX()| when | 845 // This may be negative, but that's okay (taken care of by |MAX()| when |
845 // calculating tab sizes). "mini" tabs in horizontal mode just get a special | 846 // calculating tab sizes). "mini" tabs in horizontal mode just get a special |
846 // section, they don't change size. | 847 // section, they don't change size. |
847 CGFloat availableSpaceForNonMini = availableSpace; | 848 CGFloat availableSpaceForNonMini = availableSpace; |
848 availableSpaceForNonMini -= | 849 availableSpaceForNonMini -= |
849 [self numberOfOpenMiniTabs] * (kMiniTabWidth - kTabOverlap); | 850 [self numberOfOpenMiniTabs] * (kMiniTabWidth - kTabOverlap); |
850 | 851 |
851 // Initialize |nonMiniTabWidth| in case there aren't any non-mini-tabs; this | 852 // Initialize |nonMiniTabWidth| in case there aren't any non-mini-tabs; this |
852 // value shouldn't actually be used. | 853 // value shouldn't actually be used. |
853 CGFloat nonMiniTabWidth = kMaxTabWidth; | 854 CGFloat nonMiniTabWidth = kMaxTabWidth; |
| 855 CGFloat nonMiniTabWidthFraction = 0; |
854 const NSInteger numberOfOpenNonMiniTabs = [self numberOfOpenNonMiniTabs]; | 856 const NSInteger numberOfOpenNonMiniTabs = [self numberOfOpenNonMiniTabs]; |
855 if (numberOfOpenNonMiniTabs) { | 857 if (numberOfOpenNonMiniTabs) { |
856 // Find the width of a non-mini-tab. This only applies to horizontal | 858 // Find the width of a non-mini-tab. This only applies to horizontal |
857 // mode. Add in the amount we "get back" from the tabs overlapping. | 859 // mode. Add in the amount we "get back" from the tabs overlapping. |
858 availableSpaceForNonMini += (numberOfOpenNonMiniTabs - 1) * kTabOverlap; | 860 availableSpaceForNonMini += (numberOfOpenNonMiniTabs - 1) * kTabOverlap; |
859 | 861 |
860 // Divide up the space between the non-mini-tabs. | 862 // Divide up the space between the non-mini-tabs. |
861 nonMiniTabWidth = availableSpaceForNonMini / numberOfOpenNonMiniTabs; | 863 nonMiniTabWidth = availableSpaceForNonMini / numberOfOpenNonMiniTabs; |
862 | 864 |
863 // Clamp the width between the max and min. | 865 // Clamp the width between the max and min. |
864 nonMiniTabWidth = MAX(MIN(nonMiniTabWidth, kMaxTabWidth), kMinTabWidth); | 866 nonMiniTabWidth = MAX(MIN(nonMiniTabWidth, kMaxTabWidth), kMinTabWidth); |
| 867 |
| 868 // Separate integral and fractional parts. |
| 869 CGFloat integralPart = std::floor(nonMiniTabWidth); |
| 870 nonMiniTabWidthFraction = nonMiniTabWidth - integralPart; |
| 871 nonMiniTabWidth = integralPart; |
865 } | 872 } |
866 | 873 |
867 BOOL visible = [[tabStripView_ window] isVisible]; | 874 BOOL visible = [[tabStripView_ window] isVisible]; |
868 | 875 |
869 CGFloat offset = [self leftIndentForControls]; | 876 CGFloat offset = [self leftIndentForControls]; |
870 bool hasPlaceholderGap = false; | 877 bool hasPlaceholderGap = false; |
871 // Whether or not the last tab processed by the loop was a mini tab. | 878 // Whether or not the last tab processed by the loop was a mini tab. |
872 BOOL isLastTabMini = NO; | 879 BOOL isLastTabMini = NO; |
| 880 CGFloat tabWidthAccumulatedFraction = 0; |
| 881 NSInteger laidOutNonMiniTabs = 0; |
873 for (TabController* tab in tabArray_.get()) { | 882 for (TabController* tab in tabArray_.get()) { |
874 // Ignore a tab that is going through a close animation. | 883 // Ignore a tab that is going through a close animation. |
875 if ([closingControllers_ containsObject:tab]) | 884 if ([closingControllers_ containsObject:tab]) |
876 continue; | 885 continue; |
877 | 886 |
878 BOOL isPlaceholder = [[tab view] isEqual:placeholderTab_]; | 887 BOOL isPlaceholder = [[tab view] isEqual:placeholderTab_]; |
879 NSRect tabFrame = [[tab view] frame]; | 888 NSRect tabFrame = [[tab view] frame]; |
880 tabFrame.size.height = [[self class] defaultTabHeight] + 1; | 889 tabFrame.size.height = [[self class] defaultTabHeight] + 1; |
881 tabFrame.origin.y = 0; | 890 tabFrame.origin.y = 0; |
882 tabFrame.origin.x = offset; | 891 tabFrame.origin.x = offset; |
(...skipping 30 matching lines...) Expand all Loading... |
913 hasPlaceholderGap = true; | 922 hasPlaceholderGap = true; |
914 offset += NSWidth(placeholderFrame_); | 923 offset += NSWidth(placeholderFrame_); |
915 offset -= kTabOverlap; | 924 offset -= kTabOverlap; |
916 tabFrame.origin.x = offset; | 925 tabFrame.origin.x = offset; |
917 } | 926 } |
918 } | 927 } |
919 | 928 |
920 // Set the width. Selected tabs are slightly wider when things get really | 929 // Set the width. Selected tabs are slightly wider when things get really |
921 // small and thus we enforce a different minimum width. | 930 // small and thus we enforce a different minimum width. |
922 BOOL isMini = [tab mini]; | 931 BOOL isMini = [tab mini]; |
923 tabFrame.size.width = isMini ? | 932 if (isMini) { |
924 ([tab app] ? kAppTabWidth : kMiniTabWidth) : nonMiniTabWidth; | 933 tabFrame.size.width = [tab app] ? kAppTabWidth : kMiniTabWidth; |
| 934 } else { |
| 935 // Tabs have non-integer widths. Assign the integer part to the tab, and |
| 936 // keep an accumulation of the fractional parts. When the fractional |
| 937 // accumulation gets to be more than one pixel, assign that to the current |
| 938 // tab being laid out. This is vaguely inspired by Bresenham's line |
| 939 // algorithm. |
| 940 tabFrame.size.width = nonMiniTabWidth; |
| 941 tabWidthAccumulatedFraction += nonMiniTabWidthFraction; |
| 942 |
| 943 if (tabWidthAccumulatedFraction >= 1.0) { |
| 944 ++tabFrame.size.width; |
| 945 --tabWidthAccumulatedFraction; |
| 946 } |
| 947 |
| 948 // In case of rounding error, give any left over pixels to the last tab. |
| 949 if (laidOutNonMiniTabs == numberOfOpenNonMiniTabs - 1 && |
| 950 tabWidthAccumulatedFraction > 0.5) { |
| 951 ++tabFrame.size.width; |
| 952 } |
| 953 |
| 954 ++laidOutNonMiniTabs; |
| 955 } |
| 956 |
925 if ([tab selected]) | 957 if ([tab selected]) |
926 tabFrame.size.width = MAX(tabFrame.size.width, kMinSelectedTabWidth); | 958 tabFrame.size.width = MAX(tabFrame.size.width, kMinSelectedTabWidth); |
927 | 959 |
928 // If this is the first non-mini tab, then add a bit of spacing between this | 960 // If this is the first non-mini tab, then add a bit of spacing between this |
929 // and the last mini tab. | 961 // and the last mini tab. |
930 if (!isMini && isLastTabMini) { | 962 if (!isMini && isLastTabMini) { |
931 offset += kLastMiniTabSpacing; | 963 offset += kLastMiniTabSpacing; |
932 tabFrame.origin.x = offset; | 964 tabFrame.origin.x = offset; |
933 } | 965 } |
934 isLastTabMini = isMini; | 966 isLastTabMini = isMini; |
(...skipping 1082 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2017 NSInteger index = [self indexFromModelIndex:modelIndex]; | 2049 NSInteger index = [self indexFromModelIndex:modelIndex]; |
2018 BrowserWindowController* controller = | 2050 BrowserWindowController* controller = |
2019 (BrowserWindowController*)[[switchView_ window] windowController]; | 2051 (BrowserWindowController*)[[switchView_ window] windowController]; |
2020 DCHECK(index >= 0); | 2052 DCHECK(index >= 0); |
2021 if (index >= 0) { | 2053 if (index >= 0) { |
2022 [controller setTab:[self viewAtIndex:index] isDraggable:YES]; | 2054 [controller setTab:[self viewAtIndex:index] isDraggable:YES]; |
2023 } | 2055 } |
2024 } | 2056 } |
2025 | 2057 |
2026 @end | 2058 @end |
OLD | NEW |