// Copyright (c) 2012 The Chromium Embedded Framework Authors. // Portions copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "libcef/browser/backing_store_osr.h" #include "libcef/browser/browser_host_impl.h" #include "libcef/browser/render_widget_host_view_osr.h" #include "base/message_loop.h" #include "content/browser/renderer_host/render_widget_host_impl.h" #include "content/public/browser/content_browser_client.h" #include "content/public/browser/render_view_host.h" #include "content/public/common/content_client.h" #include "webkit/glue/webcursor.h" /////////////////////////////////////////////////////////////////////////////// // CefRenderWidgetHostViewOSR, public: CefRenderWidgetHostViewOSR::CefRenderWidgetHostViewOSR( content::RenderWidgetHost* widget) : render_widget_host_(content::RenderWidgetHostImpl::From(widget)), about_to_validate_and_paint_(false), parent_host_view_(NULL), popup_host_view_(NULL), weak_factory_(this) { DCHECK(render_widget_host_); render_widget_host_->SetView(this); // CefBrowserHostImpl might not be created at this time for popups. if (render_widget_host_->IsRenderView()) { browser_impl_ = CefBrowserHostImpl::GetBrowserForHost( content::RenderViewHost::From(render_widget_host_)); } } CefRenderWidgetHostViewOSR::~CefRenderWidgetHostViewOSR() { } // RenderWidgetHostView implementation. void CefRenderWidgetHostViewOSR::InitAsChild(gfx::NativeView parent_view) { } content::RenderWidgetHost* CefRenderWidgetHostViewOSR::GetRenderWidgetHost() const { return render_widget_host_; } void CefRenderWidgetHostViewOSR::SetSize(const gfx::Size& size) { } void CefRenderWidgetHostViewOSR::SetBounds(const gfx::Rect& rect) { } gfx::NativeView CefRenderWidgetHostViewOSR::GetNativeView() const { return browser_impl_.get() ? browser_impl_->GetWindowHandle() : NULL; } gfx::NativeViewId CefRenderWidgetHostViewOSR::GetNativeViewId() const { if (!browser_impl_.get()) return gfx::NativeViewId(); // This Id is used on Windows as HWND to retrieve monitor info // If this Id is not a valid window, the main screen monitor info is used return reinterpret_cast(browser_impl_->GetWindowHandle()); } gfx::NativeViewAccessible CefRenderWidgetHostViewOSR::GetNativeViewAccessible() { return gfx::NativeViewAccessible(); } bool CefRenderWidgetHostViewOSR::HasFocus() const { return false; } bool CefRenderWidgetHostViewOSR::IsSurfaceAvailableForCopy() const { return false; } void CefRenderWidgetHostViewOSR::Show() { WasShown(); } void CefRenderWidgetHostViewOSR::Hide() { WasHidden(); } bool CefRenderWidgetHostViewOSR::IsShowing() { return true; } gfx::Rect CefRenderWidgetHostViewOSR::GetViewBounds() const { if (IsPopupWidget()) return popup_position_; if (!browser_impl_.get()) return gfx::Rect(); CefRect rc; browser_impl_->GetClient()->GetRenderHandler()->GetViewRect( browser_impl_->GetBrowser(), rc); return gfx::Rect(rc.x, rc.y, rc.width, rc.height); } // Implementation of RenderWidgetHostViewPort. void CefRenderWidgetHostViewOSR::InitAsPopup( RenderWidgetHostView* parent_host_view, const gfx::Rect& pos) { parent_host_view_ = static_cast( parent_host_view); browser_impl_ = parent_host_view_->get_browser_impl(); if (!browser_impl_.get()) return; parent_host_view_->CancelWidget(); parent_host_view_->set_popup_host_view(this); NotifyShowWidget(); popup_position_ = pos; NotifySizeWidget(); } void CefRenderWidgetHostViewOSR::InitAsFullscreen( RenderWidgetHostView* reference_host_view) { NOTREACHED() << "Fullscreen widgets are not supported in OSR"; } void CefRenderWidgetHostViewOSR::WasShown() { if (render_widget_host_) render_widget_host_->WasShown(); } void CefRenderWidgetHostViewOSR::WasHidden() { if (render_widget_host_) render_widget_host_->WasHidden(); } void CefRenderWidgetHostViewOSR::MovePluginWindows( const gfx::Vector2d& scroll_offset, const std::vector& moves) { } void CefRenderWidgetHostViewOSR::Focus() { } void CefRenderWidgetHostViewOSR::Blur() { } void CefRenderWidgetHostViewOSR::UpdateCursor(const WebCursor& cursor) { if (!browser_impl_.get()) return; #if defined(OS_WIN) HMODULE hModule = ::GetModuleHandle( content::GetContentClient()->browser()->GetResourceDllName()); if (!hModule) hModule = ::GetModuleHandle(NULL); WebCursor web_cursor = cursor; HCURSOR hCursor = web_cursor.GetCursor((HINSTANCE)hModule); browser_impl_->GetClient()->GetRenderHandler()->OnCursorChange( browser_impl_->GetBrowser(), hCursor); #else // TODO(port): Implement this method to work on other platforms as part of // off-screen rendering support. NOTREACHED(); #endif } void CefRenderWidgetHostViewOSR::SetIsLoading(bool is_loading) { } void CefRenderWidgetHostViewOSR::TextInputStateChanged( const ViewHostMsg_TextInputState_Params& params) { } void CefRenderWidgetHostViewOSR::ImeCancelComposition() { } void CefRenderWidgetHostViewOSR::DidUpdateBackingStore( const gfx::Rect& scroll_rect, const gfx::Vector2d& scroll_delta, const std::vector& copy_rects) { if (!scroll_rect.IsEmpty()) { std::vector dirty_rects(copy_rects); dirty_rects.push_back(scroll_rect); Paint(dirty_rects); } else { Paint(copy_rects); } } void CefRenderWidgetHostViewOSR::RenderViewGone( base::TerminationStatus status, int error_code) { render_widget_host_ = NULL; parent_host_view_ = NULL; popup_host_view_ = NULL; } #if defined(OS_WIN) && !defined(USE_AURA) void CefRenderWidgetHostViewOSR::WillWmDestroy() { // Will not be called if GetNativeView returns NULL. NOTREACHED(); } #endif gfx::Rect CefRenderWidgetHostViewOSR::GetBoundsInRootWindow() { if (!browser_impl_.get()) return gfx::Rect(); CefRect rc; if (browser_impl_->GetClient()->GetRenderHandler()->GetRootScreenRect( browser_impl_->GetBrowser(), rc)) { return gfx::Rect(rc.x, rc.y, rc.width, rc.height); } return gfx::Rect(); } void CefRenderWidgetHostViewOSR::Destroy() { if (IsPopupWidget()) { if (parent_host_view_) parent_host_view_->CancelWidget(); } else { CancelWidget(); } delete this; } void CefRenderWidgetHostViewOSR::SetTooltipText(const string16& tooltip_text) { if (!browser_impl_.get()) return; CefString tooltip(tooltip_text); CefRefPtr handler = browser_impl_->GetClient()->GetDisplayHandler(); if (handler.get()) { handler->OnTooltip(browser_impl_->GetBrowser(), tooltip); } } content::BackingStore* CefRenderWidgetHostViewOSR::AllocBackingStore( const gfx::Size& size) { return render_widget_host_ ? new BackingStoreOSR(render_widget_host_, size) : NULL; } void CefRenderWidgetHostViewOSR::CopyFromCompositingSurface( const gfx::Rect& src_subrect, const gfx::Size& dst_size, const base::Callback& callback, skia::PlatformBitmap* output) { } void CefRenderWidgetHostViewOSR::OnAcceleratedCompositingStateChange() { } void CefRenderWidgetHostViewOSR::SetHasHorizontalScrollbar( bool has_horizontal_scrollbar) { } void CefRenderWidgetHostViewOSR::SetScrollOffsetPinning( bool is_pinned_to_left, bool is_pinned_to_right) { } gfx::GLSurfaceHandle CefRenderWidgetHostViewOSR::GetCompositingSurface() { return gfx::GLSurfaceHandle(); } void CefRenderWidgetHostViewOSR::AcceleratedSurfaceBuffersSwapped( const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params, int gpu_host_id) { } void CefRenderWidgetHostViewOSR::AcceleratedSurfacePostSubBuffer( const GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params& params, int gpu_host_id) { } void CefRenderWidgetHostViewOSR::AcceleratedSurfaceSuspend() { } bool CefRenderWidgetHostViewOSR::HasAcceleratedSurface( const gfx::Size& desired_size) { return false; } bool CefRenderWidgetHostViewOSR::LockMouse() { return false; } void CefRenderWidgetHostViewOSR::UnlockMouse() { } #if defined(OS_WIN) && !defined(USE_AURA) void CefRenderWidgetHostViewOSR::SetClickthroughRegion(SkRegion* region) { } #endif void CefRenderWidgetHostViewOSR::SetBackground(const SkBitmap& background) { if (!render_widget_host_) return; RenderWidgetHostViewBase::SetBackground(background); render_widget_host_->SetBackground(background); } void CefRenderWidgetHostViewOSR::Invalidate(const gfx::Rect& rect, CefBrowserHost::PaintElementType type) { if (!IsPopupWidget() && type == PET_POPUP) { if (popup_host_view_) popup_host_view_->Invalidate(rect, type); return; } std::vector dirtyRects; dirtyRects.push_back(rect); Paint(dirtyRects); } void CefRenderWidgetHostViewOSR::Paint( const std::vector& copy_rects) { if (about_to_validate_and_paint_ || !browser_impl_.get() || !render_widget_host_) { pending_update_rects_.insert(pending_update_rects_.end(), copy_rects.begin(), copy_rects.end()); return; } about_to_validate_and_paint_ = true; BackingStoreOSR* backing_store = BackingStoreOSR::From(render_widget_host_->GetBackingStore(true)); about_to_validate_and_paint_ = false; if (backing_store) { const gfx::Rect client_rect(backing_store->size()); SkRegion damaged_rgn; for (size_t i = 0; i < copy_rects.size(); ++i) { SkIRect skRect = SkIRect::MakeLTRB( copy_rects[i].x(), copy_rects[i].y(), copy_rects[i].right(), copy_rects[i].bottom()); damaged_rgn.op(skRect, SkRegion::kUnion_Op); } for (size_t i = 0; i < pending_update_rects_.size(); ++i) { SkIRect skRect = SkIRect::MakeLTRB( pending_update_rects_[i].x(), pending_update_rects_[i].y(), pending_update_rects_[i].right(), pending_update_rects_[i].bottom()); damaged_rgn.op(skRect, SkRegion::kUnion_Op); } pending_update_rects_.clear(); CefRenderHandler::RectList rcList; SkRegion::Cliperator iterator(damaged_rgn, SkIRect::MakeWH(client_rect.width(), client_rect.height())); for (; !iterator.done(); iterator.next()) { const SkIRect& r = iterator.rect(); rcList.push_back( CefRect(r.left(), r.top(), r.width(), r.height())); } if (rcList.size() == 0) return; browser_impl_->GetClient()->GetRenderHandler()->OnPaint( browser_impl_->GetBrowser(), IsPopupWidget() ? PET_POPUP : PET_VIEW, rcList, backing_store->getPixels(), client_rect.width(), client_rect.height()); } } bool CefRenderWidgetHostViewOSR::InstallTransparency() { if (browser_impl_.get() && browser_impl_->IsTransparent()) { SkBitmap bg; bg.setConfig(SkBitmap::kARGB_8888_Config, 1, 1); // 1x1 alpha bitmap. bg.allocPixels(); bg.eraseARGB(0x00, 0x00, 0x00, 0x00); SetBackground(bg); return true; } return false; } void CefRenderWidgetHostViewOSR::CancelWidget() { if (IsPopupWidget()) { if (render_widget_host_) render_widget_host_->LostCapture(); if (browser_impl_.get()) { NotifyHideWidget(); browser_impl_ = NULL; } if (parent_host_view_) { parent_host_view_->set_popup_host_view(NULL); parent_host_view_ = NULL; } if (!weak_factory_.HasWeakPtrs()) { MessageLoop::current()->PostTask(FROM_HERE, base::Bind(&CefRenderWidgetHostViewOSR::ShutdownHost, weak_factory_.GetWeakPtr())); } } else if (popup_host_view_) { popup_host_view_->CancelWidget(); } } void CefRenderWidgetHostViewOSR::NotifyShowWidget() { if (browser_impl_.get()) { browser_impl_->GetClient()->GetRenderHandler()->OnPopupShow( browser_impl_->GetBrowser(), true); } } void CefRenderWidgetHostViewOSR::NotifyHideWidget() { if (browser_impl_.get()) { browser_impl_->GetClient()->GetRenderHandler()->OnPopupShow( browser_impl_->GetBrowser(), false); } } void CefRenderWidgetHostViewOSR::NotifySizeWidget() { if (browser_impl_.get()) { CefRect widget_pos(popup_position_.x(), popup_position_.y(), popup_position_.width(), popup_position_.height()); browser_impl_->GetClient()->GetRenderHandler()->OnPopupSize( browser_impl_->GetBrowser(), widget_pos); } } CefRefPtr CefRenderWidgetHostViewOSR::get_browser_impl() const { return browser_impl_; } void CefRenderWidgetHostViewOSR::set_browser_impl( CefRefPtr browser) { browser_impl_ = browser; } void CefRenderWidgetHostViewOSR::set_popup_host_view( CefRenderWidgetHostViewOSR* popup_view) { popup_host_view_ = popup_view; } void CefRenderWidgetHostViewOSR::ShutdownHost() { weak_factory_.InvalidateWeakPtrs(); if (render_widget_host_) render_widget_host_->Shutdown(); // Do not touch any members at this point, |this| has been deleted. } void CefRenderWidgetHostViewOSR::set_parent_host_view( CefRenderWidgetHostViewOSR* parent_view) { parent_host_view_ = parent_view; } void CefRenderWidgetHostViewOSR::SendKeyEvent( const content::NativeWebKeyboardEvent& event) { if (!IsPopupWidget() && popup_host_view_) { popup_host_view_->SendKeyEvent(event); return; } if (!render_widget_host_) return; render_widget_host_->ForwardKeyboardEvent(event); } void CefRenderWidgetHostViewOSR::SendMouseEvent( const WebKit::WebMouseEvent& event) { if (!IsPopupWidget() && popup_host_view_) { if (popup_host_view_->popup_position_.Contains(event.x, event.y)) { WebKit::WebMouseEvent popup_event(event); popup_event.x -= popup_host_view_->popup_position_.x(); popup_event.y -= popup_host_view_->popup_position_.y(); popup_event.windowX = popup_event.x; popup_event.windowY = popup_event.y; popup_host_view_->SendMouseEvent(popup_event); return; } } if (!render_widget_host_) return; render_widget_host_->ForwardMouseEvent(event); } void CefRenderWidgetHostViewOSR::SendMouseWheelEvent( const WebKit::WebMouseWheelEvent& event) { if (!IsPopupWidget() && popup_host_view_) { if (popup_host_view_->popup_position_.Contains(event.x, event.y)) { WebKit::WebMouseWheelEvent popup_event(event); popup_event.x -= popup_host_view_->popup_position_.x(); popup_event.y -= popup_host_view_->popup_position_.y(); popup_event.windowX = popup_event.x; popup_event.windowY = popup_event.y; popup_host_view_->SendMouseWheelEvent(popup_event); return; } else { // scrolling outside the popup widget, will destroy widget CancelWidget(); } } if (!render_widget_host_) return; render_widget_host_->ForwardWheelEvent(event); }