diff options
Diffstat (limited to 'webkit/tools/test_shell/webwidget_host_gtk.cc')
-rw-r--r-- | webkit/tools/test_shell/webwidget_host_gtk.cc | 436 |
1 files changed, 0 insertions, 436 deletions
diff --git a/webkit/tools/test_shell/webwidget_host_gtk.cc b/webkit/tools/test_shell/webwidget_host_gtk.cc deleted file mode 100644 index 593f1d5..0000000 --- a/webkit/tools/test_shell/webwidget_host_gtk.cc +++ /dev/null @@ -1,436 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "webkit/tools/test_shell/webwidget_host.h" - -#include <cairo/cairo.h> -#include <gtk/gtk.h> - -#include "base/basictypes.h" -#include "base/logging.h" -#include "skia/ext/bitmap_platform_device.h" -#include "skia/ext/platform_canvas.h" -#include "skia/ext/platform_device.h" -#include "third_party/WebKit/Source/Platform/chromium/public/WebSize.h" -#include "third_party/WebKit/Source/WebKit/chromium/public/gtk/WebInputEventFactory.h" -#include "third_party/WebKit/Source/WebKit/chromium/public/x11/WebScreenInfoFactory.h" -#include "third_party/WebKit/Source/WebKit/chromium/public/WebInputEvent.h" -#include "third_party/WebKit/Source/WebKit/chromium/public/WebPopupMenu.h" -#include "third_party/WebKit/Source/WebKit/chromium/public/WebScreenInfo.h" -#include "webkit/tools/test_shell/test_shell.h" -#include "webkit/tools/test_shell/test_shell_x11.h" - -using WebKit::WebInputEventFactory; -using WebKit::WebKeyboardEvent; -using WebKit::WebMouseEvent; -using WebKit::WebMouseWheelEvent; -using WebKit::WebPopupMenu; -using WebKit::WebScreenInfo; -using WebKit::WebScreenInfoFactory; -using WebKit::WebSize; -using WebKit::WebWidgetClient; - -namespace { - -// Used to store a backpointer to WebWidgetHost from our GtkWidget. -const char kWebWidgetHostKey[] = "webwidgethost"; - -// In response to an invalidation, we call into WebKit to do layout. On -// Windows, WM_PAINT is a virtual message so any extra invalidates that come up -// while it's doing layout are implicitly swallowed as soon as we actually do -// drawing via BeginPaint. -// -// Though GTK does know how to collapse multiple paint requests, it won't erase -// paint requests from the future when we start drawing. To avoid an infinite -// cycle of repaints, we track whether we're currently handling a redraw, and -// during that if we get told by WebKit that a region has become invalid, we -// still add that region to the local dirty rect but *don't* enqueue yet -// another "do a paint" message. -bool g_handling_expose = false; - -// ----------------------------------------------------------------------------- -// Callback functions to proxy to host... - -// The web contents are completely drawn and handled by WebKit, except that -// windowed plugins are GtkSockets on top of it. We need to place the -// GtkSockets inside a GtkContainer. We use a GtkFixed container, and the -// GtkSocket objects override a little bit to manage their size (see the code -// in webplugin_delegate_impl_gtk.cc). We listen on a the events we're -// interested in and forward them on to the WebWidgetHost. This class is a -// collection of static methods, implementing the widget related code. -class WebWidgetHostGtkWidget { - public: - // This will create a new widget used for hosting the web contents. We use - // our GtkDrawingAreaContainer here, for the reasons mentioned above. - static GtkWidget* CreateNewWidget(GtkWidget* parent_view, - WebWidgetHost* host) { - GtkWidget* widget = gtk_fixed_new(); - gtk_fixed_set_has_window(GTK_FIXED(widget), true); - - gtk_box_pack_start(GTK_BOX(parent_view), widget, TRUE, TRUE, 0); - - gtk_widget_add_events(widget, GDK_EXPOSURE_MASK | - GDK_POINTER_MOTION_MASK | - GDK_BUTTON_PRESS_MASK | - GDK_BUTTON_RELEASE_MASK | - GDK_KEY_PRESS_MASK | - GDK_KEY_RELEASE_MASK); - gtk_widget_set_can_focus(widget, TRUE); - g_signal_connect(widget, "size-request", - G_CALLBACK(&HandleSizeRequest), host); - g_signal_connect(widget, "size-allocate", - G_CALLBACK(&HandleSizeAllocate), host); - g_signal_connect(widget, "configure-event", - G_CALLBACK(&HandleConfigure), host); - g_signal_connect(widget, "expose-event", - G_CALLBACK(&HandleExpose), host); - g_signal_connect(widget, "destroy", - G_CALLBACK(&HandleDestroy), host); - g_signal_connect(widget, "key-press-event", - G_CALLBACK(&HandleKeyPress), host); - g_signal_connect(widget, "key-release-event", - G_CALLBACK(&HandleKeyRelease), host); - g_signal_connect(widget, "focus", - G_CALLBACK(&HandleFocus), host); - g_signal_connect(widget, "focus-in-event", - G_CALLBACK(&HandleFocusIn), host); - g_signal_connect(widget, "focus-out-event", - G_CALLBACK(&HandleFocusOut), host); - g_signal_connect(widget, "button-press-event", - G_CALLBACK(&HandleButtonPress), host); - g_signal_connect(widget, "button-release-event", - G_CALLBACK(&HandleButtonRelease), host); - g_signal_connect(widget, "motion-notify-event", - G_CALLBACK(&HandleMotionNotify), host); - g_signal_connect(widget, "scroll-event", - G_CALLBACK(&HandleScroll), host); - - g_object_set_data(G_OBJECT(widget), kWebWidgetHostKey, host); - return widget; - } - - private: - // Our size was requested. We let the GtkFixed do its normal calculation, - // after which this callback is called. The GtkFixed will come up with a - // requisition based on its children, which include plugin windows. Since - // we don't want to prevent resizing smaller than a plugin window, we need to - // control the size ourself. - static void HandleSizeRequest(GtkWidget* widget, - GtkRequisition* req, - WebWidgetHost* host) { - // This is arbitrary, but the WebKit scrollbars try to shrink themselves - // if the browser window is too small. Give them some space. - static const int kMinWidthHeight = 64; - - req->width = kMinWidthHeight; - req->height = kMinWidthHeight; - } - - // Our size has changed. - static void HandleSizeAllocate(GtkWidget* widget, - GtkAllocation* allocation, - WebWidgetHost* host) { - host->Resize(WebSize(allocation->width, allocation->height)); - } - - // Size, position, or stacking of the GdkWindow changed. - static gboolean HandleConfigure(GtkWidget* widget, - GdkEventConfigure* config, - WebWidgetHost* host) { - host->Resize(WebSize(config->width, config->height)); - return FALSE; - } - - // A portion of the GdkWindow needs to be redraw. - static gboolean HandleExpose(GtkWidget* widget, - GdkEventExpose* expose, - WebWidgetHost* host) { - // See comments above about what g_handling_expose is for. - g_handling_expose = true; - gfx::Rect rect(expose->area); - host->UpdatePaintRect(rect); - host->Paint(); - g_handling_expose = false; - return FALSE; - } - - // The GdkWindow was destroyed. - static gboolean HandleDestroy(GtkWidget* widget, void* unused) { - // The associated WebWidgetHost instance may have already been destroyed. - WebWidgetHost* host = static_cast<WebWidgetHost*>( - g_object_get_data(G_OBJECT(widget), kWebWidgetHostKey)); - if (host) - host->WindowDestroyed(); - return FALSE; - } - - // Keyboard key pressed. - static gboolean HandleKeyPress(GtkWidget* widget, - GdkEventKey* event, - WebWidgetHost* host) { - host->webwidget()->handleInputEvent( - WebInputEventFactory::keyboardEvent(event)); - - // In the browser we do a ton of work with IMEs. This is some minimal - // code to make basic text work in test_shell, but doesn't cover IME. - // This is a copy of the logic in ProcessUnfilteredKeyPressEvent in - // render_widget_host_view_gtk.cc . - if (event->type == GDK_KEY_PRESS) { - WebKeyboardEvent wke = WebInputEventFactory::keyboardEvent(event); - if (wke.text[0]) { - wke.type = WebKit::WebInputEvent::Char; - host->webwidget()->handleInputEvent(wke); - } - } - - return FALSE; - } - - // Keyboard key released. - static gboolean HandleKeyRelease(GtkWidget* widget, - GdkEventKey* event, - WebWidgetHost* host) { - return HandleKeyPress(widget, event, host); - } - - // This signal is called when arrow keys or tab is pressed. If we return - // true, we prevent focus from being moved to another widget. If we want to - // allow focus to be moved outside of web contents, we need to implement - // WebViewDelegate::TakeFocus in the test webview delegate. - static gboolean HandleFocus(GtkWidget* widget, - GdkEventFocus* focus, - WebWidgetHost* host) { - return TRUE; - } - - // Keyboard focus entered. - static gboolean HandleFocusIn(GtkWidget* widget, - GdkEventFocus* focus, - WebWidgetHost* host) { - // Ignore focus calls in layout test mode so that tests don't mess with each - // other's focus when running in parallel. - if (!TestShell::layout_test_mode()) - host->webwidget()->setFocus(true); - return TRUE; - } - - // Keyboard focus left. - static gboolean HandleFocusOut(GtkWidget* widget, - GdkEventFocus* focus, - WebWidgetHost* host) { - // Ignore focus calls in layout test mode so that tests don't mess with each - // other's focus when running in parallel. - if (!TestShell::layout_test_mode()) - host->webwidget()->setFocus(false); - return TRUE; - } - - // Mouse button down. - static gboolean HandleButtonPress(GtkWidget* widget, - GdkEventButton* event, - WebWidgetHost* host) { - if (!(event->button == 1 || event->button == 2 || event->button == 3)) - return FALSE; // We do not forward any other buttons to the renderer. - if (event->type == GDK_2BUTTON_PRESS || event->type == GDK_3BUTTON_PRESS) - return FALSE; - host->webwidget()->handleInputEvent( - WebInputEventFactory::mouseEvent(event)); - return FALSE; - } - - // Mouse button up. - static gboolean HandleButtonRelease(GtkWidget* widget, - GdkEventButton* event, - WebWidgetHost* host) { - return HandleButtonPress(widget, event, host); - } - - // Mouse pointer movements. - static gboolean HandleMotionNotify(GtkWidget* widget, - GdkEventMotion* event, - WebWidgetHost* host) { - host->webwidget()->handleInputEvent( - WebInputEventFactory::mouseEvent(event)); - return FALSE; - } - - // Mouse scroll wheel. - static gboolean HandleScroll(GtkWidget* widget, - GdkEventScroll* event, - WebWidgetHost* host) { - host->webwidget()->handleInputEvent( - WebInputEventFactory::mouseWheelEvent(event)); - return FALSE; - } - - DISALLOW_IMPLICIT_CONSTRUCTORS(WebWidgetHostGtkWidget); -}; - -} // namespace - -// This is provided so that the webview can reuse the custom GTK window code. -// static -gfx::NativeView WebWidgetHost::CreateWidget( - gfx::NativeView parent_view, WebWidgetHost* host) { - return WebWidgetHostGtkWidget::CreateNewWidget(parent_view, host); -} - -// static -WebWidgetHost* WebWidgetHost::Create(GtkWidget* parent_view, - WebWidgetClient* client) { - WebWidgetHost* host = new WebWidgetHost(); - host->view_ = CreateWidget(parent_view, host); - host->webwidget_ = WebPopupMenu::create(client); - // We manage our own double buffering because we need to be able to update - // the expose area in an ExposeEvent within the lifetime of the event handler. - gtk_widget_set_double_buffered(GTK_WIDGET(host->view_), false); - - return host; -} - -void WebWidgetHost::UpdatePaintRect(const gfx::Rect& rect) { - paint_rect_.Union(rect); -} - -void WebWidgetHost::DidInvalidateRect(const gfx::Rect& damaged_rect) { - DLOG_IF(WARNING, painting_) << "unexpected invalidation while painting"; - - UpdatePaintRect(damaged_rect); - - if (!g_handling_expose) { - gtk_widget_queue_draw_area(GTK_WIDGET(view_), damaged_rect.x(), - damaged_rect.y(), damaged_rect.width(), damaged_rect.height()); - } -} - -void WebWidgetHost::DidScrollRect(int dx, int dy, const gfx::Rect& clip_rect) { - // This is used for optimizing painting when the renderer is scrolled. We're - // currently not doing any optimizations so just invalidate the region. - DidInvalidateRect(clip_rect); -} - -void WebWidgetHost::ScheduleComposite() { - int width = logical_size_.width(); - int height = logical_size_.height(); - GdkRectangle grect = { - 0, - 0, - width, - height - }; - GdkWindow* window = view_->window; - gdk_window_invalidate_rect(window, &grect, 0); -} - -WebWidgetHost::WebWidgetHost() - : view_(NULL), - webwidget_(NULL), - scroll_dx_(0), - scroll_dy_(0), - weak_factory_(this) { - set_painting(false); -} - -WebWidgetHost::~WebWidgetHost() { - // We may be deleted before the view_. Clear out the signals so that we don't - // attempt to invoke something on a deleted object. - g_object_set_data(G_OBJECT(view_), kWebWidgetHostKey, NULL); - g_signal_handlers_disconnect_matched(view_, - G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, this); - webwidget_->close(); -} - -void WebWidgetHost::Resize(const gfx::Size &newsize) { - // The pixel buffer backing us is now the wrong size - canvas_.reset(); - logical_size_ = newsize; - webwidget_->resize(newsize); -} - -void WebWidgetHost::Paint() { - int width = logical_size_.width(); - int height = logical_size_.height(); - gfx::Rect client_rect(width, height); - - // Allocate a canvas if necessary - if (!canvas_) { - ResetScrollRect(); - paint_rect_ = client_rect; - canvas_.reset(skia::CreatePlatformCanvas(width, height, true, 0, - skia::RETURN_NULL_ON_FAILURE)); - if (!canvas_) { - // memory allocation failed, we can't paint. - LOG(ERROR) << "Failed to allocate memory for " << width << "x" << height; - return; - } - } - - webwidget_->animate(0.0); - - // This may result in more invalidation - webwidget_->layout(); - - // Paint the canvas if necessary. Allow painting to generate extra rects the - // first time we call it. This is necessary because some WebCore rendering - // objects update their layout only when painted. - // Store the total area painted in total_paint. Then tell the gdk window - // to update that area after we're done painting it. - gfx::Rect total_paint; - for (int i = 0; i < 2; ++i) { - paint_rect_.Intersect(client_rect); - if (!paint_rect_.IsEmpty()) { - gfx::Rect rect(paint_rect_); - paint_rect_ = gfx::Rect(); - - DLOG_IF(WARNING, i == 1) << "painting caused additional invalidations"; - PaintRect(rect); - total_paint.Union(rect); - } - } - //DCHECK(paint_rect_.IsEmpty()); - - // Invalidate the paint region on the widget's underlying gdk window. Note - // that gdk_window_invalidate_* will generate extra expose events, which - // we wish to avoid. So instead we use calls to begin_paint/end_paint. - GdkRectangle grect = { - total_paint.x(), - total_paint.y(), - total_paint.width(), - total_paint.height(), - }; - GdkWindow* window = view_->window; - gdk_window_begin_paint_rect(window, &grect); - - // BitBlit to the gdk window. - skia::ScopedPlatformPaint scoped_platform_paint(canvas_.get()); - cairo_t* source_surface = scoped_platform_paint.GetPlatformSurface(); - cairo_t* cairo_drawable = gdk_cairo_create(window); - cairo_set_source_surface(cairo_drawable, cairo_get_target(source_surface), - 0, 0); - cairo_paint(cairo_drawable); - cairo_destroy(cairo_drawable); - - gdk_window_end_paint(window); -} - -WebScreenInfo WebWidgetHost::GetScreenInfo() { - Display* display = test_shell_x11::GtkWidgetGetDisplay(view_); - int screen_num = test_shell_x11::GtkWidgetGetScreenNum(view_); - return WebScreenInfoFactory::screenInfo(display, screen_num); -} - -void WebWidgetHost::ResetScrollRect() { - // This method is only needed for optimized scroll painting, which we don't - // care about in the test shell, yet. -} - -void WebWidgetHost::PaintRect(const gfx::Rect& rect) { - set_painting(true); - webwidget_->paint(canvas_.get(), rect); - set_painting(false); -} - -void WebWidgetHost::WindowDestroyed() { - delete this; -} |