| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "chrome/browser/renderer_host/render_widget_host_view_views.h" | |
| 6 | |
| 7 #include <algorithm> | |
| 8 #include <string> | |
| 9 | |
| 10 #include "base/bind.h" | |
| 11 #include "base/command_line.h" | |
| 12 #include "base/logging.h" | |
| 13 #include "base/message_loop.h" | |
| 14 #include "base/metrics/histogram.h" | |
| 15 #include "base/string_number_conversions.h" | |
| 16 #include "base/time.h" | |
| 17 #include "base/utf_string_conversions.h" | |
| 18 #include "chrome/common/chrome_notification_types.h" | |
| 19 #include "chrome/common/native_web_keyboard_event_views.h" | |
| 20 #include "chrome/common/render_messages.h" | |
| 21 #include "content/browser/renderer_host/backing_store_skia.h" | |
| 22 #include "content/browser/renderer_host/render_widget_host.h" | |
| 23 #include "content/public/browser/notification_service.h" | |
| 24 #include "content/public/common/result_codes.h" | |
| 25 #include "grit/ui_strings.h" | |
| 26 #include "third_party/WebKit/Source/WebKit/chromium/public/WebCompositionUnderli
ne.h" | |
| 27 #include "third_party/WebKit/Source/WebKit/chromium/public/WebInputEvent.h" | |
| 28 #include "third_party/WebKit/Source/WebKit/chromium/public/gtk/WebInputEventFact
ory.h" | |
| 29 #include "third_party/WebKit/Source/WebKit/chromium/public/x11/WebScreenInfoFact
ory.h" | |
| 30 #include "ui/base/clipboard/clipboard.h" | |
| 31 #include "ui/base/text/text_elider.h" | |
| 32 #include "ui/gfx/canvas.h" | |
| 33 #include "ui/gfx/canvas_skia.h" | |
| 34 #include "ui/views/events/event.h" | |
| 35 #include "ui/views/ime/input_method.h" | |
| 36 #include "views/views_delegate.h" | |
| 37 #include "views/widget/tooltip_manager.h" | |
| 38 #include "views/widget/widget.h" | |
| 39 | |
| 40 #if defined(UI_COMPOSITOR_IMAGE_TRANSPORT) | |
| 41 #include "content/browser/renderer_host/accelerated_surface_container_linux.h" | |
| 42 #include "ui/gfx/gl/gl_bindings.h" | |
| 43 #endif | |
| 44 | |
| 45 #if defined(TOOLKIT_USES_GTK) | |
| 46 #include <gdk/gdkx.h> | |
| 47 #include <gtk/gtk.h> | |
| 48 #include <gtk/gtkwindow.h> | |
| 49 | |
| 50 #include "content/browser/renderer_host/gtk_window_utils.h" | |
| 51 #include "views/widget/native_widget_gtk.h" | |
| 52 #endif | |
| 53 | |
| 54 #if defined(OS_POSIX) | |
| 55 #include "content/browser/renderer_host/gtk_window_utils.h" | |
| 56 #endif | |
| 57 | |
| 58 static const int kMaxWindowWidth = 4000; | |
| 59 static const int kMaxWindowHeight = 4000; | |
| 60 static const int kTouchControllerUpdateDelay = 150; | |
| 61 | |
| 62 // static | |
| 63 const char RenderWidgetHostViewViews::kViewClassName[] = | |
| 64 "browser/renderer_host/RenderWidgetHostViewViews"; | |
| 65 | |
| 66 using WebKit::WebInputEventFactory; | |
| 67 using WebKit::WebMouseWheelEvent; | |
| 68 using WebKit::WebTouchEvent; | |
| 69 | |
| 70 namespace { | |
| 71 | |
| 72 int WebInputEventFlagsFromViewsEvent(const views::Event& event) { | |
| 73 int modifiers = 0; | |
| 74 | |
| 75 if (event.IsShiftDown()) | |
| 76 modifiers |= WebKit::WebInputEvent::ShiftKey; | |
| 77 if (event.IsControlDown()) | |
| 78 modifiers |= WebKit::WebInputEvent::ControlKey; | |
| 79 if (event.IsAltDown()) | |
| 80 modifiers |= WebKit::WebInputEvent::AltKey; | |
| 81 if (event.IsCapsLockDown()) | |
| 82 modifiers |= WebKit::WebInputEvent::CapsLockOn; | |
| 83 | |
| 84 return modifiers; | |
| 85 } | |
| 86 | |
| 87 void InitializeWebMouseEventFromViewsEvent(const views::LocatedEvent& event, | |
| 88 const gfx::Point& origin, | |
| 89 WebKit::WebMouseEvent* wmevent) { | |
| 90 wmevent->timeStampSeconds = base::Time::Now().ToDoubleT(); | |
| 91 wmevent->modifiers = WebInputEventFlagsFromViewsEvent(event); | |
| 92 | |
| 93 wmevent->windowX = wmevent->x = event.x(); | |
| 94 wmevent->windowY = wmevent->y = event.y(); | |
| 95 wmevent->globalX = wmevent->x + origin.x(); | |
| 96 wmevent->globalY = wmevent->y + origin.y(); | |
| 97 } | |
| 98 | |
| 99 } // namespace | |
| 100 | |
| 101 RenderWidgetHostViewViews::RenderWidgetHostViewViews(RenderWidgetHost* host) | |
| 102 : host_(host), | |
| 103 about_to_validate_and_paint_(false), | |
| 104 is_hidden_(false), | |
| 105 is_loading_(false), | |
| 106 native_cursor_(gfx::kNullCursor), | |
| 107 is_showing_context_menu_(false), | |
| 108 visually_deemphasized_(false), | |
| 109 touch_event_(), | |
| 110 text_input_type_(ui::TEXT_INPUT_TYPE_NONE), | |
| 111 has_composition_text_(false), | |
| 112 ALLOW_THIS_IN_INITIALIZER_LIST(touch_selection_controller_( | |
| 113 views::TouchSelectionController::create(this))), | |
| 114 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) { | |
| 115 set_focusable(true); | |
| 116 host_->SetView(this); | |
| 117 | |
| 118 #if defined(TOUCH_UI) | |
| 119 SetPaintToLayer(true); | |
| 120 registrar_.Add(this, | |
| 121 chrome::NOTIFICATION_KEYBOARD_VISIBLE_BOUNDS_CHANGED, | |
| 122 content::NotificationService::AllSources()); | |
| 123 #endif | |
| 124 } | |
| 125 | |
| 126 RenderWidgetHostViewViews::~RenderWidgetHostViewViews() { | |
| 127 } | |
| 128 | |
| 129 void RenderWidgetHostViewViews::InitAsChild() { | |
| 130 Show(); | |
| 131 } | |
| 132 | |
| 133 void RenderWidgetHostViewViews::InitAsPopup( | |
| 134 RenderWidgetHostView* parent_host_view, | |
| 135 const gfx::Rect& pos) { | |
| 136 RenderWidgetHostViewViews* parent = | |
| 137 static_cast<RenderWidgetHostViewViews*>(parent_host_view); | |
| 138 parent->AddChildView(this); | |
| 139 // If the parent loses focus then the popup will close. So we need | |
| 140 // to tell the parent it's showing a popup so that it doesn't respond to | |
| 141 // blurs. | |
| 142 parent->is_showing_context_menu_ = true; | |
| 143 | |
| 144 // pos is in screen coordinates but a view is positioned relative | |
| 145 // to its parent. Here we convert screen coordinates to relative | |
| 146 // coordinates. | |
| 147 gfx::Point p(pos.x() - parent_host_view->GetViewBounds().x(), | |
| 148 pos.y() - parent_host_view->GetViewBounds().y()); | |
| 149 views::View::SetBounds(p.x(), p.y(), pos.width(), pos.height()); | |
| 150 Show(); | |
| 151 | |
| 152 if (NeedsInputGrab()) { | |
| 153 set_focusable(true); | |
| 154 RequestFocus(); | |
| 155 } | |
| 156 } | |
| 157 | |
| 158 void RenderWidgetHostViewViews::InitAsFullscreen( | |
| 159 RenderWidgetHostView* /*reference_host_view*/) { | |
| 160 NOTIMPLEMENTED(); | |
| 161 } | |
| 162 | |
| 163 RenderWidgetHost* RenderWidgetHostViewViews::GetRenderWidgetHost() const { | |
| 164 return host_; | |
| 165 } | |
| 166 | |
| 167 void RenderWidgetHostViewViews::DidBecomeSelected() { | |
| 168 if (!is_hidden_) | |
| 169 return; | |
| 170 | |
| 171 if (tab_switch_paint_time_.is_null()) | |
| 172 tab_switch_paint_time_ = base::TimeTicks::Now(); | |
| 173 is_hidden_ = false; | |
| 174 if (host_) | |
| 175 host_->WasRestored(); | |
| 176 } | |
| 177 | |
| 178 void RenderWidgetHostViewViews::WasHidden() { | |
| 179 if (is_hidden_) | |
| 180 return; | |
| 181 | |
| 182 // If we receive any more paint messages while we are hidden, we want to | |
| 183 // ignore them so we don't re-allocate the backing store. We will paint | |
| 184 // everything again when we become selected again. | |
| 185 is_hidden_ = true; | |
| 186 | |
| 187 // If we have a renderer, then inform it that we are being hidden so it can | |
| 188 // reduce its resource utilization. | |
| 189 if (host_) | |
| 190 host_->WasHidden(); | |
| 191 | |
| 192 weak_factory_.InvalidateWeakPtrs(); | |
| 193 } | |
| 194 | |
| 195 void RenderWidgetHostViewViews::SetSize(const gfx::Size& size) { | |
| 196 // This is called when webkit has sent us a Move message. | |
| 197 int width = std::min(size.width(), kMaxWindowWidth); | |
| 198 int height = std::min(size.height(), kMaxWindowHeight); | |
| 199 if (requested_size_.width() != width || | |
| 200 requested_size_.height() != height) { | |
| 201 requested_size_ = gfx::Size(width, height); | |
| 202 views::View::SetBounds(x(), y(), width, height); | |
| 203 if (host_) | |
| 204 host_->WasResized(); | |
| 205 } | |
| 206 } | |
| 207 | |
| 208 void RenderWidgetHostViewViews::SetBounds(const gfx::Rect& rect) { | |
| 209 // TODO(oshima): chromeos/touch doesn't allow moving window. | |
| 210 SetSize(rect.size()); | |
| 211 } | |
| 212 | |
| 213 gfx::NativeView RenderWidgetHostViewViews::GetNativeView() const { | |
| 214 // TODO(oshima): There is no native view here for RWHVV. | |
| 215 // Use top level widget's native view for now. This is not | |
| 216 // correct and has to be fixed somehow. | |
| 217 return GetWidget() ? GetWidget()->GetNativeView() : NULL; | |
| 218 } | |
| 219 | |
| 220 gfx::NativeViewId RenderWidgetHostViewViews::GetNativeViewId() const { | |
| 221 #if defined(OS_WIN) | |
| 222 // TODO(oshima): Windows uses message filter to handle inquiry for | |
| 223 // window/screen info, which requires HWND. Just pass the | |
| 224 // browser window's HWND (same as before) for now. | |
| 225 return reinterpret_cast<gfx::NativeViewId>(GetNativeView()); | |
| 226 #else | |
| 227 return reinterpret_cast<gfx::NativeViewId>( | |
| 228 const_cast<RenderWidgetHostViewViews*>(this)); | |
| 229 #endif | |
| 230 } | |
| 231 | |
| 232 void RenderWidgetHostViewViews::MovePluginWindows( | |
| 233 const std::vector<webkit::npapi::WebPluginGeometry>& moves) { | |
| 234 // TODO(anicolao): NIY | |
| 235 // NOTIMPLEMENTED(); | |
| 236 } | |
| 237 | |
| 238 bool RenderWidgetHostViewViews::HasFocus() const { | |
| 239 return View::HasFocus(); | |
| 240 } | |
| 241 | |
| 242 void RenderWidgetHostViewViews::Show() { | |
| 243 SetVisible(true); | |
| 244 } | |
| 245 | |
| 246 void RenderWidgetHostViewViews::Hide() { | |
| 247 SetVisible(false); | |
| 248 } | |
| 249 | |
| 250 bool RenderWidgetHostViewViews::IsShowing() { | |
| 251 return IsVisible(); | |
| 252 } | |
| 253 | |
| 254 gfx::Rect RenderWidgetHostViewViews::GetViewBounds() const { | |
| 255 return GetScreenBounds(); | |
| 256 } | |
| 257 | |
| 258 void RenderWidgetHostViewViews::SetIsLoading(bool is_loading) { | |
| 259 is_loading_ = is_loading; | |
| 260 #if defined(TOOLKIT_USES_GTK) | |
| 261 // Only call ShowCurrentCursor() when it will actually change the cursor. | |
| 262 if (current_cursor_.GetCursorType() == GDK_LAST_CURSOR) | |
| 263 ShowCurrentCursor(); | |
| 264 #endif // TOOLKIT_USES_GTK | |
| 265 } | |
| 266 | |
| 267 void RenderWidgetHostViewViews::TextInputStateChanged( | |
| 268 ui::TextInputType type, | |
| 269 bool can_compose_inline) { | |
| 270 // TODO(kinaba): currently, can_compose_inline is ignored and always treated | |
| 271 // as true. We need to support "can_compose_inline=false" for PPAPI plugins | |
| 272 // that may want to avoid drawing composition-text by themselves and pass | |
| 273 // the responsibility to the browser. | |
| 274 | |
| 275 // This is async message and by the time the ipc arrived, | |
| 276 // RWHVV may be detached from Top level widget, in which case | |
| 277 // GetInputMethod may return NULL; | |
| 278 views::InputMethod* input_method = GetInputMethod(); | |
| 279 | |
| 280 if (text_input_type_ != type) { | |
| 281 text_input_type_ = type; | |
| 282 if (input_method) | |
| 283 input_method->OnTextInputTypeChanged(this); | |
| 284 } | |
| 285 } | |
| 286 | |
| 287 void RenderWidgetHostViewViews::ImeCancelComposition() { | |
| 288 DCHECK(GetInputMethod()); | |
| 289 GetInputMethod()->CancelComposition(this); | |
| 290 has_composition_text_ = false; | |
| 291 } | |
| 292 | |
| 293 void RenderWidgetHostViewViews::DidUpdateBackingStore( | |
| 294 const gfx::Rect& scroll_rect, int scroll_dx, int scroll_dy, | |
| 295 const std::vector<gfx::Rect>& copy_rects) { | |
| 296 if (is_hidden_) | |
| 297 return; | |
| 298 | |
| 299 // TODO(darin): Implement the equivalent of Win32's ScrollWindowEX. Can that | |
| 300 // be done using XCopyArea? Perhaps similar to | |
| 301 // BackingStore::ScrollBackingStore? | |
| 302 if (about_to_validate_and_paint_) | |
| 303 invalid_rect_ = invalid_rect_.Union(scroll_rect); | |
| 304 else | |
| 305 SchedulePaintInRect(scroll_rect); | |
| 306 | |
| 307 for (size_t i = 0; i < copy_rects.size(); ++i) { | |
| 308 // Avoid double painting. NOTE: This is only relevant given the call to | |
| 309 // Paint(scroll_rect) above. | |
| 310 gfx::Rect rect = copy_rects[i].Subtract(scroll_rect); | |
| 311 if (rect.IsEmpty()) | |
| 312 continue; | |
| 313 | |
| 314 if (about_to_validate_and_paint_) | |
| 315 invalid_rect_ = invalid_rect_.Union(rect); | |
| 316 else | |
| 317 SchedulePaintInRect(rect); | |
| 318 } | |
| 319 invalid_rect_ = invalid_rect_.Intersect(bounds()); | |
| 320 } | |
| 321 | |
| 322 void RenderWidgetHostViewViews::RenderViewGone(base::TerminationStatus status, | |
| 323 int error_code) { | |
| 324 DCHECK(host_); | |
| 325 host_->ViewDestroyed(); | |
| 326 Destroy(); | |
| 327 } | |
| 328 | |
| 329 void RenderWidgetHostViewViews::Destroy() { | |
| 330 // host_'s destruction brought us here, null it out so we don't use it | |
| 331 host_ = NULL; | |
| 332 if (parent()) { | |
| 333 if (IsPopup()) { | |
| 334 static_cast<RenderWidgetHostViewViews*> | |
| 335 (parent())->is_showing_context_menu_ = false; | |
| 336 // We're hiding the popup so we need to make sure we repaint | |
| 337 // what's underneath. | |
| 338 parent()->SchedulePaintInRect(bounds()); | |
| 339 } | |
| 340 parent()->RemoveChildView(this); | |
| 341 } | |
| 342 MessageLoop::current()->DeleteSoon(FROM_HERE, this); | |
| 343 | |
| 344 #if defined(UI_COMPOSITOR_IMAGE_TRANSPORT) | |
| 345 // Send out all outstanding ACKs so that we don't block the GPU | |
| 346 // process. | |
| 347 for (std::vector< base::Callback<void(void)> >::const_iterator | |
| 348 it = on_compositing_ended_callbacks_.begin(); | |
| 349 it != on_compositing_ended_callbacks_.end(); ++it) { | |
| 350 it->Run(); | |
| 351 } | |
| 352 on_compositing_ended_callbacks_.clear(); | |
| 353 | |
| 354 // Remove dangling reference. | |
| 355 if (GetWidget() && GetWidget()->GetCompositor()) { | |
| 356 ui::Compositor *compositor = GetWidget()->GetCompositor(); | |
| 357 if (compositor->HasObserver(this)) | |
| 358 compositor->RemoveObserver(this); | |
| 359 } | |
| 360 #endif | |
| 361 } | |
| 362 | |
| 363 void RenderWidgetHostViewViews::SetTooltipText(const string16& tip) { | |
| 364 const int kMaxTooltipLength = 8 << 10; | |
| 365 // Clamp the tooltip length to kMaxTooltipLength so that we don't | |
| 366 // accidentally DOS the user with a mega tooltip. | |
| 367 tooltip_text_ = ui::TruncateString(tip, kMaxTooltipLength); | |
| 368 if (GetWidget()) | |
| 369 GetWidget()->TooltipTextChanged(this); | |
| 370 } | |
| 371 | |
| 372 void RenderWidgetHostViewViews::SelectionChanged(const string16& text, | |
| 373 size_t offset, | |
| 374 const ui::Range& range) { | |
| 375 RenderWidgetHostView::SelectionChanged(text, offset, range); | |
| 376 // TODO(anicolao): deal with the clipboard without GTK | |
| 377 NOTIMPLEMENTED(); | |
| 378 } | |
| 379 | |
| 380 void RenderWidgetHostViewViews::SelectionBoundsChanged( | |
| 381 const gfx::Rect& start_rect, | |
| 382 const gfx::Rect& end_rect) { | |
| 383 views::InputMethod* input_method = GetInputMethod(); | |
| 384 | |
| 385 if (selection_start_rect_ == start_rect && selection_end_rect_ == end_rect) | |
| 386 return; | |
| 387 | |
| 388 selection_start_rect_ = start_rect; | |
| 389 selection_end_rect_ = end_rect; | |
| 390 | |
| 391 if (input_method) | |
| 392 input_method->OnCaretBoundsChanged(this); | |
| 393 | |
| 394 // TODO(sad): This is a workaround for a webkit bug: | |
| 395 // https://bugs.webkit.org/show_bug.cgi?id=67464 | |
| 396 // Remove this when the bug gets fixed. | |
| 397 // | |
| 398 // Webkit can send spurious selection-change on text-input (e.g. when | |
| 399 // inserting text at the beginning of a non-empty text control). But in those | |
| 400 // cases, it does send the correct selection information quickly afterwards. | |
| 401 // So delay the notification to the touch-selection controller. | |
| 402 if (!weak_factory_.HasWeakPtrs()) { | |
| 403 MessageLoop::current()->PostDelayedTask(FROM_HERE, | |
| 404 base::Bind( | |
| 405 &RenderWidgetHostViewViews::UpdateTouchSelectionController, | |
| 406 weak_factory_.GetWeakPtr()), | |
| 407 kTouchControllerUpdateDelay); | |
| 408 } | |
| 409 } | |
| 410 | |
| 411 void RenderWidgetHostViewViews::Observe( | |
| 412 int type, | |
| 413 const content::NotificationSource& source, | |
| 414 const content::NotificationDetails& details) { | |
| 415 #if defined(TOUCH_UI) | |
| 416 if (type != chrome::NOTIFICATION_KEYBOARD_VISIBLE_BOUNDS_CHANGED) { | |
| 417 NOTREACHED(); | |
| 418 return; | |
| 419 } | |
| 420 | |
| 421 if (!GetWidget()) | |
| 422 return; | |
| 423 | |
| 424 gfx::Rect keyboard_rect = *content::Details<gfx::Rect>(details).ptr(); | |
| 425 if (keyboard_rect != keyboard_rect_) { | |
| 426 keyboard_rect_ = keyboard_rect; | |
| 427 gfx::Rect screen_bounds = GetScreenBounds(); | |
| 428 gfx::Rect intersecting_rect = screen_bounds.Intersect(keyboard_rect); | |
| 429 gfx::Rect available_rect = screen_bounds.Subtract(intersecting_rect); | |
| 430 | |
| 431 // Convert available rect to window (RWHVV) coordinates. | |
| 432 gfx::Point origin = available_rect.origin(); | |
| 433 gfx::Rect r = GetWidget()->GetClientAreaScreenBounds(); | |
| 434 origin.SetPoint(origin.x() - r.x(), origin.y() - r.y()); | |
| 435 views::View::ConvertPointFromWidget(this, &origin); | |
| 436 available_rect.set_origin(origin); | |
| 437 if (!available_rect.IsEmpty()) | |
| 438 host_->ScrollFocusedEditableNodeIntoRect(available_rect); | |
| 439 } | |
| 440 #endif | |
| 441 } | |
| 442 | |
| 443 void RenderWidgetHostViewViews::ShowingContextMenu(bool showing) { | |
| 444 is_showing_context_menu_ = showing; | |
| 445 } | |
| 446 | |
| 447 BackingStore* RenderWidgetHostViewViews::AllocBackingStore( | |
| 448 const gfx::Size& size) { | |
| 449 return new BackingStoreSkia(host_, size); | |
| 450 } | |
| 451 | |
| 452 void RenderWidgetHostViewViews::OnAcceleratedCompositingStateChange() { | |
| 453 #if defined(TOOLKIT_USES_GTK) | |
| 454 bool activated = host_->is_accelerated_compositing_active(); | |
| 455 #if defined(UI_COMPOSITOR_IMAGE_TRANSPORT) | |
| 456 // If we don't use a views compositor, we currently have no way of | |
| 457 // supporting rendering via the GPU process. | |
| 458 if (!get_use_acceleration_when_possible() && activated) | |
| 459 NOTREACHED(); | |
| 460 #else | |
| 461 if (activated) | |
| 462 NOTIMPLEMENTED(); | |
| 463 #endif | |
| 464 #endif | |
| 465 } | |
| 466 | |
| 467 void RenderWidgetHostViewViews::SetBackground(const SkBitmap& background) { | |
| 468 RenderWidgetHostView::SetBackground(background); | |
| 469 if (host_) | |
| 470 host_->SetBackground(background); | |
| 471 } | |
| 472 | |
| 473 void RenderWidgetHostViewViews::SetVisuallyDeemphasized( | |
| 474 const SkColor* color, bool animate) { | |
| 475 // TODO(anicolao) | |
| 476 } | |
| 477 | |
| 478 void RenderWidgetHostViewViews::UnhandledWheelEvent( | |
| 479 const WebKit::WebMouseWheelEvent& event) { | |
| 480 } | |
| 481 | |
| 482 void RenderWidgetHostViewViews::SetHasHorizontalScrollbar( | |
| 483 bool has_horizontal_scrollbar) { | |
| 484 } | |
| 485 | |
| 486 void RenderWidgetHostViewViews::SetScrollOffsetPinning( | |
| 487 bool is_pinned_to_left, bool is_pinned_to_right) { | |
| 488 } | |
| 489 | |
| 490 bool RenderWidgetHostViewViews::LockMouse() { | |
| 491 NOTIMPLEMENTED(); | |
| 492 return false; | |
| 493 } | |
| 494 | |
| 495 void RenderWidgetHostViewViews::UnlockMouse() { | |
| 496 NOTIMPLEMENTED(); | |
| 497 } | |
| 498 | |
| 499 void RenderWidgetHostViewViews::SelectRect(const gfx::Point& start, | |
| 500 const gfx::Point& end) { | |
| 501 if (host_) | |
| 502 host_->SelectRange(start, end); | |
| 503 } | |
| 504 | |
| 505 bool RenderWidgetHostViewViews::IsCommandIdChecked(int command_id) const { | |
| 506 NOTREACHED(); | |
| 507 return true; | |
| 508 } | |
| 509 | |
| 510 bool RenderWidgetHostViewViews::IsCommandIdEnabled(int command_id) const { | |
| 511 bool editable = GetTextInputType() != ui::TEXT_INPUT_TYPE_NONE; | |
| 512 bool has_selection = !selection_range_.is_empty(); | |
| 513 string16 result; | |
| 514 switch (command_id) { | |
| 515 case IDS_APP_CUT: | |
| 516 return editable && has_selection; | |
| 517 case IDS_APP_COPY: | |
| 518 return has_selection; | |
| 519 case IDS_APP_PASTE: | |
| 520 views::ViewsDelegate::views_delegate->GetClipboard()-> | |
| 521 ReadText(ui::Clipboard::BUFFER_STANDARD, &result); | |
| 522 return editable && !result.empty(); | |
| 523 case IDS_APP_DELETE: | |
| 524 return editable && has_selection; | |
| 525 case IDS_APP_SELECT_ALL: | |
| 526 return true; | |
| 527 default: | |
| 528 NOTREACHED(); | |
| 529 return false; | |
| 530 } | |
| 531 return true; | |
| 532 } | |
| 533 | |
| 534 bool RenderWidgetHostViewViews::GetAcceleratorForCommandId( | |
| 535 int command_id, | |
| 536 ui::Accelerator* accelerator) { | |
| 537 NOTREACHED(); | |
| 538 return true; | |
| 539 } | |
| 540 | |
| 541 void RenderWidgetHostViewViews::ExecuteCommand(int command_id) { | |
| 542 switch (command_id) { | |
| 543 case IDS_APP_CUT: | |
| 544 host_->Cut(); | |
| 545 break; | |
| 546 case IDS_APP_COPY: | |
| 547 host_->Copy(); | |
| 548 break; | |
| 549 case IDS_APP_PASTE: | |
| 550 host_->Paste(); | |
| 551 break; | |
| 552 case IDS_APP_DELETE: | |
| 553 host_->Delete(); | |
| 554 break; | |
| 555 case IDS_APP_SELECT_ALL: | |
| 556 host_->SelectAll(); | |
| 557 break; | |
| 558 default: | |
| 559 NOTREACHED(); | |
| 560 } | |
| 561 } | |
| 562 | |
| 563 std::string RenderWidgetHostViewViews::GetClassName() const { | |
| 564 return kViewClassName; | |
| 565 } | |
| 566 | |
| 567 gfx::NativeCursor RenderWidgetHostViewViews::GetCursor( | |
| 568 const views::MouseEvent& event) { | |
| 569 return native_cursor_; | |
| 570 } | |
| 571 | |
| 572 bool RenderWidgetHostViewViews::OnMousePressed(const views::MouseEvent& event) { | |
| 573 // The special buttons on a mouse (e.g. back, forward etc.) are not correctly | |
| 574 // recognized by views Events. Ignore those events here, so that the event | |
| 575 // bubbles up the view hierarchy and the appropriate parent view can handle | |
| 576 // them. | |
| 577 if (!(event.flags() & (ui::EF_LEFT_BUTTON_DOWN | | |
| 578 ui::EF_RIGHT_BUTTON_DOWN | | |
| 579 ui::EF_MIDDLE_BUTTON_DOWN))) { | |
| 580 return false; | |
| 581 } | |
| 582 | |
| 583 if (!host_) | |
| 584 return false; | |
| 585 | |
| 586 RequestFocus(); | |
| 587 | |
| 588 // Confirm existing composition text on mouse click events, to make sure | |
| 589 // the input caret won't be moved with an ongoing composition text. | |
| 590 FinishImeCompositionSession(); | |
| 591 | |
| 592 // TODO(anicolao): validate event generation. | |
| 593 WebKit::WebMouseEvent e = WebMouseEventFromViewsEvent(event); | |
| 594 | |
| 595 // TODO(anicolao): deal with double clicks | |
| 596 e.type = WebKit::WebInputEvent::MouseDown; | |
| 597 e.clickCount = 1; | |
| 598 | |
| 599 host_->ForwardMouseEvent(e); | |
| 600 return true; | |
| 601 } | |
| 602 | |
| 603 bool RenderWidgetHostViewViews::OnMouseDragged(const views::MouseEvent& event) { | |
| 604 OnMouseMoved(event); | |
| 605 return true; | |
| 606 } | |
| 607 | |
| 608 void RenderWidgetHostViewViews::OnMouseReleased( | |
| 609 const views::MouseEvent& event) { | |
| 610 if (!(event.flags() & (ui::EF_LEFT_BUTTON_DOWN | | |
| 611 ui::EF_RIGHT_BUTTON_DOWN | | |
| 612 ui::EF_MIDDLE_BUTTON_DOWN))) { | |
| 613 return; | |
| 614 } | |
| 615 | |
| 616 if (!host_) | |
| 617 return; | |
| 618 | |
| 619 WebKit::WebMouseEvent e = WebMouseEventFromViewsEvent(event); | |
| 620 e.type = WebKit::WebInputEvent::MouseUp; | |
| 621 e.clickCount = 1; | |
| 622 host_->ForwardMouseEvent(e); | |
| 623 } | |
| 624 | |
| 625 void RenderWidgetHostViewViews::OnMouseMoved(const views::MouseEvent& event) { | |
| 626 if (!host_) | |
| 627 return; | |
| 628 | |
| 629 WebKit::WebMouseEvent e = WebMouseEventFromViewsEvent(event); | |
| 630 e.type = WebKit::WebInputEvent::MouseMove; | |
| 631 host_->ForwardMouseEvent(e); | |
| 632 } | |
| 633 | |
| 634 void RenderWidgetHostViewViews::OnMouseEntered(const views::MouseEvent& event) { | |
| 635 // Already generated synthetically by webkit. | |
| 636 } | |
| 637 | |
| 638 void RenderWidgetHostViewViews::OnMouseExited(const views::MouseEvent& event) { | |
| 639 // Already generated synthetically by webkit. | |
| 640 } | |
| 641 | |
| 642 bool RenderWidgetHostViewViews::OnKeyPressed(const views::KeyEvent& event) { | |
| 643 // TODO(suzhe): Support editor key bindings. | |
| 644 if (!host_) | |
| 645 return false; | |
| 646 host_->ForwardKeyboardEvent(NativeWebKeyboardEventViews(event)); | |
| 647 return true; | |
| 648 } | |
| 649 | |
| 650 bool RenderWidgetHostViewViews::OnKeyReleased(const views::KeyEvent& event) { | |
| 651 if (!host_) | |
| 652 return false; | |
| 653 host_->ForwardKeyboardEvent(NativeWebKeyboardEventViews(event)); | |
| 654 return true; | |
| 655 } | |
| 656 | |
| 657 bool RenderWidgetHostViewViews::OnMouseWheel( | |
| 658 const views::MouseWheelEvent& event) { | |
| 659 if (!host_) | |
| 660 return false; | |
| 661 | |
| 662 WebMouseWheelEvent wmwe; | |
| 663 InitializeWebMouseEventFromViewsEvent(event, GetMirroredPosition(), &wmwe); | |
| 664 | |
| 665 wmwe.type = WebKit::WebInputEvent::MouseWheel; | |
| 666 wmwe.button = WebKit::WebMouseEvent::ButtonNone; | |
| 667 | |
| 668 // TODO(sadrul): How do we determine if it's a horizontal scroll? | |
| 669 wmwe.deltaY = event.offset(); | |
| 670 wmwe.wheelTicksY = wmwe.deltaY > 0 ? 1 : -1; | |
| 671 | |
| 672 host_->ForwardWheelEvent(wmwe); | |
| 673 return true; | |
| 674 } | |
| 675 | |
| 676 ui::TextInputClient* RenderWidgetHostViewViews::GetTextInputClient() { | |
| 677 return this; | |
| 678 } | |
| 679 | |
| 680 bool RenderWidgetHostViewViews::GetTooltipText(const gfx::Point& p, | |
| 681 string16* tooltip) const { | |
| 682 if (tooltip_text_.length() == 0) | |
| 683 return false; | |
| 684 *tooltip = tooltip_text_; | |
| 685 return true; | |
| 686 } | |
| 687 | |
| 688 // ui::TextInputClient implementation ----------------------------------------- | |
| 689 void RenderWidgetHostViewViews::SetCompositionText( | |
| 690 const ui::CompositionText& composition) { | |
| 691 if (!host_) | |
| 692 return; | |
| 693 | |
| 694 // ui::CompositionUnderline should be identical to | |
| 695 // WebKit::WebCompositionUnderline, so that we can do reinterpret_cast safely. | |
| 696 COMPILE_ASSERT(sizeof(ui::CompositionUnderline) == | |
| 697 sizeof(WebKit::WebCompositionUnderline), | |
| 698 ui_CompositionUnderline__WebKit_WebCompositionUnderline_diff); | |
| 699 | |
| 700 // TODO(suzhe): convert both renderer_host and renderer to use | |
| 701 // ui::CompositionText. | |
| 702 const std::vector<WebKit::WebCompositionUnderline>& underlines = | |
| 703 reinterpret_cast<const std::vector<WebKit::WebCompositionUnderline>&>( | |
| 704 composition.underlines); | |
| 705 | |
| 706 // TODO(suzhe): due to a bug of webkit, we can't use selection range with | |
| 707 // composition string. See: https://bugs.webkit.org/show_bug.cgi?id=37788 | |
| 708 host_->ImeSetComposition(composition.text, underlines, | |
| 709 composition.selection.end(), | |
| 710 composition.selection.end()); | |
| 711 | |
| 712 has_composition_text_ = !composition.text.empty(); | |
| 713 } | |
| 714 | |
| 715 void RenderWidgetHostViewViews::ConfirmCompositionText() { | |
| 716 if (host_ && has_composition_text_) | |
| 717 host_->ImeConfirmComposition(); | |
| 718 has_composition_text_ = false; | |
| 719 } | |
| 720 | |
| 721 void RenderWidgetHostViewViews::ClearCompositionText() { | |
| 722 if (host_ && has_composition_text_) | |
| 723 host_->ImeCancelComposition(); | |
| 724 has_composition_text_ = false; | |
| 725 } | |
| 726 | |
| 727 void RenderWidgetHostViewViews::InsertText(const string16& text) { | |
| 728 DCHECK(text_input_type_ != ui::TEXT_INPUT_TYPE_NONE); | |
| 729 if (host_) | |
| 730 host_->ImeConfirmComposition(text); | |
| 731 has_composition_text_ = false; | |
| 732 } | |
| 733 | |
| 734 void RenderWidgetHostViewViews::InsertChar(char16 ch, int flags) { | |
| 735 if (host_) { | |
| 736 NativeWebKeyboardEventViews::FromViewsEvent from_views_event; | |
| 737 NativeWebKeyboardEventViews wke(ch, flags, base::Time::Now().ToDoubleT(), | |
| 738 from_views_event); | |
| 739 host_->ForwardKeyboardEvent(wke); | |
| 740 } | |
| 741 } | |
| 742 | |
| 743 ui::TextInputType RenderWidgetHostViewViews::GetTextInputType() const { | |
| 744 return text_input_type_; | |
| 745 } | |
| 746 | |
| 747 gfx::Rect RenderWidgetHostViewViews::GetCaretBounds() { | |
| 748 return selection_start_rect_.Union(selection_end_rect_); | |
| 749 } | |
| 750 | |
| 751 bool RenderWidgetHostViewViews::HasCompositionText() { | |
| 752 return has_composition_text_; | |
| 753 } | |
| 754 | |
| 755 bool RenderWidgetHostViewViews::GetTextRange(ui::Range* range) { | |
| 756 range->set_start(selection_text_offset_); | |
| 757 range->set_end(selection_text_offset_ + selection_text_.length()); | |
| 758 return true; | |
| 759 } | |
| 760 | |
| 761 bool RenderWidgetHostViewViews::GetCompositionTextRange(ui::Range* range) { | |
| 762 // TODO(suzhe): implement this method when fixing http://crbug.com/55130. | |
| 763 NOTIMPLEMENTED(); | |
| 764 return false; | |
| 765 } | |
| 766 | |
| 767 bool RenderWidgetHostViewViews::GetSelectionRange(ui::Range* range) { | |
| 768 range->set_start(selection_range_.start()); | |
| 769 range->set_end(selection_range_.end()); | |
| 770 return true; | |
| 771 } | |
| 772 | |
| 773 bool RenderWidgetHostViewViews::SetSelectionRange(const ui::Range& range) { | |
| 774 // TODO(suzhe): implement this method when fixing http://crbug.com/55130. | |
| 775 NOTIMPLEMENTED(); | |
| 776 return false; | |
| 777 } | |
| 778 | |
| 779 bool RenderWidgetHostViewViews::DeleteRange(const ui::Range& range) { | |
| 780 // TODO(suzhe): implement this method when fixing http://crbug.com/55130. | |
| 781 NOTIMPLEMENTED(); | |
| 782 return false; | |
| 783 } | |
| 784 | |
| 785 bool RenderWidgetHostViewViews::GetTextFromRange( | |
| 786 const ui::Range& range, | |
| 787 string16* text) { | |
| 788 ui::Range selection_text_range(selection_text_offset_, | |
| 789 selection_text_offset_ + selection_text_.length()); | |
| 790 | |
| 791 if (!selection_text_range.Contains(range)) { | |
| 792 text->clear(); | |
| 793 return false; | |
| 794 } | |
| 795 if (selection_text_range.EqualsIgnoringDirection(range)) { | |
| 796 // Avoid calling substr which performance is low. | |
| 797 *text = selection_text_; | |
| 798 } else { | |
| 799 *text = selection_text_.substr( | |
| 800 range.GetMin() - selection_text_offset_, | |
| 801 range.length()); | |
| 802 } | |
| 803 return true; | |
| 804 } | |
| 805 | |
| 806 void RenderWidgetHostViewViews::OnInputMethodChanged() { | |
| 807 if (!host_) | |
| 808 return; | |
| 809 | |
| 810 DCHECK(GetInputMethod()); | |
| 811 host_->SetInputMethodActive(GetInputMethod()->IsActive()); | |
| 812 | |
| 813 // TODO(suzhe): implement the newly added “locale” property of HTML DOM | |
| 814 // TextEvent. | |
| 815 } | |
| 816 | |
| 817 bool RenderWidgetHostViewViews::ChangeTextDirectionAndLayoutAlignment( | |
| 818 base::i18n::TextDirection direction) { | |
| 819 if (!host_) | |
| 820 return false; | |
| 821 host_->UpdateTextDirection( | |
| 822 direction == base::i18n::RIGHT_TO_LEFT ? | |
| 823 WebKit::WebTextDirectionRightToLeft : | |
| 824 WebKit::WebTextDirectionLeftToRight); | |
| 825 host_->NotifyTextDirection(); | |
| 826 return true; | |
| 827 } | |
| 828 | |
| 829 void RenderWidgetHostViewViews::OnPaint(gfx::Canvas* canvas) { | |
| 830 if (is_hidden_ || !host_) | |
| 831 return; | |
| 832 | |
| 833 DCHECK(!host_->is_accelerated_compositing_active() || | |
| 834 get_use_acceleration_when_possible()); | |
| 835 | |
| 836 // If we aren't using the views compositor, then | |
| 837 // paint a "hole" in the canvas so that the render of the web page is on | |
| 838 // top of whatever else has already been painted in the views hierarchy. | |
| 839 // Later views might still get to paint on top. | |
| 840 if (!get_use_acceleration_when_possible()) | |
| 841 canvas->FillRect(SK_ColorBLACK, GetLocalBounds(), SkXfermode::kClear_Mode); | |
| 842 | |
| 843 DCHECK(!about_to_validate_and_paint_); | |
| 844 | |
| 845 // TODO(anicolao): get the damage somehow | |
| 846 // invalid_rect_ = damage_rect; | |
| 847 invalid_rect_ = bounds(); | |
| 848 gfx::Point origin; | |
| 849 ConvertPointToWidget(this, &origin); | |
| 850 | |
| 851 about_to_validate_and_paint_ = true; | |
| 852 BackingStore* backing_store = host_->GetBackingStore(true); | |
| 853 // Calling GetBackingStore maybe have changed |invalid_rect_|... | |
| 854 about_to_validate_and_paint_ = false; | |
| 855 | |
| 856 gfx::Rect paint_rect = gfx::Rect(0, 0, kMaxWindowWidth, kMaxWindowHeight); | |
| 857 paint_rect = paint_rect.Intersect(invalid_rect_); | |
| 858 | |
| 859 if (backing_store) { | |
| 860 #if defined(TOOLKIT_USES_GTK) | |
| 861 // Only render the widget if it is attached to a window; there's a short | |
| 862 // period where this object isn't attached to a window but hasn't been | |
| 863 // Destroy()ed yet and it receives paint messages... | |
| 864 if (IsReadyToPaint()) { | |
| 865 #endif | |
| 866 if (!visually_deemphasized_) { | |
| 867 // In the common case, use XCopyArea. We don't draw more than once, so | |
| 868 // we don't need to double buffer. | |
| 869 if (IsPopup()) { | |
| 870 origin.SetPoint(origin.x() + paint_rect.x(), | |
| 871 origin.y() + paint_rect.y()); | |
| 872 paint_rect.SetRect(0, 0, paint_rect.width(), paint_rect.height()); | |
| 873 } | |
| 874 static_cast<BackingStoreSkia*>(backing_store)->SkiaShowRect( | |
| 875 gfx::Point(paint_rect.x(), paint_rect.y()), canvas); | |
| 876 } else { | |
| 877 // TODO(sad) | |
| 878 NOTIMPLEMENTED(); | |
| 879 } | |
| 880 #if defined(TOOLKIT_USES_GTK) | |
| 881 } | |
| 882 #endif | |
| 883 if (!whiteout_start_time_.is_null()) { | |
| 884 base::TimeDelta whiteout_duration = base::TimeTicks::Now() - | |
| 885 whiteout_start_time_; | |
| 886 UMA_HISTOGRAM_TIMES("MPArch.RWHH_WhiteoutDuration", whiteout_duration); | |
| 887 | |
| 888 // Reset the start time to 0 so that we start recording again the next | |
| 889 // time the backing store is NULL... | |
| 890 whiteout_start_time_ = base::TimeTicks(); | |
| 891 } | |
| 892 if (!tab_switch_paint_time_.is_null()) { | |
| 893 base::TimeDelta tab_switch_paint_duration = base::TimeTicks::Now() - | |
| 894 tab_switch_paint_time_; | |
| 895 UMA_HISTOGRAM_TIMES("MPArch.RWH_TabSwitchPaintDuration", | |
| 896 tab_switch_paint_duration); | |
| 897 // Reset tab_switch_paint_time_ to 0 so future tab selections are | |
| 898 // recorded. | |
| 899 tab_switch_paint_time_ = base::TimeTicks(); | |
| 900 } | |
| 901 } else { | |
| 902 if (whiteout_start_time_.is_null()) | |
| 903 whiteout_start_time_ = base::TimeTicks::Now(); | |
| 904 | |
| 905 if (get_use_acceleration_when_possible()) | |
| 906 canvas->FillRect(SK_ColorWHITE, GetLocalBounds()); | |
| 907 } | |
| 908 } | |
| 909 | |
| 910 void RenderWidgetHostViewViews::Focus() { | |
| 911 RequestFocus(); | |
| 912 } | |
| 913 | |
| 914 void RenderWidgetHostViewViews::Blur() { | |
| 915 // TODO(estade): We should be clearing native focus as well, but I know of no | |
| 916 // way to do that without focusing another widget. | |
| 917 if (host_) { | |
| 918 host_->SetActive(false); | |
| 919 host_->Blur(); | |
| 920 } | |
| 921 } | |
| 922 | |
| 923 void RenderWidgetHostViewViews::OnFocus() { | |
| 924 if (!host_) | |
| 925 return; | |
| 926 | |
| 927 DCHECK(GetInputMethod()); | |
| 928 View::OnFocus(); | |
| 929 ShowCurrentCursor(); | |
| 930 host_->GotFocus(); | |
| 931 host_->SetActive(true); | |
| 932 host_->SetInputMethodActive(GetInputMethod()->IsActive()); | |
| 933 | |
| 934 UpdateTouchSelectionController(); | |
| 935 } | |
| 936 | |
| 937 void RenderWidgetHostViewViews::OnBlur() { | |
| 938 if (!host_) | |
| 939 return; | |
| 940 View::OnBlur(); | |
| 941 // If we are showing a context menu, maintain the illusion that webkit has | |
| 942 // focus. | |
| 943 if (!is_showing_context_menu_ && !is_hidden_) | |
| 944 host_->Blur(); | |
| 945 host_->SetInputMethodActive(false); | |
| 946 | |
| 947 if (touch_selection_controller_.get()) | |
| 948 touch_selection_controller_->ClientViewLostFocus(); | |
| 949 } | |
| 950 | |
| 951 bool RenderWidgetHostViewViews::NeedsInputGrab() { | |
| 952 return popup_type_ == WebKit::WebPopupTypeSelect; | |
| 953 } | |
| 954 | |
| 955 bool RenderWidgetHostViewViews::IsPopup() { | |
| 956 return popup_type_ != WebKit::WebPopupTypeNone; | |
| 957 } | |
| 958 | |
| 959 WebKit::WebMouseEvent RenderWidgetHostViewViews::WebMouseEventFromViewsEvent( | |
| 960 const views::MouseEvent& event) { | |
| 961 WebKit::WebMouseEvent wmevent; | |
| 962 InitializeWebMouseEventFromViewsEvent(event, GetMirroredPosition(), &wmevent); | |
| 963 | |
| 964 // Setting |wmevent.button| is not necessary for -move events, but it is | |
| 965 // necessary for -clicks and -drags. | |
| 966 if (event.IsMiddleMouseButton()) { | |
| 967 wmevent.modifiers |= WebKit::WebInputEvent::MiddleButtonDown; | |
| 968 wmevent.button = WebKit::WebMouseEvent::ButtonMiddle; | |
| 969 } | |
| 970 if (event.IsRightMouseButton()) { | |
| 971 wmevent.modifiers |= WebKit::WebInputEvent::RightButtonDown; | |
| 972 wmevent.button = WebKit::WebMouseEvent::ButtonRight; | |
| 973 } | |
| 974 if (event.IsLeftMouseButton()) { | |
| 975 wmevent.modifiers |= WebKit::WebInputEvent::LeftButtonDown; | |
| 976 wmevent.button = WebKit::WebMouseEvent::ButtonLeft; | |
| 977 } | |
| 978 | |
| 979 return wmevent; | |
| 980 } | |
| 981 | |
| 982 void RenderWidgetHostViewViews::FinishImeCompositionSession() { | |
| 983 if (!has_composition_text_) | |
| 984 return; | |
| 985 if (host_) | |
| 986 host_->ImeConfirmComposition(); | |
| 987 DCHECK(GetInputMethod()); | |
| 988 GetInputMethod()->CancelComposition(this); | |
| 989 has_composition_text_ = false; | |
| 990 } | |
| 991 | |
| 992 void RenderWidgetHostViewViews::UpdateTouchSelectionController() { | |
| 993 gfx::Point start = selection_start_rect_.origin(); | |
| 994 start.Offset(0, selection_start_rect_.height()); | |
| 995 gfx::Point end = selection_end_rect_.origin(); | |
| 996 end.Offset(0, selection_end_rect_.height()); | |
| 997 | |
| 998 if (touch_selection_controller_.get()) | |
| 999 touch_selection_controller_->SelectionChanged(start, end); | |
| 1000 } | |
| 1001 | |
| 1002 #if !defined(OS_WIN) | |
| 1003 void RenderWidgetHostViewViews::UpdateCursor(const WebCursor& cursor) { | |
| 1004 // Optimize the common case, where the cursor hasn't changed. | |
| 1005 // However, we can switch between different pixmaps, so only on the | |
| 1006 // non-pixmap branch. | |
| 1007 #if defined(TOOLKIT_USES_GTK) | |
| 1008 if (current_cursor_.GetCursorType() != GDK_CURSOR_IS_PIXMAP && | |
| 1009 current_cursor_.GetCursorType() == cursor.GetCursorType()) { | |
| 1010 return; | |
| 1011 } | |
| 1012 #endif | |
| 1013 current_cursor_ = cursor; | |
| 1014 ShowCurrentCursor(); | |
| 1015 } | |
| 1016 | |
| 1017 void RenderWidgetHostViewViews::ShowCurrentCursor() { | |
| 1018 #if !defined(USE_AURA) | |
| 1019 // The widget may not have a window. If that's the case, abort mission. This | |
| 1020 // is the same issue as that explained above in Paint(). | |
| 1021 if (!IsReadyToPaint()) | |
| 1022 return; | |
| 1023 #endif | |
| 1024 | |
| 1025 native_cursor_ = current_cursor_.GetNativeCursor(); | |
| 1026 } | |
| 1027 | |
| 1028 #if defined(TOOLKIT_USES_GTK) | |
| 1029 bool RenderWidgetHostViewViews::IsReadyToPaint() { | |
| 1030 views::Widget* top = NULL; | |
| 1031 | |
| 1032 // TODO(oshima): move this functionality to Widget. | |
| 1033 if (views::ViewsDelegate::views_delegate && | |
| 1034 views::ViewsDelegate::views_delegate->GetDefaultParentView()) { | |
| 1035 top = views::ViewsDelegate::views_delegate->GetDefaultParentView()-> | |
| 1036 GetWidget(); | |
| 1037 } else { | |
| 1038 // Use GetTopLevelWidget()'s native view to get platform | |
| 1039 // native widget. This is a workaround to get window's NativeWidgetGtk | |
| 1040 // under both views desktop (where toplevel is NativeWidgetViews, | |
| 1041 // whose GetNativeView returns gtk widget of the native window) | |
| 1042 // and non views desktop (where toplevel is NativeWidgetGtk). | |
| 1043 top = GetWidget() ? | |
| 1044 views::Widget::GetWidgetForNativeView( | |
| 1045 GetWidget()->GetTopLevelWidget()->GetNativeView()) : | |
| 1046 NULL; | |
| 1047 } | |
| 1048 | |
| 1049 return top ? | |
| 1050 !!(static_cast<const views::NativeWidgetGtk*>(top->native_widget())-> | |
| 1051 window_contents()->window) : false; | |
| 1052 } | |
| 1053 #endif | |
| 1054 | |
| 1055 #endif // !OS_WIN | |
| 1056 | |
| 1057 #if defined(TOOLKIT_USES_GTK) | |
| 1058 void RenderWidgetHostViewViews::CreatePluginContainer( | |
| 1059 gfx::PluginWindowHandle id) { | |
| 1060 // TODO(anicolao): plugin_container_manager_.CreatePluginContainer(id); | |
| 1061 } | |
| 1062 | |
| 1063 void RenderWidgetHostViewViews::DestroyPluginContainer( | |
| 1064 gfx::PluginWindowHandle id) { | |
| 1065 // TODO(anicolao): plugin_container_manager_.DestroyPluginContainer(id); | |
| 1066 } | |
| 1067 | |
| 1068 #endif // TOOLKIT_USES_GTK | |
| 1069 | |
| 1070 #if defined(OS_POSIX) || defined(USE_AURA) | |
| 1071 void RenderWidgetHostViewViews::GetDefaultScreenInfo( | |
| 1072 WebKit::WebScreenInfo* results) { | |
| 1073 NOTIMPLEMENTED(); | |
| 1074 } | |
| 1075 | |
| 1076 void RenderWidgetHostViewViews::GetScreenInfo(WebKit::WebScreenInfo* results) { | |
| 1077 #if !defined(USE_AURA) | |
| 1078 views::Widget* widget = GetWidget() ? GetWidget()->GetTopLevelWidget() : NULL; | |
| 1079 if (widget && widget->GetNativeView()) | |
| 1080 content::GetScreenInfoFromNativeWindow(widget->GetNativeView()->window, | |
| 1081 results); | |
| 1082 else | |
| 1083 RenderWidgetHostView::GetDefaultScreenInfo(results); | |
| 1084 #else | |
| 1085 RenderWidgetHostView::GetDefaultScreenInfo(results); | |
| 1086 #endif | |
| 1087 } | |
| 1088 | |
| 1089 gfx::Rect RenderWidgetHostViewViews::GetRootWindowBounds() { | |
| 1090 views::Widget* widget = GetWidget() ? GetWidget()->GetTopLevelWidget() : NULL; | |
| 1091 return widget ? widget->GetWindowScreenBounds() : gfx::Rect(); | |
| 1092 } | |
| 1093 #endif | |
| 1094 | |
| 1095 #if !defined(OS_WIN) && !defined(UI_COMPOSITOR_IMAGE_TRANSPORT) | |
| 1096 gfx::PluginWindowHandle RenderWidgetHostViewViews::GetCompositingSurface() { | |
| 1097 // TODO(oshima): The original implementation was broken as | |
| 1098 // GtkNativeViewManager doesn't know about NativeWidgetGtk. Figure | |
| 1099 // out if this makes sense without compositor. If it does, then find | |
| 1100 // out the right way to handle. | |
| 1101 NOTIMPLEMENTED(); | |
| 1102 return gfx::kNullPluginWindow; | |
| 1103 } | |
| 1104 #endif | |
| 1105 | |
| 1106 #if defined(UI_COMPOSITOR_IMAGE_TRANSPORT) | |
| 1107 gfx::PluginWindowHandle RenderWidgetHostViewViews::GetCompositingSurface() { | |
| 1108 // On TOUCH_UI builds, the GPU process renders to an offscreen surface | |
| 1109 // (created by the GPU process), which is later displayed by the browser. | |
| 1110 // As the GPU process creates this surface, we can return any non-zero value. | |
| 1111 return 1; | |
| 1112 } | |
| 1113 | |
| 1114 void RenderWidgetHostViewViews::AcceleratedSurfaceNew( | |
| 1115 int32 width, | |
| 1116 int32 height, | |
| 1117 uint64* surface_id, | |
| 1118 TransportDIB::Handle* surface_handle) { | |
| 1119 scoped_refptr<AcceleratedSurfaceContainerLinux> surface( | |
| 1120 AcceleratedSurfaceContainerLinux::Create(gfx::Size(width, height))); | |
| 1121 if (!surface->Initialize(surface_id)) { | |
| 1122 LOG(ERROR) << "Failed to create AcceleratedSurfaceContainer"; | |
| 1123 return; | |
| 1124 } | |
| 1125 *surface_handle = surface->Handle(); | |
| 1126 | |
| 1127 accelerated_surface_containers_[*surface_id] = surface; | |
| 1128 } | |
| 1129 | |
| 1130 void RenderWidgetHostViewViews::AcceleratedSurfaceRelease(uint64 surface_id) { | |
| 1131 accelerated_surface_containers_.erase(surface_id); | |
| 1132 } | |
| 1133 | |
| 1134 void RenderWidgetHostViewViews::AcceleratedSurfaceBuffersSwapped( | |
| 1135 uint64 surface_id, | |
| 1136 int32 route_id, | |
| 1137 int gpu_host_id) { | |
| 1138 SetExternalTexture(accelerated_surface_containers_[surface_id]->GetTexture()); | |
| 1139 glFlush(); | |
| 1140 | |
| 1141 if (!GetWidget() || !GetWidget()->GetCompositor()) { | |
| 1142 // We have no compositor, so we have no way to display the surface. | |
| 1143 // Must still send the ACK. | |
| 1144 host_->AcknowledgeSwapBuffers(route_id, gpu_host_id); | |
| 1145 } else { | |
| 1146 // Add sending an ACK to the list of things to do OnCompositingEnded | |
| 1147 on_compositing_ended_callbacks_.push_back( | |
| 1148 base::Bind(&RenderWidgetHost::AcknowledgeSwapBuffers, | |
| 1149 base::Unretained(host_), route_id, gpu_host_id)); | |
| 1150 ui::Compositor *compositor = GetWidget()->GetCompositor(); | |
| 1151 if (!compositor->HasObserver(this)) | |
| 1152 compositor->AddObserver(this); | |
| 1153 } | |
| 1154 } | |
| 1155 | |
| 1156 void RenderWidgetHostViewViews::OnCompositingEnded(ui::Compositor* compositor) { | |
| 1157 for (std::vector< base::Callback<void(void)> >::const_iterator | |
| 1158 it = on_compositing_ended_callbacks_.begin(); | |
| 1159 it != on_compositing_ended_callbacks_.end(); ++it) { | |
| 1160 it->Run(); | |
| 1161 } | |
| 1162 on_compositing_ended_callbacks_.clear(); | |
| 1163 compositor->RemoveObserver(this); | |
| 1164 } | |
| 1165 | |
| 1166 #endif | |
| OLD | NEW |