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. 4 5#include "base/command_line.h" 6#include "base/mac/mac_util.h" 7#include "base/mac/sdk_forward_declarations.h" 8#import "chrome/browser/ui/cocoa/nsview_additions.h" 9#include "chrome/common/chrome_switches.h" 10#include "ui/base/ui_base_switches.h" 11#include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h" 12 13#include "base/logging.h" 14 15@implementation NSView (ChromeAdditions) 16 17- (CGFloat)cr_lineWidth { 18 // All shipping retina macs run at least 10.7. 19 if (![self respondsToSelector:@selector(convertSizeFromBacking:)]) 20 return 1; 21 return [self convertSizeFromBacking:NSMakeSize(1, 1)].width; 22} 23 24- (BOOL)cr_isMouseInView { 25 NSPoint mouseLoc = [[self window] mouseLocationOutsideOfEventStream]; 26 mouseLoc = [[self superview] convertPoint:mouseLoc fromView:nil]; 27 return [self hitTest:mouseLoc] == self; 28} 29 30- (BOOL)cr_isBelowView:(NSView*)otherView { 31 NSArray* subviews = [[self superview] subviews]; 32 33 NSUInteger selfIndex = [subviews indexOfObject:self]; 34 DCHECK_NE(NSNotFound, selfIndex); 35 36 NSUInteger otherIndex = [subviews indexOfObject:otherView]; 37 DCHECK_NE(NSNotFound, otherIndex); 38 39 return selfIndex < otherIndex; 40} 41 42- (BOOL)cr_isAboveView:(NSView*)otherView { 43 return ![self cr_isBelowView:otherView]; 44} 45 46- (void)cr_ensureSubview:(NSView*)subview 47 isPositioned:(NSWindowOrderingMode)place 48 relativeTo:(NSView *)otherView { 49 DCHECK(place == NSWindowAbove || place == NSWindowBelow); 50 BOOL isAbove = place == NSWindowAbove; 51 if ([[subview superview] isEqual:self] && 52 [subview cr_isAboveView:otherView] == isAbove) { 53 return; 54 } 55 56 [subview removeFromSuperview]; 57 [self addSubview:subview 58 positioned:place 59 relativeTo:otherView]; 60} 61 62- (NSColor*)cr_keyboardFocusIndicatorColor { 63 return [[NSColor keyboardFocusIndicatorColor] 64 colorWithAlphaComponent:0.5 / [self cr_lineWidth]]; 65} 66 67- (void)cr_recursivelySetNeedsDisplay:(BOOL)flag { 68 [self setNeedsDisplay:YES]; 69 for (NSView* child in [self subviews]) 70 [child cr_recursivelySetNeedsDisplay:flag]; 71} 72 73- (void)cr_setWantsLayer:(BOOL)wantsLayer { 74 if (CommandLine::ForCurrentProcess()->HasSwitch( 75 switches::kDisableCoreAnimation)) 76 return; 77 78 // Dynamically removing layers on SnowLeopard will sometimes result in 79 // crashes. Once a view has a layer on SnowLeopard, it is stuck with it. 80 // http://crbug.com/348328 81 if (!wantsLayer && base::mac::IsOSSnowLeopard()) 82 return; 83 84 [self setWantsLayer:wantsLayer]; 85} 86 87static NSView* g_ancestorBeingDrawnFrom = nil; 88static NSView* g_childBeingDrawnTo = nil; 89 90- (void)cr_drawUsingAncestor:(NSView*)ancestorView inRect:(NSRect)rect { 91 gfx::ScopedNSGraphicsContextSaveGState scopedGSState; 92 NSRect frame = [self convertRect:[self bounds] toView:ancestorView]; 93 NSAffineTransform* transform = [NSAffineTransform transform]; 94 if ([self isFlipped] == [ancestorView isFlipped]) { 95 [transform translateXBy:-NSMinX(frame) yBy:-NSMinY(frame)]; 96 } else { 97 [transform translateXBy:-NSMinX(frame) yBy:NSMaxY(frame)]; 98 [transform scaleXBy:1.0 yBy:-1.0]; 99 } 100 [transform concat]; 101 102 // This can be made robust to recursive calls, but is as of yet unneeded. 103 DCHECK(!g_ancestorBeingDrawnFrom && !g_childBeingDrawnTo); 104 g_ancestorBeingDrawnFrom = ancestorView; 105 g_childBeingDrawnTo = self; 106 [ancestorView drawRect:[ancestorView bounds]]; 107 g_childBeingDrawnTo = nil; 108 g_ancestorBeingDrawnFrom = nil; 109} 110 111- (NSView*)cr_viewBeingDrawnTo { 112 if (!g_ancestorBeingDrawnFrom) 113 return self; 114 DCHECK(g_ancestorBeingDrawnFrom == self); 115 return g_childBeingDrawnTo; 116} 117 118@end 119