From 2cff005220a16c7d1f814d5495887823b634f077 Mon Sep 17 00:00:00 2001 From: "jam@chromium.org" Date: Fri, 18 Mar 2011 16:51:44 +0000 Subject: Move render_widget files to content. TBR=avi Review URL: http://codereview.chromium.org/6709032 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@78703 0039d316-1c4b-4281-b951-d872f2087c98 --- chrome/chrome_renderer.gypi | 11 - chrome/chrome_tests.gypi | 6 +- chrome/renderer/render_view.cc | 4 +- chrome/renderer/render_view.h | 2 +- chrome/renderer/render_widget.cc | 1114 -------------------- chrome/renderer/render_widget.h | 381 ------- chrome/renderer/render_widget_browsertest.cc | 149 --- chrome/renderer/render_widget_browsertest.h | 58 - chrome/renderer/render_widget_fullscreen.cc | 51 - chrome/renderer/render_widget_fullscreen.h | 30 - chrome/renderer/render_widget_fullscreen_pepper.cc | 395 ------- chrome/renderer/render_widget_fullscreen_pepper.h | 89 -- chrome/renderer/render_widget_unittest.cc | 61 -- chrome/renderer/renderer.sb | 30 - .../phishing_thumbnailer_browsertest.cc | 2 +- content/content_renderer.gypi | 16 + content/renderer/ggl.cc | 2 +- content/renderer/render_widget.cc | 1114 ++++++++++++++++++++ content/renderer/render_widget.h | 381 +++++++ content/renderer/render_widget_browsertest.cc | 150 +++ content/renderer/render_widget_browsertest.h | 58 + content/renderer/render_widget_fullscreen.cc | 51 + content/renderer/render_widget_fullscreen.h | 30 + .../renderer/render_widget_fullscreen_pepper.cc | 395 +++++++ content/renderer/render_widget_fullscreen_pepper.h | 89 ++ content/renderer/render_widget_unittest.cc | 61 ++ content/renderer/renderer.sb | 30 + 27 files changed, 2383 insertions(+), 2377 deletions(-) delete mode 100644 chrome/renderer/render_widget.cc delete mode 100644 chrome/renderer/render_widget.h delete mode 100644 chrome/renderer/render_widget_browsertest.cc delete mode 100644 chrome/renderer/render_widget_browsertest.h delete mode 100644 chrome/renderer/render_widget_fullscreen.cc delete mode 100644 chrome/renderer/render_widget_fullscreen.h delete mode 100644 chrome/renderer/render_widget_fullscreen_pepper.cc delete mode 100644 chrome/renderer/render_widget_fullscreen_pepper.h delete mode 100644 chrome/renderer/render_widget_unittest.cc delete mode 100644 chrome/renderer/renderer.sb create mode 100644 content/renderer/render_widget.cc create mode 100644 content/renderer/render_widget.h create mode 100644 content/renderer/render_widget_browsertest.cc create mode 100644 content/renderer/render_widget_browsertest.h create mode 100644 content/renderer/render_widget_fullscreen.cc create mode 100644 content/renderer/render_widget_fullscreen.h create mode 100644 content/renderer/render_widget_fullscreen_pepper.cc create mode 100644 content/renderer/render_widget_fullscreen_pepper.h create mode 100644 content/renderer/render_widget_unittest.cc create mode 100644 content/renderer/renderer.sb diff --git a/chrome/chrome_renderer.gypi b/chrome/chrome_renderer.gypi index dc65d2a..7908e2d 100644 --- a/chrome/chrome_renderer.gypi +++ b/chrome/chrome_renderer.gypi @@ -119,12 +119,6 @@ 'renderer/render_view.h', 'renderer/render_view_observer.cc', 'renderer/render_view_observer.h', - 'renderer/render_widget.cc', - 'renderer/render_widget.h', - 'renderer/render_widget_fullscreen.cc', - 'renderer/render_widget_fullscreen.h', - 'renderer/render_widget_fullscreen_pepper.cc', - 'renderer/render_widget_fullscreen_pepper.h', 'renderer/renderer_glue.cc', 'renderer/renderer_histogram_snapshots.cc', 'renderer/renderer_histogram_snapshots.h', @@ -179,11 +173,6 @@ 'renderer/visitedlink_slave.cc', 'renderer/visitedlink_slave.h', ], - 'link_settings': { - 'mac_bundle_resources': [ - 'renderer/renderer.sb', - ], - }, 'conditions': [ ['disable_nacl!=1', { 'dependencies': [ diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index 39c15cd..7ed376b 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -1753,7 +1753,6 @@ 'renderer/net/renderer_predictor_unittest.cc', 'renderer/render_process_unittest.cc', 'renderer/render_thread_unittest.cc', - 'renderer/render_widget_unittest.cc', 'renderer/renderer_about_handler_unittest.cc', 'renderer/renderer_main_unittest.cc', 'renderer/safe_browsing/features_unittest.cc', @@ -1840,6 +1839,7 @@ '../content/renderer/gpu_video_decoder_host_unittest.cc', '../content/renderer/media/audio_renderer_impl_unittest.cc', '../content/renderer/paint_aggregator_unittest.cc', + '../content/renderer/render_widget_unittest.cc', '../testing/gtest_mac_unittest.mm', '../third_party/cld/encodings/compact_lang_det/compact_lang_det_unittest_small.cc', '../webkit/fileapi/file_system_dir_url_request_job_unittest.cc', @@ -2293,8 +2293,6 @@ 'renderer/page_click_tracker_browsertest.cc', 'renderer/render_view_browsertest.cc', 'renderer/render_view_browsertest_mac.mm', - 'renderer/render_widget_browsertest.cc', - 'renderer/render_widget_browsertest.h', 'renderer/safe_browsing/malware_dom_details_browsertest.cc', 'renderer/safe_browsing/phishing_classifier_browsertest.cc', 'renderer/safe_browsing/phishing_classifier_delegate_browsertest.cc', @@ -2322,6 +2320,8 @@ '../content/browser/webui/web_ui_handler_browsertest.cc', '../content/browser/webui/web_ui_handler_browsertest.h', '../content/common/file_path_watcher/file_path_watcher_browsertest.cc', + '../content/renderer/render_widget_browsertest.cc', + '../content/renderer/render_widget_browsertest.h', ], 'conditions': [ ['chromeos==0', { diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc index fc07924..a1f408a 100644 --- a/chrome/renderer/render_view.cc +++ b/chrome/renderer/render_view.cc @@ -66,8 +66,6 @@ #include "chrome/renderer/render_thread.h" #include "chrome/renderer/render_view_observer.h" #include "chrome/renderer/render_view_visitor.h" -#include "chrome/renderer/render_widget_fullscreen.h" -#include "chrome/renderer/render_widget_fullscreen_pepper.h" #include "chrome/renderer/safe_browsing/malware_dom_details.h" #include "chrome/renderer/safe_browsing/phishing_classifier_delegate.h" #include "chrome/renderer/searchbox.h" @@ -99,6 +97,8 @@ #include "content/renderer/plugin_channel_host.h" #include "content/renderer/renderer_webapplicationcachehost_impl.h" #include "content/renderer/renderer_webstoragenamespace_impl.h" +#include "content/renderer/render_widget_fullscreen.h" +#include "content/renderer/render_widget_fullscreen_pepper.h" #include "content/renderer/speech_input_dispatcher.h" #include "content/renderer/webgraphicscontext3d_command_buffer_impl.h" #include "content/renderer/webplugin_delegate_proxy.h" diff --git a/chrome/renderer/render_view.h b/chrome/renderer/render_view.h index 17bf707..0b32c1c 100644 --- a/chrome/renderer/render_view.h +++ b/chrome/renderer/render_view.h @@ -28,11 +28,11 @@ #include "chrome/common/view_types.h" #include "chrome/renderer/external_popup_menu.h" #include "chrome/renderer/page_load_histograms.h" -#include "chrome/renderer/render_widget.h" #include "content/renderer/renderer_webcookiejar_impl.h" #include "content/common/navigation_gesture.h" #include "content/common/page_zoom.h" #include "content/renderer/pepper_plugin_delegate_impl.h" +#include "content/renderer/render_widget.h" #include "ipc/ipc_platform_file.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebAccessibilityNotification.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebConsoleMessage.h" diff --git a/chrome/renderer/render_widget.cc b/chrome/renderer/render_widget.cc deleted file mode 100644 index 2b47560..0000000 --- a/chrome/renderer/render_widget.cc +++ /dev/null @@ -1,1114 +0,0 @@ -// Copyright (c) 2010 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 "chrome/renderer/render_widget.h" - -#include "app/surface/transport_dib.h" -#include "base/command_line.h" -#include "base/logging.h" -#include "base/message_loop.h" -#include "base/metrics/histogram.h" -#include "base/scoped_ptr.h" -#include "build/build_config.h" -#include "chrome/common/chrome_switches.h" -#include "chrome/common/render_messages.h" -#include "chrome/common/render_messages_params.h" -#include "chrome/renderer/render_process.h" -#include "chrome/renderer/render_thread.h" -#include "content/renderer/renderer_webkitclient_impl.h" -#include "gpu/common/gpu_trace_event.h" -#include "ipc/ipc_sync_message.h" -#include "skia/ext/platform_canvas.h" -#include "third_party/skia/include/core/SkShader.h" -#include "third_party/WebKit/Source/WebKit/chromium/public/WebCursorInfo.h" -#include "third_party/WebKit/Source/WebKit/chromium/public/WebPopupMenu.h" -#include "third_party/WebKit/Source/WebKit/chromium/public/WebPopupMenuInfo.h" -#include "third_party/WebKit/Source/WebKit/chromium/public/WebRect.h" -#include "third_party/WebKit/Source/WebKit/chromium/public/WebScreenInfo.h" -#include "third_party/WebKit/Source/WebKit/chromium/public/WebSize.h" -#include "ui/gfx/point.h" -#include "ui/gfx/size.h" -#include "webkit/glue/webkit_glue.h" -#include "webkit/plugins/npapi/webplugin.h" -#include "webkit/plugins/ppapi/ppapi_plugin_instance.h" - -#if defined(OS_POSIX) -#include "ipc/ipc_channel_posix.h" -#include "third_party/skia/include/core/SkPixelRef.h" -#include "third_party/skia/include/core/SkMallocPixelRef.h" -#endif // defined(OS_POSIX) - -#include "third_party/WebKit/Source/WebKit/chromium/public/WebWidget.h" - -using WebKit::WebCompositionUnderline; -using WebKit::WebCursorInfo; -using WebKit::WebInputEvent; -using WebKit::WebMouseEvent; -using WebKit::WebNavigationPolicy; -using WebKit::WebPopupMenu; -using WebKit::WebPopupMenuInfo; -using WebKit::WebPopupType; -using WebKit::WebRect; -using WebKit::WebScreenInfo; -using WebKit::WebSize; -using WebKit::WebTextDirection; -using WebKit::WebTextInputType; -using WebKit::WebVector; -using WebKit::WebWidget; - -RenderWidget::RenderWidget(RenderThreadBase* render_thread, - WebKit::WebPopupType popup_type) - : routing_id_(MSG_ROUTING_NONE), - webwidget_(NULL), - opener_id_(MSG_ROUTING_NONE), - render_thread_(render_thread), - host_window_(0), - current_paint_buf_(NULL), - next_paint_flags_(0), - update_reply_pending_(false), - did_show_(false), - is_hidden_(false), - needs_repainting_on_restore_(false), - has_focus_(false), - handling_input_event_(false), - closing_(false), - input_method_is_active_(false), - text_input_type_(WebKit::WebTextInputTypeNone), - popup_type_(popup_type), - pending_window_rect_count_(0), - suppress_next_char_events_(false), - is_accelerated_compositing_active_(false), - animation_update_pending_(false), - animation_task_posted_(false) { - RenderProcess::current()->AddRefProcess(); - DCHECK(render_thread_); -} - -RenderWidget::~RenderWidget() { - DCHECK(!webwidget_) << "Leaking our WebWidget!"; - if (current_paint_buf_) { - RenderProcess::current()->ReleaseTransportDIB(current_paint_buf_); - current_paint_buf_ = NULL; - } - RenderProcess::current()->ReleaseProcess(); -} - -// static -RenderWidget* RenderWidget::Create(int32 opener_id, - RenderThreadBase* render_thread, - WebKit::WebPopupType popup_type) { - DCHECK(opener_id != MSG_ROUTING_NONE); - scoped_refptr widget(new RenderWidget(render_thread, - popup_type)); - widget->Init(opener_id); // adds reference - return widget; -} - -// static -WebWidget* RenderWidget::CreateWebWidget(RenderWidget* render_widget) { - switch (render_widget->popup_type_) { - case WebKit::WebPopupTypeNone: // Nothing to create. - break; - case WebKit::WebPopupTypeSelect: - case WebKit::WebPopupTypeSuggestion: - return WebPopupMenu::create(render_widget); - default: - NOTREACHED(); - } - return NULL; -} - -void RenderWidget::Init(int32 opener_id) { - DoInit(opener_id, - RenderWidget::CreateWebWidget(this), - new ViewHostMsg_CreateWidget(opener_id, popup_type_, &routing_id_)); -} - -void RenderWidget::DoInit(int32 opener_id, - WebWidget* web_widget, - IPC::SyncMessage* create_widget_message) { - DCHECK(!webwidget_); - - if (opener_id != MSG_ROUTING_NONE) - opener_id_ = opener_id; - - webwidget_ = web_widget; - - bool result = render_thread_->Send(create_widget_message); - if (result) { - render_thread_->AddRoute(routing_id_, this); - // Take a reference on behalf of the RenderThread. This will be balanced - // when we receive ViewMsg_Close. - AddRef(); - } else { - DCHECK(false); - } -} - -// This is used to complete pending inits and non-pending inits. For non- -// pending cases, the parent will be the same as the current parent. This -// indicates we do not need to reparent or anything. -void RenderWidget::CompleteInit(gfx::NativeViewId parent_hwnd) { - DCHECK(routing_id_ != MSG_ROUTING_NONE); - - host_window_ = parent_hwnd; - - Send(new ViewHostMsg_RenderViewReady(routing_id_)); -} - -bool RenderWidget::OnMessageReceived(const IPC::Message& message) { - bool handled = true; - IPC_BEGIN_MESSAGE_MAP(RenderWidget, message) - IPC_MESSAGE_HANDLER(ViewMsg_Close, OnClose) - IPC_MESSAGE_HANDLER(ViewMsg_CreatingNew_ACK, OnCreatingNewAck) - IPC_MESSAGE_HANDLER(ViewMsg_Resize, OnResize) - IPC_MESSAGE_HANDLER(ViewMsg_WasHidden, OnWasHidden) - IPC_MESSAGE_HANDLER(ViewMsg_WasRestored, OnWasRestored) - IPC_MESSAGE_HANDLER(ViewMsg_UpdateRect_ACK, OnUpdateRectAck) - IPC_MESSAGE_HANDLER(ViewMsg_HandleInputEvent, OnHandleInputEvent) - IPC_MESSAGE_HANDLER(ViewMsg_MouseCaptureLost, OnMouseCaptureLost) - IPC_MESSAGE_HANDLER(ViewMsg_SetFocus, OnSetFocus) - IPC_MESSAGE_HANDLER(ViewMsg_SetInputMethodActive, OnSetInputMethodActive) - IPC_MESSAGE_HANDLER(ViewMsg_ImeSetComposition, OnImeSetComposition) - IPC_MESSAGE_HANDLER(ViewMsg_ImeConfirmComposition, OnImeConfirmComposition) - IPC_MESSAGE_HANDLER(ViewMsg_PaintAtSize, OnMsgPaintAtSize) - IPC_MESSAGE_HANDLER(ViewMsg_Repaint, OnMsgRepaint) - IPC_MESSAGE_HANDLER(ViewMsg_SetTextDirection, OnSetTextDirection) - IPC_MESSAGE_HANDLER(ViewMsg_Move_ACK, OnRequestMoveAck) - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP() - return handled; -} - -bool RenderWidget::Send(IPC::Message* message) { - // Don't send any messages after the browser has told us to close. - if (closing_) { - delete message; - return false; - } - - // If given a messsage without a routing ID, then assign our routing ID. - if (message->routing_id() == MSG_ROUTING_NONE) - message->set_routing_id(routing_id_); - - return render_thread_->Send(message); -} - -// Got a response from the browser after the renderer decided to create a new -// view. -void RenderWidget::OnCreatingNewAck(gfx::NativeViewId parent) { - DCHECK(routing_id_ != MSG_ROUTING_NONE); - - CompleteInit(parent); -} - -void RenderWidget::OnClose() { - if (closing_) - return; - closing_ = true; - - // Browser correspondence is no longer needed at this point. - if (routing_id_ != MSG_ROUTING_NONE) { - render_thread_->RemoveRoute(routing_id_); - SetHidden(false); - } - - // If there is a Send call on the stack, then it could be dangerous to close - // now. Post a task that only gets invoked when there are no nested message - // loops. - MessageLoop::current()->PostNonNestableTask(FROM_HERE, - NewRunnableMethod(this, &RenderWidget::Close)); - - // Balances the AddRef taken when we called AddRoute. - Release(); -} - -void RenderWidget::OnResize(const gfx::Size& new_size, - const gfx::Rect& resizer_rect) { - // During shutdown we can just ignore this message. - if (!webwidget_) - return; - - // We shouldn't be asked to resize to our current size. - DCHECK(size_ != new_size || resizer_rect_ != resizer_rect); - - // Remember the rect where the resize corner will be drawn. - resizer_rect_ = resizer_rect; - - if (size_ == new_size) - return; - - // TODO(darin): We should not need to reset this here. - SetHidden(false); - needs_repainting_on_restore_ = false; - - size_ = new_size; - - // We should not be sent a Resize message if we have not ACK'd the previous - DCHECK(!next_paint_is_resize_ack()); - - paint_aggregator_.ClearPendingUpdate(); - - // When resizing, we want to wait to paint before ACK'ing the resize. This - // ensures that we only resize as fast as we can paint. We only need to send - // an ACK if we are resized to a non-empty rect. - webwidget_->resize(new_size); - if (!new_size.IsEmpty()) { - if (!is_accelerated_compositing_active_) { - // Resize should have caused an invalidation of the entire view. - DCHECK(paint_aggregator_.HasPendingUpdate()); - } - - // We will send the Resize_ACK flag once we paint again. - set_next_paint_is_resize_ack(); - } -} - -void RenderWidget::OnWasHidden() { - // Go into a mode where we stop generating paint and scrolling events. - SetHidden(true); -} - -void RenderWidget::OnWasRestored(bool needs_repainting) { - // During shutdown we can just ignore this message. - if (!webwidget_) - return; - - // See OnWasHidden - SetHidden(false); - - if (!needs_repainting && !needs_repainting_on_restore_) - return; - needs_repainting_on_restore_ = false; - - // Tag the next paint as a restore ack, which is picked up by - // DoDeferredUpdate when it sends out the next PaintRect message. - set_next_paint_is_restore_ack(); - - // Generate a full repaint. - if (!is_accelerated_compositing_active_) { - didInvalidateRect(gfx::Rect(size_.width(), size_.height())); - } else { - scheduleComposite(); - } -} - -void RenderWidget::OnRequestMoveAck() { - DCHECK(pending_window_rect_count_); - pending_window_rect_count_--; -} - -void RenderWidget::OnUpdateRectAck() { - DCHECK(update_reply_pending()); - update_reply_pending_ = false; - - // If we sent an UpdateRect message with a zero-sized bitmap, then we should - // have no current paint buffer. - if (current_paint_buf_) { - RenderProcess::current()->ReleaseTransportDIB(current_paint_buf_); - current_paint_buf_ = NULL; - } - - // Notify subclasses. - DidFlushPaint(); - - // Continue painting if necessary... - CallDoDeferredUpdate(); -} - -void RenderWidget::OnHandleInputEvent(const IPC::Message& message) { - void* iter = NULL; - - const char* data; - int data_length; - handling_input_event_ = true; - if (!message.ReadData(&iter, &data, &data_length)) { - handling_input_event_ = false; - return; - } - - const WebInputEvent* input_event = - reinterpret_cast(data); - - bool is_keyboard_shortcut = false; - // is_keyboard_shortcut flag is only available for RawKeyDown events. - if (input_event->type == WebInputEvent::RawKeyDown) - message.ReadBool(&iter, &is_keyboard_shortcut); - - bool processed = false; - if (input_event->type != WebInputEvent::Char || !suppress_next_char_events_) { - suppress_next_char_events_ = false; - if (webwidget_) - processed = webwidget_->handleInputEvent(*input_event); - } - - // If this RawKeyDown event corresponds to a browser keyboard shortcut and - // it's not processed by webkit, then we need to suppress the upcoming Char - // events. - if (!processed && is_keyboard_shortcut) - suppress_next_char_events_ = true; - - IPC::Message* response = new ViewHostMsg_HandleInputEvent_ACK(routing_id_); - response->WriteInt(input_event->type); - response->WriteBool(processed); - - if ((input_event->type == WebInputEvent::MouseMove || - input_event->type == WebInputEvent::MouseWheel || - input_event->type == WebInputEvent::TouchMove) && - paint_aggregator_.HasPendingUpdate()) { - // We want to rate limit the input events in this case, so we'll wait for - // painting to finish before ACKing this message. - if (pending_input_event_ack_.get()) { - // As two different kinds of events could cause us to postpone an ack - // we send it now, if we have one pending. The Browser should never - // send us the same kind of event we are delaying the ack for. - Send(pending_input_event_ack_.release()); - } - pending_input_event_ack_.reset(response); - } else { - Send(response); - } - - handling_input_event_ = false; - - if (WebInputEvent::isKeyboardEventType(input_event->type)) - DidHandleKeyEvent(); - if (WebInputEvent::isMouseEventType(input_event->type)) - DidHandleMouseEvent(*(static_cast(input_event))); -} - -void RenderWidget::OnMouseCaptureLost() { - if (webwidget_) - webwidget_->mouseCaptureLost(); -} - -void RenderWidget::OnSetFocus(bool enable) { - has_focus_ = enable; - if (webwidget_) - webwidget_->setFocus(enable); -} - -void RenderWidget::ClearFocus() { - // We may have got the focus from the browser before this gets processed, in - // which case we do not want to unfocus ourself. - if (!has_focus_ && webwidget_) - webwidget_->setFocus(false); -} - -void RenderWidget::PaintRect(const gfx::Rect& rect, - const gfx::Point& canvas_origin, - skia::PlatformCanvas* canvas) { - - canvas->save(); - - // Bring the canvas into the coordinate system of the paint rect. - canvas->translate(static_cast(-canvas_origin.x()), - static_cast(-canvas_origin.y())); - - // If there is a custom background, tile it. - if (!background_.empty()) { - SkPaint paint; - SkShader* shader = SkShader::CreateBitmapShader(background_, - SkShader::kRepeat_TileMode, - SkShader::kRepeat_TileMode); - paint.setShader(shader)->unref(); - paint.setXfermodeMode(SkXfermode::kSrcOver_Mode); - canvas->drawPaint(paint); - } - - // First see if this rect is a plugin that can paint itself faster. - TransportDIB* optimized_dib = NULL; - gfx::Rect optimized_copy_rect, optimized_copy_location; - webkit::ppapi::PluginInstance* optimized_instance = - GetBitmapForOptimizedPluginPaint(rect, &optimized_dib, - &optimized_copy_location, - &optimized_copy_rect); - if (optimized_instance) { - // This plugin can be optimize-painted and we can just ask it to paint - // itself. We don't actually need the TransportDIB in this case. - // - // This is an optimization for PPAPI plugins that know they're on top of - // the page content. If this rect is inside such a plugin, we can save some - // time and avoid re-rendering the page content which we know will be - // covered by the plugin later (this time can be significant, especially - // for a playing movie that is invalidating a lot). - // - // In the plugin movie case, hopefully the similar call to - // GetBitmapForOptimizedPluginPaint in DoDeferredUpdate handles the - // painting, because that avoids copying the plugin image to a different - // paint rect. Unfortunately, if anything on the page is animating other - // than the movie, it break this optimization since the union of the - // invalid regions will be larger than the plugin. - // - // This code optimizes that case, where we can still avoid painting in - // WebKit and filling the background (which can be slow) and just painting - // the plugin. Unlike the DoDeferredUpdate case, an extra copy is still - // required. - optimized_instance->Paint(webkit_glue::ToWebCanvas(canvas), - optimized_copy_location, rect); - } else { - // Normal painting case. - webwidget_->paint(webkit_glue::ToWebCanvas(canvas), rect); - - // Flush to underlying bitmap. TODO(darin): is this needed? - canvas->getTopPlatformDevice().accessBitmap(false); - } - - PaintDebugBorder(rect, canvas); - canvas->restore(); -} - -void RenderWidget::PaintDebugBorder(const gfx::Rect& rect, - skia::PlatformCanvas* canvas) { - static bool kPaintBorder = - CommandLine::ForCurrentProcess()->HasSwitch(switches::kShowPaintRects); - if (!kPaintBorder) - return; - - // Cycle through these colors to help distinguish new paint rects. - const SkColor colors[] = { - SkColorSetARGB(0x3F, 0xFF, 0, 0), - SkColorSetARGB(0x3F, 0xFF, 0, 0xFF), - SkColorSetARGB(0x3F, 0, 0, 0xFF), - }; - static int color_selector = 0; - - SkPaint paint; - paint.setStyle(SkPaint::kStroke_Style); - paint.setColor(colors[color_selector++ % arraysize(colors)]); - paint.setStrokeWidth(1); - - SkIRect irect; - irect.set(rect.x(), rect.y(), rect.right() - 1, rect.bottom() - 1); - canvas->drawIRect(irect, paint); -} - -void RenderWidget::AnimationCallback() { - animation_task_posted_ = false; - if (!animation_update_pending_) - return; - if (!animation_floor_time_.is_null()) { - // Record when we fired (according to base::Time::Now()) relative to when - // we posted the task to quantify how much the base::Time/base::TimeTicks - // skew is affecting animations. - base::TimeDelta animation_callback_delay = base::Time::Now() - - (animation_floor_time_ - base::TimeDelta::FromMilliseconds(16)); - UMA_HISTOGRAM_CUSTOM_TIMES("Renderer4.AnimationCallbackDelayTime", - animation_callback_delay, - base::TimeDelta::FromMilliseconds(0), - base::TimeDelta::FromMilliseconds(30), - 25); - } - CallDoDeferredUpdate(); -} - -void RenderWidget::AnimateIfNeeded() { - if (!animation_update_pending_) - return; - base::Time now = base::Time::Now(); - if (now >= animation_floor_time_) { - animation_floor_time_ = now + base::TimeDelta::FromMilliseconds(16); - // Set a timer to call us back after 16ms (targetting 60FPS) before - // running animation callbacks so that if a callback requests another - // we'll be sure to run it at the proper time. - MessageLoop::current()->PostDelayedTask(FROM_HERE, NewRunnableMethod( - this, &RenderWidget::AnimationCallback), 16); - animation_task_posted_ = true; - animation_update_pending_ = false; - // Explicitly pump the WebCore Timer queue to avoid starvation on OS X. - // See crbug.com/71735. - // TODO(jamesr) Remove this call once crbug.com/72007 is fixed. - RenderThread::current()->GetWebKitClientImpl()->DoTimeout(); - webwidget_->animate(); - return; - } - if (animation_task_posted_) - return; - // This code uses base::Time::Now() to calculate the floor and next fire - // time because javascript's Date object uses base::Time::Now(). The - // message loop uses base::TimeTicks, which on windows can have a - // different granularity than base::Time. - // The upshot of all this is that this function might be called before - // base::Time::Now() has advanced past the animation_floor_time_. To - // avoid exposing this delay to javascript, we keep posting delayed - // tasks until base::Time::Now() has advanced far enough. - int64 delay = (animation_floor_time_ - now).InMillisecondsRoundedUp(); - animation_task_posted_ = true; - MessageLoop::current()->PostDelayedTask(FROM_HERE, - NewRunnableMethod(this, &RenderWidget::AnimationCallback), delay); -} - -void RenderWidget::CallDoDeferredUpdate() { - DoDeferredUpdate(); - - if (pending_input_event_ack_.get()) - Send(pending_input_event_ack_.release()); -} - -void RenderWidget::DoDeferredUpdate() { - GPU_TRACE_EVENT0("render_widget", "DoDeferredUpdate"); - - if (!webwidget_ || update_reply_pending()) - return; - - // Suppress updating when we are hidden. - if (is_hidden_ || size_.IsEmpty()) { - paint_aggregator_.ClearPendingUpdate(); - needs_repainting_on_restore_ = true; - return; - } - - AnimateIfNeeded(); - - // Layout may generate more invalidation. It may also enable the - // GPU acceleration, so make sure to run layout before we send the - // GpuRenderingActivated message. - webwidget_->layout(); - - // Suppress painting if nothing is dirty. This has to be done after updating - // animations running layout as these may generate further invalidations. - if (!paint_aggregator_.HasPendingUpdate()) - return; - - // OK, save the pending update to a local since painting may cause more - // invalidation. Some WebCore rendering objects only layout when painted. - PaintAggregator::PendingUpdate update; - paint_aggregator_.PopPendingUpdate(&update); - - gfx::Rect scroll_damage = update.GetScrollDamage(); - gfx::Rect bounds = update.GetPaintBounds().Union(scroll_damage); - - // A plugin may be able to do an optimized paint. First check this, in which - // case we can skip all of the bitmap generation and regular paint code. - // This optimization allows PPAPI plugins that declare themselves on top of - // the page (like a traditional windowed plugin) to be able to animate (think - // movie playing) without repeatedly re-painting the page underneath, or - // copying the plugin backing store (since we can send the plugin's backing - // store directly to the browser). - // - // This optimization only works when the entire invalid region is contained - // within the plugin. There is a related optimization in PaintRect for the - // case where there may be multiple invalid regions. - TransportDIB::Id dib_id = TransportDIB::Id(); - TransportDIB* dib = NULL; - std::vector copy_rects; - gfx::Rect optimized_copy_rect, optimized_copy_location; - if (update.scroll_rect.IsEmpty() && - !is_accelerated_compositing_active_ && - GetBitmapForOptimizedPluginPaint(bounds, &dib, &optimized_copy_location, - &optimized_copy_rect)) { - // Only update the part of the plugin that actually changed. - optimized_copy_rect = optimized_copy_rect.Intersect(bounds); - bounds = optimized_copy_location; - copy_rects.push_back(optimized_copy_rect); - dib_id = dib->id(); - } else if (!is_accelerated_compositing_active_) { - // Compute a buffer for painting and cache it. - scoped_ptr canvas( - RenderProcess::current()->GetDrawingCanvas(¤t_paint_buf_, - bounds)); - if (!canvas.get()) { - NOTREACHED(); - return; - } - - // We may get back a smaller canvas than we asked for. - // TODO(darin): This seems like it could cause painting problems! - DCHECK_EQ(bounds.width(), canvas->getDevice()->width()); - DCHECK_EQ(bounds.height(), canvas->getDevice()->height()); - bounds.set_width(canvas->getDevice()->width()); - bounds.set_height(canvas->getDevice()->height()); - - HISTOGRAM_COUNTS_100("MPArch.RW_PaintRectCount", update.paint_rects.size()); - - // The scroll damage is just another rectangle to paint and copy. - copy_rects.swap(update.paint_rects); - if (!scroll_damage.IsEmpty()) - copy_rects.push_back(scroll_damage); - - for (size_t i = 0; i < copy_rects.size(); ++i) - PaintRect(copy_rects[i], bounds.origin(), canvas.get()); - - dib_id = current_paint_buf_->id(); - } else { // Accelerated compositing path - // Begin painting. - webwidget_->composite(false); - } - - // sending an ack to browser process that the paint is complete... - ViewHostMsg_UpdateRect_Params params; - params.bitmap = dib_id; - params.bitmap_rect = bounds; - params.dx = update.scroll_delta.x(); - params.dy = update.scroll_delta.y(); - if (is_accelerated_compositing_active_) { - // If painting is done via the gpu process then we clear out all damage - // rects to save the browser process from doing unecessary work. - params.scroll_rect = gfx::Rect(); - params.copy_rects.clear(); - } else { - params.scroll_rect = update.scroll_rect; - params.copy_rects.swap(copy_rects); // TODO(darin): clip to bounds? - } - params.view_size = size_; - params.resizer_rect = resizer_rect_; - params.plugin_window_moves.swap(plugin_window_moves_); - params.flags = next_paint_flags_; - params.scroll_offset = GetScrollOffset(); - - update_reply_pending_ = true; - Send(new ViewHostMsg_UpdateRect(routing_id_, params)); - next_paint_flags_ = 0; - - UpdateInputMethod(); - - // Let derived classes know we've painted. - DidInitiatePaint(); -} - -/////////////////////////////////////////////////////////////////////////////// -// WebWidgetClient - -void RenderWidget::didInvalidateRect(const WebRect& rect) { - // We only want one pending DoDeferredUpdate call at any time... - bool update_pending = paint_aggregator_.HasPendingUpdate(); - - // The invalidated rect might be outside the bounds of the view. - gfx::Rect view_rect(size_); - gfx::Rect damaged_rect = view_rect.Intersect(rect); - if (damaged_rect.IsEmpty()) - return; - - paint_aggregator_.InvalidateRect(damaged_rect); - - // We may not need to schedule another call to DoDeferredUpdate. - if (update_pending) - return; - if (!paint_aggregator_.HasPendingUpdate()) - return; - if (update_reply_pending()) - return; - - // Perform updating asynchronously. This serves two purposes: - // 1) Ensures that we call WebView::Paint without a bunch of other junk - // on the call stack. - // 2) Allows us to collect more damage rects before painting to help coalesce - // the work that we will need to do. - MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod( - this, &RenderWidget::CallDoDeferredUpdate)); -} - -void RenderWidget::didScrollRect(int dx, int dy, const WebRect& clip_rect) { - // Drop scrolls on the floor when we are in compositing mode. - // TODO(nduca): stop WebViewImpl from sending scrolls in the first place. - if (is_accelerated_compositing_active_) - return; - - // We only want one pending DoDeferredUpdate call at any time... - bool update_pending = paint_aggregator_.HasPendingUpdate(); - - // The scrolled rect might be outside the bounds of the view. - gfx::Rect view_rect(size_); - gfx::Rect damaged_rect = view_rect.Intersect(clip_rect); - if (damaged_rect.IsEmpty()) - return; - - paint_aggregator_.ScrollRect(dx, dy, damaged_rect); - - // We may not need to schedule another call to DoDeferredUpdate. - if (update_pending) - return; - if (!paint_aggregator_.HasPendingUpdate()) - return; - if (update_reply_pending()) - return; - - // Perform updating asynchronously. This serves two purposes: - // 1) Ensures that we call WebView::Paint without a bunch of other junk - // on the call stack. - // 2) Allows us to collect more damage rects before painting to help coalesce - // the work that we will need to do. - MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod( - this, &RenderWidget::CallDoDeferredUpdate)); -} - -void RenderWidget::didActivateAcceleratedCompositing(bool active) { - is_accelerated_compositing_active_ = active; - Send(new ViewHostMsg_DidActivateAcceleratedCompositing( - routing_id_, is_accelerated_compositing_active_)); -} - -void RenderWidget::scheduleComposite() { - // TODO(nduca): replace with something a little less hacky. The reason this - // hack is still used is because the Invalidate-DoDeferredUpdate loop - // contains a lot of host-renderer synchronization logic that is still - // important for the accelerated compositing case. The option of simply - // duplicating all that code is less desirable than "faking out" the - // invalidation path using a magical damage rect. - didInvalidateRect(WebRect(0, 0, 1, 1)); -} - -void RenderWidget::scheduleAnimation() { - if (!animation_update_pending_) { - animation_update_pending_ = true; - if (!animation_task_posted_) { - animation_task_posted_ = true; - MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod( - this, &RenderWidget::AnimationCallback)); - } - } -} - -void RenderWidget::didChangeCursor(const WebCursorInfo& cursor_info) { - // TODO(darin): Eliminate this temporary. - WebCursor cursor(cursor_info); - - // Only send a SetCursor message if we need to make a change. - if (!current_cursor_.IsEqual(cursor)) { - current_cursor_ = cursor; - Send(new ViewHostMsg_SetCursor(routing_id_, cursor)); - } -} - -// We are supposed to get a single call to Show for a newly created RenderWidget -// that was created via RenderWidget::CreateWebView. So, we wait until this -// point to dispatch the ShowWidget message. -// -// This method provides us with the information about how to display the newly -// created RenderWidget (i.e., as a constrained popup or as a new tab). -// -void RenderWidget::show(WebNavigationPolicy) { - DCHECK(!did_show_) << "received extraneous Show call"; - DCHECK(routing_id_ != MSG_ROUTING_NONE); - DCHECK(opener_id_ != MSG_ROUTING_NONE); - - if (did_show_) - return; - - did_show_ = true; - // NOTE: initial_pos_ may still have its default values at this point, but - // that's okay. It'll be ignored if as_popup is false, or the browser - // process will impose a default position otherwise. - Send(new ViewHostMsg_ShowWidget(opener_id_, routing_id_, initial_pos_)); - SetPendingWindowRect(initial_pos_); -} - -void RenderWidget::didFocus() { -} - -void RenderWidget::didBlur() { -} - -void RenderWidget::DoDeferredClose() { - Send(new ViewHostMsg_Close(routing_id_)); -} - -void RenderWidget::closeWidgetSoon() { - // If a page calls window.close() twice, we'll end up here twice, but that's - // OK. It is safe to send multiple Close messages. - - // Ask the RenderWidgetHost to initiate close. We could be called from deep - // in Javascript. If we ask the RendwerWidgetHost to close now, the window - // could be closed before the JS finishes executing. So instead, post a - // message back to the message loop, which won't run until the JS is - // complete, and then the Close message can be sent. - MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod( - this, &RenderWidget::DoDeferredClose)); -} - -void RenderWidget::Close() { - if (webwidget_) { - webwidget_->close(); - webwidget_ = NULL; - } -} - -WebRect RenderWidget::windowRect() { - if (pending_window_rect_count_) - return pending_window_rect_; - - gfx::Rect rect; - Send(new ViewHostMsg_GetWindowRect(routing_id_, host_window_, &rect)); - return rect; -} - -void RenderWidget::setWindowRect(const WebRect& pos) { - if (did_show_) { - Send(new ViewHostMsg_RequestMove(routing_id_, pos)); - SetPendingWindowRect(pos); - } else { - initial_pos_ = pos; - } -} - -void RenderWidget::SetPendingWindowRect(const WebRect& rect) { - pending_window_rect_ = rect; - pending_window_rect_count_++; -} - -WebRect RenderWidget::rootWindowRect() { - if (pending_window_rect_count_) { - // NOTE(mbelshe): If there is a pending_window_rect_, then getting - // the RootWindowRect is probably going to return wrong results since the - // browser may not have processed the Move yet. There isn't really anything - // good to do in this case, and it shouldn't happen - since this size is - // only really needed for windowToScreen, which is only used for Popups. - return pending_window_rect_; - } - - gfx::Rect rect; - Send(new ViewHostMsg_GetRootWindowRect(routing_id_, host_window_, &rect)); - return rect; -} - -WebRect RenderWidget::windowResizerRect() { - return resizer_rect_; -} - -void RenderWidget::OnSetInputMethodActive(bool is_active) { - // To prevent this renderer process from sending unnecessary IPC messages to - // a browser process, we permit the renderer process to send IPC messages - // only during the input method attached to the browser process is active. - input_method_is_active_ = is_active; -} - -void RenderWidget::OnImeSetComposition( - const string16& text, - const std::vector& underlines, - int selection_start, int selection_end) { - if (!webwidget_) - return; - if (!webwidget_->setComposition( - text, WebVector(underlines), - selection_start, selection_end)) { - // If we failed to set the composition text, then we need to let the browser - // process to cancel the input method's ongoing composition session, to make - // sure we are in a consistent state. - Send(new ViewHostMsg_ImeCancelComposition(routing_id())); - } -} - -void RenderWidget::OnImeConfirmComposition(const string16& text) { - if (webwidget_) - webwidget_->confirmComposition(text); -} - -// This message causes the renderer to render an image of the -// desired_size, regardless of whether the tab is hidden or not. -void RenderWidget::OnMsgPaintAtSize(const TransportDIB::Handle& dib_handle, - int tag, - const gfx::Size& page_size, - const gfx::Size& desired_size) { - if (!webwidget_ || !TransportDIB::is_valid(dib_handle)) { - if (TransportDIB::is_valid(dib_handle)) { - // Close our unused handle. -#if defined(OS_WIN) - ::CloseHandle(dib_handle); -#elif defined(OS_MACOSX) - base::SharedMemory::CloseHandle(dib_handle); -#endif - } - return; - } - - if (page_size.IsEmpty() || desired_size.IsEmpty()) { - // If one of these is empty, then we just return the dib we were - // given, to avoid leaking it. - Send(new ViewHostMsg_PaintAtSize_ACK(routing_id_, tag, desired_size)); - return; - } - - // Map the given DIB ID into this process, and unmap it at the end - // of this function. - scoped_ptr paint_at_size_buffer( - TransportDIB::CreateWithHandle(dib_handle)); - - gfx::Size canvas_size = page_size; - float x_scale = static_cast(desired_size.width()) / - static_cast(canvas_size.width()); - float y_scale = static_cast(desired_size.height()) / - static_cast(canvas_size.height()); - - gfx::Rect orig_bounds(canvas_size); - canvas_size.set_width(static_cast(canvas_size.width() * x_scale)); - canvas_size.set_height(static_cast(canvas_size.height() * y_scale)); - gfx::Rect bounds(canvas_size); - - scoped_ptr canvas( - paint_at_size_buffer->GetPlatformCanvas(canvas_size.width(), - canvas_size.height())); - if (!canvas.get()) { - NOTREACHED(); - return; - } - - // Reset bounds to what we actually received, but they should be the - // same. - DCHECK_EQ(bounds.width(), canvas->getDevice()->width()); - DCHECK_EQ(bounds.height(), canvas->getDevice()->height()); - bounds.set_width(canvas->getDevice()->width()); - bounds.set_height(canvas->getDevice()->height()); - - canvas->save(); - // Add the scale factor to the canvas, so that we'll get the desired size. - canvas->scale(SkFloatToScalar(x_scale), SkFloatToScalar(y_scale)); - - // Have to make sure we're laid out at the right size before - // rendering. - gfx::Size old_size = webwidget_->size(); - webwidget_->resize(page_size); - webwidget_->layout(); - - // Paint the entire thing (using original bounds, not scaled bounds). - PaintRect(orig_bounds, orig_bounds.origin(), canvas.get()); - canvas->restore(); - - // Return the widget to its previous size. - webwidget_->resize(old_size); - - Send(new ViewHostMsg_PaintAtSize_ACK(routing_id_, tag, bounds.size())); -} - -void RenderWidget::OnMsgRepaint(const gfx::Size& size_to_paint) { - // During shutdown we can just ignore this message. - if (!webwidget_) - return; - - set_next_paint_is_repaint_ack(); - if (is_accelerated_compositing_active_) { - scheduleComposite(); - } else { - gfx::Rect repaint_rect(size_to_paint.width(), size_to_paint.height()); - didInvalidateRect(repaint_rect); - } -} - -void RenderWidget::OnSetTextDirection(WebTextDirection direction) { - if (!webwidget_) - return; - webwidget_->setTextDirection(direction); -} - -webkit::ppapi::PluginInstance* RenderWidget::GetBitmapForOptimizedPluginPaint( - const gfx::Rect& paint_bounds, - TransportDIB** dib, - gfx::Rect* location, - gfx::Rect* clip) { - // Bare RenderWidgets don't support optimized plugin painting. - return NULL; -} - -gfx::Point RenderWidget::GetScrollOffset() { - // Bare RenderWidgets don't support scroll offset. - return gfx::Point(0, 0); -} - -void RenderWidget::SetHidden(bool hidden) { - if (is_hidden_ == hidden) - return; - - // The status has changed. Tell the RenderThread about it. - is_hidden_ = hidden; - if (is_hidden_) - render_thread_->WidgetHidden(); - else - render_thread_->WidgetRestored(); -} - -void RenderWidget::SetBackground(const SkBitmap& background) { - background_ = background; - - // Generate a full repaint. - didInvalidateRect(gfx::Rect(size_.width(), size_.height())); -} - -bool RenderWidget::next_paint_is_resize_ack() const { - return ViewHostMsg_UpdateRect_Flags::is_resize_ack(next_paint_flags_); -} - -bool RenderWidget::next_paint_is_restore_ack() const { - return ViewHostMsg_UpdateRect_Flags::is_restore_ack(next_paint_flags_); -} - -void RenderWidget::set_next_paint_is_resize_ack() { - next_paint_flags_ |= ViewHostMsg_UpdateRect_Flags::IS_RESIZE_ACK; -} - -void RenderWidget::set_next_paint_is_restore_ack() { - next_paint_flags_ |= ViewHostMsg_UpdateRect_Flags::IS_RESTORE_ACK; -} - -void RenderWidget::set_next_paint_is_repaint_ack() { - next_paint_flags_ |= ViewHostMsg_UpdateRect_Flags::IS_REPAINT_ACK; -} - -void RenderWidget::UpdateInputMethod() { - if (!input_method_is_active_) - return; - - WebTextInputType new_type = WebKit::WebTextInputTypeNone; - WebRect new_caret_bounds; - - if (webwidget_) { - new_type = webwidget_->textInputType(); - new_caret_bounds = webwidget_->caretOrSelectionBounds(); - } - - // Only sends text input type and caret bounds to the browser process if they - // are changed. - if (text_input_type_ != new_type || caret_bounds_ != new_caret_bounds) { - text_input_type_ = new_type; - caret_bounds_ = new_caret_bounds; - Send(new ViewHostMsg_ImeUpdateTextInputState( - routing_id(), new_type, new_caret_bounds)); - } -} - -WebScreenInfo RenderWidget::screenInfo() { - WebScreenInfo results; - Send(new ViewHostMsg_GetScreenInfo(routing_id_, host_window_, &results)); - return results; -} - -void RenderWidget::resetInputMethod() { - if (!input_method_is_active_) - return; - - // If the last text input type is not None, then we should finish any - // ongoing composition regardless of the new text input type. - if (text_input_type_ != WebKit::WebTextInputTypeNone) { - // If a composition text exists, then we need to let the browser process - // to cancel the input method's ongoing composition session. - if (webwidget_->confirmComposition()) - Send(new ViewHostMsg_ImeCancelComposition(routing_id())); - } -} - -void RenderWidget::SchedulePluginMove( - const webkit::npapi::WebPluginGeometry& move) { - size_t i = 0; - for (; i < plugin_window_moves_.size(); ++i) { - if (plugin_window_moves_[i].window == move.window) { - if (move.rects_valid) { - plugin_window_moves_[i] = move; - } else { - plugin_window_moves_[i].visible = move.visible; - } - break; - } - } - - if (i == plugin_window_moves_.size()) - plugin_window_moves_.push_back(move); -} - -void RenderWidget::CleanupWindowInPluginMoves(gfx::PluginWindowHandle window) { - for (WebPluginGeometryVector::iterator i = plugin_window_moves_.begin(); - i != plugin_window_moves_.end(); ++i) { - if (i->window == window) { - plugin_window_moves_.erase(i); - break; - } - } -} diff --git a/chrome/renderer/render_widget.h b/chrome/renderer/render_widget.h deleted file mode 100644 index 8325718..0000000 --- a/chrome/renderer/render_widget.h +++ /dev/null @@ -1,381 +0,0 @@ -// Copyright (c) 2009 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. - -#ifndef CHROME_RENDERER_RENDER_WIDGET_H_ -#define CHROME_RENDERER_RENDER_WIDGET_H_ -#pragma once - -#include - -#include "app/surface/transport_dib.h" -#include "base/basictypes.h" -#include "base/ref_counted.h" -#include "chrome/renderer/render_process.h" -#include "content/renderer/paint_aggregator.h" -#include "ipc/ipc_channel.h" -#include "third_party/WebKit/Source/WebKit/chromium/public/WebCompositionUnderline.h" -#include "third_party/WebKit/Source/WebKit/chromium/public/WebPopupType.h" -#include "third_party/WebKit/Source/WebKit/chromium/public/WebRect.h" -#include "third_party/WebKit/Source/WebKit/chromium/public/WebTextDirection.h" -#include "third_party/WebKit/Source/WebKit/chromium/public/WebTextInputType.h" -#include "third_party/WebKit/Source/WebKit/chromium/public/WebWidgetClient.h" -#include "third_party/skia/include/core/SkBitmap.h" -#include "ui/gfx/native_widget_types.h" -#include "ui/gfx/rect.h" -#include "ui/gfx/size.h" -#include "webkit/glue/webcursor.h" - -class RenderThreadBase; - -namespace gfx { -class Point; -} - -namespace IPC { -class SyncMessage; -} - -namespace skia { -class PlatformCanvas; -} - -namespace WebKit { -class WebMouseEvent; -class WebWidget; -struct WebPopupMenuInfo; -} - -namespace webkit { -namespace npapi { -struct WebPluginGeometry; -} // namespace npapi - -namespace ppapi { -class PluginInstance; -} // namespace ppapi -} // namespace webkit - -// RenderWidget provides a communication bridge between a WebWidget and -// a RenderWidgetHost, the latter of which lives in a different process. -class RenderWidget : public IPC::Channel::Listener, - public IPC::Message::Sender, - virtual public WebKit::WebWidgetClient, - public base::RefCounted { - public: - // Creates a new RenderWidget. The opener_id is the routing ID of the - // RenderView that this widget lives inside. The render_thread is any - // RenderThreadBase implementation, mostly commonly RenderThread::current(). - static RenderWidget* Create(int32 opener_id, - RenderThreadBase* render_thread, - WebKit::WebPopupType popup_type); - - // Creates a WebWidget based on the popup type. - static WebKit::WebWidget* CreateWebWidget(RenderWidget* render_widget); - - // The routing ID assigned by the RenderProcess. Will be MSG_ROUTING_NONE if - // not yet assigned a view ID, in which case, the process MUST NOT send - // messages with this ID to the parent. - int32 routing_id() const { - return routing_id_; - } - - // May return NULL when the window is closing. - WebKit::WebWidget* webwidget() const { - return webwidget_; - } - - gfx::NativeViewId host_window() const { - return host_window_; - } - - bool has_focus() const { return has_focus_; } - - // IPC::Channel::Listener - virtual bool OnMessageReceived(const IPC::Message& msg); - - // IPC::Message::Sender - virtual bool Send(IPC::Message* msg); - - // WebKit::WebWidgetClient - virtual void didInvalidateRect(const WebKit::WebRect&); - virtual void didScrollRect(int dx, int dy, const WebKit::WebRect& clipRect); - virtual void didActivateAcceleratedCompositing(bool active); - virtual void scheduleComposite(); - virtual void scheduleAnimation(); - virtual void didFocus(); - virtual void didBlur(); - virtual void didChangeCursor(const WebKit::WebCursorInfo&); - virtual void closeWidgetSoon(); - virtual void show(WebKit::WebNavigationPolicy); - virtual void runModal() {} - virtual WebKit::WebRect windowRect(); - virtual void setWindowRect(const WebKit::WebRect&); - virtual WebKit::WebRect windowResizerRect(); - virtual WebKit::WebRect rootWindowRect(); - virtual WebKit::WebScreenInfo screenInfo(); - virtual void resetInputMethod(); - - // Called when a plugin is moved. These events are queued up and sent with - // the next paint or scroll message to the host. - void SchedulePluginMove(const webkit::npapi::WebPluginGeometry& move); - - // Called when a plugin window has been destroyed, to make sure the currently - // pending moves don't try to reference it. - void CleanupWindowInPluginMoves(gfx::PluginWindowHandle window); - - // Close the underlying WebWidget. - virtual void Close(); - - protected: - // Friend RefCounted so that the dtor can be non-public. Using this class - // without ref-counting is an error. - friend class base::RefCounted; - // For unit tests. - friend class RenderWidgetTest; - - RenderWidget(RenderThreadBase* render_thread, - WebKit::WebPopupType popup_type); - virtual ~RenderWidget(); - - // Initializes this view with the given opener. CompleteInit must be called - // later. - void Init(int32 opener_id); - - // Called by Init and subclasses to perform initialization. - void DoInit(int32 opener_id, - WebKit::WebWidget* web_widget, - IPC::SyncMessage* create_widget_message); - - // Finishes creation of a pending view started with Init. - void CompleteInit(gfx::NativeViewId parent); - - // Paints the given rectangular region of the WebWidget into canvas (a - // shared memory segment returned by AllocPaintBuf on Windows). The caller - // must ensure that the given rect fits within the bounds of the WebWidget. - void PaintRect(const gfx::Rect& rect, const gfx::Point& canvas_origin, - skia::PlatformCanvas* canvas); - - // Paints a border at the given rect for debugging purposes. - void PaintDebugBorder(const gfx::Rect& rect, skia::PlatformCanvas* canvas); - - void AnimationCallback(); - void AnimateIfNeeded(); - void CallDoDeferredUpdate(); - void DoDeferredUpdate(); - void DoDeferredClose(); - void DoDeferredSetWindowRect(const WebKit::WebRect& pos); - - // Set the background of the render widget to a bitmap. The bitmap will be - // tiled in both directions if it isn't big enough to fill the area. This is - // mainly intended to be used in conjuction with WebView::SetIsTransparent(). - virtual void SetBackground(const SkBitmap& bitmap); - - // RenderWidget IPC message handlers - void OnClose(); - void OnCreatingNewAck(gfx::NativeViewId parent); - virtual void OnResize(const gfx::Size& new_size, - const gfx::Rect& resizer_rect); - virtual void OnWasHidden(); - virtual void OnWasRestored(bool needs_repainting); - void OnUpdateRectAck(); - void OnCreateVideoAck(int32 video_id); - void OnUpdateVideoAck(int32 video_id); - void OnRequestMoveAck(); - void OnHandleInputEvent(const IPC::Message& message); - void OnMouseCaptureLost(); - virtual void OnSetFocus(bool enable); - void OnSetInputMethodActive(bool is_active); - void OnImeSetComposition( - const string16& text, - const std::vector& underlines, - int selection_start, - int selection_end); - void OnImeConfirmComposition(const string16& text); - void OnMsgPaintAtSize(const TransportDIB::Handle& dib_id, - int tag, - const gfx::Size& page_size, - const gfx::Size& desired_size); - void OnMsgRepaint(const gfx::Size& size_to_paint); - void OnSetTextDirection(WebKit::WebTextDirection direction); - - // Override point to notify derived classes that a paint has happened. - // DidInitiatePaint happens when we've generated a new bitmap and sent it to - // the browser. DidFlushPaint happens once we've received the ACK that the - // screen has actually been updated. - virtual void DidInitiatePaint() {} - virtual void DidFlushPaint() {} - - // Detects if a suitable opaque plugin covers the given paint bounds with no - // compositing necessary. - // - // Returns the plugin instance that's the source of the paint if the paint - // can be handled by just blitting the plugin bitmap. In this case, the - // location, clipping, and ID of the backing store will be filled into the - // given output parameters. - // - // A return value of null means optimized painting can not be used and we - // should continue with the normal painting code path. - virtual webkit::ppapi::PluginInstance* GetBitmapForOptimizedPluginPaint( - const gfx::Rect& paint_bounds, - TransportDIB** dib, - gfx::Rect* location, - gfx::Rect* clip); - - // Gets the scroll offset of this widget, if this widget has a notion of - // scroll offset. - virtual gfx::Point GetScrollOffset(); - - // Sets the "hidden" state of this widget. All accesses to is_hidden_ should - // use this method so that we can properly inform the RenderThread of our - // state. - void SetHidden(bool hidden); - - bool is_hidden() const { return is_hidden_; } - - // True if an UpdateRect_ACK message is pending. - bool update_reply_pending() const { - return update_reply_pending_; - } - - bool next_paint_is_resize_ack() const; - bool next_paint_is_restore_ack() const; - void set_next_paint_is_resize_ack(); - void set_next_paint_is_restore_ack(); - void set_next_paint_is_repaint_ack(); - - // Checks if the input method state and caret position have been changed. - // If they are changed, the new value will be sent to the browser process. - void UpdateInputMethod(); - - // Tells the renderer it does not have focus. Used to prevent us from getting - // the focus on our own when the browser did not focus us. - void ClearFocus(); - - // Set the pending window rect. - // Because the real render_widget is hosted in another process, there is - // a time period where we may have set a new window rect which has not yet - // been processed by the browser. So we maintain a pending window rect - // size. If JS code sets the WindowRect, and then immediately calls - // GetWindowRect() we'll use this pending window rect as the size. - void SetPendingWindowRect(const WebKit::WebRect& r); - - // Called by OnHandleInputEvent() to notify subclasses that a key event was - // just handled. - virtual void DidHandleKeyEvent() {} - - // Called by OnHandleInputEvent() to notify subclasses that a mouse event was - // just handled. - virtual void DidHandleMouseEvent(const WebKit::WebMouseEvent& event) {} - - // Routing ID that allows us to communicate to the parent browser process - // RenderWidgetHost. When MSG_ROUTING_NONE, no messages may be sent. - int32 routing_id_; - - // We are responsible for destroying this object via its Close method. - WebKit::WebWidget* webwidget_; - - // Set to the ID of the view that initiated creating this view, if any. When - // the view was initiated by the browser (the common case), this will be - // MSG_ROUTING_NONE. This is used in determining ownership when opening - // child tabs. See RenderWidget::createWebViewWithRequest. - // - // This ID may refer to an invalid view if that view is closed before this - // view is. - int32 opener_id_; - - // The thread that does our IPC. - RenderThreadBase* render_thread_; - - // The position where this view should be initially shown. - gfx::Rect initial_pos_; - - // The window we are embedded within. TODO(darin): kill this. - gfx::NativeViewId host_window_; - - // We store the current cursor object so we can avoid spamming SetCursor - // messages. - WebCursor current_cursor_; - - // The size of the RenderWidget. - gfx::Size size_; - - // The TransportDIB that is being used to transfer an image to the browser. - TransportDIB* current_paint_buf_; - - PaintAggregator paint_aggregator_; - - // The area that must be reserved for drawing the resize corner. - gfx::Rect resizer_rect_; - - // Flags for the next ViewHostMsg_UpdateRect message. - int next_paint_flags_; - - // True if we are expecting an UpdateRect_ACK message (i.e., that a - // UpdateRect message has been sent). - bool update_reply_pending_; - - // Set to true if we should ignore RenderWidget::Show calls. - bool did_show_; - - // Indicates that we shouldn't bother generated paint events. - bool is_hidden_; - - // Indicates that we should be repainted when restored. This flag is set to - // true if we receive an invalidation / scroll event from webkit while our - // is_hidden_ flag is set to true. This is used to force a repaint once we - // restore to account for the fact that our host would not know about the - // invalidation / scroll event(s) from webkit while we are hidden. - bool needs_repainting_on_restore_; - - // Indicates whether we have been focused/unfocused by the browser. - bool has_focus_; - - // Are we currently handling an input event? - bool handling_input_event_; - - // True if we have requested this widget be closed. No more messages will - // be sent, except for a Close. - bool closing_; - - // Indicates if an input method is active in the browser process. - bool input_method_is_active_; - - // Stores the current text input type of |webwidget_|. - WebKit::WebTextInputType text_input_type_; - - // Stores the current caret bounds of input focus. - WebKit::WebRect caret_bounds_; - - // The kind of popup this widget represents, NONE if not a popup. - WebKit::WebPopupType popup_type_; - - // Holds all the needed plugin window moves for a scroll. - typedef std::vector WebPluginGeometryVector; - WebPluginGeometryVector plugin_window_moves_; - - // A custom background for the widget. - SkBitmap background_; - - // While we are waiting for the browser to update window sizes, - // we track the pending size temporarily. - int pending_window_rect_count_; - WebKit::WebRect pending_window_rect_; - - scoped_ptr pending_input_event_ack_; - - // Indicates if the next sequence of Char events should be suppressed or not. - bool suppress_next_char_events_; - - // Set to true if painting to the window is handled by the accelerated - // compositor. - bool is_accelerated_compositing_active_; - - base::Time animation_floor_time_; - bool animation_update_pending_; - bool animation_task_posted_; - - DISALLOW_COPY_AND_ASSIGN(RenderWidget); -}; - -#endif // CHROME_RENDERER_RENDER_WIDGET_H_ diff --git a/chrome/renderer/render_widget_browsertest.cc b/chrome/renderer/render_widget_browsertest.cc deleted file mode 100644 index 41192d0..0000000 --- a/chrome/renderer/render_widget_browsertest.cc +++ /dev/null @@ -1,149 +0,0 @@ -// Copyright (c) 2010 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 "app/surface/transport_dib.h" -#include "base/basictypes.h" -#include "base/file_path.h" -#include "base/file_util.h" -#include "base/ref_counted_memory.h" -#include "base/stringprintf.h" -#include "chrome/common/render_messages.h" -#include "chrome/common/render_messages_params.h" -#include "chrome/renderer/render_widget_browsertest.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "third_party/skia/include/core/SkBitmap.h" -#include "third_party/WebKit/Source/WebKit/chromium/public/WebSize.h" -#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h" -#include "ui/gfx/codec/jpeg_codec.h" -#include "ui/gfx/size.h" - -const int RenderWidgetTest::kNumBytesPerPixel = 4; -const int RenderWidgetTest::kLargeWidth = 1024; -const int RenderWidgetTest::kLargeHeight = 768; -const int RenderWidgetTest::kSmallWidth = 600; -const int RenderWidgetTest::kSmallHeight = 450; -const int RenderWidgetTest::kTextPositionX = 800; -const int RenderWidgetTest::kTextPositionY = 600; -const uint32 RenderWidgetTest::kRedARGB = 0xFFFF0000; - -RenderWidgetTest::RenderWidgetTest() {} - -void RenderWidgetTest::ResizeAndPaint(const gfx::Size& page_size, - const gfx::Size& desired_size, - SkBitmap* snapshot) { - ASSERT_TRUE(snapshot); - static int g_sequence_num = 0; - // Use a new sequence number for each DIB. - scoped_ptr pixels( - TransportDIB::Create( - page_size.width() * page_size.height() * kNumBytesPerPixel, - ++g_sequence_num)); - - // Go ahead and map the DIB into memory, so that we can use it below - // to fill tmp_bitmap. Note that we need to do this before calling - // OnMsgPaintAtSize, or the last reference to the shared memory will - // be closed and the handle will no longer be valid. - scoped_ptr mapped_pixels(TransportDIB::Map(pixels->handle())); - - view_->OnMsgPaintAtSize(pixels->handle(), g_sequence_num, page_size, - desired_size); - ProcessPendingMessages(); - const IPC::Message* msg = render_thread_.sink().GetUniqueMessageMatching( - ViewHostMsg_PaintAtSize_ACK::ID); - ASSERT_NE(static_cast(NULL), msg); - ViewHostMsg_PaintAtSize_ACK::Param params; - ViewHostMsg_PaintAtSize_ACK::Read(msg, ¶ms); - render_thread_.sink().ClearMessages(); - EXPECT_EQ(g_sequence_num, params.a); - gfx::Size size = params.b; - EXPECT_EQ(desired_size, size); - - SkBitmap tmp_bitmap; - tmp_bitmap.setConfig(SkBitmap::kARGB_8888_Config, - size.width(), size.height()); - tmp_bitmap.setPixels(mapped_pixels->memory()); - // Copy the pixels from the TransportDIB object to the given snapshot. - ASSERT_TRUE(tmp_bitmap.copyTo(snapshot, SkBitmap::kARGB_8888_Config)); -} - -void RenderWidgetTest::TestResizeAndPaint() { - // Hello World message is only visible if the view size is at least - // kTextPositionX x kTextPositionY - LoadHTML(StringPrintf( - "
Hello World
", - kTextPositionY, kTextPositionX).c_str()); - WebKit::WebSize old_size = view_->webview()->size(); - - SkBitmap bitmap; - // If we re-size the view to something smaller than where the 'Hello World' - // text is displayed we won't see any text in the snapshot. Hence, - // the snapshot should not contain any red. - gfx::Size size(kSmallWidth, kSmallHeight); - ResizeAndPaint(size, size, &bitmap); - // Make sure that the view has been re-sized to its old size. - EXPECT_TRUE(old_size == view_->webview()->size()); - EXPECT_EQ(kSmallWidth, bitmap.width()); - EXPECT_EQ(kSmallHeight, bitmap.height()); - EXPECT_FALSE(ImageContainsColor(bitmap, kRedARGB)); - - // Since we ask for the view to be re-sized to something larger than where the - // 'Hello World' text is written the text should be visible in the snapshot. - // Hence, the snapshot should contain some red. - size.SetSize(kLargeWidth, kLargeHeight); - ResizeAndPaint(size, size, &bitmap); - EXPECT_TRUE(old_size == view_->webview()->size()); - EXPECT_EQ(kLargeWidth, bitmap.width()); - EXPECT_EQ(kLargeHeight, bitmap.height()); - EXPECT_TRUE(ImageContainsColor(bitmap, kRedARGB)); - - // Even if the desired size is smaller than where the text is located we - // should still see the 'Hello World' message since the view size is - // still large enough. - ResizeAndPaint(size, gfx::Size(kSmallWidth, kSmallHeight), &bitmap); - EXPECT_TRUE(old_size == view_->webview()->size()); - EXPECT_EQ(kSmallWidth, bitmap.width()); - EXPECT_EQ(kSmallHeight, bitmap.height()); - EXPECT_TRUE(ImageContainsColor(bitmap, kRedARGB)); -} - -bool RenderWidgetTest::ImageContainsColor(const SkBitmap& bitmap, - uint32 argb_color) { - SkAutoLockPixels lock(bitmap); - bool ready = bitmap.readyToDraw(); - EXPECT_TRUE(ready); - if (!ready) { - return false; - } - for (int x = 0; x < bitmap.width(); ++x) { - for (int y = 0; y < bitmap.height(); ++y) { - if (argb_color == *bitmap.getAddr32(x, y)) { - return true; - } - } - } - return false; -} - -void RenderWidgetTest::OutputBitmapToFile(const SkBitmap& bitmap, - const FilePath& file_path) { - scoped_refptr bitmap_data(new RefCountedBytes()); - SkAutoLockPixels lock(bitmap); - ASSERT_TRUE(gfx::JPEGCodec::Encode( - reinterpret_cast(bitmap.getAddr32(0, 0)), - gfx::JPEGCodec::FORMAT_BGRA, - bitmap.width(), - bitmap.height(), - static_cast(bitmap.rowBytes()), - 90 /* quality */, - &bitmap_data->data)); - ASSERT_LT(0, file_util::WriteFile( - file_path, - reinterpret_cast(bitmap_data->front()), - bitmap_data->size())); -} - -TEST_F(RenderWidgetTest, OnMsgPaintAtSize) { - TestResizeAndPaint(); -} diff --git a/chrome/renderer/render_widget_browsertest.h b/chrome/renderer/render_widget_browsertest.h deleted file mode 100644 index 42ae02d..0000000 --- a/chrome/renderer/render_widget_browsertest.h +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) 2010 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. - -#ifndef CHROME_RENDERER_RENDER_WIDGET_BROWSERTEST_H_ -#define CHROME_RENDERER_RENDER_WIDGET_BROWSERTEST_H_ -#pragma once - -#include "base/basictypes.h" -#include "base/file_path.h" -#include "chrome/test/render_view_test.h" - -namespace gfx { -class Size; -} - -class SkBitmap; -class TransportDIB; - -class RenderWidgetTest : public RenderViewTest { - public: - RenderWidgetTest(); - - protected: - static const int kNumBytesPerPixel; - static const int kLargeWidth; - static const int kLargeHeight; - static const int kSmallWidth; - static const int kSmallHeight; - static const int kTextPositionX; - static const int kTextPositionY; - static const uint32 kRedARGB; - - // Helper function which calls OnMsgPaintAtSize and also paints the result - // in the given bitmap. The widget is resized to |page_size| before we paint - // and the final image is resized to |desired_size|. This method is virtual so - // that TestResizeAndPaint() can be reused by subclasses of this test class. - virtual void ResizeAndPaint(const gfx::Size& page_size, - const gfx::Size& desired_size, - SkBitmap* snapshot); - - // Test for ResizeAndPaint. - void TestResizeAndPaint(); - - // Helper function which returns true if the given bitmap contains the given - // ARGB color and false otherwise. - bool ImageContainsColor(const SkBitmap& bitmap, uint32 argb_color); - - // This can be used for debugging if you want to output a bitmap - // image to a file. - // FilePath tmp_path; - // file_util::CreateTemporaryFile(&tmp_path); - // OutputBitmapToFile(bitmap, tmp_path); - // LOG(INFO) << "Bitmap image stored at: " << tmp_path.value(); - void OutputBitmapToFile(const SkBitmap& bitmap, const FilePath& file_path); -}; - -#endif // CHROME_RENDERER_RENDER_WIDGET_BROWSERTEST_H_ diff --git a/chrome/renderer/render_widget_fullscreen.cc b/chrome/renderer/render_widget_fullscreen.cc deleted file mode 100644 index 021b074..0000000 --- a/chrome/renderer/render_widget_fullscreen.cc +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) 2010 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 "chrome/renderer/render_widget_fullscreen.h" - -#include "chrome/common/render_messages.h" -#include "chrome/renderer/render_thread.h" -#include "third_party/WebKit/Source/WebKit/chromium/public/WebWidget.h" - -using WebKit::WebWidget; - -// static -RenderWidgetFullscreen* RenderWidgetFullscreen::Create( - int32 opener_id, RenderThreadBase* render_thread) { - DCHECK_NE(MSG_ROUTING_NONE, opener_id); - scoped_refptr widget( - new RenderWidgetFullscreen(render_thread)); - widget->Init(opener_id); - return widget.release(); -} - -WebWidget* RenderWidgetFullscreen::CreateWebWidget() { - // TODO(boliu): Handle full screen render widgets here. - return RenderWidget::CreateWebWidget(this); -} - -void RenderWidgetFullscreen::Init(int32 opener_id) { - DCHECK(!webwidget_); - - RenderWidget::DoInit( - opener_id, - CreateWebWidget(), - new ViewHostMsg_CreateFullscreenWidget(opener_id, &routing_id_)); -} - -void RenderWidgetFullscreen::show(WebKit::WebNavigationPolicy) { - DCHECK(!did_show_) << "received extraneous Show call"; - DCHECK_NE(MSG_ROUTING_NONE, routing_id_); - DCHECK_NE(MSG_ROUTING_NONE, opener_id_); - - if (!did_show_) { - did_show_ = true; - Send(new ViewHostMsg_ShowFullscreenWidget(opener_id_, routing_id_)); - SetPendingWindowRect(initial_pos_); - } -} - -RenderWidgetFullscreen::RenderWidgetFullscreen(RenderThreadBase* render_thread) - : RenderWidget(render_thread, WebKit::WebPopupTypeNone) { -} diff --git a/chrome/renderer/render_widget_fullscreen.h b/chrome/renderer/render_widget_fullscreen.h deleted file mode 100644 index 3a87518..0000000 --- a/chrome/renderer/render_widget_fullscreen.h +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) 2010 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. - -#ifndef CHROME_RENDERER_RENDER_WIDGET_FULLSCREEN_H_ -#define CHROME_RENDERER_RENDER_WIDGET_FULLSCREEN_H_ - -#include "chrome/renderer/render_widget.h" - -#include "third_party/WebKit/Source/WebKit/chromium/public/WebWidget.h" - -// TODO(boliu): Override non-supported methods with no-op? eg setWindowRect(). -class RenderWidgetFullscreen : public RenderWidget { - public: - // Creates a new RenderWidget. The opener_id is the routing ID of the - // RenderView that this widget lives inside. The render_thread is any - // RenderThreadBase implementation, mostly commonly RenderThread::current(). - static RenderWidgetFullscreen* Create(int32 opener_id, - RenderThreadBase* render_thread); - - virtual void show(WebKit::WebNavigationPolicy); - - protected: - virtual WebKit::WebWidget* CreateWebWidget(); - RenderWidgetFullscreen(RenderThreadBase* render_thread); - - void Init(int32 opener_id); -}; - -#endif // CHROME_RENDERER_RENDER_WIDGET_FULLSCREEN_H_ diff --git a/chrome/renderer/render_widget_fullscreen_pepper.cc b/chrome/renderer/render_widget_fullscreen_pepper.cc deleted file mode 100644 index cd1f56a..0000000 --- a/chrome/renderer/render_widget_fullscreen_pepper.cc +++ /dev/null @@ -1,395 +0,0 @@ -// Copyright (c) 2010 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 "chrome/renderer/render_widget_fullscreen_pepper.h" - -#include "chrome/common/render_messages.h" -#include "chrome/renderer/render_thread.h" -#include "content/renderer/ggl.h" -#include "content/renderer/gpu_channel_host.h" -#include "content/renderer/pepper_platform_context_3d_impl.h" -#include "gpu/command_buffer/client/gles2_implementation.h" -#include "third_party/WebKit/Source/WebKit/chromium/public/WebCursorInfo.h" -#include "third_party/WebKit/Source/WebKit/chromium/public/WebSize.h" -#include "third_party/WebKit/Source/WebKit/chromium/public/WebWidget.h" -#include "webkit/plugins/ppapi/plugin_delegate.h" -#include "webkit/plugins/ppapi/ppapi_plugin_instance.h" - -using WebKit::WebCanvas; -using WebKit::WebCompositionUnderline; -using WebKit::WebCursorInfo; -using WebKit::WebInputEvent; -using WebKit::WebRect; -using WebKit::WebSize; -using WebKit::WebString; -using WebKit::WebTextDirection; -using WebKit::WebTextInputType; -using WebKit::WebVector; -using WebKit::WebWidget; - -namespace { - -// WebWidget that simply wraps the pepper plugin. -class PepperWidget : public WebWidget { - public: - PepperWidget(webkit::ppapi::PluginInstance* plugin, - RenderWidgetFullscreenPepper* widget) - : plugin_(plugin), - widget_(widget), - cursor_(WebCursorInfo::TypePointer) { - } - - // WebWidget API - virtual void close() { - delete this; - } - - virtual WebSize size() { - return size_; - } - - virtual void resize(const WebSize& size) { - size_ = size; - WebRect plugin_rect(0, 0, size_.width, size_.height); - plugin_->ViewChanged(plugin_rect, plugin_rect); - widget_->Invalidate(); - } - - virtual void animate() { - } - - virtual void layout() { - } - - virtual void paint(WebCanvas* canvas, const WebRect& rect) { - WebRect plugin_rect(0, 0, size_.width, size_.height); - plugin_->Paint(canvas, plugin_rect, rect); - } - - virtual void composite(bool finish) { - ggl::Context* context = widget_->context(); - DCHECK(context); - gpu::gles2::GLES2Implementation* gl = ggl::GetImplementation(context); - unsigned int texture = plugin_->GetBackingTextureId(); - gl->BindTexture(GL_TEXTURE_2D, texture); - gl->DrawArrays(GL_TRIANGLES, 0, 3); - ggl::SwapBuffers(context); - } - - virtual void themeChanged() { - NOTIMPLEMENTED(); - } - - virtual bool handleInputEvent(const WebInputEvent& event) { - return plugin_->HandleInputEvent(event, &cursor_); - } - - virtual void mouseCaptureLost() { - NOTIMPLEMENTED(); - } - - virtual void setFocus(bool focus) { - NOTIMPLEMENTED(); - } - - // TODO(piman): figure out IME and implement these if necessary. - virtual bool setComposition( - const WebString& text, - const WebVector& underlines, - int selectionStart, - int selectionEnd) { - return false; - } - - virtual bool confirmComposition() { - return false; - } - - virtual bool confirmComposition(const WebString& text) { - return false; - } - - virtual WebTextInputType textInputType() { - return WebKit::WebTextInputTypeNone; - } - - virtual WebRect caretOrSelectionBounds() { - return WebRect(); - } - - virtual void setTextDirection(WebTextDirection) { - } - - virtual bool isAcceleratedCompositingActive() const { - return widget_->context() && (plugin_->GetBackingTextureId() != 0); - } - - private: - scoped_refptr plugin_; - RenderWidgetFullscreenPepper* widget_; - WebSize size_; - WebCursorInfo cursor_; - - DISALLOW_COPY_AND_ASSIGN(PepperWidget); -}; - -} // anonymous namespace - -// static -RenderWidgetFullscreenPepper* RenderWidgetFullscreenPepper::Create( - int32 opener_id, RenderThreadBase* render_thread, - webkit::ppapi::PluginInstance* plugin) { - DCHECK_NE(MSG_ROUTING_NONE, opener_id); - scoped_refptr widget( - new RenderWidgetFullscreenPepper(render_thread, plugin)); - widget->Init(opener_id); - return widget.release(); -} - -RenderWidgetFullscreenPepper::RenderWidgetFullscreenPepper( - RenderThreadBase* render_thread, - webkit::ppapi::PluginInstance* plugin) - : RenderWidgetFullscreen(render_thread), - plugin_(plugin), - context_(NULL), - buffer_(0), - program_(0) { -} - -RenderWidgetFullscreenPepper::~RenderWidgetFullscreenPepper() { - DestroyContext(); -} - -void RenderWidgetFullscreenPepper::Invalidate() { - InvalidateRect(gfx::Rect(size_.width(), size_.height())); -} - -void RenderWidgetFullscreenPepper::InvalidateRect(const WebKit::WebRect& rect) { - if (CheckCompositing()) { - scheduleComposite(); - } else { - didInvalidateRect(rect); - } -} - -void RenderWidgetFullscreenPepper::ScrollRect( - int dx, int dy, const WebKit::WebRect& rect) { - if (CheckCompositing()) { - scheduleComposite(); - } else { - didScrollRect(dx, dy, rect); - } -} - -void RenderWidgetFullscreenPepper::Destroy() { - // This function is called by the plugin instance as it's going away, so reset - // plugin_ to NULL to avoid calling into a dangling pointer e.g. on Close(). - plugin_ = NULL; - Send(new ViewHostMsg_Close(routing_id_)); -} - -webkit::ppapi::PluginDelegate::PlatformContext3D* -RenderWidgetFullscreenPepper::CreateContext3D() { - if (!context_) { - CreateContext(); - } - if (!context_) - return NULL; - return new PlatformContext3DImpl(context_); -} - -void RenderWidgetFullscreenPepper::DidInitiatePaint() { - if (plugin_) - plugin_->ViewInitiatedPaint(); -} - -void RenderWidgetFullscreenPepper::DidFlushPaint() { - if (plugin_) - plugin_->ViewFlushedPaint(); -} - -void RenderWidgetFullscreenPepper::Close() { - // If the fullscreen window is closed (e.g. user pressed escape), reset to - // normal mode. - if (plugin_) - plugin_->SetFullscreen(false, false); -} - -webkit::ppapi::PluginInstance* -RenderWidgetFullscreenPepper::GetBitmapForOptimizedPluginPaint( - const gfx::Rect& paint_bounds, - TransportDIB** dib, - gfx::Rect* location, - gfx::Rect* clip) { - if (plugin_ && - plugin_->GetBitmapForOptimizedPluginPaint(paint_bounds, dib, - location, clip)) - return plugin_; - return NULL; -} - -void RenderWidgetFullscreenPepper::OnResize(const gfx::Size& size, - const gfx::Rect& resizer_rect) { - if (context_) { - gpu::gles2::GLES2Implementation* gl = ggl::GetImplementation(context_); -#if defined(OS_MACOSX) - ggl::ResizeOnscreenContext(context_, size); -#else - gl->ResizeCHROMIUM(size.width(), size.height()); -#endif - gl->Viewport(0, 0, size.width(), size.height()); - } - RenderWidget::OnResize(size, resizer_rect); -} - -WebWidget* RenderWidgetFullscreenPepper::CreateWebWidget() { - return new PepperWidget(plugin_, this); -} - -void RenderWidgetFullscreenPepper::CreateContext() { - DCHECK(!context_); - RenderThread* render_thread = RenderThread::current(); - DCHECK(render_thread); - GpuChannelHost* host = render_thread->EstablishGpuChannelSync(); - if (!host) - return; - const int32 attribs[] = { - ggl::GGL_ALPHA_SIZE, 8, - ggl::GGL_DEPTH_SIZE, 0, - ggl::GGL_STENCIL_SIZE, 0, - ggl::GGL_SAMPLES, 0, - ggl::GGL_SAMPLE_BUFFERS, 0, - ggl::GGL_NONE, - }; - context_ = ggl::CreateViewContext( - host, - routing_id(), - "GL_OES_packed_depth_stencil GL_OES_depth24", - attribs); - if (!context_ || !InitContext()) { - DestroyContext(); - return; - } - ggl::SetSwapBuffersCallback( - context_, - NewCallback(this, &RenderWidgetFullscreenPepper::DidFlushPaint)); -} - -void RenderWidgetFullscreenPepper::DestroyContext() { - if (context_) { - gpu::gles2::GLES2Implementation* gl = ggl::GetImplementation(context_); - if (program_) { - gl->DeleteProgram(program_); - program_ = 0; - } - if (buffer_) { - gl->DeleteBuffers(1, &buffer_); - buffer_ = 0; - } - ggl::DestroyContext(context_); - context_ = NULL; - } -} - -namespace { - -const char kVertexShader[] = - "attribute vec2 in_tex_coord;\n" - "varying vec2 tex_coord;\n" - "void main() {\n" - " gl_Position = vec4(in_tex_coord.x * 2. - 1.,\n" - " in_tex_coord.y * 2. - 1.,\n" - " 0.,\n" - " 1.);\n" - " tex_coord = vec2(in_tex_coord.x, in_tex_coord.y);\n" - "}\n"; - -const char kFragmentShader[] = - "precision mediump float;\n" - "varying vec2 tex_coord;\n" - "uniform sampler2D in_texture;\n" - "void main() {\n" - " gl_FragColor = texture2D(in_texture, tex_coord);\n" - "}\n"; - -GLuint CreateShaderFromSource(gpu::gles2::GLES2Implementation* gl, - GLenum type, - const char* source) { - GLuint shader = gl->CreateShader(type); - gl->ShaderSource(shader, 1, &source, NULL); - gl->CompileShader(shader); - int status; - gl->GetShaderiv(shader, GL_COMPILE_STATUS, &status); - if (!status) { - int size = 0; - gl->GetShaderiv(shader, GL_INFO_LOG_LENGTH, &size); - scoped_array log(new char[size]); - gl->GetShaderInfoLog(shader, size, NULL, log.get()); - DLOG(ERROR) << "Compilation failed: " << log.get(); - gl->DeleteShader(shader); - shader = 0; - } - return shader; -} - -const float kTexCoords[] = { - 0.f, 0.f, - 0.f, 2.f, - 2.f, 0.f, -}; - -} // anonymous namespace - -bool RenderWidgetFullscreenPepper::InitContext() { - gpu::gles2::GLES2Implementation* gl = ggl::GetImplementation(context_); - program_ = gl->CreateProgram(); - - GLuint vertex_shader = - CreateShaderFromSource(gl, GL_VERTEX_SHADER, kVertexShader); - if (!vertex_shader) - return false; - gl->AttachShader(program_, vertex_shader); - gl->DeleteShader(vertex_shader); - - GLuint fragment_shader = - CreateShaderFromSource(gl, GL_FRAGMENT_SHADER, kFragmentShader); - if (!fragment_shader) - return false; - gl->AttachShader(program_, fragment_shader); - gl->DeleteShader(fragment_shader); - - gl->BindAttribLocation(program_, 0, "in_tex_coord"); - gl->LinkProgram(program_); - int status; - gl->GetProgramiv(program_, GL_LINK_STATUS, &status); - if (!status) { - int size = 0; - gl->GetProgramiv(program_, GL_INFO_LOG_LENGTH, &size); - scoped_array log(new char[size]); - gl->GetProgramInfoLog(program_, size, NULL, log.get()); - DLOG(ERROR) << "Link failed: " << log.get(); - return false; - } - gl->UseProgram(program_); - int texture_location = gl->GetUniformLocation(program_, "in_texture"); - gl->Uniform1i(texture_location, 0); - - gl->GenBuffers(1, &buffer_); - gl->BindBuffer(GL_ARRAY_BUFFER, buffer_); - gl->BufferData(GL_ARRAY_BUFFER, - sizeof(kTexCoords), - kTexCoords, - GL_STATIC_DRAW); - gl->VertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, NULL); - gl->EnableVertexAttribArray(0); - return true; -} - -bool RenderWidgetFullscreenPepper::CheckCompositing() { - bool compositing = webwidget_->isAcceleratedCompositingActive(); - if (compositing != is_accelerated_compositing_active_) { - didActivateAcceleratedCompositing(compositing); - } - return compositing; -} diff --git a/chrome/renderer/render_widget_fullscreen_pepper.h b/chrome/renderer/render_widget_fullscreen_pepper.h deleted file mode 100644 index 9e201da..0000000 --- a/chrome/renderer/render_widget_fullscreen_pepper.h +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright (c) 2010 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. - -#ifndef CHROME_RENDERER_RENDER_WIDGET_FULLSCREEN_PEPPER_H_ -#define CHROME_RENDERER_RENDER_WIDGET_FULLSCREEN_PEPPER_H_ - -#include "chrome/renderer/render_widget_fullscreen.h" -#include "third_party/WebKit/Source/WebKit/chromium/public/WebWidget.h" -#include "webkit/plugins/ppapi/fullscreen_container.h" - -namespace webkit { -namespace ppapi { - -class PluginInstance; - -} // namespace ppapi -} // namespace webkit - -namespace ggl { -class Context; -} // namespace ggl - -// A RenderWidget that hosts a fullscreen pepper plugin. This provides a -// FullscreenContainer that the plugin instance can callback into to e.g. -// invalidate rects. -class RenderWidgetFullscreenPepper : public RenderWidgetFullscreen, - public webkit::ppapi::FullscreenContainer { - public: - static RenderWidgetFullscreenPepper* Create( - int32 opener_id, - RenderThreadBase* render_thread, - webkit::ppapi::PluginInstance* plugin); - - // pepper::FullscreenContainer API. - virtual void Invalidate(); - virtual void InvalidateRect(const WebKit::WebRect& rect); - virtual void ScrollRect(int dx, int dy, const WebKit::WebRect& rect); - virtual void Destroy(); - virtual webkit::ppapi::PluginDelegate::PlatformContext3D* CreateContext3D(); - - ggl::Context* context() const { return context_; } - - protected: - RenderWidgetFullscreenPepper(RenderThreadBase* render_thread, - webkit::ppapi::PluginInstance* plugin); - virtual ~RenderWidgetFullscreenPepper(); - - // RenderWidget API. - virtual void DidInitiatePaint(); - virtual void DidFlushPaint(); - virtual void Close(); - virtual webkit::ppapi::PluginInstance* GetBitmapForOptimizedPluginPaint( - const gfx::Rect& paint_bounds, - TransportDIB** dib, - gfx::Rect* location, - gfx::Rect* clip); - virtual void OnResize(const gfx::Size& new_size, - const gfx::Rect& resizer_rect); - - // RenderWidgetFullscreen API. - virtual WebKit::WebWidget* CreateWebWidget(); - - private: - // Creates the GL context for compositing. - void CreateContext(); - - // Destroys the GL context for compositing. - void DestroyContext(); - - // Initialize the GL states and resources for compositing. - bool InitContext(); - - // Checks (and returns) whether accelerated compositing should be on or off, - // and notify the browser. - bool CheckCompositing(); - - // The plugin instance this widget wraps. - webkit::ppapi::PluginInstance* plugin_; - - // GL context for compositing. - ggl::Context* context_; - unsigned int buffer_; - unsigned int program_; - - DISALLOW_COPY_AND_ASSIGN(RenderWidgetFullscreenPepper); -}; - -#endif // CHROME_RENDERER_RENDER_WIDGET_FULLSCREEN_PEPPER_H_ diff --git a/chrome/renderer/render_widget_unittest.cc b/chrome/renderer/render_widget_unittest.cc deleted file mode 100644 index 2703b7d..0000000 --- a/chrome/renderer/render_widget_unittest.cc +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (c) 2010 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 "testing/gtest/include/gtest/gtest.h" - -#include "base/ref_counted.h" -#include "chrome/renderer/mock_render_process.h" -#include "chrome/renderer/mock_render_thread.h" -#include "chrome/renderer/render_widget.h" -#include "chrome/renderer/render_thread.h" -#include "third_party/WebKit/Source/WebKit/chromium/public/WebPopupType.h" - -namespace { - -const int32 kRouteId = 5; -const int32 kOpenerId = 7; - -class RenderWidgetTest : public testing::Test { - public: - - protected: - MessageLoop msg_loop_; - MockRenderThread render_thread_; - - // The widget, each test should verify this is non-NULL before continuing. - scoped_refptr widget_; - - private: - // testing::Test - virtual void SetUp() { - mock_process_.reset(new MockRenderProcess); - render_thread_.set_routing_id(kRouteId); - widget_ = RenderWidget::Create(kOpenerId, &render_thread_, - WebKit::WebPopupTypeNone); - ASSERT_TRUE(widget_); - } - virtual void TearDown() { - widget_ = NULL; - mock_process_.reset(); - } - - scoped_ptr mock_process_; -}; - -TEST_F(RenderWidgetTest, CreateAndCloseWidget) { - // After the RenderWidget it must have sent a message to the render thread - // that sets the opener id. - EXPECT_EQ(kOpenerId, render_thread_.opener_id()); - ASSERT_TRUE(render_thread_.has_widget()); - - // Now simulate a close of the Widget. - render_thread_.SendCloseMessage(); - EXPECT_FALSE(render_thread_.has_widget()); - - // Run the loop so the release task from the renderwidget executes. - msg_loop_.PostTask(FROM_HERE, new MessageLoop::QuitTask()); - msg_loop_.Run(); -} - -} // namespace diff --git a/chrome/renderer/renderer.sb b/chrome/renderer/renderer.sb deleted file mode 100644 index 6a0bf0d..0000000 --- a/chrome/renderer/renderer.sb +++ /dev/null @@ -1,30 +0,0 @@ -;; -;; Copyright (c) 2009 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. -;; - -; *** The contents of chrome/common/common.sb are implicitly included here. *** - -; Needed for Fonts. -(allow file-read* (regex #"^/System/Library/Fonts($|/)")) ; 10.5.6 -; 10.6 for loading fonts in the renderer. -; on 10.5 this is needed for the PDF plugin. -(allow file-read* (regex #"^/Library/Fonts($|/)")) -(allow mach-lookup (global-name "com.apple.FontObjectsServer")) ; 10.5.6 -;10.6_ONLY (allow mach-lookup (global-name "com.apple.FontServer")) ; 10.6 - -(allow file-read* - (regex #"^/System/Library/ColorSync($|/)") ; 10.5.6 - http://crbug.com/46648 - (literal "/Library/Preferences/.GlobalPreferences.plist") ; http://crbug.com/60917 - (literal "@USER_HOMEDIR_AS_LITERAL@/Library/Preferences/.GlobalPreferences.plist") -) - -; http://crbug.com/11269 -;10.6_ONLY (allow file-read* (subpath "@USER_HOMEDIR_AS_LITERAL@/Library/Fonts")) ; 10.6 - -; http://crbug.com/60917 -(allow file-read-metadata - (literal "/") - (literal "/var") -) diff --git a/chrome/renderer/safe_browsing/phishing_thumbnailer_browsertest.cc b/chrome/renderer/safe_browsing/phishing_thumbnailer_browsertest.cc index 10c4cf9..b57a510 100644 --- a/chrome/renderer/safe_browsing/phishing_thumbnailer_browsertest.cc +++ b/chrome/renderer/safe_browsing/phishing_thumbnailer_browsertest.cc @@ -3,8 +3,8 @@ // found in the LICENSE file. #include "base/basictypes.h" -#include "chrome/renderer/render_widget_browsertest.h" #include "chrome/renderer/safe_browsing/phishing_thumbnailer.h" +#include "content/renderer/render_widget_browsertest.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/skia/include/core/SkBitmap.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebSize.h" diff --git a/content/content_renderer.gypi b/content/content_renderer.gypi index 7703967..51b4365 100644 --- a/content/content_renderer.gypi +++ b/content/content_renderer.gypi @@ -72,6 +72,12 @@ 'renderer/pepper_plugin_delegate_impl.h', 'renderer/plugin_channel_host.cc', 'renderer/plugin_channel_host.h', + 'renderer/render_widget.cc', + 'renderer/render_widget.h', + 'renderer/render_widget_fullscreen.cc', + 'renderer/render_widget_fullscreen.h', + 'renderer/render_widget_fullscreen_pepper.cc', + 'renderer/render_widget_fullscreen_pepper.h', 'renderer/renderer_sandbox_support_linux.cc', 'renderer/renderer_sandbox_support_linux.h', 'renderer/renderer_webapplicationcachehost_impl.cc', @@ -130,6 +136,16 @@ '../build/linux/system.gyp:gtk', ], }], + ['OS=="mac"', { + 'sources!': [ + 'common/process_watcher_posix.cc', + ], + 'link_settings': { + 'mac_bundle_resources': [ + 'renderer/renderer.sb', + ], + }, + }], ], }, ], diff --git a/content/renderer/ggl.cc b/content/renderer/ggl.cc index cfb34c4..981d879 100644 --- a/content/renderer/ggl.cc +++ b/content/renderer/ggl.cc @@ -7,11 +7,11 @@ #include "base/lazy_instance.h" #include "base/ref_counted.h" #include "base/weak_ptr.h" -#include "chrome/renderer/render_widget.h" #include "content/renderer/command_buffer_proxy.h" #include "content/renderer/gpu_channel_host.h" #include "content/renderer/gpu_video_service_host.h" #include "content/renderer/media/gles2_video_decode_context.h" +#include "content/renderer/render_widget.h" #include "ipc/ipc_channel_handle.h" #if defined(ENABLE_GPU) diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc new file mode 100644 index 0000000..47ebd21 --- /dev/null +++ b/content/renderer/render_widget.cc @@ -0,0 +1,1114 @@ +// Copyright (c) 2010 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 "content/renderer/render_widget.h" + +#include "app/surface/transport_dib.h" +#include "base/command_line.h" +#include "base/logging.h" +#include "base/message_loop.h" +#include "base/metrics/histogram.h" +#include "base/scoped_ptr.h" +#include "build/build_config.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/common/render_messages.h" +#include "chrome/common/render_messages_params.h" +#include "chrome/renderer/render_process.h" +#include "chrome/renderer/render_thread.h" +#include "content/renderer/renderer_webkitclient_impl.h" +#include "gpu/common/gpu_trace_event.h" +#include "ipc/ipc_sync_message.h" +#include "skia/ext/platform_canvas.h" +#include "third_party/skia/include/core/SkShader.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebCursorInfo.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebPopupMenu.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebPopupMenuInfo.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebRect.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebScreenInfo.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebSize.h" +#include "ui/gfx/point.h" +#include "ui/gfx/size.h" +#include "webkit/glue/webkit_glue.h" +#include "webkit/plugins/npapi/webplugin.h" +#include "webkit/plugins/ppapi/ppapi_plugin_instance.h" + +#if defined(OS_POSIX) +#include "ipc/ipc_channel_posix.h" +#include "third_party/skia/include/core/SkPixelRef.h" +#include "third_party/skia/include/core/SkMallocPixelRef.h" +#endif // defined(OS_POSIX) + +#include "third_party/WebKit/Source/WebKit/chromium/public/WebWidget.h" + +using WebKit::WebCompositionUnderline; +using WebKit::WebCursorInfo; +using WebKit::WebInputEvent; +using WebKit::WebMouseEvent; +using WebKit::WebNavigationPolicy; +using WebKit::WebPopupMenu; +using WebKit::WebPopupMenuInfo; +using WebKit::WebPopupType; +using WebKit::WebRect; +using WebKit::WebScreenInfo; +using WebKit::WebSize; +using WebKit::WebTextDirection; +using WebKit::WebTextInputType; +using WebKit::WebVector; +using WebKit::WebWidget; + +RenderWidget::RenderWidget(RenderThreadBase* render_thread, + WebKit::WebPopupType popup_type) + : routing_id_(MSG_ROUTING_NONE), + webwidget_(NULL), + opener_id_(MSG_ROUTING_NONE), + render_thread_(render_thread), + host_window_(0), + current_paint_buf_(NULL), + next_paint_flags_(0), + update_reply_pending_(false), + did_show_(false), + is_hidden_(false), + needs_repainting_on_restore_(false), + has_focus_(false), + handling_input_event_(false), + closing_(false), + input_method_is_active_(false), + text_input_type_(WebKit::WebTextInputTypeNone), + popup_type_(popup_type), + pending_window_rect_count_(0), + suppress_next_char_events_(false), + is_accelerated_compositing_active_(false), + animation_update_pending_(false), + animation_task_posted_(false) { + RenderProcess::current()->AddRefProcess(); + DCHECK(render_thread_); +} + +RenderWidget::~RenderWidget() { + DCHECK(!webwidget_) << "Leaking our WebWidget!"; + if (current_paint_buf_) { + RenderProcess::current()->ReleaseTransportDIB(current_paint_buf_); + current_paint_buf_ = NULL; + } + RenderProcess::current()->ReleaseProcess(); +} + +// static +RenderWidget* RenderWidget::Create(int32 opener_id, + RenderThreadBase* render_thread, + WebKit::WebPopupType popup_type) { + DCHECK(opener_id != MSG_ROUTING_NONE); + scoped_refptr widget(new RenderWidget(render_thread, + popup_type)); + widget->Init(opener_id); // adds reference + return widget; +} + +// static +WebWidget* RenderWidget::CreateWebWidget(RenderWidget* render_widget) { + switch (render_widget->popup_type_) { + case WebKit::WebPopupTypeNone: // Nothing to create. + break; + case WebKit::WebPopupTypeSelect: + case WebKit::WebPopupTypeSuggestion: + return WebPopupMenu::create(render_widget); + default: + NOTREACHED(); + } + return NULL; +} + +void RenderWidget::Init(int32 opener_id) { + DoInit(opener_id, + RenderWidget::CreateWebWidget(this), + new ViewHostMsg_CreateWidget(opener_id, popup_type_, &routing_id_)); +} + +void RenderWidget::DoInit(int32 opener_id, + WebWidget* web_widget, + IPC::SyncMessage* create_widget_message) { + DCHECK(!webwidget_); + + if (opener_id != MSG_ROUTING_NONE) + opener_id_ = opener_id; + + webwidget_ = web_widget; + + bool result = render_thread_->Send(create_widget_message); + if (result) { + render_thread_->AddRoute(routing_id_, this); + // Take a reference on behalf of the RenderThread. This will be balanced + // when we receive ViewMsg_Close. + AddRef(); + } else { + DCHECK(false); + } +} + +// This is used to complete pending inits and non-pending inits. For non- +// pending cases, the parent will be the same as the current parent. This +// indicates we do not need to reparent or anything. +void RenderWidget::CompleteInit(gfx::NativeViewId parent_hwnd) { + DCHECK(routing_id_ != MSG_ROUTING_NONE); + + host_window_ = parent_hwnd; + + Send(new ViewHostMsg_RenderViewReady(routing_id_)); +} + +bool RenderWidget::OnMessageReceived(const IPC::Message& message) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(RenderWidget, message) + IPC_MESSAGE_HANDLER(ViewMsg_Close, OnClose) + IPC_MESSAGE_HANDLER(ViewMsg_CreatingNew_ACK, OnCreatingNewAck) + IPC_MESSAGE_HANDLER(ViewMsg_Resize, OnResize) + IPC_MESSAGE_HANDLER(ViewMsg_WasHidden, OnWasHidden) + IPC_MESSAGE_HANDLER(ViewMsg_WasRestored, OnWasRestored) + IPC_MESSAGE_HANDLER(ViewMsg_UpdateRect_ACK, OnUpdateRectAck) + IPC_MESSAGE_HANDLER(ViewMsg_HandleInputEvent, OnHandleInputEvent) + IPC_MESSAGE_HANDLER(ViewMsg_MouseCaptureLost, OnMouseCaptureLost) + IPC_MESSAGE_HANDLER(ViewMsg_SetFocus, OnSetFocus) + IPC_MESSAGE_HANDLER(ViewMsg_SetInputMethodActive, OnSetInputMethodActive) + IPC_MESSAGE_HANDLER(ViewMsg_ImeSetComposition, OnImeSetComposition) + IPC_MESSAGE_HANDLER(ViewMsg_ImeConfirmComposition, OnImeConfirmComposition) + IPC_MESSAGE_HANDLER(ViewMsg_PaintAtSize, OnMsgPaintAtSize) + IPC_MESSAGE_HANDLER(ViewMsg_Repaint, OnMsgRepaint) + IPC_MESSAGE_HANDLER(ViewMsg_SetTextDirection, OnSetTextDirection) + IPC_MESSAGE_HANDLER(ViewMsg_Move_ACK, OnRequestMoveAck) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +bool RenderWidget::Send(IPC::Message* message) { + // Don't send any messages after the browser has told us to close. + if (closing_) { + delete message; + return false; + } + + // If given a messsage without a routing ID, then assign our routing ID. + if (message->routing_id() == MSG_ROUTING_NONE) + message->set_routing_id(routing_id_); + + return render_thread_->Send(message); +} + +// Got a response from the browser after the renderer decided to create a new +// view. +void RenderWidget::OnCreatingNewAck(gfx::NativeViewId parent) { + DCHECK(routing_id_ != MSG_ROUTING_NONE); + + CompleteInit(parent); +} + +void RenderWidget::OnClose() { + if (closing_) + return; + closing_ = true; + + // Browser correspondence is no longer needed at this point. + if (routing_id_ != MSG_ROUTING_NONE) { + render_thread_->RemoveRoute(routing_id_); + SetHidden(false); + } + + // If there is a Send call on the stack, then it could be dangerous to close + // now. Post a task that only gets invoked when there are no nested message + // loops. + MessageLoop::current()->PostNonNestableTask(FROM_HERE, + NewRunnableMethod(this, &RenderWidget::Close)); + + // Balances the AddRef taken when we called AddRoute. + Release(); +} + +void RenderWidget::OnResize(const gfx::Size& new_size, + const gfx::Rect& resizer_rect) { + // During shutdown we can just ignore this message. + if (!webwidget_) + return; + + // We shouldn't be asked to resize to our current size. + DCHECK(size_ != new_size || resizer_rect_ != resizer_rect); + + // Remember the rect where the resize corner will be drawn. + resizer_rect_ = resizer_rect; + + if (size_ == new_size) + return; + + // TODO(darin): We should not need to reset this here. + SetHidden(false); + needs_repainting_on_restore_ = false; + + size_ = new_size; + + // We should not be sent a Resize message if we have not ACK'd the previous + DCHECK(!next_paint_is_resize_ack()); + + paint_aggregator_.ClearPendingUpdate(); + + // When resizing, we want to wait to paint before ACK'ing the resize. This + // ensures that we only resize as fast as we can paint. We only need to send + // an ACK if we are resized to a non-empty rect. + webwidget_->resize(new_size); + if (!new_size.IsEmpty()) { + if (!is_accelerated_compositing_active_) { + // Resize should have caused an invalidation of the entire view. + DCHECK(paint_aggregator_.HasPendingUpdate()); + } + + // We will send the Resize_ACK flag once we paint again. + set_next_paint_is_resize_ack(); + } +} + +void RenderWidget::OnWasHidden() { + // Go into a mode where we stop generating paint and scrolling events. + SetHidden(true); +} + +void RenderWidget::OnWasRestored(bool needs_repainting) { + // During shutdown we can just ignore this message. + if (!webwidget_) + return; + + // See OnWasHidden + SetHidden(false); + + if (!needs_repainting && !needs_repainting_on_restore_) + return; + needs_repainting_on_restore_ = false; + + // Tag the next paint as a restore ack, which is picked up by + // DoDeferredUpdate when it sends out the next PaintRect message. + set_next_paint_is_restore_ack(); + + // Generate a full repaint. + if (!is_accelerated_compositing_active_) { + didInvalidateRect(gfx::Rect(size_.width(), size_.height())); + } else { + scheduleComposite(); + } +} + +void RenderWidget::OnRequestMoveAck() { + DCHECK(pending_window_rect_count_); + pending_window_rect_count_--; +} + +void RenderWidget::OnUpdateRectAck() { + DCHECK(update_reply_pending()); + update_reply_pending_ = false; + + // If we sent an UpdateRect message with a zero-sized bitmap, then we should + // have no current paint buffer. + if (current_paint_buf_) { + RenderProcess::current()->ReleaseTransportDIB(current_paint_buf_); + current_paint_buf_ = NULL; + } + + // Notify subclasses. + DidFlushPaint(); + + // Continue painting if necessary... + CallDoDeferredUpdate(); +} + +void RenderWidget::OnHandleInputEvent(const IPC::Message& message) { + void* iter = NULL; + + const char* data; + int data_length; + handling_input_event_ = true; + if (!message.ReadData(&iter, &data, &data_length)) { + handling_input_event_ = false; + return; + } + + const WebInputEvent* input_event = + reinterpret_cast(data); + + bool is_keyboard_shortcut = false; + // is_keyboard_shortcut flag is only available for RawKeyDown events. + if (input_event->type == WebInputEvent::RawKeyDown) + message.ReadBool(&iter, &is_keyboard_shortcut); + + bool processed = false; + if (input_event->type != WebInputEvent::Char || !suppress_next_char_events_) { + suppress_next_char_events_ = false; + if (webwidget_) + processed = webwidget_->handleInputEvent(*input_event); + } + + // If this RawKeyDown event corresponds to a browser keyboard shortcut and + // it's not processed by webkit, then we need to suppress the upcoming Char + // events. + if (!processed && is_keyboard_shortcut) + suppress_next_char_events_ = true; + + IPC::Message* response = new ViewHostMsg_HandleInputEvent_ACK(routing_id_); + response->WriteInt(input_event->type); + response->WriteBool(processed); + + if ((input_event->type == WebInputEvent::MouseMove || + input_event->type == WebInputEvent::MouseWheel || + input_event->type == WebInputEvent::TouchMove) && + paint_aggregator_.HasPendingUpdate()) { + // We want to rate limit the input events in this case, so we'll wait for + // painting to finish before ACKing this message. + if (pending_input_event_ack_.get()) { + // As two different kinds of events could cause us to postpone an ack + // we send it now, if we have one pending. The Browser should never + // send us the same kind of event we are delaying the ack for. + Send(pending_input_event_ack_.release()); + } + pending_input_event_ack_.reset(response); + } else { + Send(response); + } + + handling_input_event_ = false; + + if (WebInputEvent::isKeyboardEventType(input_event->type)) + DidHandleKeyEvent(); + if (WebInputEvent::isMouseEventType(input_event->type)) + DidHandleMouseEvent(*(static_cast(input_event))); +} + +void RenderWidget::OnMouseCaptureLost() { + if (webwidget_) + webwidget_->mouseCaptureLost(); +} + +void RenderWidget::OnSetFocus(bool enable) { + has_focus_ = enable; + if (webwidget_) + webwidget_->setFocus(enable); +} + +void RenderWidget::ClearFocus() { + // We may have got the focus from the browser before this gets processed, in + // which case we do not want to unfocus ourself. + if (!has_focus_ && webwidget_) + webwidget_->setFocus(false); +} + +void RenderWidget::PaintRect(const gfx::Rect& rect, + const gfx::Point& canvas_origin, + skia::PlatformCanvas* canvas) { + + canvas->save(); + + // Bring the canvas into the coordinate system of the paint rect. + canvas->translate(static_cast(-canvas_origin.x()), + static_cast(-canvas_origin.y())); + + // If there is a custom background, tile it. + if (!background_.empty()) { + SkPaint paint; + SkShader* shader = SkShader::CreateBitmapShader(background_, + SkShader::kRepeat_TileMode, + SkShader::kRepeat_TileMode); + paint.setShader(shader)->unref(); + paint.setXfermodeMode(SkXfermode::kSrcOver_Mode); + canvas->drawPaint(paint); + } + + // First see if this rect is a plugin that can paint itself faster. + TransportDIB* optimized_dib = NULL; + gfx::Rect optimized_copy_rect, optimized_copy_location; + webkit::ppapi::PluginInstance* optimized_instance = + GetBitmapForOptimizedPluginPaint(rect, &optimized_dib, + &optimized_copy_location, + &optimized_copy_rect); + if (optimized_instance) { + // This plugin can be optimize-painted and we can just ask it to paint + // itself. We don't actually need the TransportDIB in this case. + // + // This is an optimization for PPAPI plugins that know they're on top of + // the page content. If this rect is inside such a plugin, we can save some + // time and avoid re-rendering the page content which we know will be + // covered by the plugin later (this time can be significant, especially + // for a playing movie that is invalidating a lot). + // + // In the plugin movie case, hopefully the similar call to + // GetBitmapForOptimizedPluginPaint in DoDeferredUpdate handles the + // painting, because that avoids copying the plugin image to a different + // paint rect. Unfortunately, if anything on the page is animating other + // than the movie, it break this optimization since the union of the + // invalid regions will be larger than the plugin. + // + // This code optimizes that case, where we can still avoid painting in + // WebKit and filling the background (which can be slow) and just painting + // the plugin. Unlike the DoDeferredUpdate case, an extra copy is still + // required. + optimized_instance->Paint(webkit_glue::ToWebCanvas(canvas), + optimized_copy_location, rect); + } else { + // Normal painting case. + webwidget_->paint(webkit_glue::ToWebCanvas(canvas), rect); + + // Flush to underlying bitmap. TODO(darin): is this needed? + canvas->getTopPlatformDevice().accessBitmap(false); + } + + PaintDebugBorder(rect, canvas); + canvas->restore(); +} + +void RenderWidget::PaintDebugBorder(const gfx::Rect& rect, + skia::PlatformCanvas* canvas) { + static bool kPaintBorder = + CommandLine::ForCurrentProcess()->HasSwitch(switches::kShowPaintRects); + if (!kPaintBorder) + return; + + // Cycle through these colors to help distinguish new paint rects. + const SkColor colors[] = { + SkColorSetARGB(0x3F, 0xFF, 0, 0), + SkColorSetARGB(0x3F, 0xFF, 0, 0xFF), + SkColorSetARGB(0x3F, 0, 0, 0xFF), + }; + static int color_selector = 0; + + SkPaint paint; + paint.setStyle(SkPaint::kStroke_Style); + paint.setColor(colors[color_selector++ % arraysize(colors)]); + paint.setStrokeWidth(1); + + SkIRect irect; + irect.set(rect.x(), rect.y(), rect.right() - 1, rect.bottom() - 1); + canvas->drawIRect(irect, paint); +} + +void RenderWidget::AnimationCallback() { + animation_task_posted_ = false; + if (!animation_update_pending_) + return; + if (!animation_floor_time_.is_null()) { + // Record when we fired (according to base::Time::Now()) relative to when + // we posted the task to quantify how much the base::Time/base::TimeTicks + // skew is affecting animations. + base::TimeDelta animation_callback_delay = base::Time::Now() - + (animation_floor_time_ - base::TimeDelta::FromMilliseconds(16)); + UMA_HISTOGRAM_CUSTOM_TIMES("Renderer4.AnimationCallbackDelayTime", + animation_callback_delay, + base::TimeDelta::FromMilliseconds(0), + base::TimeDelta::FromMilliseconds(30), + 25); + } + CallDoDeferredUpdate(); +} + +void RenderWidget::AnimateIfNeeded() { + if (!animation_update_pending_) + return; + base::Time now = base::Time::Now(); + if (now >= animation_floor_time_) { + animation_floor_time_ = now + base::TimeDelta::FromMilliseconds(16); + // Set a timer to call us back after 16ms (targetting 60FPS) before + // running animation callbacks so that if a callback requests another + // we'll be sure to run it at the proper time. + MessageLoop::current()->PostDelayedTask(FROM_HERE, NewRunnableMethod( + this, &RenderWidget::AnimationCallback), 16); + animation_task_posted_ = true; + animation_update_pending_ = false; + // Explicitly pump the WebCore Timer queue to avoid starvation on OS X. + // See crbug.com/71735. + // TODO(jamesr) Remove this call once crbug.com/72007 is fixed. + RenderThread::current()->GetWebKitClientImpl()->DoTimeout(); + webwidget_->animate(); + return; + } + if (animation_task_posted_) + return; + // This code uses base::Time::Now() to calculate the floor and next fire + // time because javascript's Date object uses base::Time::Now(). The + // message loop uses base::TimeTicks, which on windows can have a + // different granularity than base::Time. + // The upshot of all this is that this function might be called before + // base::Time::Now() has advanced past the animation_floor_time_. To + // avoid exposing this delay to javascript, we keep posting delayed + // tasks until base::Time::Now() has advanced far enough. + int64 delay = (animation_floor_time_ - now).InMillisecondsRoundedUp(); + animation_task_posted_ = true; + MessageLoop::current()->PostDelayedTask(FROM_HERE, + NewRunnableMethod(this, &RenderWidget::AnimationCallback), delay); +} + +void RenderWidget::CallDoDeferredUpdate() { + DoDeferredUpdate(); + + if (pending_input_event_ack_.get()) + Send(pending_input_event_ack_.release()); +} + +void RenderWidget::DoDeferredUpdate() { + GPU_TRACE_EVENT0("render_widget", "DoDeferredUpdate"); + + if (!webwidget_ || update_reply_pending()) + return; + + // Suppress updating when we are hidden. + if (is_hidden_ || size_.IsEmpty()) { + paint_aggregator_.ClearPendingUpdate(); + needs_repainting_on_restore_ = true; + return; + } + + AnimateIfNeeded(); + + // Layout may generate more invalidation. It may also enable the + // GPU acceleration, so make sure to run layout before we send the + // GpuRenderingActivated message. + webwidget_->layout(); + + // Suppress painting if nothing is dirty. This has to be done after updating + // animations running layout as these may generate further invalidations. + if (!paint_aggregator_.HasPendingUpdate()) + return; + + // OK, save the pending update to a local since painting may cause more + // invalidation. Some WebCore rendering objects only layout when painted. + PaintAggregator::PendingUpdate update; + paint_aggregator_.PopPendingUpdate(&update); + + gfx::Rect scroll_damage = update.GetScrollDamage(); + gfx::Rect bounds = update.GetPaintBounds().Union(scroll_damage); + + // A plugin may be able to do an optimized paint. First check this, in which + // case we can skip all of the bitmap generation and regular paint code. + // This optimization allows PPAPI plugins that declare themselves on top of + // the page (like a traditional windowed plugin) to be able to animate (think + // movie playing) without repeatedly re-painting the page underneath, or + // copying the plugin backing store (since we can send the plugin's backing + // store directly to the browser). + // + // This optimization only works when the entire invalid region is contained + // within the plugin. There is a related optimization in PaintRect for the + // case where there may be multiple invalid regions. + TransportDIB::Id dib_id = TransportDIB::Id(); + TransportDIB* dib = NULL; + std::vector copy_rects; + gfx::Rect optimized_copy_rect, optimized_copy_location; + if (update.scroll_rect.IsEmpty() && + !is_accelerated_compositing_active_ && + GetBitmapForOptimizedPluginPaint(bounds, &dib, &optimized_copy_location, + &optimized_copy_rect)) { + // Only update the part of the plugin that actually changed. + optimized_copy_rect = optimized_copy_rect.Intersect(bounds); + bounds = optimized_copy_location; + copy_rects.push_back(optimized_copy_rect); + dib_id = dib->id(); + } else if (!is_accelerated_compositing_active_) { + // Compute a buffer for painting and cache it. + scoped_ptr canvas( + RenderProcess::current()->GetDrawingCanvas(¤t_paint_buf_, + bounds)); + if (!canvas.get()) { + NOTREACHED(); + return; + } + + // We may get back a smaller canvas than we asked for. + // TODO(darin): This seems like it could cause painting problems! + DCHECK_EQ(bounds.width(), canvas->getDevice()->width()); + DCHECK_EQ(bounds.height(), canvas->getDevice()->height()); + bounds.set_width(canvas->getDevice()->width()); + bounds.set_height(canvas->getDevice()->height()); + + HISTOGRAM_COUNTS_100("MPArch.RW_PaintRectCount", update.paint_rects.size()); + + // The scroll damage is just another rectangle to paint and copy. + copy_rects.swap(update.paint_rects); + if (!scroll_damage.IsEmpty()) + copy_rects.push_back(scroll_damage); + + for (size_t i = 0; i < copy_rects.size(); ++i) + PaintRect(copy_rects[i], bounds.origin(), canvas.get()); + + dib_id = current_paint_buf_->id(); + } else { // Accelerated compositing path + // Begin painting. + webwidget_->composite(false); + } + + // sending an ack to browser process that the paint is complete... + ViewHostMsg_UpdateRect_Params params; + params.bitmap = dib_id; + params.bitmap_rect = bounds; + params.dx = update.scroll_delta.x(); + params.dy = update.scroll_delta.y(); + if (is_accelerated_compositing_active_) { + // If painting is done via the gpu process then we clear out all damage + // rects to save the browser process from doing unecessary work. + params.scroll_rect = gfx::Rect(); + params.copy_rects.clear(); + } else { + params.scroll_rect = update.scroll_rect; + params.copy_rects.swap(copy_rects); // TODO(darin): clip to bounds? + } + params.view_size = size_; + params.resizer_rect = resizer_rect_; + params.plugin_window_moves.swap(plugin_window_moves_); + params.flags = next_paint_flags_; + params.scroll_offset = GetScrollOffset(); + + update_reply_pending_ = true; + Send(new ViewHostMsg_UpdateRect(routing_id_, params)); + next_paint_flags_ = 0; + + UpdateInputMethod(); + + // Let derived classes know we've painted. + DidInitiatePaint(); +} + +/////////////////////////////////////////////////////////////////////////////// +// WebWidgetClient + +void RenderWidget::didInvalidateRect(const WebRect& rect) { + // We only want one pending DoDeferredUpdate call at any time... + bool update_pending = paint_aggregator_.HasPendingUpdate(); + + // The invalidated rect might be outside the bounds of the view. + gfx::Rect view_rect(size_); + gfx::Rect damaged_rect = view_rect.Intersect(rect); + if (damaged_rect.IsEmpty()) + return; + + paint_aggregator_.InvalidateRect(damaged_rect); + + // We may not need to schedule another call to DoDeferredUpdate. + if (update_pending) + return; + if (!paint_aggregator_.HasPendingUpdate()) + return; + if (update_reply_pending()) + return; + + // Perform updating asynchronously. This serves two purposes: + // 1) Ensures that we call WebView::Paint without a bunch of other junk + // on the call stack. + // 2) Allows us to collect more damage rects before painting to help coalesce + // the work that we will need to do. + MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod( + this, &RenderWidget::CallDoDeferredUpdate)); +} + +void RenderWidget::didScrollRect(int dx, int dy, const WebRect& clip_rect) { + // Drop scrolls on the floor when we are in compositing mode. + // TODO(nduca): stop WebViewImpl from sending scrolls in the first place. + if (is_accelerated_compositing_active_) + return; + + // We only want one pending DoDeferredUpdate call at any time... + bool update_pending = paint_aggregator_.HasPendingUpdate(); + + // The scrolled rect might be outside the bounds of the view. + gfx::Rect view_rect(size_); + gfx::Rect damaged_rect = view_rect.Intersect(clip_rect); + if (damaged_rect.IsEmpty()) + return; + + paint_aggregator_.ScrollRect(dx, dy, damaged_rect); + + // We may not need to schedule another call to DoDeferredUpdate. + if (update_pending) + return; + if (!paint_aggregator_.HasPendingUpdate()) + return; + if (update_reply_pending()) + return; + + // Perform updating asynchronously. This serves two purposes: + // 1) Ensures that we call WebView::Paint without a bunch of other junk + // on the call stack. + // 2) Allows us to collect more damage rects before painting to help coalesce + // the work that we will need to do. + MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod( + this, &RenderWidget::CallDoDeferredUpdate)); +} + +void RenderWidget::didActivateAcceleratedCompositing(bool active) { + is_accelerated_compositing_active_ = active; + Send(new ViewHostMsg_DidActivateAcceleratedCompositing( + routing_id_, is_accelerated_compositing_active_)); +} + +void RenderWidget::scheduleComposite() { + // TODO(nduca): replace with something a little less hacky. The reason this + // hack is still used is because the Invalidate-DoDeferredUpdate loop + // contains a lot of host-renderer synchronization logic that is still + // important for the accelerated compositing case. The option of simply + // duplicating all that code is less desirable than "faking out" the + // invalidation path using a magical damage rect. + didInvalidateRect(WebRect(0, 0, 1, 1)); +} + +void RenderWidget::scheduleAnimation() { + if (!animation_update_pending_) { + animation_update_pending_ = true; + if (!animation_task_posted_) { + animation_task_posted_ = true; + MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod( + this, &RenderWidget::AnimationCallback)); + } + } +} + +void RenderWidget::didChangeCursor(const WebCursorInfo& cursor_info) { + // TODO(darin): Eliminate this temporary. + WebCursor cursor(cursor_info); + + // Only send a SetCursor message if we need to make a change. + if (!current_cursor_.IsEqual(cursor)) { + current_cursor_ = cursor; + Send(new ViewHostMsg_SetCursor(routing_id_, cursor)); + } +} + +// We are supposed to get a single call to Show for a newly created RenderWidget +// that was created via RenderWidget::CreateWebView. So, we wait until this +// point to dispatch the ShowWidget message. +// +// This method provides us with the information about how to display the newly +// created RenderWidget (i.e., as a constrained popup or as a new tab). +// +void RenderWidget::show(WebNavigationPolicy) { + DCHECK(!did_show_) << "received extraneous Show call"; + DCHECK(routing_id_ != MSG_ROUTING_NONE); + DCHECK(opener_id_ != MSG_ROUTING_NONE); + + if (did_show_) + return; + + did_show_ = true; + // NOTE: initial_pos_ may still have its default values at this point, but + // that's okay. It'll be ignored if as_popup is false, or the browser + // process will impose a default position otherwise. + Send(new ViewHostMsg_ShowWidget(opener_id_, routing_id_, initial_pos_)); + SetPendingWindowRect(initial_pos_); +} + +void RenderWidget::didFocus() { +} + +void RenderWidget::didBlur() { +} + +void RenderWidget::DoDeferredClose() { + Send(new ViewHostMsg_Close(routing_id_)); +} + +void RenderWidget::closeWidgetSoon() { + // If a page calls window.close() twice, we'll end up here twice, but that's + // OK. It is safe to send multiple Close messages. + + // Ask the RenderWidgetHost to initiate close. We could be called from deep + // in Javascript. If we ask the RendwerWidgetHost to close now, the window + // could be closed before the JS finishes executing. So instead, post a + // message back to the message loop, which won't run until the JS is + // complete, and then the Close message can be sent. + MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod( + this, &RenderWidget::DoDeferredClose)); +} + +void RenderWidget::Close() { + if (webwidget_) { + webwidget_->close(); + webwidget_ = NULL; + } +} + +WebRect RenderWidget::windowRect() { + if (pending_window_rect_count_) + return pending_window_rect_; + + gfx::Rect rect; + Send(new ViewHostMsg_GetWindowRect(routing_id_, host_window_, &rect)); + return rect; +} + +void RenderWidget::setWindowRect(const WebRect& pos) { + if (did_show_) { + Send(new ViewHostMsg_RequestMove(routing_id_, pos)); + SetPendingWindowRect(pos); + } else { + initial_pos_ = pos; + } +} + +void RenderWidget::SetPendingWindowRect(const WebRect& rect) { + pending_window_rect_ = rect; + pending_window_rect_count_++; +} + +WebRect RenderWidget::rootWindowRect() { + if (pending_window_rect_count_) { + // NOTE(mbelshe): If there is a pending_window_rect_, then getting + // the RootWindowRect is probably going to return wrong results since the + // browser may not have processed the Move yet. There isn't really anything + // good to do in this case, and it shouldn't happen - since this size is + // only really needed for windowToScreen, which is only used for Popups. + return pending_window_rect_; + } + + gfx::Rect rect; + Send(new ViewHostMsg_GetRootWindowRect(routing_id_, host_window_, &rect)); + return rect; +} + +WebRect RenderWidget::windowResizerRect() { + return resizer_rect_; +} + +void RenderWidget::OnSetInputMethodActive(bool is_active) { + // To prevent this renderer process from sending unnecessary IPC messages to + // a browser process, we permit the renderer process to send IPC messages + // only during the input method attached to the browser process is active. + input_method_is_active_ = is_active; +} + +void RenderWidget::OnImeSetComposition( + const string16& text, + const std::vector& underlines, + int selection_start, int selection_end) { + if (!webwidget_) + return; + if (!webwidget_->setComposition( + text, WebVector(underlines), + selection_start, selection_end)) { + // If we failed to set the composition text, then we need to let the browser + // process to cancel the input method's ongoing composition session, to make + // sure we are in a consistent state. + Send(new ViewHostMsg_ImeCancelComposition(routing_id())); + } +} + +void RenderWidget::OnImeConfirmComposition(const string16& text) { + if (webwidget_) + webwidget_->confirmComposition(text); +} + +// This message causes the renderer to render an image of the +// desired_size, regardless of whether the tab is hidden or not. +void RenderWidget::OnMsgPaintAtSize(const TransportDIB::Handle& dib_handle, + int tag, + const gfx::Size& page_size, + const gfx::Size& desired_size) { + if (!webwidget_ || !TransportDIB::is_valid(dib_handle)) { + if (TransportDIB::is_valid(dib_handle)) { + // Close our unused handle. +#if defined(OS_WIN) + ::CloseHandle(dib_handle); +#elif defined(OS_MACOSX) + base::SharedMemory::CloseHandle(dib_handle); +#endif + } + return; + } + + if (page_size.IsEmpty() || desired_size.IsEmpty()) { + // If one of these is empty, then we just return the dib we were + // given, to avoid leaking it. + Send(new ViewHostMsg_PaintAtSize_ACK(routing_id_, tag, desired_size)); + return; + } + + // Map the given DIB ID into this process, and unmap it at the end + // of this function. + scoped_ptr paint_at_size_buffer( + TransportDIB::CreateWithHandle(dib_handle)); + + gfx::Size canvas_size = page_size; + float x_scale = static_cast(desired_size.width()) / + static_cast(canvas_size.width()); + float y_scale = static_cast(desired_size.height()) / + static_cast(canvas_size.height()); + + gfx::Rect orig_bounds(canvas_size); + canvas_size.set_width(static_cast(canvas_size.width() * x_scale)); + canvas_size.set_height(static_cast(canvas_size.height() * y_scale)); + gfx::Rect bounds(canvas_size); + + scoped_ptr canvas( + paint_at_size_buffer->GetPlatformCanvas(canvas_size.width(), + canvas_size.height())); + if (!canvas.get()) { + NOTREACHED(); + return; + } + + // Reset bounds to what we actually received, but they should be the + // same. + DCHECK_EQ(bounds.width(), canvas->getDevice()->width()); + DCHECK_EQ(bounds.height(), canvas->getDevice()->height()); + bounds.set_width(canvas->getDevice()->width()); + bounds.set_height(canvas->getDevice()->height()); + + canvas->save(); + // Add the scale factor to the canvas, so that we'll get the desired size. + canvas->scale(SkFloatToScalar(x_scale), SkFloatToScalar(y_scale)); + + // Have to make sure we're laid out at the right size before + // rendering. + gfx::Size old_size = webwidget_->size(); + webwidget_->resize(page_size); + webwidget_->layout(); + + // Paint the entire thing (using original bounds, not scaled bounds). + PaintRect(orig_bounds, orig_bounds.origin(), canvas.get()); + canvas->restore(); + + // Return the widget to its previous size. + webwidget_->resize(old_size); + + Send(new ViewHostMsg_PaintAtSize_ACK(routing_id_, tag, bounds.size())); +} + +void RenderWidget::OnMsgRepaint(const gfx::Size& size_to_paint) { + // During shutdown we can just ignore this message. + if (!webwidget_) + return; + + set_next_paint_is_repaint_ack(); + if (is_accelerated_compositing_active_) { + scheduleComposite(); + } else { + gfx::Rect repaint_rect(size_to_paint.width(), size_to_paint.height()); + didInvalidateRect(repaint_rect); + } +} + +void RenderWidget::OnSetTextDirection(WebTextDirection direction) { + if (!webwidget_) + return; + webwidget_->setTextDirection(direction); +} + +webkit::ppapi::PluginInstance* RenderWidget::GetBitmapForOptimizedPluginPaint( + const gfx::Rect& paint_bounds, + TransportDIB** dib, + gfx::Rect* location, + gfx::Rect* clip) { + // Bare RenderWidgets don't support optimized plugin painting. + return NULL; +} + +gfx::Point RenderWidget::GetScrollOffset() { + // Bare RenderWidgets don't support scroll offset. + return gfx::Point(0, 0); +} + +void RenderWidget::SetHidden(bool hidden) { + if (is_hidden_ == hidden) + return; + + // The status has changed. Tell the RenderThread about it. + is_hidden_ = hidden; + if (is_hidden_) + render_thread_->WidgetHidden(); + else + render_thread_->WidgetRestored(); +} + +void RenderWidget::SetBackground(const SkBitmap& background) { + background_ = background; + + // Generate a full repaint. + didInvalidateRect(gfx::Rect(size_.width(), size_.height())); +} + +bool RenderWidget::next_paint_is_resize_ack() const { + return ViewHostMsg_UpdateRect_Flags::is_resize_ack(next_paint_flags_); +} + +bool RenderWidget::next_paint_is_restore_ack() const { + return ViewHostMsg_UpdateRect_Flags::is_restore_ack(next_paint_flags_); +} + +void RenderWidget::set_next_paint_is_resize_ack() { + next_paint_flags_ |= ViewHostMsg_UpdateRect_Flags::IS_RESIZE_ACK; +} + +void RenderWidget::set_next_paint_is_restore_ack() { + next_paint_flags_ |= ViewHostMsg_UpdateRect_Flags::IS_RESTORE_ACK; +} + +void RenderWidget::set_next_paint_is_repaint_ack() { + next_paint_flags_ |= ViewHostMsg_UpdateRect_Flags::IS_REPAINT_ACK; +} + +void RenderWidget::UpdateInputMethod() { + if (!input_method_is_active_) + return; + + WebTextInputType new_type = WebKit::WebTextInputTypeNone; + WebRect new_caret_bounds; + + if (webwidget_) { + new_type = webwidget_->textInputType(); + new_caret_bounds = webwidget_->caretOrSelectionBounds(); + } + + // Only sends text input type and caret bounds to the browser process if they + // are changed. + if (text_input_type_ != new_type || caret_bounds_ != new_caret_bounds) { + text_input_type_ = new_type; + caret_bounds_ = new_caret_bounds; + Send(new ViewHostMsg_ImeUpdateTextInputState( + routing_id(), new_type, new_caret_bounds)); + } +} + +WebScreenInfo RenderWidget::screenInfo() { + WebScreenInfo results; + Send(new ViewHostMsg_GetScreenInfo(routing_id_, host_window_, &results)); + return results; +} + +void RenderWidget::resetInputMethod() { + if (!input_method_is_active_) + return; + + // If the last text input type is not None, then we should finish any + // ongoing composition regardless of the new text input type. + if (text_input_type_ != WebKit::WebTextInputTypeNone) { + // If a composition text exists, then we need to let the browser process + // to cancel the input method's ongoing composition session. + if (webwidget_->confirmComposition()) + Send(new ViewHostMsg_ImeCancelComposition(routing_id())); + } +} + +void RenderWidget::SchedulePluginMove( + const webkit::npapi::WebPluginGeometry& move) { + size_t i = 0; + for (; i < plugin_window_moves_.size(); ++i) { + if (plugin_window_moves_[i].window == move.window) { + if (move.rects_valid) { + plugin_window_moves_[i] = move; + } else { + plugin_window_moves_[i].visible = move.visible; + } + break; + } + } + + if (i == plugin_window_moves_.size()) + plugin_window_moves_.push_back(move); +} + +void RenderWidget::CleanupWindowInPluginMoves(gfx::PluginWindowHandle window) { + for (WebPluginGeometryVector::iterator i = plugin_window_moves_.begin(); + i != plugin_window_moves_.end(); ++i) { + if (i->window == window) { + plugin_window_moves_.erase(i); + break; + } + } +} diff --git a/content/renderer/render_widget.h b/content/renderer/render_widget.h new file mode 100644 index 0000000..905a7a8 --- /dev/null +++ b/content/renderer/render_widget.h @@ -0,0 +1,381 @@ +// Copyright (c) 2009 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. + +#ifndef CONTENT_RENDERER_RENDER_WIDGET_H_ +#define CONTENT_RENDERER_RENDER_WIDGET_H_ +#pragma once + +#include + +#include "app/surface/transport_dib.h" +#include "base/basictypes.h" +#include "base/ref_counted.h" +#include "chrome/renderer/render_process.h" +#include "content/renderer/paint_aggregator.h" +#include "ipc/ipc_channel.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebCompositionUnderline.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebPopupType.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebRect.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebTextDirection.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebTextInputType.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebWidgetClient.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "ui/gfx/native_widget_types.h" +#include "ui/gfx/rect.h" +#include "ui/gfx/size.h" +#include "webkit/glue/webcursor.h" + +class RenderThreadBase; + +namespace gfx { +class Point; +} + +namespace IPC { +class SyncMessage; +} + +namespace skia { +class PlatformCanvas; +} + +namespace WebKit { +class WebMouseEvent; +class WebWidget; +struct WebPopupMenuInfo; +} + +namespace webkit { +namespace npapi { +struct WebPluginGeometry; +} // namespace npapi + +namespace ppapi { +class PluginInstance; +} // namespace ppapi +} // namespace webkit + +// RenderWidget provides a communication bridge between a WebWidget and +// a RenderWidgetHost, the latter of which lives in a different process. +class RenderWidget : public IPC::Channel::Listener, + public IPC::Message::Sender, + virtual public WebKit::WebWidgetClient, + public base::RefCounted { + public: + // Creates a new RenderWidget. The opener_id is the routing ID of the + // RenderView that this widget lives inside. The render_thread is any + // RenderThreadBase implementation, mostly commonly RenderThread::current(). + static RenderWidget* Create(int32 opener_id, + RenderThreadBase* render_thread, + WebKit::WebPopupType popup_type); + + // Creates a WebWidget based on the popup type. + static WebKit::WebWidget* CreateWebWidget(RenderWidget* render_widget); + + // The routing ID assigned by the RenderProcess. Will be MSG_ROUTING_NONE if + // not yet assigned a view ID, in which case, the process MUST NOT send + // messages with this ID to the parent. + int32 routing_id() const { + return routing_id_; + } + + // May return NULL when the window is closing. + WebKit::WebWidget* webwidget() const { + return webwidget_; + } + + gfx::NativeViewId host_window() const { + return host_window_; + } + + bool has_focus() const { return has_focus_; } + + // IPC::Channel::Listener + virtual bool OnMessageReceived(const IPC::Message& msg); + + // IPC::Message::Sender + virtual bool Send(IPC::Message* msg); + + // WebKit::WebWidgetClient + virtual void didInvalidateRect(const WebKit::WebRect&); + virtual void didScrollRect(int dx, int dy, const WebKit::WebRect& clipRect); + virtual void didActivateAcceleratedCompositing(bool active); + virtual void scheduleComposite(); + virtual void scheduleAnimation(); + virtual void didFocus(); + virtual void didBlur(); + virtual void didChangeCursor(const WebKit::WebCursorInfo&); + virtual void closeWidgetSoon(); + virtual void show(WebKit::WebNavigationPolicy); + virtual void runModal() {} + virtual WebKit::WebRect windowRect(); + virtual void setWindowRect(const WebKit::WebRect&); + virtual WebKit::WebRect windowResizerRect(); + virtual WebKit::WebRect rootWindowRect(); + virtual WebKit::WebScreenInfo screenInfo(); + virtual void resetInputMethod(); + + // Called when a plugin is moved. These events are queued up and sent with + // the next paint or scroll message to the host. + void SchedulePluginMove(const webkit::npapi::WebPluginGeometry& move); + + // Called when a plugin window has been destroyed, to make sure the currently + // pending moves don't try to reference it. + void CleanupWindowInPluginMoves(gfx::PluginWindowHandle window); + + // Close the underlying WebWidget. + virtual void Close(); + + protected: + // Friend RefCounted so that the dtor can be non-public. Using this class + // without ref-counting is an error. + friend class base::RefCounted; + // For unit tests. + friend class RenderWidgetTest; + + RenderWidget(RenderThreadBase* render_thread, + WebKit::WebPopupType popup_type); + virtual ~RenderWidget(); + + // Initializes this view with the given opener. CompleteInit must be called + // later. + void Init(int32 opener_id); + + // Called by Init and subclasses to perform initialization. + void DoInit(int32 opener_id, + WebKit::WebWidget* web_widget, + IPC::SyncMessage* create_widget_message); + + // Finishes creation of a pending view started with Init. + void CompleteInit(gfx::NativeViewId parent); + + // Paints the given rectangular region of the WebWidget into canvas (a + // shared memory segment returned by AllocPaintBuf on Windows). The caller + // must ensure that the given rect fits within the bounds of the WebWidget. + void PaintRect(const gfx::Rect& rect, const gfx::Point& canvas_origin, + skia::PlatformCanvas* canvas); + + // Paints a border at the given rect for debugging purposes. + void PaintDebugBorder(const gfx::Rect& rect, skia::PlatformCanvas* canvas); + + void AnimationCallback(); + void AnimateIfNeeded(); + void CallDoDeferredUpdate(); + void DoDeferredUpdate(); + void DoDeferredClose(); + void DoDeferredSetWindowRect(const WebKit::WebRect& pos); + + // Set the background of the render widget to a bitmap. The bitmap will be + // tiled in both directions if it isn't big enough to fill the area. This is + // mainly intended to be used in conjuction with WebView::SetIsTransparent(). + virtual void SetBackground(const SkBitmap& bitmap); + + // RenderWidget IPC message handlers + void OnClose(); + void OnCreatingNewAck(gfx::NativeViewId parent); + virtual void OnResize(const gfx::Size& new_size, + const gfx::Rect& resizer_rect); + virtual void OnWasHidden(); + virtual void OnWasRestored(bool needs_repainting); + void OnUpdateRectAck(); + void OnCreateVideoAck(int32 video_id); + void OnUpdateVideoAck(int32 video_id); + void OnRequestMoveAck(); + void OnHandleInputEvent(const IPC::Message& message); + void OnMouseCaptureLost(); + virtual void OnSetFocus(bool enable); + void OnSetInputMethodActive(bool is_active); + void OnImeSetComposition( + const string16& text, + const std::vector& underlines, + int selection_start, + int selection_end); + void OnImeConfirmComposition(const string16& text); + void OnMsgPaintAtSize(const TransportDIB::Handle& dib_id, + int tag, + const gfx::Size& page_size, + const gfx::Size& desired_size); + void OnMsgRepaint(const gfx::Size& size_to_paint); + void OnSetTextDirection(WebKit::WebTextDirection direction); + + // Override point to notify derived classes that a paint has happened. + // DidInitiatePaint happens when we've generated a new bitmap and sent it to + // the browser. DidFlushPaint happens once we've received the ACK that the + // screen has actually been updated. + virtual void DidInitiatePaint() {} + virtual void DidFlushPaint() {} + + // Detects if a suitable opaque plugin covers the given paint bounds with no + // compositing necessary. + // + // Returns the plugin instance that's the source of the paint if the paint + // can be handled by just blitting the plugin bitmap. In this case, the + // location, clipping, and ID of the backing store will be filled into the + // given output parameters. + // + // A return value of null means optimized painting can not be used and we + // should continue with the normal painting code path. + virtual webkit::ppapi::PluginInstance* GetBitmapForOptimizedPluginPaint( + const gfx::Rect& paint_bounds, + TransportDIB** dib, + gfx::Rect* location, + gfx::Rect* clip); + + // Gets the scroll offset of this widget, if this widget has a notion of + // scroll offset. + virtual gfx::Point GetScrollOffset(); + + // Sets the "hidden" state of this widget. All accesses to is_hidden_ should + // use this method so that we can properly inform the RenderThread of our + // state. + void SetHidden(bool hidden); + + bool is_hidden() const { return is_hidden_; } + + // True if an UpdateRect_ACK message is pending. + bool update_reply_pending() const { + return update_reply_pending_; + } + + bool next_paint_is_resize_ack() const; + bool next_paint_is_restore_ack() const; + void set_next_paint_is_resize_ack(); + void set_next_paint_is_restore_ack(); + void set_next_paint_is_repaint_ack(); + + // Checks if the input method state and caret position have been changed. + // If they are changed, the new value will be sent to the browser process. + void UpdateInputMethod(); + + // Tells the renderer it does not have focus. Used to prevent us from getting + // the focus on our own when the browser did not focus us. + void ClearFocus(); + + // Set the pending window rect. + // Because the real render_widget is hosted in another process, there is + // a time period where we may have set a new window rect which has not yet + // been processed by the browser. So we maintain a pending window rect + // size. If JS code sets the WindowRect, and then immediately calls + // GetWindowRect() we'll use this pending window rect as the size. + void SetPendingWindowRect(const WebKit::WebRect& r); + + // Called by OnHandleInputEvent() to notify subclasses that a key event was + // just handled. + virtual void DidHandleKeyEvent() {} + + // Called by OnHandleInputEvent() to notify subclasses that a mouse event was + // just handled. + virtual void DidHandleMouseEvent(const WebKit::WebMouseEvent& event) {} + + // Routing ID that allows us to communicate to the parent browser process + // RenderWidgetHost. When MSG_ROUTING_NONE, no messages may be sent. + int32 routing_id_; + + // We are responsible for destroying this object via its Close method. + WebKit::WebWidget* webwidget_; + + // Set to the ID of the view that initiated creating this view, if any. When + // the view was initiated by the browser (the common case), this will be + // MSG_ROUTING_NONE. This is used in determining ownership when opening + // child tabs. See RenderWidget::createWebViewWithRequest. + // + // This ID may refer to an invalid view if that view is closed before this + // view is. + int32 opener_id_; + + // The thread that does our IPC. + RenderThreadBase* render_thread_; + + // The position where this view should be initially shown. + gfx::Rect initial_pos_; + + // The window we are embedded within. TODO(darin): kill this. + gfx::NativeViewId host_window_; + + // We store the current cursor object so we can avoid spamming SetCursor + // messages. + WebCursor current_cursor_; + + // The size of the RenderWidget. + gfx::Size size_; + + // The TransportDIB that is being used to transfer an image to the browser. + TransportDIB* current_paint_buf_; + + PaintAggregator paint_aggregator_; + + // The area that must be reserved for drawing the resize corner. + gfx::Rect resizer_rect_; + + // Flags for the next ViewHostMsg_UpdateRect message. + int next_paint_flags_; + + // True if we are expecting an UpdateRect_ACK message (i.e., that a + // UpdateRect message has been sent). + bool update_reply_pending_; + + // Set to true if we should ignore RenderWidget::Show calls. + bool did_show_; + + // Indicates that we shouldn't bother generated paint events. + bool is_hidden_; + + // Indicates that we should be repainted when restored. This flag is set to + // true if we receive an invalidation / scroll event from webkit while our + // is_hidden_ flag is set to true. This is used to force a repaint once we + // restore to account for the fact that our host would not know about the + // invalidation / scroll event(s) from webkit while we are hidden. + bool needs_repainting_on_restore_; + + // Indicates whether we have been focused/unfocused by the browser. + bool has_focus_; + + // Are we currently handling an input event? + bool handling_input_event_; + + // True if we have requested this widget be closed. No more messages will + // be sent, except for a Close. + bool closing_; + + // Indicates if an input method is active in the browser process. + bool input_method_is_active_; + + // Stores the current text input type of |webwidget_|. + WebKit::WebTextInputType text_input_type_; + + // Stores the current caret bounds of input focus. + WebKit::WebRect caret_bounds_; + + // The kind of popup this widget represents, NONE if not a popup. + WebKit::WebPopupType popup_type_; + + // Holds all the needed plugin window moves for a scroll. + typedef std::vector WebPluginGeometryVector; + WebPluginGeometryVector plugin_window_moves_; + + // A custom background for the widget. + SkBitmap background_; + + // While we are waiting for the browser to update window sizes, + // we track the pending size temporarily. + int pending_window_rect_count_; + WebKit::WebRect pending_window_rect_; + + scoped_ptr pending_input_event_ack_; + + // Indicates if the next sequence of Char events should be suppressed or not. + bool suppress_next_char_events_; + + // Set to true if painting to the window is handled by the accelerated + // compositor. + bool is_accelerated_compositing_active_; + + base::Time animation_floor_time_; + bool animation_update_pending_; + bool animation_task_posted_; + + DISALLOW_COPY_AND_ASSIGN(RenderWidget); +}; + +#endif // CONTENT_RENDERER_RENDER_WIDGET_H_ diff --git a/content/renderer/render_widget_browsertest.cc b/content/renderer/render_widget_browsertest.cc new file mode 100644 index 0000000..a1b46d2 --- /dev/null +++ b/content/renderer/render_widget_browsertest.cc @@ -0,0 +1,150 @@ +// Copyright (c) 2010 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 "content/renderer/render_widget_browsertest.h" + +#include "app/surface/transport_dib.h" +#include "base/basictypes.h" +#include "base/file_path.h" +#include "base/file_util.h" +#include "base/ref_counted_memory.h" +#include "base/stringprintf.h" +#include "chrome/common/render_messages.h" +#include "chrome/common/render_messages_params.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebSize.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h" +#include "ui/gfx/codec/jpeg_codec.h" +#include "ui/gfx/size.h" + +const int RenderWidgetTest::kNumBytesPerPixel = 4; +const int RenderWidgetTest::kLargeWidth = 1024; +const int RenderWidgetTest::kLargeHeight = 768; +const int RenderWidgetTest::kSmallWidth = 600; +const int RenderWidgetTest::kSmallHeight = 450; +const int RenderWidgetTest::kTextPositionX = 800; +const int RenderWidgetTest::kTextPositionY = 600; +const uint32 RenderWidgetTest::kRedARGB = 0xFFFF0000; + +RenderWidgetTest::RenderWidgetTest() {} + +void RenderWidgetTest::ResizeAndPaint(const gfx::Size& page_size, + const gfx::Size& desired_size, + SkBitmap* snapshot) { + ASSERT_TRUE(snapshot); + static int g_sequence_num = 0; + // Use a new sequence number for each DIB. + scoped_ptr pixels( + TransportDIB::Create( + page_size.width() * page_size.height() * kNumBytesPerPixel, + ++g_sequence_num)); + + // Go ahead and map the DIB into memory, so that we can use it below + // to fill tmp_bitmap. Note that we need to do this before calling + // OnMsgPaintAtSize, or the last reference to the shared memory will + // be closed and the handle will no longer be valid. + scoped_ptr mapped_pixels(TransportDIB::Map(pixels->handle())); + + view_->OnMsgPaintAtSize(pixels->handle(), g_sequence_num, page_size, + desired_size); + ProcessPendingMessages(); + const IPC::Message* msg = render_thread_.sink().GetUniqueMessageMatching( + ViewHostMsg_PaintAtSize_ACK::ID); + ASSERT_NE(static_cast(NULL), msg); + ViewHostMsg_PaintAtSize_ACK::Param params; + ViewHostMsg_PaintAtSize_ACK::Read(msg, ¶ms); + render_thread_.sink().ClearMessages(); + EXPECT_EQ(g_sequence_num, params.a); + gfx::Size size = params.b; + EXPECT_EQ(desired_size, size); + + SkBitmap tmp_bitmap; + tmp_bitmap.setConfig(SkBitmap::kARGB_8888_Config, + size.width(), size.height()); + tmp_bitmap.setPixels(mapped_pixels->memory()); + // Copy the pixels from the TransportDIB object to the given snapshot. + ASSERT_TRUE(tmp_bitmap.copyTo(snapshot, SkBitmap::kARGB_8888_Config)); +} + +void RenderWidgetTest::TestResizeAndPaint() { + // Hello World message is only visible if the view size is at least + // kTextPositionX x kTextPositionY + LoadHTML(StringPrintf( + "
Hello World
", + kTextPositionY, kTextPositionX).c_str()); + WebKit::WebSize old_size = view_->webview()->size(); + + SkBitmap bitmap; + // If we re-size the view to something smaller than where the 'Hello World' + // text is displayed we won't see any text in the snapshot. Hence, + // the snapshot should not contain any red. + gfx::Size size(kSmallWidth, kSmallHeight); + ResizeAndPaint(size, size, &bitmap); + // Make sure that the view has been re-sized to its old size. + EXPECT_TRUE(old_size == view_->webview()->size()); + EXPECT_EQ(kSmallWidth, bitmap.width()); + EXPECT_EQ(kSmallHeight, bitmap.height()); + EXPECT_FALSE(ImageContainsColor(bitmap, kRedARGB)); + + // Since we ask for the view to be re-sized to something larger than where the + // 'Hello World' text is written the text should be visible in the snapshot. + // Hence, the snapshot should contain some red. + size.SetSize(kLargeWidth, kLargeHeight); + ResizeAndPaint(size, size, &bitmap); + EXPECT_TRUE(old_size == view_->webview()->size()); + EXPECT_EQ(kLargeWidth, bitmap.width()); + EXPECT_EQ(kLargeHeight, bitmap.height()); + EXPECT_TRUE(ImageContainsColor(bitmap, kRedARGB)); + + // Even if the desired size is smaller than where the text is located we + // should still see the 'Hello World' message since the view size is + // still large enough. + ResizeAndPaint(size, gfx::Size(kSmallWidth, kSmallHeight), &bitmap); + EXPECT_TRUE(old_size == view_->webview()->size()); + EXPECT_EQ(kSmallWidth, bitmap.width()); + EXPECT_EQ(kSmallHeight, bitmap.height()); + EXPECT_TRUE(ImageContainsColor(bitmap, kRedARGB)); +} + +bool RenderWidgetTest::ImageContainsColor(const SkBitmap& bitmap, + uint32 argb_color) { + SkAutoLockPixels lock(bitmap); + bool ready = bitmap.readyToDraw(); + EXPECT_TRUE(ready); + if (!ready) { + return false; + } + for (int x = 0; x < bitmap.width(); ++x) { + for (int y = 0; y < bitmap.height(); ++y) { + if (argb_color == *bitmap.getAddr32(x, y)) { + return true; + } + } + } + return false; +} + +void RenderWidgetTest::OutputBitmapToFile(const SkBitmap& bitmap, + const FilePath& file_path) { + scoped_refptr bitmap_data(new RefCountedBytes()); + SkAutoLockPixels lock(bitmap); + ASSERT_TRUE(gfx::JPEGCodec::Encode( + reinterpret_cast(bitmap.getAddr32(0, 0)), + gfx::JPEGCodec::FORMAT_BGRA, + bitmap.width(), + bitmap.height(), + static_cast(bitmap.rowBytes()), + 90 /* quality */, + &bitmap_data->data)); + ASSERT_LT(0, file_util::WriteFile( + file_path, + reinterpret_cast(bitmap_data->front()), + bitmap_data->size())); +} + +TEST_F(RenderWidgetTest, OnMsgPaintAtSize) { + TestResizeAndPaint(); +} diff --git a/content/renderer/render_widget_browsertest.h b/content/renderer/render_widget_browsertest.h new file mode 100644 index 0000000..f091efb --- /dev/null +++ b/content/renderer/render_widget_browsertest.h @@ -0,0 +1,58 @@ +// Copyright (c) 2010 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. + +#ifndef CONTENT_RENDERER_RENDER_WIDGET_BROWSERTEST_H_ +#define CONTENT_RENDERER_RENDER_WIDGET_BROWSERTEST_H_ +#pragma once + +#include "base/basictypes.h" +#include "base/file_path.h" +#include "chrome/test/render_view_test.h" + +namespace gfx { +class Size; +} + +class SkBitmap; +class TransportDIB; + +class RenderWidgetTest : public RenderViewTest { + public: + RenderWidgetTest(); + + protected: + static const int kNumBytesPerPixel; + static const int kLargeWidth; + static const int kLargeHeight; + static const int kSmallWidth; + static const int kSmallHeight; + static const int kTextPositionX; + static const int kTextPositionY; + static const uint32 kRedARGB; + + // Helper function which calls OnMsgPaintAtSize and also paints the result + // in the given bitmap. The widget is resized to |page_size| before we paint + // and the final image is resized to |desired_size|. This method is virtual so + // that TestResizeAndPaint() can be reused by subclasses of this test class. + virtual void ResizeAndPaint(const gfx::Size& page_size, + const gfx::Size& desired_size, + SkBitmap* snapshot); + + // Test for ResizeAndPaint. + void TestResizeAndPaint(); + + // Helper function which returns true if the given bitmap contains the given + // ARGB color and false otherwise. + bool ImageContainsColor(const SkBitmap& bitmap, uint32 argb_color); + + // This can be used for debugging if you want to output a bitmap + // image to a file. + // FilePath tmp_path; + // file_util::CreateTemporaryFile(&tmp_path); + // OutputBitmapToFile(bitmap, tmp_path); + // LOG(INFO) << "Bitmap image stored at: " << tmp_path.value(); + void OutputBitmapToFile(const SkBitmap& bitmap, const FilePath& file_path); +}; + +#endif // CONTENT_RENDERER_RENDER_WIDGET_BROWSERTEST_H_ diff --git a/content/renderer/render_widget_fullscreen.cc b/content/renderer/render_widget_fullscreen.cc new file mode 100644 index 0000000..1fc5c6d --- /dev/null +++ b/content/renderer/render_widget_fullscreen.cc @@ -0,0 +1,51 @@ +// Copyright (c) 2010 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 "content/renderer/render_widget_fullscreen.h" + +#include "chrome/common/render_messages.h" +#include "chrome/renderer/render_thread.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebWidget.h" + +using WebKit::WebWidget; + +// static +RenderWidgetFullscreen* RenderWidgetFullscreen::Create( + int32 opener_id, RenderThreadBase* render_thread) { + DCHECK_NE(MSG_ROUTING_NONE, opener_id); + scoped_refptr widget( + new RenderWidgetFullscreen(render_thread)); + widget->Init(opener_id); + return widget.release(); +} + +WebWidget* RenderWidgetFullscreen::CreateWebWidget() { + // TODO(boliu): Handle full screen render widgets here. + return RenderWidget::CreateWebWidget(this); +} + +void RenderWidgetFullscreen::Init(int32 opener_id) { + DCHECK(!webwidget_); + + RenderWidget::DoInit( + opener_id, + CreateWebWidget(), + new ViewHostMsg_CreateFullscreenWidget(opener_id, &routing_id_)); +} + +void RenderWidgetFullscreen::show(WebKit::WebNavigationPolicy) { + DCHECK(!did_show_) << "received extraneous Show call"; + DCHECK_NE(MSG_ROUTING_NONE, routing_id_); + DCHECK_NE(MSG_ROUTING_NONE, opener_id_); + + if (!did_show_) { + did_show_ = true; + Send(new ViewHostMsg_ShowFullscreenWidget(opener_id_, routing_id_)); + SetPendingWindowRect(initial_pos_); + } +} + +RenderWidgetFullscreen::RenderWidgetFullscreen(RenderThreadBase* render_thread) + : RenderWidget(render_thread, WebKit::WebPopupTypeNone) { +} diff --git a/content/renderer/render_widget_fullscreen.h b/content/renderer/render_widget_fullscreen.h new file mode 100644 index 0000000..7e18037 --- /dev/null +++ b/content/renderer/render_widget_fullscreen.h @@ -0,0 +1,30 @@ +// Copyright (c) 2010 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. + +#ifndef CONTENT_RENDERER_RENDER_WIDGET_FULLSCREEN_H_ +#define CONTENT_RENDERER_RENDER_WIDGET_FULLSCREEN_H_ + +#include "content/renderer/render_widget.h" + +#include "third_party/WebKit/Source/WebKit/chromium/public/WebWidget.h" + +// TODO(boliu): Override non-supported methods with no-op? eg setWindowRect(). +class RenderWidgetFullscreen : public RenderWidget { + public: + // Creates a new RenderWidget. The opener_id is the routing ID of the + // RenderView that this widget lives inside. The render_thread is any + // RenderThreadBase implementation, mostly commonly RenderThread::current(). + static RenderWidgetFullscreen* Create(int32 opener_id, + RenderThreadBase* render_thread); + + virtual void show(WebKit::WebNavigationPolicy); + + protected: + virtual WebKit::WebWidget* CreateWebWidget(); + RenderWidgetFullscreen(RenderThreadBase* render_thread); + + void Init(int32 opener_id); +}; + +#endif // CONTENT_RENDERER_RENDER_WIDGET_FULLSCREEN_H_ diff --git a/content/renderer/render_widget_fullscreen_pepper.cc b/content/renderer/render_widget_fullscreen_pepper.cc new file mode 100644 index 0000000..128129b --- /dev/null +++ b/content/renderer/render_widget_fullscreen_pepper.cc @@ -0,0 +1,395 @@ +// Copyright (c) 2010 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 "content/renderer/render_widget_fullscreen_pepper.h" + +#include "chrome/common/render_messages.h" +#include "chrome/renderer/render_thread.h" +#include "content/renderer/ggl.h" +#include "content/renderer/gpu_channel_host.h" +#include "content/renderer/pepper_platform_context_3d_impl.h" +#include "gpu/command_buffer/client/gles2_implementation.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebCursorInfo.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebSize.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebWidget.h" +#include "webkit/plugins/ppapi/plugin_delegate.h" +#include "webkit/plugins/ppapi/ppapi_plugin_instance.h" + +using WebKit::WebCanvas; +using WebKit::WebCompositionUnderline; +using WebKit::WebCursorInfo; +using WebKit::WebInputEvent; +using WebKit::WebRect; +using WebKit::WebSize; +using WebKit::WebString; +using WebKit::WebTextDirection; +using WebKit::WebTextInputType; +using WebKit::WebVector; +using WebKit::WebWidget; + +namespace { + +// WebWidget that simply wraps the pepper plugin. +class PepperWidget : public WebWidget { + public: + PepperWidget(webkit::ppapi::PluginInstance* plugin, + RenderWidgetFullscreenPepper* widget) + : plugin_(plugin), + widget_(widget), + cursor_(WebCursorInfo::TypePointer) { + } + + // WebWidget API + virtual void close() { + delete this; + } + + virtual WebSize size() { + return size_; + } + + virtual void resize(const WebSize& size) { + size_ = size; + WebRect plugin_rect(0, 0, size_.width, size_.height); + plugin_->ViewChanged(plugin_rect, plugin_rect); + widget_->Invalidate(); + } + + virtual void animate() { + } + + virtual void layout() { + } + + virtual void paint(WebCanvas* canvas, const WebRect& rect) { + WebRect plugin_rect(0, 0, size_.width, size_.height); + plugin_->Paint(canvas, plugin_rect, rect); + } + + virtual void composite(bool finish) { + ggl::Context* context = widget_->context(); + DCHECK(context); + gpu::gles2::GLES2Implementation* gl = ggl::GetImplementation(context); + unsigned int texture = plugin_->GetBackingTextureId(); + gl->BindTexture(GL_TEXTURE_2D, texture); + gl->DrawArrays(GL_TRIANGLES, 0, 3); + ggl::SwapBuffers(context); + } + + virtual void themeChanged() { + NOTIMPLEMENTED(); + } + + virtual bool handleInputEvent(const WebInputEvent& event) { + return plugin_->HandleInputEvent(event, &cursor_); + } + + virtual void mouseCaptureLost() { + NOTIMPLEMENTED(); + } + + virtual void setFocus(bool focus) { + NOTIMPLEMENTED(); + } + + // TODO(piman): figure out IME and implement these if necessary. + virtual bool setComposition( + const WebString& text, + const WebVector& underlines, + int selectionStart, + int selectionEnd) { + return false; + } + + virtual bool confirmComposition() { + return false; + } + + virtual bool confirmComposition(const WebString& text) { + return false; + } + + virtual WebTextInputType textInputType() { + return WebKit::WebTextInputTypeNone; + } + + virtual WebRect caretOrSelectionBounds() { + return WebRect(); + } + + virtual void setTextDirection(WebTextDirection) { + } + + virtual bool isAcceleratedCompositingActive() const { + return widget_->context() && (plugin_->GetBackingTextureId() != 0); + } + + private: + scoped_refptr plugin_; + RenderWidgetFullscreenPepper* widget_; + WebSize size_; + WebCursorInfo cursor_; + + DISALLOW_COPY_AND_ASSIGN(PepperWidget); +}; + +} // anonymous namespace + +// static +RenderWidgetFullscreenPepper* RenderWidgetFullscreenPepper::Create( + int32 opener_id, RenderThreadBase* render_thread, + webkit::ppapi::PluginInstance* plugin) { + DCHECK_NE(MSG_ROUTING_NONE, opener_id); + scoped_refptr widget( + new RenderWidgetFullscreenPepper(render_thread, plugin)); + widget->Init(opener_id); + return widget.release(); +} + +RenderWidgetFullscreenPepper::RenderWidgetFullscreenPepper( + RenderThreadBase* render_thread, + webkit::ppapi::PluginInstance* plugin) + : RenderWidgetFullscreen(render_thread), + plugin_(plugin), + context_(NULL), + buffer_(0), + program_(0) { +} + +RenderWidgetFullscreenPepper::~RenderWidgetFullscreenPepper() { + DestroyContext(); +} + +void RenderWidgetFullscreenPepper::Invalidate() { + InvalidateRect(gfx::Rect(size_.width(), size_.height())); +} + +void RenderWidgetFullscreenPepper::InvalidateRect(const WebKit::WebRect& rect) { + if (CheckCompositing()) { + scheduleComposite(); + } else { + didInvalidateRect(rect); + } +} + +void RenderWidgetFullscreenPepper::ScrollRect( + int dx, int dy, const WebKit::WebRect& rect) { + if (CheckCompositing()) { + scheduleComposite(); + } else { + didScrollRect(dx, dy, rect); + } +} + +void RenderWidgetFullscreenPepper::Destroy() { + // This function is called by the plugin instance as it's going away, so reset + // plugin_ to NULL to avoid calling into a dangling pointer e.g. on Close(). + plugin_ = NULL; + Send(new ViewHostMsg_Close(routing_id_)); +} + +webkit::ppapi::PluginDelegate::PlatformContext3D* +RenderWidgetFullscreenPepper::CreateContext3D() { + if (!context_) { + CreateContext(); + } + if (!context_) + return NULL; + return new PlatformContext3DImpl(context_); +} + +void RenderWidgetFullscreenPepper::DidInitiatePaint() { + if (plugin_) + plugin_->ViewInitiatedPaint(); +} + +void RenderWidgetFullscreenPepper::DidFlushPaint() { + if (plugin_) + plugin_->ViewFlushedPaint(); +} + +void RenderWidgetFullscreenPepper::Close() { + // If the fullscreen window is closed (e.g. user pressed escape), reset to + // normal mode. + if (plugin_) + plugin_->SetFullscreen(false, false); +} + +webkit::ppapi::PluginInstance* +RenderWidgetFullscreenPepper::GetBitmapForOptimizedPluginPaint( + const gfx::Rect& paint_bounds, + TransportDIB** dib, + gfx::Rect* location, + gfx::Rect* clip) { + if (plugin_ && + plugin_->GetBitmapForOptimizedPluginPaint(paint_bounds, dib, + location, clip)) + return plugin_; + return NULL; +} + +void RenderWidgetFullscreenPepper::OnResize(const gfx::Size& size, + const gfx::Rect& resizer_rect) { + if (context_) { + gpu::gles2::GLES2Implementation* gl = ggl::GetImplementation(context_); +#if defined(OS_MACOSX) + ggl::ResizeOnscreenContext(context_, size); +#else + gl->ResizeCHROMIUM(size.width(), size.height()); +#endif + gl->Viewport(0, 0, size.width(), size.height()); + } + RenderWidget::OnResize(size, resizer_rect); +} + +WebWidget* RenderWidgetFullscreenPepper::CreateWebWidget() { + return new PepperWidget(plugin_, this); +} + +void RenderWidgetFullscreenPepper::CreateContext() { + DCHECK(!context_); + RenderThread* render_thread = RenderThread::current(); + DCHECK(render_thread); + GpuChannelHost* host = render_thread->EstablishGpuChannelSync(); + if (!host) + return; + const int32 attribs[] = { + ggl::GGL_ALPHA_SIZE, 8, + ggl::GGL_DEPTH_SIZE, 0, + ggl::GGL_STENCIL_SIZE, 0, + ggl::GGL_SAMPLES, 0, + ggl::GGL_SAMPLE_BUFFERS, 0, + ggl::GGL_NONE, + }; + context_ = ggl::CreateViewContext( + host, + routing_id(), + "GL_OES_packed_depth_stencil GL_OES_depth24", + attribs); + if (!context_ || !InitContext()) { + DestroyContext(); + return; + } + ggl::SetSwapBuffersCallback( + context_, + NewCallback(this, &RenderWidgetFullscreenPepper::DidFlushPaint)); +} + +void RenderWidgetFullscreenPepper::DestroyContext() { + if (context_) { + gpu::gles2::GLES2Implementation* gl = ggl::GetImplementation(context_); + if (program_) { + gl->DeleteProgram(program_); + program_ = 0; + } + if (buffer_) { + gl->DeleteBuffers(1, &buffer_); + buffer_ = 0; + } + ggl::DestroyContext(context_); + context_ = NULL; + } +} + +namespace { + +const char kVertexShader[] = + "attribute vec2 in_tex_coord;\n" + "varying vec2 tex_coord;\n" + "void main() {\n" + " gl_Position = vec4(in_tex_coord.x * 2. - 1.,\n" + " in_tex_coord.y * 2. - 1.,\n" + " 0.,\n" + " 1.);\n" + " tex_coord = vec2(in_tex_coord.x, in_tex_coord.y);\n" + "}\n"; + +const char kFragmentShader[] = + "precision mediump float;\n" + "varying vec2 tex_coord;\n" + "uniform sampler2D in_texture;\n" + "void main() {\n" + " gl_FragColor = texture2D(in_texture, tex_coord);\n" + "}\n"; + +GLuint CreateShaderFromSource(gpu::gles2::GLES2Implementation* gl, + GLenum type, + const char* source) { + GLuint shader = gl->CreateShader(type); + gl->ShaderSource(shader, 1, &source, NULL); + gl->CompileShader(shader); + int status; + gl->GetShaderiv(shader, GL_COMPILE_STATUS, &status); + if (!status) { + int size = 0; + gl->GetShaderiv(shader, GL_INFO_LOG_LENGTH, &size); + scoped_array log(new char[size]); + gl->GetShaderInfoLog(shader, size, NULL, log.get()); + DLOG(ERROR) << "Compilation failed: " << log.get(); + gl->DeleteShader(shader); + shader = 0; + } + return shader; +} + +const float kTexCoords[] = { + 0.f, 0.f, + 0.f, 2.f, + 2.f, 0.f, +}; + +} // anonymous namespace + +bool RenderWidgetFullscreenPepper::InitContext() { + gpu::gles2::GLES2Implementation* gl = ggl::GetImplementation(context_); + program_ = gl->CreateProgram(); + + GLuint vertex_shader = + CreateShaderFromSource(gl, GL_VERTEX_SHADER, kVertexShader); + if (!vertex_shader) + return false; + gl->AttachShader(program_, vertex_shader); + gl->DeleteShader(vertex_shader); + + GLuint fragment_shader = + CreateShaderFromSource(gl, GL_FRAGMENT_SHADER, kFragmentShader); + if (!fragment_shader) + return false; + gl->AttachShader(program_, fragment_shader); + gl->DeleteShader(fragment_shader); + + gl->BindAttribLocation(program_, 0, "in_tex_coord"); + gl->LinkProgram(program_); + int status; + gl->GetProgramiv(program_, GL_LINK_STATUS, &status); + if (!status) { + int size = 0; + gl->GetProgramiv(program_, GL_INFO_LOG_LENGTH, &size); + scoped_array log(new char[size]); + gl->GetProgramInfoLog(program_, size, NULL, log.get()); + DLOG(ERROR) << "Link failed: " << log.get(); + return false; + } + gl->UseProgram(program_); + int texture_location = gl->GetUniformLocation(program_, "in_texture"); + gl->Uniform1i(texture_location, 0); + + gl->GenBuffers(1, &buffer_); + gl->BindBuffer(GL_ARRAY_BUFFER, buffer_); + gl->BufferData(GL_ARRAY_BUFFER, + sizeof(kTexCoords), + kTexCoords, + GL_STATIC_DRAW); + gl->VertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, NULL); + gl->EnableVertexAttribArray(0); + return true; +} + +bool RenderWidgetFullscreenPepper::CheckCompositing() { + bool compositing = webwidget_->isAcceleratedCompositingActive(); + if (compositing != is_accelerated_compositing_active_) { + didActivateAcceleratedCompositing(compositing); + } + return compositing; +} diff --git a/content/renderer/render_widget_fullscreen_pepper.h b/content/renderer/render_widget_fullscreen_pepper.h new file mode 100644 index 0000000..a3905ce --- /dev/null +++ b/content/renderer/render_widget_fullscreen_pepper.h @@ -0,0 +1,89 @@ +// Copyright (c) 2010 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. + +#ifndef CONTENT_RENDERER_RENDER_WIDGET_FULLSCREEN_PEPPER_H_ +#define CONTENT_RENDERER_RENDER_WIDGET_FULLSCREEN_PEPPER_H_ + +#include "content/renderer/render_widget_fullscreen.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebWidget.h" +#include "webkit/plugins/ppapi/fullscreen_container.h" + +namespace webkit { +namespace ppapi { + +class PluginInstance; + +} // namespace ppapi +} // namespace webkit + +namespace ggl { +class Context; +} // namespace ggl + +// A RenderWidget that hosts a fullscreen pepper plugin. This provides a +// FullscreenContainer that the plugin instance can callback into to e.g. +// invalidate rects. +class RenderWidgetFullscreenPepper : public RenderWidgetFullscreen, + public webkit::ppapi::FullscreenContainer { + public: + static RenderWidgetFullscreenPepper* Create( + int32 opener_id, + RenderThreadBase* render_thread, + webkit::ppapi::PluginInstance* plugin); + + // pepper::FullscreenContainer API. + virtual void Invalidate(); + virtual void InvalidateRect(const WebKit::WebRect& rect); + virtual void ScrollRect(int dx, int dy, const WebKit::WebRect& rect); + virtual void Destroy(); + virtual webkit::ppapi::PluginDelegate::PlatformContext3D* CreateContext3D(); + + ggl::Context* context() const { return context_; } + + protected: + RenderWidgetFullscreenPepper(RenderThreadBase* render_thread, + webkit::ppapi::PluginInstance* plugin); + virtual ~RenderWidgetFullscreenPepper(); + + // RenderWidget API. + virtual void DidInitiatePaint(); + virtual void DidFlushPaint(); + virtual void Close(); + virtual webkit::ppapi::PluginInstance* GetBitmapForOptimizedPluginPaint( + const gfx::Rect& paint_bounds, + TransportDIB** dib, + gfx::Rect* location, + gfx::Rect* clip); + virtual void OnResize(const gfx::Size& new_size, + const gfx::Rect& resizer_rect); + + // RenderWidgetFullscreen API. + virtual WebKit::WebWidget* CreateWebWidget(); + + private: + // Creates the GL context for compositing. + void CreateContext(); + + // Destroys the GL context for compositing. + void DestroyContext(); + + // Initialize the GL states and resources for compositing. + bool InitContext(); + + // Checks (and returns) whether accelerated compositing should be on or off, + // and notify the browser. + bool CheckCompositing(); + + // The plugin instance this widget wraps. + webkit::ppapi::PluginInstance* plugin_; + + // GL context for compositing. + ggl::Context* context_; + unsigned int buffer_; + unsigned int program_; + + DISALLOW_COPY_AND_ASSIGN(RenderWidgetFullscreenPepper); +}; + +#endif // CONTENT_RENDERER_RENDER_WIDGET_FULLSCREEN_PEPPER_H_ diff --git a/content/renderer/render_widget_unittest.cc b/content/renderer/render_widget_unittest.cc new file mode 100644 index 0000000..1811289 --- /dev/null +++ b/content/renderer/render_widget_unittest.cc @@ -0,0 +1,61 @@ +// Copyright (c) 2010 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 "testing/gtest/include/gtest/gtest.h" + +#include "base/ref_counted.h" +#include "chrome/renderer/mock_render_process.h" +#include "chrome/renderer/mock_render_thread.h" +#include "chrome/renderer/render_thread.h" +#include "content/renderer/render_widget.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebPopupType.h" + +namespace { + +const int32 kRouteId = 5; +const int32 kOpenerId = 7; + +class RenderWidgetTest : public testing::Test { + public: + + protected: + MessageLoop msg_loop_; + MockRenderThread render_thread_; + + // The widget, each test should verify this is non-NULL before continuing. + scoped_refptr widget_; + + private: + // testing::Test + virtual void SetUp() { + mock_process_.reset(new MockRenderProcess); + render_thread_.set_routing_id(kRouteId); + widget_ = RenderWidget::Create(kOpenerId, &render_thread_, + WebKit::WebPopupTypeNone); + ASSERT_TRUE(widget_); + } + virtual void TearDown() { + widget_ = NULL; + mock_process_.reset(); + } + + scoped_ptr mock_process_; +}; + +TEST_F(RenderWidgetTest, CreateAndCloseWidget) { + // After the RenderWidget it must have sent a message to the render thread + // that sets the opener id. + EXPECT_EQ(kOpenerId, render_thread_.opener_id()); + ASSERT_TRUE(render_thread_.has_widget()); + + // Now simulate a close of the Widget. + render_thread_.SendCloseMessage(); + EXPECT_FALSE(render_thread_.has_widget()); + + // Run the loop so the release task from the renderwidget executes. + msg_loop_.PostTask(FROM_HERE, new MessageLoop::QuitTask()); + msg_loop_.Run(); +} + +} // namespace diff --git a/content/renderer/renderer.sb b/content/renderer/renderer.sb new file mode 100644 index 0000000..6a0bf0d --- /dev/null +++ b/content/renderer/renderer.sb @@ -0,0 +1,30 @@ +;; +;; Copyright (c) 2009 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. +;; + +; *** The contents of chrome/common/common.sb are implicitly included here. *** + +; Needed for Fonts. +(allow file-read* (regex #"^/System/Library/Fonts($|/)")) ; 10.5.6 +; 10.6 for loading fonts in the renderer. +; on 10.5 this is needed for the PDF plugin. +(allow file-read* (regex #"^/Library/Fonts($|/)")) +(allow mach-lookup (global-name "com.apple.FontObjectsServer")) ; 10.5.6 +;10.6_ONLY (allow mach-lookup (global-name "com.apple.FontServer")) ; 10.6 + +(allow file-read* + (regex #"^/System/Library/ColorSync($|/)") ; 10.5.6 - http://crbug.com/46648 + (literal "/Library/Preferences/.GlobalPreferences.plist") ; http://crbug.com/60917 + (literal "@USER_HOMEDIR_AS_LITERAL@/Library/Preferences/.GlobalPreferences.plist") +) + +; http://crbug.com/11269 +;10.6_ONLY (allow file-read* (subpath "@USER_HOMEDIR_AS_LITERAL@/Library/Fonts")) ; 10.6 + +; http://crbug.com/60917 +(allow file-read-metadata + (literal "/") + (literal "/var") +) -- cgit v1.1