blob: 26db55db192e3f43bd5b3381ce6f9d39185c27cd [file] [log] [blame]
// Copyright (c) 2010 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.
#ifndef NP_NO_QUICKDRAW
#include "webkit/plugins/npapi/quickdraw_drawing_manager_mac.h"
#include "webkit/plugins/npapi/coregraphics_private_symbols_mac.h"
// Turn off GCC warnings about deprecated functions (since QuickDraw is a
// deprecated API). According to the GCC documentation, this can only be done
// per file, not pushed and popped like some options can be.
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
namespace webkit {
namespace npapi {
QuickDrawDrawingManager::QuickDrawDrawingManager()
: plugin_window_(NULL), target_context_(NULL), fast_path_enabled_(false),
current_port_(NULL), target_world_(NULL), plugin_world_(NULL) {}
QuickDrawDrawingManager::~QuickDrawDrawingManager() {
DestroyGWorlds();
}
void QuickDrawDrawingManager::SetFastPathEnabled(bool enabled) {
if (fast_path_enabled_ == enabled)
return;
fast_path_enabled_ = enabled;
if (enabled) {
if (!target_world_)
UpdateGWorlds();
// Copy our last window snapshot into our new source, since the plugin
// may not repaint everything.
CopyGWorldBits(target_world_, plugin_world_, plugin_size_);
current_port_ = plugin_world_;
} else {
current_port_ = GetWindowPort(plugin_window_);
}
}
void QuickDrawDrawingManager::SetTargetContext(CGContextRef context,
const gfx::Size& plugin_size) {
target_context_ = context;
if (plugin_size != plugin_size_) {
plugin_size_ = plugin_size;
// Pitch the old GWorlds, since they are the wrong size now.
DestroyGWorlds();
if (fast_path_enabled_)
UpdateGWorlds();
}
}
void QuickDrawDrawingManager::SetPluginWindow(WindowRef window) {
plugin_window_ = window;
if (!fast_path_enabled_)
current_port_ = GetWindowPort(window);
}
void QuickDrawDrawingManager::UpdateContext() {
if (fast_path_enabled_)
CopyGWorldBits(plugin_world_, target_world_, plugin_size_);
else
ScrapeWindow(plugin_window_, target_context_, plugin_size_);
}
bool QuickDrawDrawingManager::IsFastPathEnabled() {
return fast_path_enabled_;
}
void QuickDrawDrawingManager::MakePortCurrent() {
if (fast_path_enabled_)
SetGWorld(current_port_, NULL);
else
SetPort(current_port_);
}
void QuickDrawDrawingManager::DestroyGWorlds() {
if (plugin_world_) {
DisposeGWorld(plugin_world_);
plugin_world_ = NULL;
}
if (target_world_) {
DisposeGWorld(target_world_);
target_world_ = NULL;
}
}
void QuickDrawDrawingManager::UpdateGWorlds() {
DestroyGWorlds();
if (!target_context_)
return;
Rect window_bounds = {
0, 0, plugin_size_.height(), plugin_size_.width()
};
// Create a GWorld pointing at the same bits as our target context.
if (target_context_) {
NewGWorldFromPtr(
&target_world_, k32BGRAPixelFormat, &window_bounds, NULL, NULL, 0,
static_cast<Ptr>(CGBitmapContextGetData(target_context_)),
static_cast<SInt32>(CGBitmapContextGetBytesPerRow(target_context_)));
}
// Create a GWorld for the plugin to paint into whenever it wants; since
// QuickDraw plugins don't draw at known times, they can't be allowed to draw
// directly into the shared memory.
NewGWorld(&plugin_world_, k32ARGBPixelFormat, &window_bounds,
NULL, NULL, kNativeEndianPixMap);
if (fast_path_enabled_)
current_port_ = plugin_world_;
}
void QuickDrawDrawingManager::ScrapeWindow(WindowRef window,
CGContextRef target_context,
const gfx::Size& plugin_size) {
if (!target_context)
return;
CGRect window_bounds = CGRectMake(0, 0,
plugin_size.width(),
plugin_size.height());
CGWindowID window_id = HIWindowGetCGWindowID(window);
CGContextSaveGState(target_context);
CGContextTranslateCTM(target_context, 0, plugin_size.height());
CGContextScaleCTM(target_context, 1.0, -1.0);
CGContextCopyWindowCaptureContentsToRect(target_context, window_bounds,
_CGSDefaultConnection(),
window_id, 0);
CGContextRestoreGState(target_context);
}
void QuickDrawDrawingManager::CopyGWorldBits(GWorldPtr source, GWorldPtr dest,
const gfx::Size& plugin_size) {
if (!(source && dest))
return;
Rect window_bounds = { 0, 0, plugin_size.height(), plugin_size.width() };
PixMapHandle source_pixmap = GetGWorldPixMap(source);
if (LockPixels(source_pixmap)) {
PixMapHandle dest_pixmap = GetGWorldPixMap(dest);
if (LockPixels(dest_pixmap)) {
SetGWorld(dest, NULL);
// Set foreground and background colors to avoid "colorizing" the image.
ForeColor(blackColor);
BackColor(whiteColor);
CopyBits(reinterpret_cast<BitMap*>(*source_pixmap),
reinterpret_cast<BitMap*>(*dest_pixmap),
&window_bounds, &window_bounds, srcCopy, NULL);
UnlockPixels(dest_pixmap);
}
UnlockPixels(source_pixmap);
}
}
} // namespace npapi
} // namespace webkit
#endif // !NP_NO_QUICKDRAW