2011-02-15 19:07:24 +01:00
|
|
|
// 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.
|
|
|
|
|
2012-01-10 00:46:23 +01:00
|
|
|
#include "libcef/webwidget_host.h"
|
|
|
|
#include "libcef/cef_thread.h"
|
2011-02-15 19:07:24 +01:00
|
|
|
|
2011-10-12 21:09:15 +02:00
|
|
|
#include "base/bind.h"
|
2012-08-13 18:27:44 +02:00
|
|
|
#include "base/logging.h"
|
2011-02-15 19:07:24 +01:00
|
|
|
#include "base/message_loop.h"
|
2011-12-16 15:51:10 +01:00
|
|
|
#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebSize.h"
|
2011-03-24 21:36:47 +01:00
|
|
|
#include "third_party/WebKit/Source/WebKit/chromium/public/WebWidget.h"
|
2012-08-21 21:48:29 +02:00
|
|
|
#include "webkit/glue/webkit_glue.h"
|
2011-03-24 21:36:47 +01:00
|
|
|
|
|
|
|
using webkit::npapi::WebPluginGeometry;
|
|
|
|
using WebKit::WebSize;
|
|
|
|
|
2012-08-15 01:33:57 +02:00
|
|
|
const int WebWidgetHost::kDefaultFrameRate = 30;
|
|
|
|
const int WebWidgetHost::kMaxFrameRate = 90;
|
2011-02-15 19:07:24 +01:00
|
|
|
|
2012-08-21 21:48:29 +02:00
|
|
|
void WebWidgetHost::InvalidateRect(const gfx::Rect& rect) {
|
|
|
|
if (rect.IsEmpty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
int width, height;
|
|
|
|
GetSize(width, height);
|
2012-11-06 18:13:58 +01:00
|
|
|
gfx::Rect client_rect(width, height);
|
|
|
|
client_rect.Intersect(rect);
|
|
|
|
if (client_rect.IsEmpty())
|
2012-08-21 21:48:29 +02:00
|
|
|
return;
|
|
|
|
|
2012-11-06 18:13:58 +01:00
|
|
|
UpdatePaintRect(client_rect);
|
2012-08-21 21:48:29 +02:00
|
|
|
|
|
|
|
if (view_)
|
2012-11-06 18:13:58 +01:00
|
|
|
InvalidateWindowRect(client_rect);
|
2012-08-21 21:48:29 +02:00
|
|
|
else
|
|
|
|
ScheduleTimer();
|
|
|
|
}
|
|
|
|
|
2011-12-16 13:24:09 +01:00
|
|
|
void WebWidgetHost::ScheduleComposite() {
|
2012-08-21 21:48:29 +02:00
|
|
|
ScheduleTimer();
|
2011-12-16 13:24:09 +01:00
|
|
|
}
|
|
|
|
|
2011-02-15 19:07:24 +01:00
|
|
|
void WebWidgetHost::ScheduleAnimation() {
|
2012-08-21 21:48:29 +02:00
|
|
|
ScheduleTimer();
|
2011-02-15 19:07:24 +01:00
|
|
|
}
|
2011-03-24 21:36:47 +01:00
|
|
|
|
2012-08-21 21:48:29 +02:00
|
|
|
bool WebWidgetHost::GetImage(int width, int height, void* rgba_buffer) {
|
|
|
|
if (!canvas_.get())
|
|
|
|
return false;
|
2011-11-09 21:09:24 +01:00
|
|
|
|
2012-08-21 21:48:29 +02:00
|
|
|
const SkBitmap& bitmap = canvas_->getDevice()->accessBitmap(false);
|
|
|
|
DCHECK(bitmap.config() == SkBitmap::kARGB_8888_Config);
|
2011-03-24 21:36:47 +01:00
|
|
|
|
2012-08-21 21:48:29 +02:00
|
|
|
if (width == canvas_->getDevice()->width() &&
|
|
|
|
height == canvas_->getDevice()->height()) {
|
|
|
|
// The specified width and height values are the same as the canvas size.
|
|
|
|
// Return the existing canvas contents.
|
|
|
|
const void* pixels = bitmap.getPixels();
|
|
|
|
memcpy(rgba_buffer, pixels, width * height * 4);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create a new canvas of the requested size.
|
|
|
|
scoped_ptr<skia::PlatformCanvas> new_canvas(
|
|
|
|
new skia::PlatformCanvas(width, height, true));
|
|
|
|
|
|
|
|
new_canvas->writePixels(bitmap, 0, 0);
|
|
|
|
const SkBitmap& new_bitmap = new_canvas->getDevice()->accessBitmap(false);
|
|
|
|
DCHECK(new_bitmap.config() == SkBitmap::kARGB_8888_Config);
|
|
|
|
|
|
|
|
// Return the new canvas contents.
|
|
|
|
const void* pixels = new_bitmap.getPixels();
|
|
|
|
memcpy(rgba_buffer, pixels, width * height * 4);
|
|
|
|
return true;
|
2012-08-15 01:33:57 +02:00
|
|
|
}
|
|
|
|
|
2011-03-24 21:36:47 +01:00
|
|
|
void WebWidgetHost::SetSize(int width, int height) {
|
|
|
|
webwidget_->resize(WebSize(width, height));
|
2012-08-21 21:48:29 +02:00
|
|
|
InvalidateRect(gfx::Rect(0, 0, width, height));
|
2011-03-24 21:36:47 +01:00
|
|
|
EnsureTooltip();
|
|
|
|
}
|
|
|
|
|
|
|
|
void WebWidgetHost::GetSize(int& width, int& height) {
|
|
|
|
const WebSize& size = webwidget_->size();
|
|
|
|
width = size.width;
|
|
|
|
height = size.height;
|
|
|
|
}
|
|
|
|
|
2012-01-10 00:46:23 +01:00
|
|
|
void WebWidgetHost::AddWindowedPlugin(gfx::PluginWindowHandle handle) {
|
2011-03-24 21:36:47 +01:00
|
|
|
WebPluginGeometry geometry;
|
|
|
|
plugin_map_.insert(std::make_pair(handle, geometry));
|
|
|
|
}
|
|
|
|
|
2012-01-10 00:46:23 +01:00
|
|
|
void WebWidgetHost::RemoveWindowedPlugin(gfx::PluginWindowHandle handle) {
|
2011-03-24 21:36:47 +01:00
|
|
|
PluginMap::iterator it = plugin_map_.find(handle);
|
|
|
|
DCHECK(it != plugin_map_.end());
|
|
|
|
plugin_map_.erase(it);
|
|
|
|
}
|
|
|
|
|
2012-01-10 00:46:23 +01:00
|
|
|
void WebWidgetHost::MoveWindowedPlugin(const WebPluginGeometry& move) {
|
2011-03-24 21:36:47 +01:00
|
|
|
PluginMap::iterator it = plugin_map_.find(move.window);
|
|
|
|
DCHECK(it != plugin_map_.end());
|
|
|
|
|
|
|
|
it->second.window = move.window;
|
|
|
|
if (move.rects_valid) {
|
|
|
|
it->second.window_rect = move.window_rect;
|
|
|
|
it->second.clip_rect = move.clip_rect;
|
|
|
|
it->second.cutout_rects = move.cutout_rects;
|
|
|
|
it->second.rects_valid = true;
|
|
|
|
}
|
|
|
|
it->second.visible = move.visible;
|
|
|
|
}
|
|
|
|
|
2012-01-10 00:46:23 +01:00
|
|
|
gfx::PluginWindowHandle WebWidgetHost::GetWindowedPluginAt(int x, int y) {
|
2011-03-24 21:36:47 +01:00
|
|
|
if (!plugin_map_.empty()) {
|
|
|
|
PluginMap::const_iterator it = plugin_map_.begin();
|
2012-01-10 00:46:23 +01:00
|
|
|
for (; it != plugin_map_.end(); ++it) {
|
2011-03-24 21:36:47 +01:00
|
|
|
if (it->second.visible && it->second.window_rect.Contains(x, y))
|
|
|
|
return it->second.window;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-24 22:20:52 +02:00
|
|
|
return gfx::kNullPluginWindow;
|
2011-03-24 21:36:47 +01:00
|
|
|
}
|
|
|
|
|
2012-08-15 01:33:57 +02:00
|
|
|
void WebWidgetHost::SetFrameRate(int frames_per_second) {
|
|
|
|
if (frames_per_second <= 0)
|
|
|
|
frames_per_second = kDefaultFrameRate;
|
|
|
|
if (frames_per_second > kMaxFrameRate)
|
|
|
|
frames_per_second = kMaxFrameRate;
|
|
|
|
|
|
|
|
frame_delay_ = 1000 / frames_per_second;
|
|
|
|
}
|
|
|
|
|
2012-08-21 21:48:29 +02:00
|
|
|
void WebWidgetHost::UpdatePaintRect(const gfx::Rect& rect) {
|
|
|
|
#if defined(OS_WIN) || defined(OS_MACOSX)
|
|
|
|
paint_rgn_.op(rect.x(), rect.y(), rect.right(), rect.bottom(),
|
|
|
|
SkRegion::kUnion_Op);
|
|
|
|
#else
|
|
|
|
// TODO(cef): Update all ports to use regions instead of rectangles.
|
2012-11-06 18:13:58 +01:00
|
|
|
paint_rect_.Union(rect);
|
2012-08-21 21:48:29 +02:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void WebWidgetHost::PaintRect(const gfx::Rect& rect) {
|
|
|
|
#ifndef NDEBUG
|
|
|
|
DCHECK(!painting_);
|
|
|
|
#endif
|
|
|
|
DCHECK(canvas_.get());
|
|
|
|
|
|
|
|
if (rect.IsEmpty())
|
2012-08-15 01:33:57 +02:00
|
|
|
return;
|
|
|
|
|
2012-08-21 21:48:29 +02:00
|
|
|
if (IsTransparent()) {
|
|
|
|
// When using transparency mode clear the rectangle before painting.
|
|
|
|
SkPaint clearpaint;
|
|
|
|
clearpaint.setARGB(0, 0, 0, 0);
|
|
|
|
clearpaint.setXfermodeMode(SkXfermode::kClear_Mode);
|
2012-08-15 01:33:57 +02:00
|
|
|
|
2012-08-21 21:48:29 +02:00
|
|
|
SkRect skrc;
|
|
|
|
skrc.set(rect.x(), rect.y(), rect.right(), rect.bottom());
|
|
|
|
canvas_->drawRect(skrc, clearpaint);
|
|
|
|
}
|
|
|
|
|
|
|
|
set_painting(true);
|
|
|
|
webwidget_->paint(webkit_glue::ToWebCanvas(canvas_.get()), rect);
|
|
|
|
set_painting(false);
|
2012-08-15 01:33:57 +02:00
|
|
|
}
|
|
|
|
|
2012-08-21 21:48:29 +02:00
|
|
|
void WebWidgetHost::ScheduleTimer() {
|
|
|
|
if (timer_.IsRunning())
|
2012-08-15 01:33:57 +02:00
|
|
|
return;
|
|
|
|
|
2012-08-21 21:48:29 +02:00
|
|
|
// This method may be called multiple times while the timer callback is
|
|
|
|
// executing. If so re-execute this method a single time after the callback
|
|
|
|
// has completed.
|
|
|
|
if (timer_executing_) {
|
|
|
|
if (!timer_wanted_)
|
|
|
|
timer_wanted_ = true;
|
2012-08-13 18:27:44 +02:00
|
|
|
return;
|
2012-08-21 21:48:29 +02:00
|
|
|
}
|
2012-08-13 18:27:44 +02:00
|
|
|
|
2012-08-15 01:33:57 +02:00
|
|
|
// Maintain the desired rate.
|
2012-08-21 21:48:29 +02:00
|
|
|
base::TimeDelta delta = base::TimeTicks::Now() - timer_last_;
|
2012-08-15 01:33:57 +02:00
|
|
|
int64 actualRate = delta.InMilliseconds();
|
|
|
|
if (actualRate >= frame_delay_)
|
|
|
|
delta = base::TimeDelta::FromMilliseconds(1);
|
|
|
|
else
|
|
|
|
delta = base::TimeDelta::FromMilliseconds(frame_delay_ - actualRate);
|
|
|
|
|
2012-08-21 21:48:29 +02:00
|
|
|
timer_.Start(
|
2012-08-13 18:27:44 +02:00
|
|
|
FROM_HERE,
|
2012-08-15 01:33:57 +02:00
|
|
|
delta,
|
2012-08-13 18:27:44 +02:00
|
|
|
this,
|
2012-08-21 21:48:29 +02:00
|
|
|
&WebWidgetHost::DoTimer);
|
2012-08-13 18:27:44 +02:00
|
|
|
}
|
|
|
|
|
2012-08-21 21:48:29 +02:00
|
|
|
void WebWidgetHost::DoTimer() {
|
|
|
|
timer_executing_ = true;
|
|
|
|
|
|
|
|
if (view_) {
|
|
|
|
// Window rendering is enabled and we've received a requestAnimationFrame
|
|
|
|
// or similar call. Trigger the OS to invalidate/repaint the client area at
|
|
|
|
// the requested frequency.
|
|
|
|
InvalidateWindow();
|
|
|
|
} else {
|
|
|
|
// Window rendering is disabled. Generate OnPaint() calls at the requested
|
|
|
|
// frequency.
|
2012-05-16 18:56:38 +02:00
|
|
|
#if defined(OS_MACOSX)
|
2012-08-21 21:48:29 +02:00
|
|
|
SkRegion region;
|
|
|
|
Paint(region);
|
2012-05-16 18:56:38 +02:00
|
|
|
#else
|
2012-08-21 21:48:29 +02:00
|
|
|
Paint();
|
2012-05-16 18:56:38 +02:00
|
|
|
#endif
|
2012-08-21 21:48:29 +02:00
|
|
|
}
|
2012-08-15 01:33:57 +02:00
|
|
|
|
2012-08-21 21:48:29 +02:00
|
|
|
timer_executing_ = false;
|
|
|
|
|
|
|
|
timer_last_ = base::TimeTicks::Now();
|
|
|
|
|
|
|
|
if (timer_wanted_) {
|
|
|
|
timer_wanted_ = false;
|
|
|
|
ScheduleTimer();
|
|
|
|
}
|
2011-03-24 21:36:47 +01:00
|
|
|
}
|