| 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 | |
| 9 #include "base/command_line.h" | |
| 10 #include "base/logging.h" | 7 #include "base/logging.h" |
| 11 #include "base/mac/mac_util.h" | |
| 12 #include "base/mac/scoped_nsautorelease_pool.h" | |
| 13 #include "base/mac/scoped_nsobject.h" | |
| 14 #include "ui/base/ui_base_switches.h" | |
| 15 | |
| 16 @interface NSWindow (UndocumentedAPI) | |
| 17 // Normally, punching a hole in a window by painting a subview with a | |
| 18 // transparent color causes the shadow for that area to also not be present. | |
| 19 // That feature is "content has shadow", which means that shadows are effective | |
| 20 // even in the content area of the window. If, however, "content has shadow" is | |
| 21 // turned off, then the transparent area of the content casts a shadow. The one | |
| 22 // tricky part is that even if "content has shadow" is turned off, "the content" | |
| 23 // is defined as being the scanline from the leftmost opaque part to the | |
| 24 // rightmost opaque part. Therefore, to force the entire window to have a | |
| 25 // shadow, make sure that for the entire content region, there is an opaque area | |
| 26 // on the right and left edge of the window. | |
| 27 - (void)_setContentHasShadow:(BOOL)shadow; | |
| 28 @end | |
| 29 | |
| 30 @interface OpaqueView : NSView | |
| 31 @end | |
| 32 | |
| 33 namespace { | |
| 34 | |
| 35 bool CoreAnimationIsEnabled() { | |
| 36 static bool is_enabled = !CommandLine::ForCurrentProcess()->HasSwitch( | |
| 37 switches::kDisableCoreAnimation); | |
| 38 return is_enabled; | |
| 39 } | |
| 40 | |
| 41 NSComparisonResult OpaqueViewsOnTop(id view1, id view2, void* context) { | |
| 42 BOOL view_1_is_opaque_view = [view1 isKindOfClass:[OpaqueView class]]; | |
| 43 BOOL view_2_is_opaque_view = [view2 isKindOfClass:[OpaqueView class]]; | |
| 44 if (view_1_is_opaque_view && view_2_is_opaque_view) | |
| 45 return NSOrderedSame; | |
| 46 if (view_1_is_opaque_view) | |
| 47 return NSOrderedDescending; | |
| 48 if (view_2_is_opaque_view) | |
| 49 return NSOrderedAscending; | |
| 50 return NSOrderedSame; | |
| 51 } | |
| 52 | |
| 53 } // namespace | |
| 54 | |
| 55 @implementation OpaqueView | |
| 56 | |
| 57 - (void)drawRect:(NSRect)r { | |
| 58 [[NSColor blackColor] set]; | |
| 59 NSRectFill(r); | |
| 60 } | |
| 61 | |
| 62 - (void)resetCursorRects { | |
| 63 // When a view is moved relative to its peers, its cursor rects are reset. | |
| 64 // (This is an undocumented side-effect.) At that time, verify that any | |
| 65 // OpaqueViews are z-ordered in the front, and enforce it if need be. | |
| 66 | |
| 67 NSView* rootView = [self superview]; | |
| 68 DCHECK_EQ((NSView*)nil, [rootView superview]); | |
| 69 NSArray* subviews = [rootView subviews]; | |
| 70 | |
| 71 // If a window has any opaques, it will have exactly two. | |
| 72 DCHECK_EQ(2U, [[subviews indexesOfObjectsPassingTest: | |
| 73 ^(id el, NSUInteger i, BOOL *stop) { | |
| 74 return [el isKindOfClass:[OpaqueView class]]; | |
| 75 }] count]); | |
| 76 | |
| 77 NSUInteger count = [subviews count]; | |
| 78 if (count < 2) | |
| 79 return; | |
| 80 | |
| 81 if (![[subviews objectAtIndex:count - 1] isKindOfClass:[OpaqueView class]] || | |
| 82 ![[subviews objectAtIndex:count - 2] isKindOfClass:[OpaqueView class]]) { | |
| 83 // Do not sort the subviews array here and call -[NSView setSubviews:] as | |
| 84 // that causes a crash on 10.6. | |
| 85 [rootView sortSubviewsUsingFunction:OpaqueViewsOnTop context:NULL]; | |
| 86 } | |
| 87 } | |
| 88 | |
| 89 @end | |
| 90 | 8 |
| 91 @implementation UnderlayOpenGLHostingWindow | 9 @implementation UnderlayOpenGLHostingWindow |
| 92 | 10 |
| 93 - (id)initWithContentRect:(NSRect)contentRect | 11 - (id)initWithContentRect:(NSRect)contentRect |
| 94 styleMask:(NSUInteger)windowStyle | 12 styleMask:(NSUInteger)windowStyle |
| 95 backing:(NSBackingStoreType)bufferingType | 13 backing:(NSBackingStoreType)bufferingType |
| 96 defer:(BOOL)deferCreation { | 14 defer:(BOOL)deferCreation { |
| 97 // It is invalid to create windows with zero width or height. It screws things | 15 // It is invalid to create windows with zero width or height. It screws things |
| 98 // up royally: | 16 // up royally: |
| 99 // - It causes console spew: <http://crbug.com/78973> | 17 // - It causes console spew: <http://crbug.com/78973> |
| 100 // - It breaks Expose: <http://sourceforge.net/projects/heat-meteo/forums/foru
m/268087/topic/4582610> | 18 // - It breaks Expose: <http://sourceforge.net/projects/heat-meteo/forums/foru
m/268087/topic/4582610> |
| 101 // | 19 // |
| 102 // This is a banned practice | 20 // This is a banned practice |
| 103 // <http://www.chromium.org/developers/coding-style/cocoa-dos-and-donts>. Do | 21 // <http://www.chromium.org/developers/coding-style/cocoa-dos-and-donts>. Do |
| 104 // not do this. Use kWindowSizeDeterminedLater in | 22 // not do this. Use kWindowSizeDeterminedLater in |
| 105 // ui/base/cocoa/window_size_constants.h instead. | 23 // ui/base/cocoa/window_size_constants.h instead. |
| 106 // | 24 // |
| 107 // (This is checked here because UnderlayOpenGLHostingWindow is the base of | 25 // (This is checked here because UnderlayOpenGLHostingWindow is the base of |
| 108 // most Chromium windows, not because this is related to its functionality.) | 26 // most Chromium windows, not because this is related to its functionality.) |
| 109 DCHECK(!NSIsEmptyRect(contentRect)); | 27 DCHECK(!NSIsEmptyRect(contentRect)); |
| 110 if ((self = [super initWithContentRect:contentRect | 28 self = [super initWithContentRect:contentRect |
| 111 styleMask:windowStyle | 29 styleMask:windowStyle |
| 112 backing:bufferingType | 30 backing:bufferingType |
| 113 defer:deferCreation])) { | 31 defer:deferCreation]; |
| 114 if (CoreAnimationIsEnabled()) { | |
| 115 // If CoreAnimation is used, then the hole punching technique won't be | |
| 116 // used. Bail now and don't play any special games with the shadow. | |
| 117 // TODO(avi): Rip all this shadow code out once CoreAnimation can't be | |
| 118 // turned off. http://crbug.com/336554 | |
| 119 return self; | |
| 120 } | |
| 121 | |
| 122 // OpenGL-accelerated content works by punching holes in windows. Therefore | |
| 123 // all windows hosting OpenGL content must not be opaque. | |
| 124 [self setOpaque:NO]; | |
| 125 | |
| 126 if (windowStyle & NSTitledWindowMask) { | |
| 127 // Only fiddle with shadows if the window is a proper window with a | |
| 128 // title bar and all. | |
| 129 [self _setContentHasShadow:NO]; | |
| 130 | |
| 131 NSView* rootView = [[self contentView] superview]; | |
| 132 const NSRect rootBounds = [rootView bounds]; | |
| 133 | |
| 134 // On 10.7/8, the bottom corners of the window are rounded by magic at a | |
| 135 // deeper level than the NSThemeFrame, so it is OK to have the opaques | |
| 136 // go all the way to the bottom. | |
| 137 const CGFloat kTopEdgeInset = 16; | |
| 138 const CGFloat kAlphaValueJustOpaqueEnough = 0.005; | |
| 139 | |
| 140 base::scoped_nsobject<NSView> leftOpaque([[OpaqueView alloc] | |
| 141 initWithFrame:NSMakeRect(NSMinX(rootBounds), | |
| 142 NSMinY(rootBounds), | |
| 143 1, | |
| 144 NSHeight(rootBounds) - kTopEdgeInset)]); | |
| 145 [leftOpaque setAutoresizingMask:NSViewMaxXMargin | | |
| 146 NSViewHeightSizable]; | |
| 147 [leftOpaque setAlphaValue:kAlphaValueJustOpaqueEnough]; | |
| 148 [rootView addSubview:leftOpaque]; | |
| 149 | |
| 150 base::scoped_nsobject<NSView> rightOpaque([[OpaqueView alloc] | |
| 151 initWithFrame:NSMakeRect(NSMaxX(rootBounds) - 1, | |
| 152 NSMinY(rootBounds), | |
| 153 1, | |
| 154 NSHeight(rootBounds) - kTopEdgeInset)]); | |
| 155 [rightOpaque setAutoresizingMask:NSViewMinXMargin | | |
| 156 NSViewHeightSizable]; | |
| 157 [rightOpaque setAlphaValue:kAlphaValueJustOpaqueEnough]; | |
| 158 [rootView addSubview:rightOpaque]; | |
| 159 } | |
| 160 } | |
| 161 | |
| 162 return self; | 32 return self; |
| 163 } | 33 } |
| 164 | 34 |
| 165 @end | 35 @end |
| OLD | NEW |