Bug 829284 - Unity plugin doesn't display in HiDPI mode. r=bgirard

This commit is contained in:
Steven Michaud 2013-01-23 16:19:15 -06:00
parent c3ea912316
commit 555c9efaae
5 changed files with 97 additions and 79 deletions

View File

@ -3050,7 +3050,8 @@ PluginInstanceChild::EnsureCurrentBuffer(void)
bool avoidCGCrashes = !nsCocoaFeatures::OnMountainLionOrLater() &&
(GetQuirks() & PluginModuleChild::QUIRK_FLASH_AVOID_CGMODE_CRASHES);
caLayer = mozilla::plugins::PluginUtilsOSX::GetCGLayer(CallCGDraw, this,
avoidCGCrashes);
avoidCGCrashes,
mContentsScaleFactor);
if (!caLayer) {
PLUGIN_LOG_DEBUG(("GetCGLayer failed."));

View File

@ -25,7 +25,8 @@ void InvokeNativeEventLoop();
// Need to call back and send a cocoa draw event to the plugin.
typedef void (*DrawPluginFunc) (CGContextRef, void*, nsIntRect aUpdateRect);
void* GetCGLayer(DrawPluginFunc aFunc, void* aPluginInstance, bool aAvoidCGCrashes);
void* GetCGLayer(DrawPluginFunc aFunc, void* aPluginInstance,
bool aAvoidCGCrashes, double aContentsScaleFactor);
void ReleaseCGLayer(void* cgLayer);
void Repaint(void* cgLayer, nsIntRect aRect);

View File

@ -134,9 +134,36 @@ CGBitmapContextSetDataFunc CGBitmapContextSetDataPtr = NULL;
@end
void* mozilla::plugins::PluginUtilsOSX::GetCGLayer(DrawPluginFunc aFunc, void* aPluginInstance,
bool aAvoidCGCrashes)
bool aAvoidCGCrashes, double aContentsScaleFactor)
{
CGBridgeLayer *bridgeLayer = [[CGBridgeLayer alloc] init ];
CGBridgeLayer *bridgeLayer = [[CGBridgeLayer alloc] init];
// We need to make bridgeLayer behave properly when its superlayer changes
// size (in nsCARenderer::SetBounds()).
bridgeLayer.autoresizingMask = kCALayerWidthSizable | kCALayerHeightSizable;
bridgeLayer.needsDisplayOnBoundsChange = YES;
NSNull *nullValue = [NSNull null];
NSDictionary *actions = [NSDictionary dictionaryWithObjectsAndKeys:
nullValue, @"bounds",
nullValue, @"contents",
nullValue, @"contentsRect",
nullValue, @"position",
nil];
[bridgeLayer setStyle:[NSDictionary dictionaryWithObject:actions forKey:@"actions"]];
// For reasons that aren't clear (perhaps one or more OS bugs), we can only
// use full HiDPI resolution here if the tree is built with the 10.7 SDK or
// up. If we build with the 10.6 SDK, changing the contentsScale property
// of bridgeLayer (even to the same value) causes it to stop working (go
// blank). This doesn't happen with objects that are members of the CALayer
// class (as opposed to one of its subclasses).
#if defined(MAC_OS_X_VERSION_10_7) && \
MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
if ([bridgeLayer respondsToSelector:@selector(setContentsScale:)]) {
bridgeLayer.contentsScale = aContentsScaleFactor;
}
#endif
[bridgeLayer setDrawFunc:aFunc
pluginInstance:aPluginInstance
avoidCGCrashes:aAvoidCGCrashes];

View File

@ -25,9 +25,9 @@ enum AllowOfflineRendererEnum { ALLOW_OFFLINE_RENDERER, DISALLOW_OFFLINE_RENDERE
class nsCARenderer : public mozilla::RefCounted<nsCARenderer> {
public:
nsCARenderer() : mCARenderer(nullptr), mFBOTexture(0), mOpenGLContext(nullptr),
mCGImage(nullptr), mCGData(nullptr), mIOSurface(nullptr), mFBO(0),
mIOTexture(0),
nsCARenderer() : mCARenderer(nullptr), mWrapperCALayer(nullptr), mFBOTexture(0),
mOpenGLContext(nullptr), mCGImage(nullptr), mCGData(nullptr),
mIOSurface(nullptr), mFBO(0), mIOTexture(0),
mUnsupportedWidth(UINT32_MAX), mUnsupportedHeight(UINT32_MAX),
mAllowOfflineRenderer(DISALLOW_OFFLINE_RENDERER),
mContentsScaleFactor(1.0) {}
@ -62,7 +62,7 @@ public:
// Remove & Add the layer without destroying
// the renderer for fast back buffer swapping.
void DettachCALayer();
void DetachCALayer();
void AttachCALayer(void *aCALayer);
#ifdef DEBUG
static void SaveToDisk(MacIOSurface *surf);
@ -77,6 +77,7 @@ private:
void Destroy();
void *mCARenderer;
void *mWrapperCALayer;
GLuint mFBOTexture;
_CGLContextObject *mOpenGLContext;
CGImageRef mCGImage;

View File

@ -489,6 +489,10 @@ void nsCARenderer::Destroy() {
caRenderer.layer = nullptr;
[caRenderer release];
}
if (mWrapperCALayer) {
CALayer* wrapperLayer = (CALayer*)mWrapperCALayer;
[wrapperLayer release];
}
if (mOpenGLContext) {
if (mFBO || mIOTexture || mFBOTexture) {
// Release these resources with the context that allocated them
@ -517,6 +521,7 @@ void nsCARenderer::Destroy() {
// mCGData is deallocated by cgdata_release_callback
mCARenderer = nil;
mWrapperCALayer = nil;
mFBOTexture = 0;
mOpenGLContext = nullptr;
mCGImage = nullptr;
@ -538,9 +543,6 @@ nsresult nsCARenderer::SetupRenderer(void *aCALayer, int aWidth, int aHeight,
return NS_ERROR_FAILURE;
}
CALayer* layer = (CALayer*)aCALayer;
CARenderer* caRenderer = nullptr;
CGLPixelFormatAttribute attributes[] = {
kCGLPFAAccelerated,
kCGLPFADepthSize, (CGLPixelFormatAttribute)24,
@ -569,17 +571,27 @@ nsresult nsCARenderer::SetupRenderer(void *aCALayer, int aWidth, int aHeight,
}
::CGLDestroyPixelFormat(format);
caRenderer = [[CARenderer rendererWithCGLContext:mOpenGLContext
options:nil] retain];
mCARenderer = caRenderer;
CARenderer* caRenderer = [[CARenderer rendererWithCGLContext:mOpenGLContext
options:nil] retain];
if (caRenderer == nil) {
mUnsupportedWidth = aWidth;
mUnsupportedHeight = aHeight;
Destroy();
return NS_ERROR_FAILURE;
}
CALayer* wrapperCALayer = [[CALayer layer] retain];
if (wrapperCALayer == nil) {
[caRenderer release];
mUnsupportedWidth = aWidth;
mUnsupportedHeight = aHeight;
Destroy();
return NS_ERROR_FAILURE;
}
caRenderer.layer = layer;
mCARenderer = caRenderer;
mWrapperCALayer = wrapperCALayer;
caRenderer.layer = wrapperCALayer;
[wrapperCALayer addSublayer:(CALayer*)aCALayer];
mContentsScaleFactor = aContentsScaleFactor;
size_t intScaleFactor = ceil(mContentsScaleFactor);
SetBounds(aWidth, aHeight);
@ -696,82 +708,54 @@ nsresult nsCARenderer::SetupRenderer(void *aCALayer, int aWidth, int aHeight,
void nsCARenderer::SetBounds(int aWidth, int aHeight) {
CARenderer* caRenderer = (CARenderer*)mCARenderer;
CALayer* layer = [mCARenderer layer];
CALayer* wrapperLayer = (CALayer*)mWrapperCALayer;
NSArray* sublayers = [wrapperLayer sublayers];
CALayer* pluginLayer = (CALayer*) [sublayers objectAtIndex:0];
// Create a transaction and disable animations
// to make the position update instant.
[CATransaction begin];
NSMutableDictionary *newActions = [[NSMutableDictionary alloc] initWithObjectsAndKeys:[NSNull null], @"onOrderIn",
[NSNull null], @"onOrderOut",
[NSNull null], @"sublayers",
[NSNull null], @"contents",
[NSNull null], @"position",
[NSNull null], @"bounds",
nil];
layer.actions = newActions;
NSMutableDictionary *newActions =
[[NSMutableDictionary alloc] initWithObjectsAndKeys:
[NSNull null], @"onOrderIn",
[NSNull null], @"onOrderOut",
[NSNull null], @"sublayers",
[NSNull null], @"contents",
[NSNull null], @"position",
[NSNull null], @"bounds",
nil];
wrapperLayer.actions = newActions;
[newActions release];
// If we're in HiDPI mode, mContentsScaleFactor will (presumably) be 2.0.
// For some reason, to make things work properly in HiDPI mode we need to
// make caRenderer's 'bounds' and 'layer' different sizes -- to set 'bounds'
// to the size of 'layer's backing store. To make plugins display at HiDPI
// resolution we also need to set 'layer's contentScale to
// mContentsScaleFactor.
// to the size of 'layer's backing store. And to avoid this possibly
// confusing the plugin, we need to hide it's effects from the plugin by
// making pluginLayer (usually the CALayer* provided by the plugin) a
// sublayer of our own wrapperLayer (see bug 829284).
size_t intScaleFactor = ceil(mContentsScaleFactor);
[CATransaction setValue: [NSNumber numberWithFloat:0.0f] forKey: kCATransactionAnimationDuration];
[CATransaction setValue: (id) kCFBooleanTrue forKey: kCATransactionDisableActions];
[layer setBounds:CGRectMake(0, 0, aWidth, aHeight)];
[layer setPosition:CGPointMake(aWidth/2.0, aHeight/2.0)];
[wrapperLayer setBounds:CGRectMake(0, 0, aWidth, aHeight)];
[wrapperLayer setPosition:CGPointMake(aWidth/2.0, aHeight/2.0)];
[pluginLayer setBounds:CGRectMake(0, 0, aWidth, aHeight)];
[pluginLayer setFrame:CGRectMake(0, 0, aWidth, aHeight)];
caRenderer.bounds = CGRectMake(0, 0, aWidth * intScaleFactor, aHeight * intScaleFactor);
if (mContentsScaleFactor != 1.0) {
CGAffineTransform affineTransform = [layer affineTransform];
CGAffineTransform affineTransform = [wrapperLayer affineTransform];
affineTransform.a = mContentsScaleFactor;
affineTransform.d = mContentsScaleFactor;
affineTransform.tx = ((double)aWidth)/mContentsScaleFactor;
affineTransform.ty = ((double)aHeight)/mContentsScaleFactor;
[layer setAffineTransform:affineTransform];
if ([layer respondsToSelector:@selector(setContentsScale:)]) {
// For reasons that aren't clear (perhaps one or more OS bugs), if layer
// belongs to a subclass of CALayer we can only use full HiDPI resolution
// here if the tree is built with the 10.7 SDK or up: If we change
// layer.contentsScale (even to the same value), layer simply stops
// working (goes blank). And even if we're building with the 10.7 SDK,
// we can't use full HiDPI resolution if layer belongs to CAOpenGLLayer
// or a subclass: Changing layer.contentsScale to values higher than
// 1.0 makes it display only in the lower left part of its "box".
// We use CGBridgeLayer (a subclass of CALayer) to implement CoreGraphics
// mode for OOP plugins. Shockwave uses a subclass of CAOpenGLLayer
// (SWRenderer) to implement CoreAnimation mode. The SlingPlayer plugin
// uses another subclass of CAOpenGLLayer (CoreAnimationLayer).
#if !defined(MAC_OS_X_VERSION_10_7) || \
MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
if ([layer isMemberOfClass:[CALayer class]])
#else
if (![layer isKindOfClass:[CAOpenGLLayer class]])
#endif
{
layer.contentsScale = mContentsScaleFactor;
}
}
[wrapperLayer setAffineTransform:affineTransform];
} else {
// These settings are the default values. But they might have been
// changed as above if we were previously running in a HiDPI mode
// (i.e. if we just switched from that to a non-HiDPI mode).
[layer setAffineTransform:CGAffineTransformIdentity];
if ([layer respondsToSelector:@selector(setContentsScale:)]) {
#if !defined(MAC_OS_X_VERSION_10_7) || \
MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
if ([layer isMemberOfClass:[CALayer class]])
#else
if (![layer isKindOfClass:[CAOpenGLLayer class]])
#endif
{
layer.contentsScale = 1.0;
}
}
[wrapperLayer setAffineTransform:CGAffineTransformIdentity];
}
[CATransaction commit];
}
void nsCARenderer::SetViewport(int aWidth, int aHeight) {
@ -855,11 +839,12 @@ nsresult nsCARenderer::Render(int aWidth, int aHeight,
if (aWidth == 0 || aHeight == 0 || aContentsScaleFactor <= 0)
return NS_OK;
if (!mCARenderer) {
if (!mCARenderer || !mWrapperCALayer) {
return NS_ERROR_FAILURE;
}
CARenderer* caRenderer = (CARenderer*)mCARenderer;
CALayer* wrapperLayer = (CALayer*)mWrapperCALayer;
size_t intScaleFactor = ceil(aContentsScaleFactor);
int renderer_width = caRenderer.bounds.size.width / intScaleFactor;
int renderer_height = caRenderer.bounds.size.height / intScaleFactor;
@ -868,9 +853,10 @@ nsresult nsCARenderer::Render(int aWidth, int aHeight,
mContentsScaleFactor != aContentsScaleFactor) {
// XXX: This should be optimized to not rescale the buffer
// if we are resizing down.
// caLayer is the CALayer* provided by the plugin, so we need to preserve
// it across the call to Destroy().
CALayer* caLayer = [caRenderer layer];
// caLayer may be the CALayer* provided by the plugin, so we need to
// preserve it across the call to Destroy().
NSArray* sublayers = [wrapperLayer sublayers];
CALayer* caLayer = (CALayer*) [sublayers objectAtIndex:0];
// mIOSurface is set by AttachIOSurface(), not by SetupRenderer(). So
// since it may have been set by a prior call to AttachIOSurface(), we
// need to preserve it across the call to Destroy().
@ -1005,17 +991,19 @@ nsresult nsCARenderer::DrawSurfaceToCGContext(CGContextRef aContext,
return NS_OK;
}
void nsCARenderer::DettachCALayer() {
CARenderer* caRenderer = (CARenderer*)mCARenderer;
caRenderer.layer = nil;
void nsCARenderer::DetachCALayer() {
CALayer* wrapperLayer = (CALayer*)mWrapperCALayer;
NSArray* sublayers = [wrapperLayer sublayers];
CALayer* oldLayer = (CALayer*) [sublayers objectAtIndex:0];
[oldLayer removeFromSuperlayer];
}
void nsCARenderer::AttachCALayer(void *aCALayer) {
CARenderer* caRenderer = (CARenderer*)mCARenderer;
CALayer* caLayer = (CALayer*)aCALayer;
caRenderer.layer = caLayer;
CALayer* wrapperLayer = (CALayer*)mWrapperCALayer;
NSArray* sublayers = [wrapperLayer sublayers];
CALayer* oldLayer = (CALayer*) [sublayers objectAtIndex:0];
[oldLayer removeFromSuperlayer];
[wrapperLayer addSublayer:(CALayer*)aCALayer];
}
#ifdef DEBUG