Wednesday, December 31, 2008

Change the default zoom mode in Google Chromium

As a WebKit based browser, Google Chrome use the text zoom mode as default zoom mode. It means, if you choose the Zoom -> Larger in the page context menu, or press the Ctrl + '+' accelerator, all the text font size in the page will be increased by 20%. On the other hand, if you do the same thing in FireFox, the whole page will be zoomed instead the text font size.

In my opinion, I feel the page zoom mode more comfortable, although I don't think any of those mode is better than the other. At least in my 24' LCD with 1080p, I need the page zoom width enough to fill the right space.

So, I just modified Chrome source code, add two alternative accelerators for page zoom mode; I also add a command line switch to set the default zoom mode when starting.

The changes are straight, because WebKit had provided the build-in support for page zoom mode, and Chrome also had an internal switch for zoom mode.

Following steps are the changes base on latest SVN revision.

  1. Add two new command definition in the \app\chrome_dll_resource.h file, which define the alternative zoom command itself.

    #define IDC_ZOOM_VIEW_PLUS 38004
    #define IDC_ZOOM_VIEW_MINUS 38005

    And add new accelerator like Ctrl + Alt + '+'/'-' in the IDR_MAINFRAME table (app\chrom_dll.rc)

    VK_ADD,              IDC_ZOOM_VIEW_PLUS, VIRTKEY, CONTROL, ALT
    VK_SUBTRACT,         IDC_ZOOM_VIEW_MINUS, VIRTKEY, CONTROL, ALT



  2. Handle the commands in the Browser::ExecuteCommand function (\browser\browser.cc), and add a parameter for ZoomIn/ZoomOut functions which is the zoom mode

    // Zoom
    case IDC_ZOOM_PLUS: ZoomIn(true); break;
    case IDC_ZOOM_NORMAL: ZoomReset(); break;
    case IDC_ZOOM_MINUS: ZoomOut(true); break;
    case IDC_ZOOM_VIEW_PLUS: ZoomIn(false); break;
    case IDC_ZOOM_VIEW_MINUS: ZoomOut(false); break;
  3. Add two new zoom mode in PageZoom (\common\page_zoom.h), which will be used for page zoom; and refactor ZoomIn/ZoomOut functions (\browser\browser.cc) for new modes.

    enum Function {
    VIEW_SMALLER = -2,
    SMALLER = -1,
    STANDARD = 0,
    LARGER = 1,
    VIEW_LARGER = 2, };

    void Browser::ZoomIn(bool isTextOnly) {
    UserMetrics::RecordAction(L"ZoomPlus", profile_);
    GetSelectedTabContents()->AsWebContents()->render_view_host()->Zoom( isTextOnly ? PageZoom::LARGER : PageZoom::VIEW_LARGER);}

    void Browser::ZoomOut(bool isTextOnly) {
    UserMetrics::RecordAction(L"ZoomMinus", profile_);
    GetSelectedTabContents()->AsWebContents()->render_view_host()->Zoom( isTextOnly ? PageZoom::SMALLER : PageZoom::VIEW_SMALLER);}

    Then, the RenderViewHost::Zoom function will wrap the zoom mode as a ViewMsg_Zoom message, and send it to the render process.
  4. Modify the render handler, which redirect ViewMsg_Zoom message to OnZoom function (\renderer\render_view.cc)

    IPC_MESSAGE_HANDLER(ViewMsg_Zoom, OnZoom)

    The OnZoom function has a hard code kZoomIsTextOnly constant. So, we just change its value base on the command line parameter; and set two kind of zoom mode base on its default setting.

    void RenderView::OnZoom(int function) {
    static const bool zoomIsTextOnly = CommandLine().HasSwitch(switches::kZoomIsTextOnly);

    switch (function) {
    case PageZoom::VIEW_SMALLER:
    webview()->ZoomOut(!zoomIsTextOnly); break;
    case PageZoom::SMALLER: webview()->ZoomOut(zoomIsTextOnly); break;
    case PageZoom::STANDARD: webview()->ResetZoom(); break;
    case PageZoom::LARGER: webview()->ZoomIn(zoomIsTextOnly); break;
    case PageZoom::VIEW_LARGER: webview()->ZoomIn(!zoomIsTextOnly); break;
    default: NOTREACHED(); }}
  5. Besides the command workflow, there are some bookkeeping works.

    We need update the command status base on the current stage in the Browser::UpdateCommandsForTabState function (browser\browser.cc)

    controller_.UpdateCommandEnabled(IDC_ZOOM_VIEW_PLUS, is_web_contents);
    controller_.UpdateCommandEnabled(IDC_ZOOM_VIEW_MINUS, is_web_contents);
  6. To change the default zoom mode, I added a new switch for command line in \common\chrome_switches.h/.cc

    // Turns on text only mode zoom supportconst wchar_t
    kZoomIsTextOnly[] = L"zoom-is-text-only";

    and add it into the switch_names array in RenderProcessHost::Init function (browser\render_process_host.cc). So, the browser process will propagate the switch to the child render process.

    static const wchar_t* const switch_names[] = {
    //...
    switches::kZoomIsTextOnly, };

Besides, I found a similar feature request has been submited to the chrome issues tracking. So, I will add some comment as patch for this issue. Wish Google could merge it into next offical release :)