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 |