summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoramanda@chromium.org <amanda@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-07-11 01:57:28 +0000
committeramanda@chromium.org <amanda@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-07-11 01:57:28 +0000
commit6bf1a81cdfcc48f20cf53c2601f4456f2d9d30ef (patch)
tree7bedf19228a20b83189ab96e617e72210991c7c4
parent7e05f6c4baad4f81e06835b83febe2784568ebe1 (diff)
downloadchromium_src-6bf1a81cdfcc48f20cf53c2601f4456f2d9d30ef.zip
chromium_src-6bf1a81cdfcc48f20cf53c2601f4456f2d9d30ef.tar.gz
chromium_src-6bf1a81cdfcc48f20cf53c2601f4456f2d9d30ef.tar.bz2
Wire up windowless plugins. Mostly Mac related, some cross
platform aspects. BUG=10809 TEST=none Review URL: http://codereview.chromium.org/113637 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@20453 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--app/app.gyp1
-rw-r--r--app/gfx/canvas.cc10
-rw-r--r--app/gfx/canvas_mac.mm79
-rw-r--r--chrome/common/plugin_messages_internal.h4
-rw-r--r--chrome/common/transport_dib_mac.cc2
-rw-r--r--chrome/plugin/plugin_main.cc63
-rw-r--r--chrome/plugin/webplugin_delegate_stub.cc6
-rw-r--r--chrome/plugin/webplugin_delegate_stub.h4
-rw-r--r--chrome/plugin/webplugin_proxy.cc95
-rw-r--r--chrome/plugin/webplugin_proxy.h20
-rw-r--r--chrome/renderer/render_view.cc13
-rw-r--r--chrome/renderer/webplugin_delegate_proxy.cc181
-rw-r--r--chrome/renderer/webplugin_delegate_proxy.h21
-rw-r--r--webkit/glue/plugins/plugin_host.cc24
-rw-r--r--webkit/glue/plugins/webplugin_delegate_impl.h4
-rw-r--r--webkit/glue/plugins/webplugin_delegate_impl_mac.mm375
16 files changed, 611 insertions, 291 deletions
diff --git a/app/app.gyp b/app/app.gyp
index faced76..5c989ae 100644
--- a/app/app.gyp
+++ b/app/app.gyp
@@ -68,6 +68,7 @@
'gfx/canvas.cc',
'gfx/canvas.h',
'gfx/canvas_linux.cc',
+ 'gfx/canvas_mac.mm',
'gfx/canvas_win.cc',
'gfx/font.h',
'gfx/font_gtk.cc',
diff --git a/app/gfx/canvas.cc b/app/gfx/canvas.cc
index d3b55ab..2cef3de 100644
--- a/app/gfx/canvas.cc
+++ b/app/gfx/canvas.cc
@@ -221,16 +221,6 @@ void Canvas::DrawStringInt(const std::wstring& text,
l10n_util::DefaultCanvasTextAlignment());
}
-#if defined(OS_MACOSX)
-void Canvas::DrawStringInt(const std::wstring& text,
- const gfx::Font& font,
- const SkColor& color,
- int x, int y, int w, int h,
- int flags) {
- NOTIMPLEMENTED();
-}
-#endif
-
void Canvas::TileImageInt(const SkBitmap& bitmap, int x, int y, int w, int h) {
TileImageInt(bitmap, 0, 0, x, y, w, h);
}
diff --git a/app/gfx/canvas_mac.mm b/app/gfx/canvas_mac.mm
new file mode 100644
index 0000000..b766b32
--- /dev/null
+++ b/app/gfx/canvas_mac.mm
@@ -0,0 +1,79 @@
+// Copyright (c) 2006-2008 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.
+
+#import <Cocoa/Cocoa.h>
+
+#include "app/gfx/canvas.h"
+
+#include "app/gfx/font.h"
+#include "app/l10n_util.h"
+#include "base/gfx/rect.h"
+#include "base/scoped_cftyperef.h"
+#include "base/sys_string_conversions.h"
+#include "third_party/skia/include/core/SkShader.h"
+
+namespace gfx {
+
+Canvas::Canvas(int width, int height, bool is_opaque)
+ : skia::PlatformCanvas(width, height, is_opaque) {
+}
+
+Canvas::Canvas() : skia::PlatformCanvas() {
+}
+
+Canvas::~Canvas() {
+}
+
+// static
+void Canvas::SizeStringInt(const std::wstring& text,
+ const gfx::Font& font,
+ int *width, int *height, int flags) {
+ *width = font.GetStringWidth(text);
+ *height = font.height();
+}
+
+void Canvas::DrawStringInt(const std::wstring& text, const gfx::Font& font,
+ const SkColor& color, int x, int y, int w, int h,
+ int flags) {
+ if (!IntersectsClipRectInt(x, y, w, h))
+ return;
+
+ CGContextRef context = beginPlatformPaint();
+ CGContextSaveGState(context);
+
+ NSColor* ns_color = [NSColor colorWithDeviceRed:SkColorGetR(color) / 255.0
+ green:SkColorGetG(color) / 255.0
+ blue:SkColorGetB(color) / 255.0
+ alpha:1.0];
+ NSMutableParagraphStyle *ns_style =
+ [[[NSParagraphStyle alloc] init] autorelease];
+ if (flags & TEXT_ALIGN_CENTER)
+ [ns_style setAlignment:NSCenterTextAlignment];
+ // TODO(awalker): Implement the rest of the Canvas text flags
+
+ NSDictionary* attributes =
+ [NSDictionary dictionaryWithObjectsAndKeys:
+ font.nativeFont(), NSFontAttributeName,
+ ns_color, NSForegroundColorAttributeName,
+ ns_style, NSParagraphStyleAttributeName,
+ nil];
+
+ NSAttributedString* ns_string =
+ [[[NSAttributedString alloc] initWithString:base::SysWideToNSString(text)
+ attributes:attributes] autorelease];
+ scoped_cftyperef<CTFramesetterRef> framesetter(
+ CTFramesetterCreateWithAttributedString(reinterpret_cast<CFAttributedStringRef>(ns_string)));
+
+ CGRect text_bounds = CGRectMake(x, y, w, h);
+ CGMutablePathRef path = CGPathCreateMutable();
+ CGPathAddRect(path, NULL, text_bounds);
+
+ scoped_cftyperef<CTFrameRef> frame(
+ CTFramesetterCreateFrame(framesetter, CFRangeMake(0, 0), path, NULL));
+ CTFrameDraw(frame, context);
+ CGContextRestoreGState(context);
+ endPlatformPaint();
+}
+
+} // namespace gfx
diff --git a/chrome/common/plugin_messages_internal.h b/chrome/common/plugin_messages_internal.h
index dc853c2..974de00 100644
--- a/chrome/common/plugin_messages_internal.h
+++ b/chrome/common/plugin_messages_internal.h
@@ -162,8 +162,8 @@ IPC_BEGIN_MESSAGES(Plugin)
IPC_MESSAGE_ROUTED4(PluginMsg_UpdateGeometry,
gfx::Rect /* window_rect */,
gfx::Rect /* clip_rect */,
- TransportDIB::Id /* windowless_buffer */,
- TransportDIB::Id /* background_buffer */)
+ TransportDIB::Handle /* windowless_buffer */,
+ TransportDIB::Handle /* background_buffer */)
IPC_SYNC_MESSAGE_ROUTED0_0(PluginMsg_SetFocus)
diff --git a/chrome/common/transport_dib_mac.cc b/chrome/common/transport_dib_mac.cc
index 9ce5e4f..da66085 100644
--- a/chrome/common/transport_dib_mac.cc
+++ b/chrome/common/transport_dib_mac.cc
@@ -45,7 +45,7 @@ TransportDIB* TransportDIB::Map(TransportDIB::Handle handle) {
if (!dib->shared_memory_.Map(st.st_size)) {
delete dib;
HANDLE_EINTR(close(handle.fd));
- return false;
+ return NULL;
}
dib->size_ = st.st_size;
diff --git a/chrome/plugin/plugin_main.cc b/chrome/plugin/plugin_main.cc
index fb8880f..4cc7911 100644
--- a/chrome/plugin/plugin_main.cc
+++ b/chrome/plugin/plugin_main.cc
@@ -27,6 +27,47 @@
#include "base/global_descriptors_posix.h"
#endif
+#if defined(OS_MACOSX)
+
+// To support Mac NPAPI plugins that use the Carbon event model (i.e., most
+// shipping plugins for MacOS X 10.5 and earlier), we need some way for the
+// Carbon event dispatcher to run, even though the plugin host process itself
+// does not use Carbon events. Rather than give control to the standard
+// Carbon event loop, we schedule a periodic task on the main thread which
+// empties the Carbon event queue every 20ms (chosen to match how often Safari
+// does the equivalent operation). This allows plugins to receive idle events
+// and schedule Carbon timers without swamping the CPU. If, in the future,
+// we remove support for the Carbon event model and only support the Cocoa
+// event model, this can be removed. Note that this approach does not install
+// standard application event handlers for the menubar, AppleEvents, and so on.
+// This is intentional, since the plugin process is not actually an application
+// with its own UI elements--all rendering and event handling happens via IPC
+// to the renderer process which invoked it.
+
+namespace {
+
+const int kPluginUpdateIntervalMs = 20; // 20ms = 50Hz
+
+void PluginCarbonEventTask() {
+ EventRef theEvent;
+ EventTargetRef theTarget;
+
+ theTarget = GetEventDispatcherTarget();
+
+ // Dispatch any pending events. but do not block if there are no events.
+ while (ReceiveNextEvent(0, NULL, kEventDurationNoWait,
+ true, &theEvent) == noErr) {
+ SendEventToEventTarget (theEvent, theTarget);
+ ReleaseEvent(theEvent);
+ }
+
+ MessageLoop::current()->PostDelayedTask(FROM_HERE,
+ NewRunnableFunction(PluginCarbonEventTask), kPluginUpdateIntervalMs);
+}
+
+}
+#endif
+
// main() routine for running as the plugin process.
int PluginMain(const MainFunctionParams& parameters) {
// The main thread of the plugin services IO.
@@ -37,9 +78,9 @@ int PluginMain(const MainFunctionParams& parameters) {
// Initialize the SystemMonitor
base::SystemMonitor::Start();
-#if defined(OS_WIN)
const CommandLine& parsed_command_line = parameters.command_line_;
+#if defined(OS_WIN)
sandbox::TargetServices* target_services =
parameters.sandbox_info_.TargetServices();
@@ -59,16 +100,32 @@ int PluginMain(const MainFunctionParams& parameters) {
DCHECK(sandbox_test_module);
}
}
-
+#endif
if (parsed_command_line.HasSwitch(switches::kPluginStartupDialog)) {
+#if defined(OS_WIN)
std::wstring title = chrome::kBrowserAppName;
title += L" plugin"; // makes attaching to process easier
win_util::MessageBox(NULL, L"plugin starting...", title,
MB_OK | MB_SETFOREGROUND);
- }
+#elif defined(OS_MACOSX)
+ // TODO(playmobil): In the long term, overriding this flag doesn't seem
+ // right, either use our own flag or open a dialog we can use.
+ // This is just to ease debugging in the interim.
+ LOG(WARNING) << "Plugin ("
+ << getpid()
+ << ") paused waiting for debugger to attach @ pid";
+ pause();
#else
NOTIMPLEMENTED() << " non-windows startup, plugin startup dialog etc.";
#endif
+ }
+
+#if defined(OS_MACOSX)
+ // Spin off a consumer for the native (Carbon) event stream so
+ // that plugin timers, event handlers, etc. will work properly.
+ MessageLoop::current()->PostDelayedTask(FROM_HERE,
+ NewRunnableFunction(PluginCarbonEventTask), kPluginUpdateIntervalMs);
+#endif
{
ChildProcess plugin_process(new PluginThread());
diff --git a/chrome/plugin/webplugin_delegate_stub.cc b/chrome/plugin/webplugin_delegate_stub.cc
index 542f0a3..a8a42b0 100644
--- a/chrome/plugin/webplugin_delegate_stub.cc
+++ b/chrome/plugin/webplugin_delegate_stub.cc
@@ -272,11 +272,11 @@ void WebPluginDelegateStub::OnPrint(base::SharedMemoryHandle* shared_memory,
void WebPluginDelegateStub::OnUpdateGeometry(
const gfx::Rect& window_rect,
const gfx::Rect& clip_rect,
- const TransportDIB::Id& windowless_buffer_id,
- const TransportDIB::Id& background_buffer_id) {
+ const TransportDIB::Handle& windowless_buffer,
+ const TransportDIB::Handle& background_buffer) {
webplugin_->UpdateGeometry(
window_rect, clip_rect,
- windowless_buffer_id, background_buffer_id);
+ windowless_buffer, background_buffer);
}
void WebPluginDelegateStub::OnGetPluginScriptableObject(int* route_id,
diff --git a/chrome/plugin/webplugin_delegate_stub.h b/chrome/plugin/webplugin_delegate_stub.h
index 10ac7a4..15b88a8 100644
--- a/chrome/plugin/webplugin_delegate_stub.h
+++ b/chrome/plugin/webplugin_delegate_stub.h
@@ -71,8 +71,8 @@ class WebPluginDelegateStub : public IPC::Channel::Listener,
void OnUpdateGeometry(const gfx::Rect& window_rect,
const gfx::Rect& clip_rect,
- const TransportDIB::Id& windowless_buffer,
- const TransportDIB::Id& background_buffer);
+ const TransportDIB::Handle& windowless_buffer,
+ const TransportDIB::Handle& background_buffer);
void OnGetPluginScriptableObject(int* route_id, intptr_t* npobject_ptr);
void OnSendJavaScriptStream(const std::string& url,
const std::wstring& result,
diff --git a/chrome/plugin/webplugin_proxy.cc b/chrome/plugin/webplugin_proxy.cc
index b2fe778..94f2b2f 100644
--- a/chrome/plugin/webplugin_proxy.cc
+++ b/chrome/plugin/webplugin_proxy.cc
@@ -369,11 +369,16 @@ void WebPluginProxy::Paint(const gfx::Rect& rect) {
#if defined(OS_WIN)
if (!windowless_hdc_)
return;
+#elif defined(OS_MACOSX)
+ if (!windowless_context_.get())
+ return;
+#endif
// Clear the damaged area so that if the plugin doesn't paint there we won't
// end up with the old values.
gfx::Rect offset_rect = rect;
offset_rect.Offset(delegate_->GetRect().origin());
+#if defined(OS_WIN)
if (!background_hdc_) {
FillRect(windowless_hdc_, &offset_rect.ToRECT(),
static_cast<HBRUSH>(GetStockObject(BLACK_BRUSH)));
@@ -393,6 +398,22 @@ void WebPluginProxy::Paint(const gfx::Rect& rect) {
SelectClipRgn(windowless_hdc_, NULL);
DeleteObject(clip_region);
+#elif defined(OS_MACOSX)
+ CGContextSaveGState(windowless_context_);
+ if (!background_context_.get()) {
+ CGContextSetFillColorWithColor(windowless_context_,
+ CGColorGetConstantColor(kCGColorWhite));
+ CGContextFillRect(windowless_context_, rect.ToCGRect());
+ } else {
+ scoped_cftyperef<CGImageRef> image(
+ CGBitmapContextCreateImage(background_context_));
+ scoped_cftyperef<CGImageRef> sub_image(
+ CGImageCreateWithImageInRect(image, rect.ToCGRect()));
+ CGContextDrawImage(background_context_, rect.ToCGRect(), sub_image);
+ }
+ CGContextClipToRect(windowless_context_, rect.ToCGRect());
+ delegate_->Paint(windowless_context_, rect);
+ CGContextRestoreGState(windowless_context_);
#else
// TODO(port): windowless painting.
NOTIMPLEMENTED();
@@ -402,22 +423,21 @@ void WebPluginProxy::Paint(const gfx::Rect& rect) {
void WebPluginProxy::UpdateGeometry(
const gfx::Rect& window_rect,
const gfx::Rect& clip_rect,
- const TransportDIB::Id& windowless_buffer_id,
- const TransportDIB::Id& background_buffer_id) {
- // TODO(port): this isn't correct usage of a TransportDIB; for now,
- // the caller temporarly just stuffs the handle into the HANDLE
- // field of the TransportDIB::Id so it should behave like the older
- // code.
+ const TransportDIB::Handle& windowless_buffer,
+ const TransportDIB::Handle& background_buffer) {
gfx::Rect old = delegate_->GetRect();
gfx::Rect old_clip_rect = delegate_->GetClipRect();
delegate_->UpdateGeometry(window_rect, clip_rect);
-#if defined(OS_WIN)
bool moved = old.x() != window_rect.x() || old.y() != window_rect.y();
- if (windowless_buffer_id.handle) {
+#if defined(OS_MACOSX)
+ if (windowless_buffer.fd > 0) {
+#else
+ if (windowless_buffer) {
+#endif
// The plugin's rect changed, so now we have a new buffer to draw into.
- SetWindowlessBuffer(windowless_buffer_id.handle,
- background_buffer_id.handle);
+ SetWindowlessBuffer(windowless_buffer,
+ background_buffer);
} else if (moved) {
// The plugin moved, so update our world transform.
UpdateTransform();
@@ -428,15 +448,12 @@ void WebPluginProxy::UpdateGeometry(
old_clip_rect.IsEmpty() && !damaged_rect_.IsEmpty()) {
InvalidateRect(damaged_rect_);
}
-#else
- NOTIMPLEMENTED();
-#endif
}
#if defined(OS_WIN)
void WebPluginProxy::SetWindowlessBuffer(
- const base::SharedMemoryHandle& windowless_buffer,
- const base::SharedMemoryHandle& background_buffer) {
+ const TransportDIB::Handle& windowless_buffer,
+ const TransportDIB::Handle& background_buffer) {
// Convert the shared memory handle to a handle that works in our process,
// and then use that to create an HDC.
ConvertBuffer(windowless_buffer,
@@ -501,6 +518,54 @@ void WebPluginProxy::UpdateTransform() {
xf.eM22 = 1;
SetWorldTransform(windowless_hdc_, &xf);
}
+#elif defined(OS_MACOSX)
+void WebPluginProxy::UpdateTransform() {
+ NOTIMPLEMENTED();
+}
+
+void WebPluginProxy::SetWindowlessBuffer(
+ const TransportDIB::Handle& windowless_buffer,
+ const TransportDIB::Handle& background_buffer) {
+ // Convert the shared memory handle to a handle that works in our process,
+ // and then use that to create a CGContextRef.
+ windowless_dib_.reset(TransportDIB::Map(windowless_buffer));
+ background_dib_.reset(TransportDIB::Map(background_buffer));
+ scoped_cftyperef<CGColorSpaceRef> rgb_colorspace(
+ CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB));
+ windowless_context_.reset(CGBitmapContextCreate(
+ windowless_dib_->memory(),
+ delegate_->GetRect().width(),
+ delegate_->GetRect().height(),
+ 8, 4 * delegate_->GetRect().width(),
+ rgb_colorspace,
+ kCGImageAlphaPremultipliedFirst |
+ kCGBitmapByteOrder32Host));
+ CGContextTranslateCTM(windowless_context_, 0, delegate_->GetRect().height());
+ CGContextScaleCTM(windowless_context_, 1, -1);
+ if (background_dib_.get()) {
+ background_context_.reset(CGBitmapContextCreate(
+ background_dib_->memory(),
+ delegate_->GetRect().width(),
+ delegate_->GetRect().height(),
+ 8, 4 * delegate_->GetRect().width(),
+ rgb_colorspace,
+ kCGImageAlphaPremultipliedFirst |
+ kCGBitmapByteOrder32Host));
+ CGContextTranslateCTM(background_context_, 0,
+ delegate_->GetRect().height());
+ CGContextScaleCTM(background_context_, 1, -1);
+ }
+}
+#elif defined (OS_LINUX)
+void WebPluginProxy::UpdateTransform() {
+ NOTIMPLEMENTED();
+}
+
+void WebPluginProxy::SetWindowlessBuffer(
+ const TransportDIB::Handle& windowless_buffer,
+ const TransportDIB::Handle& background_buffer) {
+ NOTIMPLEMENTED();
+}
#endif
void WebPluginProxy::CancelDocumentLoad() {
diff --git a/chrome/plugin/webplugin_proxy.h b/chrome/plugin/webplugin_proxy.h
index 103be5c..a55a3da2 100644
--- a/chrome/plugin/webplugin_proxy.h
+++ b/chrome/plugin/webplugin_proxy.h
@@ -9,6 +9,9 @@
#include "base/hash_tables.h"
#include "base/ref_counted.h"
+#if defined(OS_MACOSX)
+#include "base/scoped_cftyperef.h"
+#endif
#include "base/scoped_handle.h"
#include "base/scoped_ptr.h"
#include "base/shared_memory.h"
@@ -104,8 +107,8 @@ class WebPluginProxy : public WebPlugin {
void UpdateGeometry(const gfx::Rect& window_rect,
const gfx::Rect& clip_rect,
- const TransportDIB::Id& windowless_buffer,
- const TransportDIB::Id& background_buffer);
+ const TransportDIB::Handle& windowless_buffer,
+ const TransportDIB::Handle& background_buffer);
void CancelDocumentLoad();
@@ -129,22 +132,22 @@ class WebPluginProxy : public WebPlugin {
// Handler for sending over the paint event to the plugin.
void OnPaint(const gfx::Rect& damaged_rect);
-#if defined(OS_WIN)
// Updates the shared memory section where windowless plugins paint.
- void SetWindowlessBuffer(const base::SharedMemoryHandle& windowless_buffer,
- const base::SharedMemoryHandle& background_buffer);
+ void SetWindowlessBuffer(const TransportDIB::Handle& windowless_buffer,
+ const TransportDIB::Handle& background_buffer);
+#if defined(OS_WIN)
// Converts a shared memory section handle from the renderer process into a
// bitmap and hdc that are mapped to this process.
void ConvertBuffer(const base::SharedMemoryHandle& buffer,
ScopedHandle* shared_section,
ScopedBitmap* bitmap,
ScopedHDC* hdc);
+#endif
// Called when a plugin's origin moves, so that we can update the world
// transform of the local HDC.
void UpdateTransform();
-#endif
typedef base::hash_map<int, WebPluginResourceClient*> ResourceClientMap;
ResourceClientMap resource_clients_;
@@ -174,6 +177,11 @@ class WebPluginProxy : public WebPlugin {
ScopedHandle background_shared_section_;
ScopedBitmap background_bitmap_;
ScopedHDC background_hdc_;
+#elif defined(OS_MACOSX)
+ scoped_ptr<TransportDIB> windowless_dib_;
+ scoped_ptr<TransportDIB> background_dib_;
+ scoped_cftyperef<CGContextRef> windowless_context_;
+ scoped_cftyperef<CGContextRef> background_context_;
#endif
ScopedRunnableMethodFactory<WebPluginProxy> runnable_method_factory_;
diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc
index 5000ec1..7bd7c28 100644
--- a/chrome/renderer/render_view.cc
+++ b/chrome/renderer/render_view.cc
@@ -1762,7 +1762,6 @@ WebPluginDelegate* RenderView::CreatePluginDelegate(
const std::string& mime_type,
const std::string& clsid,
std::string* actual_mime_type) {
-#if defined(OS_WIN) || defined(OS_LINUX)
if (!PluginChannelHost::IsListening())
return NULL;
@@ -1783,13 +1782,16 @@ WebPluginDelegate* RenderView::CreatePluginDelegate(
else
mime_type_to_use = mime_type;
-#if !defined(OS_LINUX) // In-proc plugins aren't supported on Linux.
if (RenderProcess::current()->in_process_plugins()) {
+#if defined(OS_WIN) // In-proc plugins aren't supported on Linux or Mac.
return WebPluginDelegate::Create(path,
mime_type_to_use,
gfx::NativeViewFromId(host_window_));
- }
+#else
+ NOTIMPLEMENTED();
+ return NULL;
#endif
+ }
WebPluginDelegateProxy* proxy =
WebPluginDelegateProxy::Create(url, mime_type_to_use, clsid, this);
@@ -1799,11 +1801,6 @@ WebPluginDelegate* RenderView::CreatePluginDelegate(
plugin_delegates_.push_back(proxy);
return proxy;
-#else
- // TODO(port): Plugins currently not supported
- NOTIMPLEMENTED();
- return NULL;
-#endif
}
WebKit::WebMediaPlayer* RenderView::CreateWebMediaPlayer(
diff --git a/chrome/renderer/webplugin_delegate_proxy.cc b/chrome/renderer/webplugin_delegate_proxy.cc
index e07368d..c69adb9 100644
--- a/chrome/renderer/webplugin_delegate_proxy.cc
+++ b/chrome/renderer/webplugin_delegate_proxy.cc
@@ -13,6 +13,7 @@
#include "app/gfx/canvas.h"
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
+#include "base/file_util.h"
#include "base/logging.h"
#include "base/ref_counted.h"
#include "base/string_util.h"
@@ -43,6 +44,10 @@
#include "chrome/common/ipc_channel_posix.h"
#endif
+#if defined(OS_MACOSX)
+#include "base/scoped_cftyperef.h"
+#endif
+
using WebKit::WebCursorInfo;
using WebKit::WebInputEvent;
using WebKit::WebDragData;
@@ -389,17 +394,13 @@ void WebPluginDelegateProxy::UpdateGeometry(
const gfx::Rect& clip_rect) {
plugin_rect_ = window_rect;
- // Be careful to explicitly call the default constructors for these ids,
- // as they can be POD on some platforms and we want them initialized.
- TransportDIB::Id transport_store_id = TransportDIB::Id();
- TransportDIB::Id background_store_id = TransportDIB::Id();
+ bool bitmaps_changed = false;
if (windowless_) {
-#if defined(OS_WIN)
- // TODO(port): use TransportDIB instead of allocating these directly.
if (!backing_store_canvas_.get() ||
(window_rect.width() != backing_store_canvas_->getDevice()->width() ||
window_rect.height() != backing_store_canvas_->getDevice()->height())) {
+ bitmaps_changed = true;
// Create a shared memory section that the plugin paints into
// asynchronously.
ResetWindowlessBitmaps();
@@ -412,36 +413,52 @@ void WebPluginDelegateProxy::UpdateGeometry(
ResetWindowlessBitmaps();
return;
}
-
- // TODO(port): once we use TransportDIB we will properly fill in these
- // ids; for now we just fill in the HANDLE field.
- transport_store_id.handle = transport_store_->handle();
- if (background_store_.get())
- background_store_id.handle = background_store_->handle();
}
}
-#else
- // TODO(port): refactor our allocation of backing stores.
- NOTIMPLEMENTED();
+ }
+
+ IPC::Message* msg = NULL;
+#if defined(OS_POSIX)
+ // If we're using POSIX mmap'd TransportDIBs, sending the handle across
+ // IPC establishes a new mapping rather than just sending a window ID,
+ // so only do so if we've actually recreated the shared memory bitmaps.
+ if (!bitmaps_changed) {
+ msg = new PluginMsg_UpdateGeometry(instance_id_, window_rect, clip_rect,
+ TransportDIB::Handle(), TransportDIB::Handle());
+ } else
#endif
+ if (transport_store_.get() && background_store_.get()) {
+ msg = new PluginMsg_UpdateGeometry(instance_id_, window_rect, clip_rect,
+ transport_store_->handle(), background_store_->handle());
+ } else if (transport_store_.get()) {
+ msg = new PluginMsg_UpdateGeometry(instance_id_, window_rect, clip_rect,
+ transport_store_->handle(), TransportDIB::Handle());
+ } else {
+ msg = new PluginMsg_UpdateGeometry(instance_id_, window_rect, clip_rect,
+ TransportDIB::Handle(), TransportDIB::Handle());
}
- IPC::Message* msg = new PluginMsg_UpdateGeometry(
- instance_id_, window_rect, clip_rect,
- transport_store_id, background_store_id);
msg->set_unblock(true);
Send(msg);
}
-#if defined(OS_WIN)
-// Copied from render_widget.cc
-static size_t GetPaintBufSize(const gfx::Rect& rect) {
- // TODO(darin): protect against overflow
- return 4 * rect.width() * rect.height();
+#if defined(OS_MACOSX)
+static void ReleaseTransportDIB(TransportDIB *dib) {
+ if (dib) {
+ IPC::Message* msg = new ViewHostMsg_FreeTransportDIB(dib->id());
+ RenderThread::current()->Send(msg);
+ }
}
#endif
void WebPluginDelegateProxy::ResetWindowlessBitmaps() {
+#if defined(OS_MACOSX)
+ // tell the browser to relase these TransportDIBs
+ ReleaseTransportDIB(backing_store_.get());
+ ReleaseTransportDIB(transport_store_.get());
+ ReleaseTransportDIB(background_store_.get());
+#endif
+
backing_store_.reset();
transport_store_.reset();
backing_store_canvas_.reset();
@@ -452,28 +469,36 @@ void WebPluginDelegateProxy::ResetWindowlessBitmaps() {
}
bool WebPluginDelegateProxy::CreateBitmap(
- scoped_ptr<base::SharedMemory>* memory,
+ scoped_ptr<TransportDIB>* memory,
scoped_ptr<skia::PlatformCanvas>* canvas) {
-#if defined(OS_WIN)
- size_t size = GetPaintBufSize(plugin_rect_);
- scoped_ptr<base::SharedMemory> new_shared_memory(new base::SharedMemory());
- if (!new_shared_memory->Create(L"", false, true, size))
+ int width = plugin_rect_.width();
+ int height = plugin_rect_.height();
+ const size_t stride = skia::PlatformCanvas::StrideForWidth(width);
+ const size_t size = stride * height;
+#if defined(OS_LINUX)
+ static unsigned long max_size = 0;
+ if (max_size == 0) {
+ std::string contents;
+ file_util::ReadFileToString(FilePath("/proc/sys/kernel/shmmax"), &contents);
+ max_size = strtoul(contents.c_str(), NULL, 0);
+ }
+ if (size > max_size)
return false;
-
- scoped_ptr<skia::PlatformCanvas> new_canvas(new skia::PlatformCanvas);
- if (!new_canvas->initialize(plugin_rect_.width(), plugin_rect_.height(),
- true, new_shared_memory->handle())) {
+#endif
+#if defined(OS_MACOSX)
+ TransportDIB::Handle handle;
+ IPC::Message* msg = new ViewHostMsg_AllocTransportDIB(size, &handle);
+ if (!RenderThread::current()->Send(msg))
return false;
- }
-
- memory->swap(new_shared_memory);
- canvas->swap(new_canvas);
- return true;
+ if (handle.fd < 0)
+ return false;
+ memory->reset(TransportDIB::Map(handle));
#else
- // TODO(port): use TransportDIB properly.
- NOTIMPLEMENTED();
- return false;
+ static uint32 sequence_number = 0;
+ memory->reset(TransportDIB::Create(size, sequence_number++));
#endif
+ canvas->reset((*memory)->GetPlatformCanvas(width, height));
+ return true;
}
void WebPluginDelegateProxy::Paint(gfx::NativeDrawingContext context,
@@ -489,36 +514,59 @@ void WebPluginDelegateProxy::Paint(gfx::NativeDrawingContext context,
if (!windowless_)
return;
- // TODO(port): side-stepping some windowless plugin code for now.
-#if defined(OS_WIN)
// We got a paint before the plugin's coordinates, so there's no buffer to
// copy from.
- if (!backing_store_canvas_.get())
+ if (!backing_store_canvas_.get()) {
return;
+ }
// Limit the damaged rectangle to whatever is contained inside the plugin
// rectangle, as that's the rectangle that we'll bitblt to the hdc.
gfx::Rect rect = damaged_rect.Intersect(plugin_rect_);
+ gfx::Rect offset_rect = rect;
+ offset_rect.Offset(-plugin_rect_.x(), -plugin_rect_.y());
bool background_changed = false;
if (background_store_canvas_.get() && BackgroundChanged(context, rect)) {
background_changed = true;
+#if defined(OS_WIN)
HDC background_hdc =
background_store_canvas_->getTopPlatformDevice().getBitmapDC();
- BitBlt(background_hdc, rect.x()-plugin_rect_.x(), rect.y()-plugin_rect_.y(),
+ BitBlt(background_hdc, offset_rect.x(), offset_rect.y(),
rect.width(), rect.height(), context, rect.x(), rect.y(), SRCCOPY);
+#elif defined(OS_MACOSX)
+ CGContextRef background_context =
+ background_store_canvas_->getTopPlatformDevice().GetBitmapContext();
+ scoped_cftyperef<CGImageRef>
+ background_image(CGBitmapContextCreateImage(background_context));
+ scoped_cftyperef<CGImageRef> sub_image(
+ CGImageCreateWithImageInRect(background_image, offset_rect.ToCGRect()));
+ CGContextDrawImage(context, rect.ToCGRect(), sub_image);
+#else
+ NOTIMPLEMENTED();
+#endif
}
- gfx::Rect offset_rect = rect;
- offset_rect.Offset(-plugin_rect_.x(), -plugin_rect_.y());
if (background_changed || !backing_store_painted_.Contains(offset_rect)) {
Send(new PluginMsg_Paint(instance_id_, offset_rect));
CopyFromTransportToBacking(offset_rect);
}
+#if defined(OS_WIN)
HDC backing_hdc = backing_store_canvas_->getTopPlatformDevice().getBitmapDC();
BitBlt(context, rect.x(), rect.y(), rect.width(), rect.height(), backing_hdc,
- rect.x()-plugin_rect_.x(), rect.y()-plugin_rect_.y(), SRCCOPY);
+ offset_rect.x(), offset_rect.y(), SRCCOPY);
+#elif defined(OS_MACOSX)
+ CGContextRef backing_context =
+ backing_store_canvas_->getTopPlatformDevice().GetBitmapContext();
+ scoped_cftyperef<CGImageRef>
+ backing_image(CGBitmapContextCreateImage(backing_context));
+ scoped_cftyperef<CGImageRef> sub_image(
+ CGImageCreateWithImageInRect(backing_image, offset_rect.ToCGRect()));
+ CGContextDrawImage(context, rect.ToCGRect(), sub_image);
+#else
+ NOTIMPLEMENTED();
+#endif
if (invalidate_pending_) {
// Only send the PaintAck message if this paint is in response to an
@@ -527,18 +575,12 @@ void WebPluginDelegateProxy::Paint(gfx::NativeDrawingContext context,
invalidate_pending_ = false;
Send(new PluginMsg_DidPaint(instance_id_));
}
-#else
- // TODO(port): windowless plugin paint handling goes here.
- NOTIMPLEMENTED();
-#endif
}
-#if defined(OS_WIN)
-// TODO(port): this should be portable; just avoiding windowless plugins for
-// now.
bool WebPluginDelegateProxy::BackgroundChanged(
- HDC hdc,
+ gfx::NativeDrawingContext hdc,
const gfx::Rect& rect) {
+#if defined(OS_WIN)
HBITMAP hbitmap = static_cast<HBITMAP>(GetCurrentObject(hdc, OBJ_BITMAP));
if (hbitmap == NULL) {
NOTREACHED();
@@ -578,9 +620,11 @@ bool WebPluginDelegateProxy::BackgroundChanged(
return true;
}
+#else
+ NOTIMPLEMENTED();
+#endif
return false;
}
-#endif
void WebPluginDelegateProxy::Print(gfx::NativeDrawingContext context) {
base::SharedMemoryHandle shared_memory;
@@ -860,7 +904,7 @@ void WebPluginDelegateProxy::OnGetCPBrowsingContext(uint32* context) {
*context = render_view_ ? render_view_->GetCPBrowsingContext() : 0;
}
-void WebPluginDelegateProxy::PaintSadPlugin(gfx::NativeDrawingContext hdc,
+void WebPluginDelegateProxy::PaintSadPlugin(gfx::NativeDrawingContext context,
const gfx::Rect& rect) {
const int width = plugin_rect_.width();
const int height = plugin_rect_.height();
@@ -886,7 +930,7 @@ void WebPluginDelegateProxy::PaintSadPlugin(gfx::NativeDrawingContext hdc,
#if defined(OS_WIN)
skia::PlatformDevice& device = canvas.getTopPlatformDevice();
- device.drawToHDC(hdc, plugin_rect_.x(), plugin_rect_.y(), NULL);
+ device.drawToHDC(context, plugin_rect_.x(), plugin_rect_.y(), NULL);
#elif defined(OS_LINUX)
// Though conceptually we've been handed a cairo_surface_t* and we
// could've just hooked up the canvas to draw directly onto it, our
@@ -895,33 +939,46 @@ void WebPluginDelegateProxy::PaintSadPlugin(gfx::NativeDrawingContext hdc,
// TODO(evanm): revisit when we have printing hooked up, as that might
// change our usage of cairo.
skia::PlatformDevice& device = canvas.getTopPlatformDevice();
- cairo_t* cairo = cairo_create(hdc);
+ cairo_t* cairo = cairo_create(context);
cairo_surface_t* source_surface = device.beginPlatformPaint();
cairo_set_source_surface(cairo, source_surface, plugin_rect_.x(), plugin_rect_.y());
cairo_paint(cairo);
cairo_destroy(cairo);
// We have no endPlatformPaint() on the Linux PlatformDevice.
// The surface is owned by the device.
+#elif defined(OS_MACOSX)
+ canvas.getTopPlatformDevice().DrawToContext(
+ context, plugin_rect_.x(), plugin_rect_.y(), NULL);
#else
NOTIMPLEMENTED();
#endif
}
void WebPluginDelegateProxy::CopyFromTransportToBacking(const gfx::Rect& rect) {
- if (!backing_store_canvas_.get())
+ if (!backing_store_canvas_.get()) {
return;
+ }
-#if defined(OS_WIN)
// Copy the damaged rect from the transport bitmap to the backing store.
+#if defined(OS_WIN)
HDC backing = backing_store_canvas_->getTopPlatformDevice().getBitmapDC();
HDC transport = transport_store_canvas_->getTopPlatformDevice().getBitmapDC();
BitBlt(backing, rect.x(), rect.y(), rect.width(), rect.height(),
transport, rect.x(), rect.y(), SRCCOPY);
- backing_store_painted_ = backing_store_painted_.Union(rect);
+#elif defined(OS_MACOSX)
+ gfx::NativeDrawingContext backing =
+ backing_store_canvas_->getTopPlatformDevice().GetBitmapContext();
+ gfx::NativeDrawingContext transport =
+ transport_store_canvas_->getTopPlatformDevice().GetBitmapContext();
+ scoped_cftyperef<CGImageRef> image(CGBitmapContextCreateImage(transport));
+ scoped_cftyperef<CGImageRef> sub_image(
+ CGImageCreateWithImageInRect(image, rect.ToCGRect()));
+ CGContextDrawImage(backing, rect.ToCGRect(), sub_image);
#else
// TODO(port): probably some new code in TransportDIB should go here.
NOTIMPLEMENTED();
#endif
+ backing_store_painted_ = backing_store_painted_.Union(rect);
}
void WebPluginDelegateProxy::OnHandleURLRequest(
diff --git a/chrome/renderer/webplugin_delegate_proxy.h b/chrome/renderer/webplugin_delegate_proxy.h
index f7b91e8..a772384 100644
--- a/chrome/renderer/webplugin_delegate_proxy.h
+++ b/chrome/renderer/webplugin_delegate_proxy.h
@@ -13,6 +13,7 @@
#include "base/gfx/native_widget_types.h"
#include "base/ref_counted.h"
#include "chrome/common/ipc_message.h"
+#include "chrome/common/transport_dib.h"
#include "chrome/renderer/plugin_channel_host.h"
#include "googleurl/src/gurl.h"
#include "skia/ext/platform_canvas.h"
@@ -146,14 +147,10 @@ class WebPluginDelegateProxy : public WebPluginDelegate,
// Draw a graphic indicating a crashed plugin.
void PaintSadPlugin(gfx::NativeDrawingContext context, const gfx::Rect& rect);
-#if defined(OS_WIN)
- // Returns true if the given rectangle is different in the hdc and the
- // current background bitmap.
- bool BackgroundChanged(HDC hdc, const gfx::Rect& rect);
-#else
- // TODO(port): this should be portable; just avoiding windowless plugins for
- // now.
-#endif
+ // Returns true if the given rectangle is different in the native drawing
+ // context and the current background bitmap.
+ bool BackgroundChanged(gfx::NativeDrawingContext context,
+ const gfx::Rect& rect);
// Copies the given rectangle from the transport bitmap to the backing store.
void CopyFromTransportToBacking(const gfx::Rect& rect);
@@ -162,7 +159,7 @@ class WebPluginDelegateProxy : public WebPluginDelegate,
void ResetWindowlessBitmaps();
// Creates a shared memory section and canvas.
- bool CreateBitmap(scoped_ptr<base::SharedMemory>* memory,
+ bool CreateBitmap(scoped_ptr<TransportDIB>* memory,
scoped_ptr<skia::PlatformCanvas>* canvas);
RenderView* render_view_;
@@ -195,11 +192,11 @@ class WebPluginDelegateProxy : public WebPluginDelegate,
// store when we get an invalidate from it. The background bitmap is used
// for transparent plugins, as they need the backgroud data during painting.
bool transparent_;
- scoped_ptr<base::SharedMemory> backing_store_;
+ scoped_ptr<TransportDIB> backing_store_;
scoped_ptr<skia::PlatformCanvas> backing_store_canvas_;
- scoped_ptr<base::SharedMemory> transport_store_;
+ scoped_ptr<TransportDIB> transport_store_;
scoped_ptr<skia::PlatformCanvas> transport_store_canvas_;
- scoped_ptr<base::SharedMemory> background_store_;
+ scoped_ptr<TransportDIB> background_store_;
scoped_ptr<skia::PlatformCanvas> background_store_canvas_;
// This lets us know which portion of the backing store has been painted into.
gfx::Rect backing_store_painted_;
diff --git a/webkit/glue/plugins/plugin_host.cc b/webkit/glue/plugins/plugin_host.cc
index 2e1c233..40b2e1e 100644
--- a/webkit/glue/plugins/plugin_host.cc
+++ b/webkit/glue/plugins/plugin_host.cc
@@ -600,22 +600,19 @@ void NPN_InvalidateRect(NPP id, NPRect *invalidRect) {
DCHECK(plugin.get() != NULL);
if (plugin.get() && plugin->webplugin()) {
if (invalidRect) {
- if (!plugin->windowless()) {
#if defined(OS_WIN)
+ if (!plugin->windowless()) {
RECT rect = {0};
rect.left = invalidRect->left;
rect.right = invalidRect->right;
rect.top = invalidRect->top;
rect.bottom = invalidRect->bottom;
::InvalidateRect(plugin->window_handle(), &rect, FALSE);
-#elif defined(OS_MACOSX)
- NOTIMPLEMENTED();
-#else
- NOTIMPLEMENTED();
-#endif
return;
}
-
+#elif defined(OS_LINUX)
+ NOTIMPLEMENTED();
+#endif
gfx::Rect rect(invalidRect->left,
invalidRect->top,
invalidRect->right - invalidRect->left,
@@ -633,8 +630,13 @@ void NPN_InvalidateRegion(NPP id, NPRegion invalidRegion) {
//
// Similar to NPN_InvalidateRect.
- // TODO: implement me
- DLOG(INFO) << "NPN_InvalidateRegion is not implemented yet.";
+ // TODO: this is overkill--add platform-specific region handling (at the
+ // very least, fetch the region's bounding box and pass it to InvalidateRect).
+ scoped_refptr<NPAPI::PluginInstance> plugin = FindInstance(id);
+ DCHECK(plugin.get() != NULL);
+ if (plugin.get() && plugin->webplugin()) {
+ plugin->webplugin()->Invalidate();
+ }
}
void NPN_ForceRedraw(NPP id) {
@@ -652,10 +654,8 @@ void NPN_ForceRedraw(NPP id) {
// settings. The HDC settings must be restored whenever control returns
// back to the browser, either before returning from NPP_HandleEvent or
// before calling a drawing-related netscape method.
- //
- // TODO: implement me
- DLOG(INFO) << "NPN_ForceRedraw is not implemented yet.";
+ NOTIMPLEMENTED();
}
NPError NPN_GetValue(NPP id, NPNVariable variable, void *value) {
diff --git a/webkit/glue/plugins/webplugin_delegate_impl.h b/webkit/glue/plugins/webplugin_delegate_impl.h
index a6f0715..35302dc7 100644
--- a/webkit/glue/plugins/webplugin_delegate_impl.h
+++ b/webkit/glue/plugins/webplugin_delegate_impl.h
@@ -95,6 +95,7 @@ class WebPluginDelegateImpl : public WebPluginDelegate {
NPAPI::PluginInstance *instance);
~WebPluginDelegateImpl();
+#if !defined(OS_MACOSX)
//--------------------------
// used for windowed plugins
void WindowedUpdateGeometry(const gfx::Rect& window_rect,
@@ -115,6 +116,7 @@ class WebPluginDelegateImpl : public WebPluginDelegate {
// Tells the plugin about the current state of the window.
// See NPAPI NPP_SetWindow for more information.
void WindowedSetWindow();
+#endif
#if defined(OS_WIN)
// Registers the window class for our window
@@ -153,10 +155,10 @@ class WebPluginDelegateImpl : public WebPluginDelegate {
// Closes down and destroys our plugin instance.
void DestroyInstance();
+#if !defined(OS_MACOSX)
// used for windowed plugins
gfx::PluginWindowHandle windowed_handle_;
bool windowed_did_set_window_;
-#if defined(OS_WIN)
gfx::Rect windowed_last_pos_;
#endif
diff --git a/webkit/glue/plugins/webplugin_delegate_impl_mac.mm b/webkit/glue/plugins/webplugin_delegate_impl_mac.mm
index 414d635..9232fca 100644
--- a/webkit/glue/plugins/webplugin_delegate_impl_mac.mm
+++ b/webkit/glue/plugins/webplugin_delegate_impl_mac.mm
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#import <Cocoa/Cocoa.h>
+
#include "config.h"
#include "webkit/glue/plugins/webplugin_delegate_impl.h"
@@ -29,31 +31,27 @@ using WebKit::WebKeyboardEvent;
using WebKit::WebInputEvent;
using WebKit::WebMouseEvent;
-namespace {
+// Important implementation notes: The Mac definition of NPAPI, particularly
+// the distinction between windowed and windowless modes, differs from the
+// Windows and Linux definitions. Most of those differences are
+// accomodated by the WebPluginDelegate class.
-const wchar_t kWebPluginDelegateProperty[] = L"WebPluginDelegateProperty";
-const wchar_t kPluginNameAtomProperty[] = L"PluginNameAtom";
-const wchar_t kDummyActivationWindowName[] = L"DummyWindowForActivation";
-const wchar_t kPluginOrigProc[] = L"OriginalPtr";
-const wchar_t kPluginFlashThrottle[] = L"FlashThrottle";
+namespace {
-// The fastest we are willing to process WM_USER+1 events for Flash.
+// The fastest we are willing to process idle events for Flash.
// Flash can easily exceed the limits of our CPU if we don't throttle it.
// The throttle has been chosen by testing various delays and compromising
// on acceptable Flash performance and reasonable CPU consumption.
//
-// I'd like to make the throttle delay variable, based on the amount of
+// We'd like to make the throttle delay variable, based on the amount of
// time currently required to paint Flash plugins. There isn't a good
// way to count the time spent in aggregate plugin painting, however, so
// this seems to work well enough.
-const int kFlashWMUSERMessageThrottleDelayMs = 5;
+const int kFlashIdleThrottleDelayMs = 20; // 20ms (50Hz)
// The current instance of the plugin which entered the modal loop.
WebPluginDelegateImpl* g_current_plugin_instance = NULL;
-// base::LazyInstance<std::list<MSG> > g_throttle_queue(base::LINKER_INITIALIZED);
-
-
} // namespace
WebPluginDelegate* WebPluginDelegate::Create(
@@ -81,27 +79,20 @@ WebPluginDelegateImpl::WebPluginDelegateImpl(
instance_(instance),
quirks_(0),
plugin_(NULL),
- windowless_(false),
- windowed_handle_(NULL),
- windowed_did_set_window_(false),
+ // all Mac plugins are "windowless" in the Windows/X11 sense
+ windowless_(true),
windowless_needs_set_window_(true),
handle_event_depth_(0),
user_gesture_message_posted_(this),
user_gesture_msg_factory_(this) {
memset(&window_, 0, sizeof(window_));
-
- const WebPluginInfo& plugin_info = instance_->plugin_lib()->plugin_info();
- std::string filename =
- StringToLowerASCII(plugin_info.path.BaseName().value());
-
- // plugin_module_handle_ = ::GetModuleHandle(plugin_info.path.value().c_str());
}
WebPluginDelegateImpl::~WebPluginDelegateImpl() {
DestroyInstance();
- if (!windowless_)
- WindowedDestroyWindow();
+ if (cg_context_.window)
+ DisposeWindow(cg_context_.window);
}
void WebPluginDelegateImpl::PluginDestroyed() {
@@ -128,20 +119,11 @@ bool WebPluginDelegateImpl::Initialize(const GURL& url,
if (!start_result)
return false;
- windowless_ = instance_->windowless();
- if (windowless_) {
- // For windowless plugins we should set the containing window handle
- // as the instance window handle. This is what Safari does. Not having
- // a valid window handle causes subtle bugs with plugins which retreive
- // the window handle and validate the same. The window handle can be
- // retreived via NPN_GetValue of NPNVnetscapeWindow.
- // instance_->set_window_handle(parent_);
- } else {
- if (!WindowedCreatePlugin())
- return false;
- }
+ cg_context_.window = NULL;
+ window_.window = &cg_context_;
+ window_.type = NPWindowTypeDrawable;
- // plugin->SetWindow(windowed_handle_);
+ plugin->SetWindow(NULL);
plugin_url_ = url.spec();
return true;
@@ -154,18 +136,8 @@ void WebPluginDelegateImpl::DestroyInstance() {
// this before calling set_web_plugin(NULL) because the
// instance uses the helper to do the download.
instance_->CloseStreams();
-
- window_.window = NULL;
- instance_->NPP_SetWindow(&window_);
-
instance_->NPP_Destroy();
-
instance_->set_web_plugin(NULL);
-
- if (instance_->plugin_lib()) {
- // Unpatch if this is the last plugin instance.
- }
-
instance_ = 0;
}
}
@@ -173,11 +145,36 @@ void WebPluginDelegateImpl::DestroyInstance() {
void WebPluginDelegateImpl::UpdateGeometry(
const gfx::Rect& window_rect,
const gfx::Rect& clip_rect) {
- if (windowless_) {
- WindowlessUpdateGeometry(window_rect, clip_rect);
- } else {
- WindowedUpdateGeometry(window_rect, clip_rect);
+
+ if (!window_rect.IsEmpty()) {
+ NSPoint windowOffset = {0.0, 0.0};
+ Rect window_bounds;
+ window_bounds.top = window_rect.y() + windowOffset.y;
+ window_bounds.left = window_rect.x() + windowOffset.x;
+ window_bounds.bottom = window_rect.y() + window_rect.height();
+ window_bounds.right = window_rect.x() + window_rect.width();
+
+ if (!cg_context_.window) {
+ // For all plugins we create a placeholder offscreen window for the use
+ // of NPWindow. NPAPI on the Mac requires a Carbon WindowRef for the
+ // "browser window", even if we're not using the Quickdraw drawing model.
+ // Not having a valid window reference causes subtle bugs with plugins
+ // which retreive the NPWindow and validate the same. The NPWindow
+ // can be retreived via NPN_GetValue of NPNVnetscapeWindow.
+
+ WindowRef window_ref;
+ if (CreateNewWindow(kDocumentWindowClass,
+ kWindowStandardDocumentAttributes,
+ &window_bounds,
+ &window_ref) == noErr) {
+ cg_context_.window = window_ref;
+ }
+ } else {
+ SetWindowBounds(cg_context_.window, kWindowContentRgn, &window_bounds);
+ }
}
+
+ WindowlessUpdateGeometry(window_rect, clip_rect);
}
void WebPluginDelegateImpl::Paint(CGContextRef context, const gfx::Rect& rect) {
@@ -218,12 +215,6 @@ void WebPluginDelegateImpl::SendJavaScriptStream(const std::string& url,
void WebPluginDelegateImpl::DidReceiveManualResponse(
const std::string& url, const std::string& mime_type,
const std::string& headers, uint32 expected_length, uint32 last_modified) {
- if (!windowless_) {
- // Calling NPP_WriteReady before NPP_SetWindow causes movies to not load in
- // Flash. See http://b/issue?id=892174.
- DCHECK(windowed_did_set_window_);
- }
-
instance()->DidReceiveManualResponse(url, mime_type, headers,
expected_length, last_modified);
}
@@ -250,91 +241,6 @@ void WebPluginDelegateImpl::InstallMissingPlugin() {
instance()->NPP_HandleEvent(&evt);
}
-void WebPluginDelegateImpl::WindowedUpdateGeometry(
- const gfx::Rect& window_rect,
- const gfx::Rect& clip_rect) {
- if (WindowedReposition(window_rect, clip_rect) ||
- !windowed_did_set_window_) {
- // Let the plugin know that it has been moved
- WindowedSetWindow();
- }
-}
-
-bool WebPluginDelegateImpl::WindowedCreatePlugin() {
- DCHECK(!windowed_handle_);
-
- // create window
- if (windowed_handle_ == 0)
- return false;
-
- return true;
-}
-
-void WebPluginDelegateImpl::WindowedDestroyWindow() {
- if (windowed_handle_ != NULL) {
- // destroy the window
- windowed_handle_ = 0;
- }
-}
-
-bool WebPluginDelegateImpl::WindowedReposition(
- const gfx::Rect& window_rect,
- const gfx::Rect& clip_rect) {
- if (!windowed_handle_) {
- NOTREACHED();
- return false;
- }
-
- if (window_rect_ == window_rect && clip_rect_ == clip_rect)
- return false;
-
- // Clipping is handled by WebPlugin.
- if (window_rect.size() != window_rect_.size()) {
- // resize window
- }
-
- window_rect_ = window_rect;
- clip_rect_ = clip_rect;
-
- // Ensure that the entire window gets repainted.
- // invalidate entire window
-
- return true;
-}
-
-void WebPluginDelegateImpl::WindowedSetWindow() {
- if (!instance_)
- return;
-
- if (!windowed_handle_) {
- NOTREACHED();
- return;
- }
-
- // instance()->set_window_handle(windowed_handle_);
-
- DCHECK(!instance()->windowless());
-
- window_.clipRect.top = clip_rect_.y();
- window_.clipRect.left = clip_rect_.x();
- window_.clipRect.bottom = clip_rect_.y() + clip_rect_.height();
- window_.clipRect.right = clip_rect_.x() + clip_rect_.width();
- window_.height = window_rect_.height();
- window_.width = window_rect_.width();
- window_.x = window_rect_.x();
- window_.y = window_rect_.y();
-
- cg_context_.context = NULL;
- cg_context_.window = NULL;
- window_.window = &cg_context_;
- window_.type = NPWindowTypeDrawable; // NPWindowTypeWindow;
-
- // Reset this flag before entering the instance in case of side-effects.
- windowed_did_set_window_ = true;
-
- NPError err = instance()->NPP_SetWindow(&window_);
-}
-
void WebPluginDelegateImpl::WindowlessUpdateGeometry(
const gfx::Rect& window_rect,
const gfx::Rect& clip_rect) {
@@ -349,20 +255,72 @@ void WebPluginDelegateImpl::WindowlessUpdateGeometry(
if (window_rect_ != window_rect) {
window_rect_ = window_rect;
- WindowlessSetWindow(true);
-
- NPEvent pos_changed_event;
-
- instance()->NPP_HandleEvent(&pos_changed_event);
+ window_.clipRect.top = clip_rect_.y();
+ window_.clipRect.left = clip_rect_.x();
+ window_.clipRect.bottom = clip_rect_.y() + clip_rect_.height();
+ window_.clipRect.right = clip_rect_.x() + clip_rect_.width();
+ window_.height = window_rect_.height();
+ window_.width = window_rect_.width();
+ window_.x = window_rect_.x();
+ window_.y = window_rect_.y();
+ window_.type = NPWindowTypeDrawable;
+ windowless_needs_set_window_ = true;
}
}
-void WebPluginDelegateImpl::WindowlessPaint(gfx::NativeDrawingContext hdc,
+void WebPluginDelegateImpl::WindowlessPaint(gfx::NativeDrawingContext context,
const gfx::Rect& damage_rect) {
static StatsRate plugin_paint("Plugin.Paint");
StatsScope<StatsRate> scope(plugin_paint);
+
+ // We save and restore the NSGraphicsContext state in case the plugin uses
+ // Cocoa drawing.
+ [NSGraphicsContext saveGraphicsState];
+ [NSGraphicsContext setCurrentContext:[NSGraphicsContext
+ graphicsContextWithGraphicsPort:context
+ flipped:NO]];
+
+ CGContextSaveGState(context);
+ cg_context_.context = context;
+ window_.window = &cg_context_;
+ window_.type = NPWindowTypeDrawable;
+ if (windowless_needs_set_window_) {
+ Rect window_bounds;
+ window_bounds.top = window_rect_.y();
+ window_bounds.left = window_rect_.x();
+ window_bounds.bottom = window_rect_.y() + window_rect_.height();
+ window_bounds.right = window_rect_.x() + window_rect_.width();
+ if (!cg_context_.window) {
+ // For all plugins we create a placeholder offscreen window for the use
+ // of NPWindow. NPAPI on the Mac requires a Carbon WindowRef for the
+ // "browser window", even if we're not using the Quickdraw drawing model.
+ // Not having a valid window reference causes subtle bugs with plugins
+ // which retreive the NPWindow and validate the same. The NPWindow
+ // can be retreived via NPN_GetValue of NPNVnetscapeWindow.
+
+ WindowRef window_ref;
+ if (CreateNewWindow(kDocumentWindowClass,
+ kWindowStandardDocumentAttributes,
+ &window_bounds,
+ &window_ref) == noErr) {
+ cg_context_.window = window_ref;
+ }
+ } else {
+ SetWindowBounds(cg_context_.window, kWindowContentRgn, &window_bounds);
+ }
+ instance()->NPP_SetWindow(&window_);
+ windowless_needs_set_window_ = false;
+ }
NPEvent paint_event;
+ paint_event.what = updateEvt;
+ paint_event.message = reinterpret_cast<uint32>(cg_context_.window);
+ paint_event.when = TickCount();
+ paint_event.where.h = 0;
+ paint_event.where.v = 0;
+ paint_event.modifiers = 0;
instance()->NPP_HandleEvent(&paint_event);
+ CGContextRestoreGState(context);
+ [NSGraphicsContext restoreGraphicsState];
}
void WebPluginDelegateImpl::WindowlessSetWindow(bool force_set_window) {
@@ -372,8 +330,6 @@ void WebPluginDelegateImpl::WindowlessSetWindow(bool force_set_window) {
if (window_rect_.IsEmpty()) // wait for geometry to be set.
return;
- DCHECK(instance()->windowless());
-
window_.clipRect.top = clip_rect_.y();
window_.clipRect.left = clip_rect_.x();
window_.clipRect.bottom = clip_rect_.y() + clip_rect_.height();
@@ -388,25 +344,136 @@ void WebPluginDelegateImpl::WindowlessSetWindow(bool force_set_window) {
// Reset this flag before entering the instance in case of side-effects.
windowless_needs_set_window_ = false;
+ Rect window_bounds;
+ window_bounds.top = window_rect_.y();
+ window_bounds.left = window_rect_.x();
+ window_bounds.bottom = window_rect_.y() + window_rect_.height();
+ window_bounds.right = window_rect_.x() + window_rect_.width();
+ if (!cg_context_.window) {
+ // For all plugins we create a placeholder offscreen window for the use
+ // of NPWindow. NPAPI on the Mac requires a Carbon WindowRef for the
+ // "browser window", even if we're not using the Quickdraw drawing model.
+ // Not having a valid window reference causes subtle bugs with plugins
+ // which retreive the NPWindow and validate the same. The NPWindow
+ // can be retreived via NPN_GetValue of NPNVnetscapeWindow.
+
+ WindowRef window_ref;
+ if (CreateNewWindow(kDocumentWindowClass,
+ kWindowStandardDocumentAttributes,
+ &window_bounds,
+ &window_ref) == noErr) {
+ cg_context_.window = window_ref;
+ }
+ } else {
+ SetWindowBounds(cg_context_.window, kWindowContentRgn, &window_bounds);
+ }
+
NPError err = instance()->NPP_SetWindow(&window_);
DCHECK(err == NPERR_NO_ERROR);
}
void WebPluginDelegateImpl::SetFocus() {
- DCHECK(instance()->windowless());
+ NPEvent focus_event = { 0 };
+ focus_event.what = NPEventType_GetFocusEvent;
+ focus_event.when = TickCount();
+ instance()->NPP_HandleEvent(&focus_event);
+}
- NPEvent focus_event;
+static bool NPEventFromWebMouseEvent(const WebMouseEvent& event,
+ NPEvent *np_event) {
+ np_event->where.h = event.windowX;
+ np_event->where.v = event.windowY;
+
+ if (event.modifiers & WebInputEvent::ControlKey)
+ np_event->modifiers |= controlKey;
+ if (event.modifiers & WebInputEvent::ShiftKey)
+ np_event->modifiers |= shiftKey;
+
+ switch (event.type) {
+ case WebInputEvent::MouseMove:
+ case WebInputEvent::MouseLeave:
+ case WebInputEvent::MouseEnter:
+ np_event->what = NPEventType_AdjustCursorEvent;
+ return true;
+ case WebInputEvent::MouseDown:
+ switch (event.button) {
+ case WebMouseEvent::ButtonLeft:
+ case WebMouseEvent::ButtonMiddle:
+ case WebMouseEvent::ButtonRight:
+ np_event->what = mouseDown;
+ break;
+ }
+ return true;
+ case WebInputEvent::MouseUp:
+ switch (event.button) {
+ case WebMouseEvent::ButtonLeft:
+ case WebMouseEvent::ButtonMiddle:
+ case WebMouseEvent::ButtonRight:
+ np_event->what = mouseUp;
+ break;
+ }
+ return true;
+ default:
+ NOTREACHED();
+ return false;
+ }
+}
- instance()->NPP_HandleEvent(&focus_event);
+static bool NPEventFromWebKeyboardEvent(const WebKeyboardEvent& event,
+ NPEvent *np_event) {
+ np_event->message = event.nativeKeyCode;
+
+ switch (event.type) {
+ case WebInputEvent::KeyDown:
+ np_event->what = keyDown;
+ return true;
+ case WebInputEvent::KeyUp:
+ np_event->what = keyUp;
+ return true;
+ default:
+ NOTREACHED();
+ return false;
+ }
+}
+
+static bool NPEventFromWebInputEvent(const WebInputEvent& event,
+ NPEvent* np_event) {
+ switch (event.type) {
+ case WebInputEvent::MouseMove:
+ case WebInputEvent::MouseLeave:
+ case WebInputEvent::MouseEnter:
+ case WebInputEvent::MouseDown:
+ case WebInputEvent::MouseUp:
+ if (event.size < sizeof(WebMouseEvent)) {
+ NOTREACHED();
+ return false;
+ }
+ return NPEventFromWebMouseEvent(*static_cast<const WebMouseEvent*>(&event), np_event);
+ case WebInputEvent::KeyDown:
+ case WebInputEvent::KeyUp:
+ if (event.size < sizeof(WebKeyboardEvent)) {
+ NOTREACHED();
+ return false;
+ }
+ return NPEventFromWebKeyboardEvent(*static_cast<const WebKeyboardEvent*>(&event), np_event);
+ default:
+ DLOG(WARNING) << "unknown event type" << event.type;
+ return false;
+ }
}
bool WebPluginDelegateImpl::HandleInputEvent(const WebInputEvent& event,
WebCursorInfo* cursor) {
DCHECK(windowless_) << "events should only be received in windowless mode";
DCHECK(cursor != NULL);
- // TODO: convert event into a NPEvent, and call NPP_HandleEvent(np_event).
- return true;
+ NPEvent np_event = {0};
+ if (!NPEventFromWebInputEvent(event, &np_event)) {
+ return false;
+ }
+ np_event.when = TickCount();
+ bool ret = instance()->NPP_HandleEvent(&np_event) != 0;
+ return ret;
}
WebPluginResourceClient* WebPluginDelegateImpl::CreateResourceClient(