15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/mac/mac_util.h"
646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "base/mac/sdk_forward_declarations.h"
71320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#import "ui/base/cocoa/nsview_additions.h"
8a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/logging.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)@implementation NSView (ChromeAdditions)
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)- (CGFloat)cr_lineWidth {
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // All shipping retina macs run at least 10.7.
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (![self respondsToSelector:@selector(convertSizeFromBacking:)])
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 1;
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return [self convertSizeFromBacking:NSMakeSize(1, 1)].width;
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)- (BOOL)cr_isMouseInView {
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NSPoint mouseLoc = [[self window] mouseLocationOutsideOfEventStream];
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mouseLoc = [[self superview] convertPoint:mouseLoc fromView:nil];
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return [self hitTest:mouseLoc] == self;
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)- (BOOL)cr_isBelowView:(NSView*)otherView {
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  NSArray* subviews = [[self superview] subviews];
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  NSUInteger selfIndex = [subviews indexOfObject:self];
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_NE(NSNotFound, selfIndex);
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  NSUInteger otherIndex = [subviews indexOfObject:otherView];
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_NE(NSNotFound, otherIndex);
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return selfIndex < otherIndex;
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)- (BOOL)cr_isAboveView:(NSView*)otherView {
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return ![self cr_isBelowView:otherView];
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)- (void)cr_ensureSubview:(NSView*)subview
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            isPositioned:(NSWindowOrderingMode)place
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              relativeTo:(NSView *)otherView {
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(place == NSWindowAbove || place == NSWindowBelow);
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  BOOL isAbove = place == NSWindowAbove;
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if ([[subview superview] isEqual:self] &&
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      [subview cr_isAboveView:otherView] == isAbove) {
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  [subview removeFromSuperview];
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  [self addSubview:subview
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        positioned:place
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        relativeTo:otherView];
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)- (NSColor*)cr_keyboardFocusIndicatorColor {
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return [[NSColor keyboardFocusIndicatorColor]
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      colorWithAlphaComponent:0.5 / [self cr_lineWidth]];
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
64eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch- (void)cr_recursivelySetNeedsDisplay:(BOOL)flag {
65eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  [self setNeedsDisplay:YES];
66eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  for (NSView* child in [self subviews])
67eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    [child cr_recursivelySetNeedsDisplay:flag];
68eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
69eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
70a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)static NSView* g_ancestorBeingDrawnFrom = nil;
71a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)static NSView* g_childBeingDrawnTo = nil;
72a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
73a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)- (void)cr_drawUsingAncestor:(NSView*)ancestorView inRect:(NSRect)rect {
74a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  gfx::ScopedNSGraphicsContextSaveGState scopedGSState;
75a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  NSRect frame = [self convertRect:[self bounds] toView:ancestorView];
76a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  NSAffineTransform* transform = [NSAffineTransform transform];
77a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if ([self isFlipped] == [ancestorView isFlipped]) {
78a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    [transform translateXBy:-NSMinX(frame) yBy:-NSMinY(frame)];
79a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  } else {
80a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    [transform translateXBy:-NSMinX(frame) yBy:NSMaxY(frame)];
81a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    [transform scaleXBy:1.0 yBy:-1.0];
82a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
83a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  [transform concat];
84a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
85a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // This can be made robust to recursive calls, but is as of yet unneeded.
86a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(!g_ancestorBeingDrawnFrom && !g_childBeingDrawnTo);
87a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  g_ancestorBeingDrawnFrom = ancestorView;
88a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  g_childBeingDrawnTo = self;
89a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  [ancestorView drawRect:[ancestorView bounds]];
90a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  g_childBeingDrawnTo = nil;
91a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  g_ancestorBeingDrawnFrom = nil;
92a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
93a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
94a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)- (NSView*)cr_viewBeingDrawnTo {
95a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!g_ancestorBeingDrawnFrom)
96a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return self;
97a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(g_ancestorBeingDrawnFrom == self);
98a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return g_childBeingDrawnTo;
995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)@end
102