andybons | 3322f76 | 2015-08-24 21:37:09 | [diff] [blame] | 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 |  |
| 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 |  |
| 47 |  |
| 48 |  |
| 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 |  |
| 58 |  |
| 59 |  |
| 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 |
xiaoyin.l | 1003c0b | 2016-12-06 02:51:17 | [diff] [blame] | 79 | [views::View](https://src.chromium.org/svn/trunk/src/chrome/views/view.h) is used |
andybons | 3322f76 | 2015-08-24 21:37:09 | [diff] [blame] | 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 |
qyearsley | c0dc6f4 | 2016-12-02 22:13:39 | [diff] [blame] | 95 | specifying the rectangle covered by the resizer. This callback is implemented |
andybons | 3322f76 | 2015-08-24 21:37:09 | [diff] [blame] | 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 |
xiaoyin.l | 1003c0b | 2016-12-06 02:51:17 | [diff] [blame] | 114 | [16488](https://codereview.chromium.org/16488). |
andybons | 3322f76 | 2015-08-24 21:37:09 | [diff] [blame] | 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. |