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.
4
5#import "chrome/browser/ui/cocoa/browser_window_layout.h"
6
7#include "base/logging.h"
8
9namespace chrome {
10
11const CGFloat kTabStripHeight = 37;
12
13}  // namespace chrome
14
15namespace {
16
17// Insets for the location bar, used when the full toolbar is hidden.
18// TODO(viettrungluu): We can argue about the "correct" insetting; I like the
19// following best, though arguably 0 inset is better/more correct.
20const CGFloat kLocBarLeftRightInset = 1;
21const CGFloat kLocBarTopInset = 0;
22const CGFloat kLocBarBottomInset = 1;
23
24}  // namespace
25
26@interface BrowserWindowLayout ()
27
28// Computes the y offset to use when laying out the tab strip in fullscreen
29// mode.
30- (void)computeFullscreenYOffset;
31
32// Computes the layout of the tab strip.
33- (void)computeTabStripLayout;
34
35// Computes the layout of the subviews of the content view.
36- (void)computeContentViewLayout;
37
38// Computes the height of the backing bar for the views in the omnibox area in
39// fullscreen mode.
40- (CGFloat)fullscreenBackingBarHeight;
41
42@end
43
44@implementation BrowserWindowLayout
45
46- (chrome::LayoutOutput)computeLayout {
47  memset(&output_, 0, sizeof(chrome::LayoutOutput));
48
49  [self computeFullscreenYOffset];
50  [self computeTabStripLayout];
51  [self computeContentViewLayout];
52
53  return output_;
54}
55
56- (void)setContentViewSize:(NSSize)size {
57  parameters_.contentViewSize = size;
58}
59
60- (void)setWindowSize:(NSSize)size {
61  parameters_.windowSize = size;
62}
63
64- (void)setInAnyFullscreen:(BOOL)inAnyFullscreen {
65  parameters_.inAnyFullscreen = inAnyFullscreen;
66}
67
68- (void)setFullscreenSlidingStyle:(fullscreen_mac::SlidingStyle)slidingStyle {
69  parameters_.slidingStyle = slidingStyle;
70}
71
72- (void)setFullscreenMenubarOffset:(CGFloat)menubarOffset {
73  parameters_.menubarOffset = menubarOffset;
74}
75
76- (void)setFullscreenToolbarFraction:(CGFloat)toolbarFraction {
77  parameters_.toolbarFraction = toolbarFraction;
78}
79
80- (void)setHasTabStrip:(BOOL)hasTabStrip {
81  parameters_.hasTabStrip = hasTabStrip;
82}
83
84- (void)setHasToolbar:(BOOL)hasToolbar {
85  parameters_.hasToolbar = hasToolbar;
86}
87
88- (void)setHasLocationBar:(BOOL)hasLocationBar {
89  parameters_.hasLocationBar = hasLocationBar;
90}
91
92- (void)setToolbarHeight:(CGFloat)toolbarHeight {
93  parameters_.toolbarHeight = toolbarHeight;
94}
95
96- (void)setBookmarkBarHidden:(BOOL)bookmarkBarHidden {
97  parameters_.bookmarkBarHidden = bookmarkBarHidden;
98}
99
100- (void)setPlaceBookmarkBarBelowInfoBar:(BOOL)placeBookmarkBarBelowInfoBar {
101  parameters_.placeBookmarkBarBelowInfoBar = placeBookmarkBarBelowInfoBar;
102}
103
104- (void)setBookmarkBarHeight:(CGFloat)bookmarkBarHeight {
105  parameters_.bookmarkBarHeight = bookmarkBarHeight;
106}
107
108- (void)setInfoBarHeight:(CGFloat)infoBarHeight {
109  parameters_.infoBarHeight = infoBarHeight;
110}
111
112- (void)setPageInfoBubblePointY:(CGFloat)pageInfoBubblePointY {
113  parameters_.pageInfoBubblePointY = pageInfoBubblePointY;
114}
115
116- (void)setHasDownloadShelf:(BOOL)hasDownloadShelf {
117  parameters_.hasDownloadShelf = hasDownloadShelf;
118}
119
120- (void)setDownloadShelfHeight:(CGFloat)downloadShelfHeight {
121  parameters_.downloadShelfHeight = downloadShelfHeight;
122}
123
124- (void)computeFullscreenYOffset {
125  CGFloat yOffset = 0;
126  if (parameters_.inAnyFullscreen) {
127    yOffset += parameters_.menubarOffset;
128    switch (parameters_.slidingStyle) {
129      case fullscreen_mac::OMNIBOX_TABS_PRESENT:
130        break;
131      case fullscreen_mac::OMNIBOX_TABS_HIDDEN:
132        // In presentation mode, |yOffset| accounts for the sliding position of
133        // the floating bar and the extra offset needed to dodge the menu bar.
134        yOffset += std::floor((1 - parameters_.toolbarFraction) *
135                              [self fullscreenBackingBarHeight]);
136        break;
137    }
138  }
139  fullscreenYOffset_ = yOffset;
140}
141
142- (void)computeTabStripLayout {
143  if (parameters_.hasTabStrip) {
144    maxY_ = parameters_.windowSize.height + fullscreenYOffset_;
145    CGFloat width = parameters_.contentViewSize.width;
146    output_.tabStripFrame = NSMakeRect(
147        0, maxY_ - chrome::kTabStripHeight, width, chrome::kTabStripHeight);
148    maxY_ = NSMinY(output_.tabStripFrame);
149  } else {
150    maxY_ = parameters_.contentViewSize.height + fullscreenYOffset_;
151  }
152}
153
154- (void)computeContentViewLayout {
155  chrome::LayoutParameters parameters = parameters_;
156  CGFloat maxY = maxY_;
157
158  // Sanity-check |maxY|.
159  DCHECK_GE(maxY, 0);
160  DCHECK_LE(maxY, parameters_.contentViewSize.height + fullscreenYOffset_);
161
162  CGFloat width = parameters_.contentViewSize.width;
163
164  // Lay out the toolbar.
165  if (parameters.hasToolbar) {
166    output_.toolbarFrame = NSMakeRect(
167        0, maxY - parameters_.toolbarHeight, width, parameters_.toolbarHeight);
168    maxY = NSMinY(output_.toolbarFrame);
169  } else if (parameters_.hasLocationBar) {
170    CGFloat toolbarX = kLocBarLeftRightInset;
171    CGFloat toolbarY = maxY - parameters_.toolbarHeight - kLocBarTopInset;
172    CGFloat toolbarWidth = width - 2 * kLocBarLeftRightInset;
173    output_.toolbarFrame =
174        NSMakeRect(toolbarX, toolbarY, toolbarWidth, parameters_.toolbarHeight);
175    maxY = NSMinY(output_.toolbarFrame) - kLocBarBottomInset;
176  }
177
178  // Lay out the bookmark bar, if it's above the info bar.
179  if (!parameters.bookmarkBarHidden &&
180      !parameters.placeBookmarkBarBelowInfoBar) {
181    output_.bookmarkFrame = NSMakeRect(0,
182                                       maxY - parameters.bookmarkBarHeight,
183                                       width,
184                                       parameters.bookmarkBarHeight);
185    maxY = NSMinY(output_.bookmarkFrame);
186  }
187
188  // Lay out the backing bar in fullscreen mode.
189  if (parameters_.inAnyFullscreen) {
190    output_.fullscreenBackingBarFrame =
191        NSMakeRect(0, maxY, width, [self fullscreenBackingBarHeight]);
192  }
193
194  // Place the find bar immediately below the toolbar/attached bookmark bar.
195  output_.findBarMaxY = maxY;
196  output_.fullscreenExitButtonMaxY = maxY;
197
198  if (parameters_.inAnyFullscreen &&
199      parameters_.slidingStyle == fullscreen_mac::OMNIBOX_TABS_HIDDEN) {
200    // If in presentation mode, reset |maxY| to top of screen, so that the
201    // floating bar slides over the things which appear to be in the content
202    // area.
203    maxY = parameters_.windowSize.height;
204  }
205
206  // Lay out the info bar. It is never hidden. The frame needs to be high
207  // enough to accomodate the top arrow, which might stretch all the way to the
208  // page info bubble icon.
209  if (parameters_.infoBarHeight != 0) {
210    CGFloat infoBarMaxY =
211        NSMinY(output_.toolbarFrame) + parameters.pageInfoBubblePointY;
212    CGFloat infoBarMinY = maxY - parameters_.infoBarHeight;
213    output_.infoBarFrame =
214        NSMakeRect(0, infoBarMinY, width, infoBarMaxY - infoBarMinY);
215    output_.infoBarMaxTopArrowHeight =
216        NSHeight(output_.infoBarFrame) - parameters_.infoBarHeight;
217    maxY = NSMinY(output_.infoBarFrame);
218  } else {
219    // The info bar has 0 height, but tests still expect it in the right
220    // location.
221    output_.infoBarFrame = NSMakeRect(0, maxY, width, 0);
222  }
223
224  // Lay out the bookmark bar when it is below the info bar.
225  if (!parameters.bookmarkBarHidden &&
226      parameters.placeBookmarkBarBelowInfoBar) {
227    output_.bookmarkFrame = NSMakeRect(0,
228                                       maxY - parameters.bookmarkBarHeight,
229                                       width,
230                                       parameters.bookmarkBarHeight);
231    maxY = NSMinY(output_.bookmarkFrame);
232  }
233
234  // Layout the download shelf at the bottom of the content view.
235  CGFloat minY = 0;
236  if (parameters.hasDownloadShelf) {
237    output_.downloadShelfFrame =
238        NSMakeRect(0, 0, width, parameters.downloadShelfHeight);
239    minY = NSMaxY(output_.downloadShelfFrame);
240  }
241
242  if (parameters_.inAnyFullscreen &&
243      parameters_.slidingStyle == fullscreen_mac::OMNIBOX_TABS_PRESENT) {
244    // If in Canonical Fullscreen, content should be shifted down by an amount
245    // equal to all the widgets and views at the top of the window. It should
246    // not be further shifted by the appearance/disappearance of the AppKit
247    // menu bar.
248    maxY = parameters_.windowSize.height;
249    maxY -= NSHeight(output_.toolbarFrame) + NSHeight(output_.tabStripFrame) +
250            NSHeight(output_.bookmarkFrame) + parameters.infoBarHeight;
251  }
252
253  // All the remaining space becomes the frame of the content area.
254  output_.contentAreaFrame = NSMakeRect(0, minY, width, maxY - minY);
255}
256
257- (CGFloat)fullscreenBackingBarHeight {
258  if (!parameters_.inAnyFullscreen)
259    return 0;
260
261  CGFloat totalHeight = 0;
262  if (parameters_.hasTabStrip)
263    totalHeight += chrome::kTabStripHeight;
264
265  if (parameters_.hasToolbar) {
266    totalHeight += parameters_.toolbarHeight;
267  } else if (parameters_.hasLocationBar) {
268    totalHeight +=
269        parameters_.toolbarHeight + kLocBarTopInset + kLocBarBottomInset;
270  }
271
272  if (!parameters_.bookmarkBarHidden &&
273      !parameters_.placeBookmarkBarBelowInfoBar)
274    totalHeight += parameters_.bookmarkBarHeight;
275
276  return totalHeight;
277}
278
279@end
280