Extensions cleanup: Merge IsSyncableApp+Extension, ShouldSyncApp+Extension
[chromium-blink-merge.git] / chrome / browser / ui / cocoa / browser_window_layout.mm
blob55c061c374a43838310e2ef1e4db9a10a62ec4ac
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #import "chrome/browser/ui/cocoa/browser_window_layout.h"
7 #include <math.h>
8 #include <string.h>
10 #include "base/logging.h"
11 #include "base/mac/mac_util.h"
12 #import "chrome/browser/ui/cocoa/tabs/tab_strip_controller.h"
14 namespace chrome {
16 // The height of the tab strip.
17 const CGFloat kTabStripHeight = 37;
19 }  // namespace chrome
21 namespace {
23 // Insets for the location bar, used when the full toolbar is hidden.
24 // TODO(viettrungluu): We can argue about the "correct" insetting; I like the
25 // following best, though arguably 0 inset is better/more correct.
26 const CGFloat kLocBarLeftRightInset = 1;
27 const CGFloat kLocBarTopInset = 0;
28 const CGFloat kLocBarBottomInset = 1;
30 // Space between the incognito badge and the right edge of the window.
31 const CGFloat kAvatarRightOffset = 4;
33 // Space between the location bar and the right edge of the window, when there
34 // are no extension buttons present.
35 // When there is a fullscreen button to the right of the new style profile
36 // button, we align the profile button with the location bar (although it won't
37 // be aligned when there are extension buttons).
38 const CGFloat kLocationBarRightOffset = 35;
40 }  // namespace
42 @interface BrowserWindowLayout ()
44 // Computes the y offset to use when laying out the tab strip in fullscreen
45 // mode.
46 - (void)computeFullscreenYOffset;
48 // Computes the layout of the tab strip.
49 - (void)computeTabStripLayout;
51 // Computes the layout of the subviews of the content view.
52 - (void)computeContentViewLayout;
54 // Computes the height of the backing bar for the views in the omnibox area in
55 // fullscreen mode.
56 - (CGFloat)fullscreenBackingBarHeight;
58 @end
60 @implementation BrowserWindowLayout
62 - (instancetype)init {
63   if ((self = [super init])) {
64     parameters_.isOSYosemiteOrLater = base::mac::IsOSYosemiteOrLater();
65   }
66   return self;
69 - (chrome::LayoutOutput)computeLayout {
70   memset(&output_, 0, sizeof(chrome::LayoutOutput));
72   [self computeFullscreenYOffset];
73   [self computeTabStripLayout];
74   [self computeContentViewLayout];
76   return output_;
79 - (void)setContentViewSize:(NSSize)size {
80   parameters_.contentViewSize = size;
83 - (void)setWindowSize:(NSSize)size {
84   parameters_.windowSize = size;
87 - (void)setInAnyFullscreen:(BOOL)inAnyFullscreen {
88   parameters_.inAnyFullscreen = inAnyFullscreen;
91 - (void)setFullscreenSlidingStyle:(fullscreen_mac::SlidingStyle)slidingStyle {
92   parameters_.slidingStyle = slidingStyle;
95 - (void)setFullscreenMenubarOffset:(CGFloat)menubarOffset {
96   parameters_.menubarOffset = menubarOffset;
99 - (void)setFullscreenToolbarFraction:(CGFloat)toolbarFraction {
100   parameters_.toolbarFraction = toolbarFraction;
103 - (void)setHasTabStrip:(BOOL)hasTabStrip {
104   parameters_.hasTabStrip = hasTabStrip;
107 - (void)setFullscreenButtonFrame:(NSRect)frame {
108   parameters_.fullscreenButtonFrame = frame;
111 - (void)setShouldShowAvatar:(BOOL)shouldShowAvatar {
112   parameters_.shouldShowAvatar = shouldShowAvatar;
115 - (void)setShouldUseNewAvatar:(BOOL)shouldUseNewAvatar {
116   parameters_.shouldUseNewAvatar = shouldUseNewAvatar;
119 - (void)setAvatarSize:(NSSize)avatarSize {
120   parameters_.avatarSize = avatarSize;
123 - (void)setAvatarLineWidth:(CGFloat)avatarLineWidth {
124   parameters_.avatarLineWidth = avatarLineWidth;
127 - (void)setHasToolbar:(BOOL)hasToolbar {
128   parameters_.hasToolbar = hasToolbar;
131 - (void)setHasLocationBar:(BOOL)hasLocationBar {
132   parameters_.hasLocationBar = hasLocationBar;
135 - (void)setToolbarHeight:(CGFloat)toolbarHeight {
136   parameters_.toolbarHeight = toolbarHeight;
139 - (void)setBookmarkBarHidden:(BOOL)bookmarkBarHidden {
140   parameters_.bookmarkBarHidden = bookmarkBarHidden;
143 - (void)setPlaceBookmarkBarBelowInfoBar:(BOOL)placeBookmarkBarBelowInfoBar {
144   parameters_.placeBookmarkBarBelowInfoBar = placeBookmarkBarBelowInfoBar;
147 - (void)setBookmarkBarHeight:(CGFloat)bookmarkBarHeight {
148   parameters_.bookmarkBarHeight = bookmarkBarHeight;
151 - (void)setInfoBarHeight:(CGFloat)infoBarHeight {
152   parameters_.infoBarHeight = infoBarHeight;
155 - (void)setPageInfoBubblePointY:(CGFloat)pageInfoBubblePointY {
156   parameters_.pageInfoBubblePointY = pageInfoBubblePointY;
159 - (void)setHasDownloadShelf:(BOOL)hasDownloadShelf {
160   parameters_.hasDownloadShelf = hasDownloadShelf;
163 - (void)setDownloadShelfHeight:(CGFloat)downloadShelfHeight {
164   parameters_.downloadShelfHeight = downloadShelfHeight;
167 - (void)computeFullscreenYOffset {
168   CGFloat yOffset = 0;
169   if (parameters_.inAnyFullscreen) {
170     yOffset += parameters_.menubarOffset;
171     switch (parameters_.slidingStyle) {
172       case fullscreen_mac::OMNIBOX_TABS_PRESENT:
173         break;
174       case fullscreen_mac::OMNIBOX_TABS_HIDDEN:
175         // In presentation mode, |yOffset| accounts for the sliding position of
176         // the floating bar and the extra offset needed to dodge the menu bar.
177         yOffset += std::floor((1 - parameters_.toolbarFraction) *
178                               [self fullscreenBackingBarHeight]);
179         break;
180     }
181   }
182   fullscreenYOffset_ = yOffset;
185 - (void)computeTabStripLayout {
186   if (!parameters_.hasTabStrip) {
187     maxY_ = parameters_.contentViewSize.height + fullscreenYOffset_;
188     return;
189   }
191   // Temporary variable to hold the output.
192   chrome::TabStripLayout layout = {};
194   // Lay out the tab strip.
195   maxY_ = parameters_.windowSize.height + fullscreenYOffset_;
196   CGFloat width = parameters_.contentViewSize.width;
197   layout.frame = NSMakeRect(
198       0, maxY_ - chrome::kTabStripHeight, width, chrome::kTabStripHeight);
199   maxY_ = NSMinY(layout.frame);
201   // In Yosemite, there is no longer an exit fullscreen button in the top-right
202   // corner of the OSX Menu Bar. Instead, a Cocoa application's toolbar is
203   // expected to have traffic lights. Chrome doesn't use an NSToolbar, so it
204   // needs to manually add the traffic lights to the tab strip.
205   layout.addCustomWindowControls =
206       parameters_.inAnyFullscreen && parameters_.isOSYosemiteOrLater;
208   // Set left indentation based on fullscreen mode status.
209   if (!parameters_.inAnyFullscreen || layout.addCustomWindowControls)
210     layout.leftIndent = [TabStripController defaultLeftIndentForControls];
212   // Lay out the icognito/avatar badge because calculating the indentation on
213   // the right depends on it.
214   if (parameters_.shouldShowAvatar) {
215     CGFloat badgeXOffset = -kAvatarRightOffset;
216     CGFloat badgeYOffset = 0;
217     CGFloat buttonHeight = parameters_.avatarSize.height;
219     if (parameters_.shouldUseNewAvatar) {
220       // The fullscreen icon (if present) is displayed to the right of the
221       // new style profile button.
222       if (!NSIsEmptyRect(parameters_.fullscreenButtonFrame))
223         badgeXOffset = -kLocationBarRightOffset;
225       // Center the button, but make sure that it's pixel aligned on non-retina
226       // displays. Use trunc() instead of round() to mimic the behavior of
227       // autoresizesSubviews.
228       badgeYOffset = trunc((chrome::kTabStripHeight - buttonHeight) / 2);
229     } else {
230       // Actually place the badge *above* |maxY|, by +2 to miss the divider.
231       badgeYOffset = 2 * parameters_.avatarLineWidth;
232     }
234     NSSize size = NSMakeSize(parameters_.avatarSize.width,
235                              std::min(buttonHeight, chrome::kTabStripHeight));
236     NSPoint origin =
237         NSMakePoint(width - parameters_.avatarSize.width + badgeXOffset,
238                     maxY_ + badgeYOffset);
239     layout.avatarFrame =
240         NSMakeRect(origin.x, origin.y, size.width, size.height);
241   }
243   // Calculate the right indentation.
244   // On 10.7 Lion to 10.9 Mavericks, there will be a fullscreen button when not
245   // in fullscreen mode.
246   // There may also be a profile button, which can be on the right of the
247   // fullscreen button (old style), or to its left (new style).
248   // The right indentation is calculated to prevent the tab strip from
249   // overlapping these buttons.
250   CGFloat maxX = width;
251   if (!NSIsEmptyRect(parameters_.fullscreenButtonFrame)) {
252     maxX = NSMinX(parameters_.fullscreenButtonFrame);
253   }
254   if (parameters_.shouldShowAvatar) {
255     maxX = std::min(maxX, NSMinX(layout.avatarFrame));
256   }
257   layout.rightIndent = width - maxX;
259   output_.tabStripLayout = layout;
262 - (void)computeContentViewLayout {
263   chrome::LayoutParameters parameters = parameters_;
264   CGFloat maxY = maxY_;
266   // Sanity-check |maxY|.
267   DCHECK_GE(maxY, 0);
268   DCHECK_LE(maxY, parameters_.contentViewSize.height + fullscreenYOffset_);
270   CGFloat width = parameters_.contentViewSize.width;
272   // Lay out the toolbar.
273   if (parameters.hasToolbar) {
274     output_.toolbarFrame = NSMakeRect(
275         0, maxY - parameters_.toolbarHeight, width, parameters_.toolbarHeight);
276     maxY = NSMinY(output_.toolbarFrame);
277   } else if (parameters_.hasLocationBar) {
278     CGFloat toolbarX = kLocBarLeftRightInset;
279     CGFloat toolbarY = maxY - parameters_.toolbarHeight - kLocBarTopInset;
280     CGFloat toolbarWidth = width - 2 * kLocBarLeftRightInset;
281     output_.toolbarFrame =
282         NSMakeRect(toolbarX, toolbarY, toolbarWidth, parameters_.toolbarHeight);
283     maxY = NSMinY(output_.toolbarFrame) - kLocBarBottomInset;
284   }
286   // Lay out the bookmark bar, if it's above the info bar.
287   if (!parameters.bookmarkBarHidden &&
288       !parameters.placeBookmarkBarBelowInfoBar) {
289     output_.bookmarkFrame = NSMakeRect(0,
290                                        maxY - parameters.bookmarkBarHeight,
291                                        width,
292                                        parameters.bookmarkBarHeight);
293     maxY = NSMinY(output_.bookmarkFrame);
294   }
296   // Lay out the backing bar in fullscreen mode.
297   if (parameters_.inAnyFullscreen) {
298     output_.fullscreenBackingBarFrame =
299         NSMakeRect(0, maxY, width, [self fullscreenBackingBarHeight]);
300   }
302   // Place the find bar immediately below the toolbar/attached bookmark bar.
303   output_.findBarMaxY = maxY;
304   output_.fullscreenExitButtonMaxY = maxY;
306   if (parameters_.inAnyFullscreen &&
307       parameters_.slidingStyle == fullscreen_mac::OMNIBOX_TABS_HIDDEN) {
308     // If in presentation mode, reset |maxY| to top of screen, so that the
309     // floating bar slides over the things which appear to be in the content
310     // area.
311     maxY = parameters_.windowSize.height;
312   }
314   // Lay out the info bar. It is never hidden.
315   if (parameters_.infoBarHeight != 0) {
316     CGFloat infoBarMaxY = maxY;
317     CGFloat infoBarMinY = maxY - parameters_.infoBarHeight;
319     // If there's a toolbar, then the frame needs to be high enough to
320     // accomodate the top arrow, which might stretch all the way to the page
321     // info bubble icon.
322     if (parameters_.hasToolbar) {
323       infoBarMaxY =
324           NSMinY(output_.toolbarFrame) + parameters.pageInfoBubblePointY;
325     }
327     output_.infoBarFrame =
328         NSMakeRect(0, infoBarMinY, width, infoBarMaxY - infoBarMinY);
329     output_.infoBarMaxTopArrowHeight =
330         NSHeight(output_.infoBarFrame) - parameters_.infoBarHeight;
331     maxY = NSMinY(output_.infoBarFrame);
332   } else {
333     // The info bar has 0 height, but tests still expect it in the right
334     // location.
335     output_.infoBarFrame = NSMakeRect(0, maxY, width, 0);
336   }
338   // Lay out the bookmark bar when it is below the info bar.
339   if (!parameters.bookmarkBarHidden &&
340       parameters.placeBookmarkBarBelowInfoBar) {
341     output_.bookmarkFrame = NSMakeRect(0,
342                                        maxY - parameters.bookmarkBarHeight,
343                                        width,
344                                        parameters.bookmarkBarHeight);
345     maxY = NSMinY(output_.bookmarkFrame);
346   }
348   // Layout the download shelf at the bottom of the content view.
349   CGFloat minY = 0;
350   if (parameters.hasDownloadShelf) {
351     output_.downloadShelfFrame =
352         NSMakeRect(0, 0, width, parameters.downloadShelfHeight);
353     minY = NSMaxY(output_.downloadShelfFrame);
354   }
356   if (parameters_.inAnyFullscreen &&
357       parameters_.slidingStyle == fullscreen_mac::OMNIBOX_TABS_PRESENT) {
358     // If in Canonical Fullscreen, content should be shifted down by an amount
359     // equal to all the widgets and views at the top of the window. It should
360     // not be further shifted by the appearance/disappearance of the AppKit
361     // menu bar.
362     maxY = parameters_.windowSize.height;
363     maxY -= NSHeight(output_.toolbarFrame) +
364             NSHeight(output_.tabStripLayout.frame) +
365             NSHeight(output_.bookmarkFrame) + parameters.infoBarHeight;
366   }
368   // All the remaining space becomes the frame of the content area.
369   output_.contentAreaFrame = NSMakeRect(0, minY, width, maxY - minY);
372 - (CGFloat)fullscreenBackingBarHeight {
373   if (!parameters_.inAnyFullscreen)
374     return 0;
376   CGFloat totalHeight = 0;
377   if (parameters_.hasTabStrip)
378     totalHeight += chrome::kTabStripHeight;
380   if (parameters_.hasToolbar) {
381     totalHeight += parameters_.toolbarHeight;
382   } else if (parameters_.hasLocationBar) {
383     totalHeight +=
384         parameters_.toolbarHeight + kLocBarTopInset + kLocBarBottomInset;
385   }
387   if (!parameters_.bookmarkBarHidden &&
388       !parameters_.placeBookmarkBarBelowInfoBar)
389     totalHeight += parameters_.bookmarkBarHeight;
391   return totalHeight;
394 @end
396 @implementation BrowserWindowLayout (ExposedForTesting)
398 - (void)setOSYosemiteOrLater:(BOOL)osYosemiteOrLater {
399   parameters_.isOSYosemiteOrLater = osYosemiteOrLater;
402 @end