| OLD | NEW | 
|    1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |    1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 
|    2 // Use of this source code is governed by a BSD-style license that can be |    2 // Use of this source code is governed by a BSD-style license that can be | 
|    3 // found in the LICENSE file. |    3 // found in the LICENSE file. | 
|    4  |    4  | 
|    5 #import "ui/base/cocoa/underlay_opengl_hosting_window.h" |    5 #import "ui/base/cocoa/underlay_opengl_hosting_window.h" | 
|    6  |    6  | 
 |    7 #import <objc/runtime.h> | 
 |    8  | 
|    7 #include "base/logging.h" |    9 #include "base/logging.h" | 
 |   10 #include "base/mac/mac_util.h" | 
 |   11 #include "base/mac/scoped_nsautorelease_pool.h" | 
 |   12 #include "base/memory/scoped_nsobject.h" | 
 |   13  | 
 |   14 @interface NSWindow (UndocumentedAPI) | 
 |   15 // Normally, punching a hole in a window by painting a subview with a | 
 |   16 // transparent color causes the shadow for that area to also not be present. | 
 |   17 // That feature is "content has shadow", which means that shadows are effective | 
 |   18 // even in the content area of the window. If, however, "content has shadow" is | 
 |   19 // turned off, then the transparent area of the content casts a shadow. The one | 
 |   20 // tricky part is that even if "content has shadow" is turned off, "the content" | 
 |   21 // is defined as being the scanline from the leftmost opaque part to the | 
 |   22 // rightmost opaque part.  Therefore, to force the entire window to have a | 
 |   23 // shadow, make sure that for the entire content region, there is an opaque area | 
 |   24 // on the right and left edge of the window. | 
 |   25 - (void)_setContentHasShadow:(BOOL)shadow; | 
 |   26 @end | 
 |   27  | 
 |   28 @interface OpaqueView : NSView | 
 |   29 @end | 
 |   30  | 
 |   31 @implementation OpaqueView | 
 |   32 - (void)drawRect:(NSRect)r { | 
 |   33   [[NSColor blackColor] set]; | 
 |   34   NSRectFill(r); | 
 |   35 } | 
 |   36 @end | 
 |   37  | 
 |   38 namespace { | 
 |   39  | 
 |   40 NSComparisonResult OpaqueViewsOnTop(id view1, id view2, void* context) { | 
 |   41   BOOL view_1_is_opaque_view = [view1 isKindOfClass:[OpaqueView class]]; | 
 |   42   BOOL view_2_is_opaque_view = [view2 isKindOfClass:[OpaqueView class]]; | 
 |   43   if (view_1_is_opaque_view && view_2_is_opaque_view) | 
 |   44     return NSOrderedSame; | 
 |   45   if (view_1_is_opaque_view) | 
 |   46     return NSOrderedDescending; | 
 |   47   if (view_2_is_opaque_view) | 
 |   48     return NSOrderedAscending; | 
 |   49   return NSOrderedSame; | 
 |   50 } | 
 |   51  | 
 |   52 void RootDidAddSubview(id self, SEL _cmd, NSView* subview) { | 
 |   53   if (![[self window] isKindOfClass:[UnderlayOpenGLHostingWindow class]]) | 
 |   54     return; | 
 |   55  | 
 |   56   // Make sure the opaques are on top. | 
 |   57   [self sortSubviewsUsingFunction:OpaqueViewsOnTop context:NULL]; | 
 |   58 } | 
 |   59  | 
 |   60 }  // namespace | 
|    8  |   61  | 
|    9 @implementation UnderlayOpenGLHostingWindow |   62 @implementation UnderlayOpenGLHostingWindow | 
|   10  |   63  | 
|   11 - (void)underlaySurfaceAdded { |   64 + (void)load { | 
|   12   DCHECK_GE(underlaySurfaceCount_, 0); |   65   base::mac::ScopedNSAutoreleasePool pool; | 
|   13   ++underlaySurfaceCount_; |  | 
|   14  |   66  | 
|   15   // We're having the OpenGL surface render under the window, so the window |   67   // On 10.8+ the background for textured windows are no longer drawn by | 
|   16   // needs to be not opaque. |   68   // NSGrayFrame, and NSThemeFrame is used instead <http://crbug.com/114745>. | 
|   17   if (underlaySurfaceCount_ == 1) |   69   Class borderViewClass = NSClassFromString( | 
|   18     [self setOpaque:NO]; |   70       base::mac::IsOSMountainLionOrLater() ? @"NSThemeFrame" : @"NSGrayFrame"); | 
 |   71   DCHECK(borderViewClass); | 
 |   72   if (!borderViewClass) return; | 
 |   73  | 
 |   74   // Install callback for added views. | 
 |   75   Method m = class_getInstanceMethod([NSView class], @selector(didAddSubview:)); | 
 |   76   DCHECK(m); | 
 |   77   if (m) { | 
 |   78     BOOL didAdd = class_addMethod(borderViewClass, | 
 |   79                                   @selector(didAddSubview:), | 
 |   80                                   reinterpret_cast<IMP>(&RootDidAddSubview), | 
 |   81                                   method_getTypeEncoding(m)); | 
 |   82     DCHECK(didAdd); | 
 |   83   } | 
|   19 } |   84 } | 
|   20  |   85  | 
|   21 - (void)underlaySurfaceRemoved { |   86 - (id)initWithContentRect:(NSRect)contentRect | 
|   22   --underlaySurfaceCount_; |   87                 styleMask:(NSUInteger)windowStyle | 
|   23   DCHECK_GE(underlaySurfaceCount_, 0); |   88                   backing:(NSBackingStoreType)bufferingType | 
 |   89                     defer:(BOOL)deferCreation { | 
 |   90   if ((self = [super initWithContentRect:contentRect | 
 |   91                                styleMask:windowStyle | 
 |   92                                  backing:bufferingType | 
 |   93                                    defer:deferCreation])) { | 
 |   94     // The invisible opaque area technique only works > 10.5. Fortunately, hole | 
 |   95     // punching is used only when IOSurfaces are used to transport, and that's | 
 |   96     // also only on > 10.5. Also, don't mess around with things if it's not a | 
 |   97     // proper window with a title bar and all. | 
 |   98     if (base::mac::IsOSSnowLeopardOrLater() && | 
 |   99         windowStyle && NSTitledWindowMask) { | 
 |  100       [self setOpaque:NO]; | 
 |  101       [self _setContentHasShadow:NO]; | 
|   24  |  102  | 
|   25   if (underlaySurfaceCount_ == 0) |  103       NSView* rootView = [[self contentView] superview]; | 
|   26     [self setOpaque:YES]; |  104       const NSRect rootBounds = [rootView bounds]; | 
 |  105  | 
 |  106       const CGFloat kEdgeInset = 16; | 
 |  107       const CGFloat kAlphaValueJustOpaqueEnough = 0.002; | 
 |  108  | 
 |  109       scoped_nsobject<NSView> leftOpaque([[OpaqueView alloc] initWithFrame: | 
 |  110           NSMakeRect(NSMinX(rootBounds), NSMinY(rootBounds) + kEdgeInset, | 
 |  111                      1, NSHeight(rootBounds) - 2 * kEdgeInset)]); | 
 |  112       [leftOpaque setAutoresizingMask:NSViewMaxXMargin | NSViewHeightSizable]; | 
 |  113       [leftOpaque setAlphaValue:kAlphaValueJustOpaqueEnough]; | 
 |  114       [rootView addSubview:leftOpaque]; | 
 |  115  | 
 |  116       scoped_nsobject<NSView> rightOpaque([[OpaqueView alloc] initWithFrame: | 
 |  117           NSMakeRect(NSMaxX(rootBounds) - 1, NSMinY(rootBounds) + kEdgeInset, | 
 |  118                      1, NSHeight(rootBounds) - 2 * kEdgeInset)]); | 
 |  119       [rightOpaque setAutoresizingMask:NSViewMinXMargin | NSViewHeightSizable]; | 
 |  120       [rightOpaque setAlphaValue:kAlphaValueJustOpaqueEnough]; | 
 |  121       [rootView addSubview:rightOpaque]; | 
 |  122     } | 
 |  123   } | 
 |  124  | 
 |  125   return self; | 
|   27 } |  126 } | 
|   28  |  127  | 
|   29 @end |  128 @end | 
| OLD | NEW |