Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does firefox/chrome draw the scrollbar?

Scrollbas in chrome or firefox does not have handle. They are handless control, but they do share the same apperance and behavior as the system default scrollbar. From which, we can infer that these browsers use the windows theme API, such as DrawThemeBackground, to draw the scrollbar.

However APIs such as DrawThemeBackground are GDI, chrome/firefox use skia/cario to render the whole canvas. My problem is how does they combine this two kind of technology?

Pesudo code:

WM_PAINT:
    prepare canvas;
    draw the canvas with skia/cario;
    bitblt to the dc;
    draw the theme-related handless control;(???)
    bitblt to the dc or directly draw to the dc;(???)

Do the procedure resemble the above one?

like image 303
Jichao Avatar asked Mar 19 '13 07:03

Jichao


1 Answers

Firefox

Actually cairo has a function to get DC from a cairo surface. Sample code:

VOID OnPaint(HWND hwnd, HDC hdc)
{
    RECT rc;
    ::GetClientRect(hwnd, &rc);
    //draw one line
    cairo_surface_t* surface = cairo_win32_surface_create(hdc);
    cairo_t* cr = cairo_create(surface);
    cairo_set_source_rgb(cr, 0xff, 0, 0);
    cairo_set_line_width(cr, 1);
    cairo_move_to(cr, 0, 0);
    cairo_line_to(cr, rc.right, rc.bottom);
    cairo_stroke(cr);
    cairo_destroy(cr);

    //draw the theme background
    HDC hdcNew = cairo_win32_surface_get_dc(surface);
    HTHEME hTheme = OpenThemeData(NULL, L"SCROLLBAR");
    RECT rcArrow;
    SetRect(&rcArrow, 30, 30, 45, 45);
    DrawThemeBackground(hTheme, hdcNew, SBP_ARROWBTN, ABS_DOWNDISABLED, &rcArrow, NULL);
    cairo_surface_destroy(surface);
}

gfxWindowsNativeDrawing::BeginNativeDrawing() call HDC gfxWindowsSurface::GetDCWithClip(gfxContext *ctx) finally call cairo win32.

Chrome

Skia does not provide the transformation functionality from skia canvas to hdc, but the project chrome add a extension to skia and fulfill this functionality.

in skia/ext/bitmap_platform_device_win.cc:

HDC BitmapPlatformDevice::BitmapPlatformDeviceData::GetBitmapDC() {
}

which create a memory dc from the canvas internal bitmap.

So when paint, whether you need use native dc or the general cairo/skia canvas does not matter any more.

Sample code:

void TestChromeExt(HWND hwnd, HDC hdc)
{
    RECT rc;
    GetClientRect(hwnd, &rc);
    skia::BitmapPlatformDevice* pBmpDevice = skia::BitmapPlatformDevice::Create(rc.right, rc.bottom, true);
    skia::PlatformCanvas *pCanvas = new skia::PlatformCanvas(pBmpDevice);
    pCanvas->clear(SK_ColorWHITE);
    SkPaint paint;
    paint.setColor(SK_ColorRED);
    paint.setStrokeWidth(3);
    paint.setStyle(SkPaint::kStroke_Style);
    pCanvas->drawLine(0, 0, rc.right, rc.bottom, paint);
    HDC memdc = skia::BeginPlatformPaint(pCanvas);
    RECT rcArrow;
    SetRect(&rcArrow, 100, 200, 120, 220);
    DrawThemeBackground(OpenThemeData(NULL, L"SCROLLBAR"), memdc, SBP_ARROWBTN, ABS_DOWNDISABLED, &rcArrow, NULL);
    skia::EndPlatformPaint(pCanvas);
    skia::DrawToNativeContext(pCanvas, hdc, 0, 0, &rc);
}

For Windows, to ensure the native look and feel, when visual style is enabled, these browsers would use DrawThemeBackground. However, when visual style is disabled( the classical mode is one) , they'll use DrawFrameControl to draw the controls.

like image 76
Jichao Avatar answered Oct 24 '22 09:10

Jichao