summaryrefslogtreecommitdiffstats
path: root/chrome/browser/cocoa/throbber_view.mm
blob: 26f8ec505d075d3fa616129fb4fa8bd340a393c1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#import "chrome/browser/cocoa/throbber_view.h"

#include "base/logging.h"

const float kAnimationIntervalSeconds = 0.03;  // 30ms, same as windows

@interface ThrobberView(PrivateMethods)
- (void)animate;
@end

// A very simple object that is the target for the animation timer so that
// the view isn't. We do this to avoid retain cycles as the timer
// retains its target.
@interface TimerTarget : NSObject {
 @private
  ThrobberView* throbber_;  // Weak, owns us
}
- (id)initWithThrobber:(ThrobberView*)view;
@end

@implementation TimerTarget
- (id)initWithThrobber:(ThrobberView*)view {
  if ((self = [super init])) {
    throbber_ = view;
  }
  return self;
}

- (void)animate:(NSTimer*)timer {
  [throbber_ animate];
}
@end

@implementation ThrobberView

- (id)initWithFrame:(NSRect)frame image:(NSImage*)image {
  if ((self = [super initWithFrame:frame])) {
    // Ensure that the height divides evenly into the width. Cache the
    // number of frames in the animation for later.
    NSSize imageSize = [image size];
    DCHECK(imageSize.height && imageSize.width);
    if (!imageSize.height)
      return nil;
    DCHECK((int)imageSize.width % (int)imageSize.height == 0);
    numFrames_ = (int)imageSize.width / (int)imageSize.height;
    DCHECK(numFrames_);

    // First check if we have a bitmap image rep and use it, otherwise fall
    // back to creating one.
    NSBitmapImageRep* rep = [[image representations] objectAtIndex:0];
    if (![rep isKindOfClass:[NSBitmapImageRep class]]) {
      [image lockFocus];
      NSRect imageRect = NSMakeRect(0, 0, imageSize.width, imageSize.height);
      rep = [[[NSBitmapImageRep alloc] initWithFocusedViewRect:imageRect]
                autorelease];
      [image unlockFocus];
    }
    image_.reset([[CIImage alloc] initWithBitmapImageRep:rep]);

#if 0
// TODO(pinkerton): The invalidation of the view to trigger re-draw causes
// the entire title-bar to redraw (you can see it with QuartzDebug). For some
// reason, setting isOpaque on this view, or any of its parent views, doesn't
// help. As a result, enabling this timer causes new tab to take a very long
// time on a loaded machine, crushing our perf bot when it's under load. For
// now, I'm disabling the timer so we draw the first frame of the animation,
// but nothing more. There are a couple of ways we can fix this:
// 1) Try to figure out why the invalidate is invalidating the entire title bar
// 2) Find some way to draw only the pixels we want and nothing else, but I
// don't know how we'd do that.
    // Start a timer for the animation frames.
    target_.reset([[TimerTarget alloc] initWithThrobber:self]);
    timer_ =
        [NSTimer scheduledTimerWithTimeInterval:kAnimationIntervalSeconds
                                         target:target_.get()
                                       selector:@selector(animate:)
                                       userInfo:nil
                                        repeats:YES];
#endif
  }
  return self;
}

- (void)dealloc {
  [timer_ invalidate];
  [super dealloc];
}

- (void)removeFromSuperview {
  [timer_ invalidate];
  timer_ = nil;

  [super removeFromSuperview];
}

// Called when the TimerTarget gets tickled by our timer. Increment the frame
// counter and mark as needing display.
- (void)animate {
  animationFrame_ = ++animationFrame_ % numFrames_;
  [self setNeedsDisplay:YES];
}

// Overridden to draw the appropriate frame in the image strip.
- (void)drawRect:(NSRect)rect {
  float imageDimension = [image_ extent].size.height;
  float xOffset = animationFrame_ * imageDimension;
  NSRect sourceImageRect =
      NSMakeRect(xOffset, 0, imageDimension, imageDimension);
  [image_ drawInRect:[self bounds]
             fromRect:sourceImageRect
            operation:NSCompositeSourceOver
             fraction:1.0];
}

@end