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) { | |
jbates
2012/04/10 17:54:00
If view1 and view2 are both OpaqueView, then:
Op
Avi (use Gerrit)
2012/04/10 18:34:46
Probably a good idea.
| |
41 if ([view1 isKindOfClass:[OpaqueView class]]) | |
42 return NSOrderedDescending; | |
43 if ([view2 isKindOfClass:[OpaqueView class]]) | |
44 return NSOrderedAscending; | |
45 return NSOrderedSame; | |
46 } | |
47 | |
48 void RootDidAddSubview(id self, SEL _cmd, NSView* subview) { | |
49 // Make sure the opaques are on top. | |
50 [self sortSubviewsUsingFunction:OpaqueViewsOnTop context:NULL]; | |
51 } | |
52 | |
53 } // namespace | |
8 | 54 |
9 @implementation UnderlayOpenGLHostingWindow | 55 @implementation UnderlayOpenGLHostingWindow |
10 | 56 |
11 - (void)underlaySurfaceAdded { | 57 + (void)load { |
12 DCHECK_GE(underlaySurfaceCount_, 0); | 58 base::mac::ScopedNSAutoreleasePool pool; |
13 ++underlaySurfaceCount_; | |
14 | 59 |
15 // We're having the OpenGL surface render under the window, so the window | 60 // On 10.8+ the background for textured windows are no longer drawn by |
16 // needs to be not opaque. | 61 // NSGrayFrame, and NSThemeFrame is used instead <http://crbug.com/114745>. |
17 if (underlaySurfaceCount_ == 1) | 62 Class borderViewClass = NSClassFromString( |
18 [self setOpaque:NO]; | 63 base::mac::IsOSMountainLionOrLater() ? @"NSThemeFrame" : @"NSGrayFrame"); |
64 DCHECK(borderViewClass); | |
65 if (!borderViewClass) return; | |
66 | |
67 // Install callback for added views. | |
68 Method m = class_getInstanceMethod([NSView class], @selector(didAddSubview:)); | |
69 DCHECK(m); | |
70 if (m) { | |
71 BOOL didAdd = class_addMethod(borderViewClass, | |
72 @selector(didAddSubview:), | |
73 reinterpret_cast<IMP>(&RootDidAddSubview), | |
74 method_getTypeEncoding(m)); | |
75 DCHECK(didAdd); | |
76 } | |
19 } | 77 } |
20 | 78 |
21 - (void)underlaySurfaceRemoved { | 79 - (id)initWithContentRect:(NSRect)contentRect |
22 --underlaySurfaceCount_; | 80 styleMask:(NSUInteger)windowStyle |
23 DCHECK_GE(underlaySurfaceCount_, 0); | 81 backing:(NSBackingStoreType)bufferingType |
82 defer:(BOOL)deferCreation { | |
83 if ((self = [super initWithContentRect:contentRect | |
84 styleMask:windowStyle | |
85 backing:bufferingType | |
86 defer:deferCreation])) { | |
87 // The invisible opaque area technique only works > 10.5. Fortunately, hole | |
88 // punching is used only when IOSurfaces are used to transport, and that's | |
89 // also only on > 10.5. | |
90 if (base::mac::IsOSSnowLeopardOrLater()) { | |
91 [self setOpaque:NO]; | |
92 [self _setContentHasShadow:NO]; | |
24 | 93 |
25 if (underlaySurfaceCount_ == 0) | 94 NSView* rootView = [[self contentView] superview]; |
26 [self setOpaque:YES]; | 95 NSRect rootBounds = [rootView bounds]; |
96 | |
97 const CGFloat kEdgeInset = 16; | |
98 | |
99 scoped_nsobject<NSView> leftOpaque( | |
100 [[OpaqueView alloc] initWithFrame: | |
101 NSMakeRect(NSMinX(rootBounds), NSMinY(rootBounds) + kEdgeInset, | |
102 1, NSHeight(rootBounds) - 2 * kEdgeInset)]); | |
103 [rootView addSubview:leftOpaque]; | |
104 [leftOpaque setAutoresizingMask:NSViewMaxXMargin|NSViewHeightSizable]; | |
105 [leftOpaque setAlphaValue:0.002f]; | |
jbates
2012/04/10 17:54:00
Is this chosen on purpose to round to zero when co
Avi (use Gerrit)
2012/04/10 18:34:46
You ascribe to me far more cleverness than is dese
| |
106 | |
107 scoped_nsobject<NSView> rightOpaque([[OpaqueView alloc] initWithFrame: | |
108 NSMakeRect(NSMaxX(rootBounds) - 1, NSMinY(rootBounds) + kEdgeInset, | |
109 1, NSHeight(rootBounds) - 2 * kEdgeInset)]); | |
110 [rootView addSubview:rightOpaque]; | |
111 [rightOpaque setAutoresizingMask:NSViewMinXMargin|NSViewHeightSizable]; | |
112 [rightOpaque setAlphaValue:0.002f]; | |
113 } | |
114 } | |
115 | |
116 return self; | |
27 } | 117 } |
28 | 118 |
29 @end | 119 @end |
OLD | NEW |