When Retrier succeeds, record errors it encountered.
[chromium-blink-merge.git] / ui / base / cocoa / underlay_opengl_hosting_window.mm
blob92544c9b2bd91b69a9169a321728524d6ff036f7
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
3 // found in the LICENSE file.
5 #import "ui/base/cocoa/underlay_opengl_hosting_window.h"
7 #import <objc/runtime.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"
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
28 @interface OpaqueView : NSView
29 @end
31 namespace {
33 NSComparisonResult OpaqueViewsOnTop(id view1, id view2, void* context) {
34   BOOL view_1_is_opaque_view = [view1 isKindOfClass:[OpaqueView class]];
35   BOOL view_2_is_opaque_view = [view2 isKindOfClass:[OpaqueView class]];
36   if (view_1_is_opaque_view && view_2_is_opaque_view)
37     return NSOrderedSame;
38   if (view_1_is_opaque_view)
39     return NSOrderedDescending;
40   if (view_2_is_opaque_view)
41     return NSOrderedAscending;
42   return NSOrderedSame;
45 }  // namespace
47 @implementation OpaqueView
49 - (void)drawRect:(NSRect)r {
50   [[NSColor blackColor] set];
51   NSRectFill(r);
54 - (void)resetCursorRects {
55   // When a view is moved relative to its peers, its cursor rects are reset.
56   // (This is an undocumented side-effect.) At that time, verify that any
57   // OpaqueViews are z-ordered in the front, and enforce it if need be.
59   NSView* rootView = [[[self window] contentView] superview];
60   NSArray* subviews = [rootView subviews];
62   // If a window has any opaques, it will have exactly two.
63   DCHECK_EQ(2U, [[subviews indexesOfObjectsPassingTest:
64       ^(id el, NSUInteger i, BOOL *stop) {
65         return [el isKindOfClass:[OpaqueView class]];
66       }] count]);
68   NSUInteger count = [subviews count];
69   if (count < 2)
70     return;
72   if (![[subviews objectAtIndex:count - 1] isKindOfClass:[OpaqueView class]] ||
73       ![[subviews objectAtIndex:count - 2] isKindOfClass:[OpaqueView class]]) {
74     // Do not sort the subviews array here and call -[NSView setSubviews:] as
75     // that causes a crash on 10.6.
76     [rootView sortSubviewsUsingFunction:OpaqueViewsOnTop context:NULL];
77   }
80 @end
82 @implementation UnderlayOpenGLHostingWindow
84 - (id)initWithContentRect:(NSRect)contentRect
85                 styleMask:(NSUInteger)windowStyle
86                   backing:(NSBackingStoreType)bufferingType
87                     defer:(BOOL)deferCreation {
88   // It is invalid to create windows with zero width or height. It screws things
89   // up royally:
90   // - It causes console spew: <http://crbug.com/78973>
91   // - It breaks Expose: <http://sourceforge.net/projects/heat-meteo/forums/forum/268087/topic/4582610>
92   //
93   // This is a banned practice
94   // <http://www.chromium.org/developers/coding-style/cocoa-dos-and-donts>. Do
95   // not do this. Use kWindowSizeDeterminedLater in
96   // ui/base/cocoa/window_size_constants.h instead.
97   //
98   // (This is checked here because UnderlayOpenGLHostingWindow is the base of
99   // most Chromium windows, not because this is related to its functionality.)
100   DCHECK(!NSIsEmptyRect(contentRect));
101   if ((self = [super initWithContentRect:contentRect
102                                styleMask:windowStyle
103                                  backing:bufferingType
104                                    defer:deferCreation])) {
105     // OpenGL-accelerated content works by punching holes in windows. Therefore
106     // all windows hosting OpenGL content must not be opaque.
107     [self setOpaque:NO];
109     if (windowStyle & NSTitledWindowMask) {
110       // Only fiddle with shadows if the window is a proper window with a
111       // title bar and all.
112       [self _setContentHasShadow:NO];
114       NSView* rootView = [[self contentView] superview];
115       const NSRect rootBounds = [rootView bounds];
117       // On 10.7/8, the bottom corners of the window are rounded by magic at a
118       // deeper level than the NSThemeFrame, so it is OK to have the opaques
119       // go all the way to the bottom.
120       const CGFloat kTopEdgeInset = 16;
121       const CGFloat kAlphaValueJustOpaqueEnough = 0.005;
123       scoped_nsobject<NSView> leftOpaque([[OpaqueView alloc] initWithFrame:
124           NSMakeRect(NSMinX(rootBounds), NSMinY(rootBounds),
125                      1, NSHeight(rootBounds) - kTopEdgeInset)]);
126       [leftOpaque setAutoresizingMask:NSViewMaxXMargin |
127                                       NSViewHeightSizable];
128       [leftOpaque setAlphaValue:kAlphaValueJustOpaqueEnough];
129       [rootView addSubview:leftOpaque];
131       scoped_nsobject<NSView> rightOpaque([[OpaqueView alloc] initWithFrame:
132           NSMakeRect(NSMaxX(rootBounds) - 1, NSMinY(rootBounds),
133                      1, NSHeight(rootBounds) - kTopEdgeInset)]);
134       [rightOpaque setAutoresizingMask:NSViewMinXMargin |
135                                        NSViewHeightSizable];
136       [rightOpaque setAlphaValue:kAlphaValueJustOpaqueEnough];
137       [rootView addSubview:rightOpaque];
138     }
139   }
141   return self;
144 @end