OLD | NEW |
(Empty) | |
| 1 # Browser View Resizer |
| 2 |
| 3 To fix bug [458](http://code.google.com/p/chromium/issues/detail?id=458), which |
| 4 identifies that it is hard to hit the thin window frame corner to resize the |
| 5 window. It would be better to have a resize hit area (called widget from now on) |
| 6 in the corner, as we currently have for edit boxes for example. |
| 7 |
| 8 [TOC] |
| 9 |
| 10 ## Background |
| 11 |
| 12 This is specific to the Windows OS. On the Mac, Cocoa automatically adds a |
| 13 resize widget (Not sure about Linux, we should double check). On Windows, those |
| 14 resize widgets are at the extreme right of a status bar. For example, if you |
| 15 remove the status bar from a Windows Explorer window, you lose the resize |
| 16 widget. But since Chrome never ever has a status bar and simply take over the |
| 17 bottom of the window for specific tasks (like the download shelf for example), |
| 18 we need to find a creative way of giving access to a resize widget. |
| 19 |
| 20 The bottom corners where we would like to add the resize widget are currently |
| 21 controlled by the browser view, which can have either the tab contents view or |
| 22 other dynamic views (like the download shelf view) displayed in this area. |
| 23 |
| 24 ## Requirements |
| 25 |
| 26 Since there is no status bar to simply fix a resize widget to, we must |
| 27 dynamically create a widget that can be laid either on the tab contents view or |
| 28 on other views that might temporarily take over the bottom part of the browser |
| 29 view. |
| 30 |
| 31 When no dynamic view is taking over the bottom of the browser view, the resize |
| 32 widget can sit in the bottom right corner of the tab contents view, over the tab |
| 33 contents view. |
| 34 |
| 35 ![Resize Corner](http://lh6.ggpht.com/_2OD0ww7UZAs/SUAaNi6TWYI/AAAAAAAAGmI/89jCY
Q1Cxsw/ResizeCorner-2.png) |
| 36 |
| 37 The resize widget must have the same width and height as |
| 38 the scroll bars so that it can fit in the corner currently left empty when both |
| 39 scroll bars are visible. If only one scroll bar is visible (either the |
| 40 horizontal or the vertical one), that scroll bar must still leave room for the |
| 41 resize widget to fit there (as it currently leave room for the empty corner when |
| 42 both scroll bars are visible), yet, only when the resize widget is laid on top |
| 43 of the tab contents view, not when a dynamic shelf is added at the bottom of the |
| 44 browser view. |
| 45 |
| 46 ![Resize Corner](http://lh6.ggpht.com/_2OD0ww7UZAs/SUAaNjqr_iI/AAAAAAAAGmA/56hzj
dnkVRI/ResizeCorner-1.png) |
| 47 ![Resize Corner](http://lh3.ggpht.com/_2OD0ww7UZAs/SUAaN_wDEUI/AAAAAAAAGmQ/7B4CT
ZTXOmk/ResizeCorner-3.png) |
| 48 ![Resize Corner](http://lh6.ggpht.com/_2OD0ww7UZAs/SUAaN7yme9I/AAAAAAAAGmY/Eanii
Abwi-Q/ResizeCorner-4.png) |
| 49 |
| 50 If another view (e.g., again, the download shelf) is added at the bottom of the |
| 51 browser view, below the tab contents view, and covers the bottom corners, then |
| 52 the resize widget must be laid on top of this other child view. Of course, all |
| 53 child views that can potentially be added at the bottom of the browser view, |
| 54 must be designed in a way that leaves enough room in the bottom corners for the |
| 55 resize widget. |
| 56 |
| 57 ![Resize Corner](http://lh3.ggpht.com/_2OD0ww7UZAs/SUAaN17TIrI/AAAAAAAAGmg/6bljN
Q_vZkI/ResizeCorner-5.png) |
| 58 ![Resize Corner](http://lh4.ggpht.com/_2OD0ww7UZAs/SUAaWINHA6I/AAAAAAAAGmo/-VG5F
GC8Xds/ResizeCorner-6.png) |
| 59 ![Resize Corner](http://lh6.ggpht.com/_2OD0ww7UZAs/SUAaWDUpo0I/AAAAAAAAGmw/8USPz
oMpgu0/ResizeCorner-7.png) |
| 60 |
| 61 Since the bottom corners might have different colors, based on the state and |
| 62 content of the browser view, the resize widget must have a transparent |
| 63 background. |
| 64 |
| 65 The resize widget is not animated itself. It might move with the animation of |
| 66 the view it is laid on top of (e.g., when the download shelf is being animated |
| 67 in), but we won't attempt to animate the resize widget itself (or fix it in the |
| 68 bottom right corner of the browser view while the other views get animated it). |
| 69 |
| 70 ## Design |
| 71 |
| 72 Unfortunately, we must deal with the two different cases (with or without a |
| 73 dynamic bottom view) in two different and distinct ways. |
| 74 |
| 75 ### Over a Dynamic View |
| 76 |
| 77 For the cases where there is a dynamic view at the bottom of the browser view, a |
| 78 new view class (named `BrowserResizerView`) inheriting from |
| 79 [views::View](http://src.chromium.org/svn/trunk/src/chrome/views/view.h) is used |
| 80 to display the resize widget. It is set as a child of the dynamic view laid at |
| 81 the bottom of the browser view. The Browser view takes care of properly setting |
| 82 the bounds of the resize widget view, based on the language direction. |
| 83 |
| 84 Also, it is easier and more efficient to let the browser view handle the mouse |
| 85 interactions to resize the browser. We can let Windows take care of properly |
| 86 resizing the view by returning the HTBOTTOMLEFT or HTBOTTOMRIGHT flags from the |
| 87 NCClientHitTest windows message handler when they occur over the resize widget. |
| 88 The browser view also takes care of changing the mouse cursor to the appropriate |
| 89 resizing arrows when the mouse hovers over the resize widget area. |
| 90 |
| 91 ### Without a Dynamic View |
| 92 |
| 93 To make sure that the scroll bars (handled by `WebKit`) are not drawn on top of |
| 94 the resizer widget (or vice versa), we need to properly implement the callback |
| 95 specifyinhg the rectangle covered by the resizer. This callback is implemented |
| 96 on the `RenderWidget` class that can delegate to a derive class via a new |
| 97 virtual method which returns an empty rect on the base class. Via a series of |
| 98 delegate interface calls, we eventually get back to the browser view which can |
| 99 return the size and position of the resize widget, but only if it is laid out on |
| 100 top of the tabs view, it returns an empty rect when there is a dynamic view. |
| 101 |
| 102 To handle the drawing of the resize widget over the render widget, we need to |
| 103 add code to the Windows specific version of the render widget host view which |
| 104 receives the bitmap rendered by WebKit so it can layer the transparent bitmap |
| 105 used for the resize widget. That same render widget host view must also handle |
| 106 the mouse interaction and use the same trick as the browser view to let Windows |
| 107 take care of resizing the whole frame. It must also take care of changing the |
| 108 mouse cursor to the appropriate resizing arrows when the mouse hovers over the |
| 109 resize widget area. |
| 110 |
| 111 ## Implementation |
| 112 |
| 113 You can find the changes made to make this work in patch |
| 114 [16488](http://codereview.chromium.org/16488). |
| 115 |
| 116 ## Alternatives Considered |
| 117 |
| 118 We could have tried to reuse the code that currently takes care of resizing the |
| 119 edit boxes within WebKit, but this code is wired to the overflow style of HTML |
| 120 element and would have been hard to rewire in an elegant way to be used in a |
| 121 higher level object like the browser view. Unless we missed something. |
| 122 |
| 123 We might also decide to go with the easier solution of only showing the resize |
| 124 corner within the tab contents view. In that case, it would still be recommended |
| 125 that the resize widget would not appear when dynamic views are taking over the |
| 126 bottom portion of the browser view, since it would look weird to have a resize |
| 127 corner widget that is not in the real... corner... of the browser view ;-) |
| 128 |
| 129 We may decide that we don't want to see the resize widget bitmap hide some |
| 130 pixels from the tab contents (or dynamic view) yet we would still have the |
| 131 resizing functionality via the mouse interaction and also get visual feedback |
| 132 with the mouse cursor changes while we hover over the resize widget area. |
| 133 |
| 134 We may do more research to find a way to solve this problem in a single place as |
| 135 opposed to the current dual solution, but none was found so far. |
OLD | NEW |