summaryrefslogtreecommitdiffstats
path: root/WebKitExamplePlugins/NetscapeCoreAnimationMoviePlugin/MovieControllerLayer.m
diff options
context:
space:
mode:
Diffstat (limited to 'WebKitExamplePlugins/NetscapeCoreAnimationMoviePlugin/MovieControllerLayer.m')
-rw-r--r--WebKitExamplePlugins/NetscapeCoreAnimationMoviePlugin/MovieControllerLayer.m355
1 files changed, 355 insertions, 0 deletions
diff --git a/WebKitExamplePlugins/NetscapeCoreAnimationMoviePlugin/MovieControllerLayer.m b/WebKitExamplePlugins/NetscapeCoreAnimationMoviePlugin/MovieControllerLayer.m
new file mode 100644
index 0000000..171dab4
--- /dev/null
+++ b/WebKitExamplePlugins/NetscapeCoreAnimationMoviePlugin/MovieControllerLayer.m
@@ -0,0 +1,355 @@
+/*
+ File: MovieControllerLayer.m
+
+ Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
+ Inc. ("Apple") in consideration of your agreement to the following
+ terms, and your use, installation, modification or redistribution of
+ this Apple software constitutes acceptance of these terms. If you do
+ not agree with these terms, please do not use, install, modify or
+ redistribute this Apple software.
+
+ In consideration of your agreement to abide by the following terms, and
+ subject to these terms, Apple grants you a personal, non-exclusive
+ license, under Apple's copyrights in this original Apple software (the
+ "Apple Software"), to use, reproduce, modify and redistribute the Apple
+ Software, with or without modifications, in source and/or binary forms;
+ provided that if you redistribute the Apple Software in its entirety and
+ without modifications, you must retain this notice and the following
+ text and disclaimers in all such redistributions of the Apple Software.
+ Neither the name, trademarks, service marks or logos of Apple Inc. may
+ be used to endorse or promote products derived from the Apple Software
+ without specific prior written permission from Apple. Except as
+ expressly stated in this notice, no other rights or licenses, express or
+ implied, are granted by Apple herein, including but not limited to any
+ patent rights that may be infringed by your derivative works or by other
+ works in which the Apple Software may be incorporated.
+
+ The Apple Software is provided by Apple on an "AS IS" basis. APPLE
+ MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
+ THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
+ FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
+ OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
+
+ IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
+ MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
+ AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
+ STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+ Copyright (C) 2009 Apple Inc. All Rights Reserved.
+
+ */
+
+#import "MovieControllerLayer.h"
+
+#import <QTKit/QTKit.h>
+
+@interface MovieControllerLayer ()
+- (BOOL)_isPlaying;
+- (NSTimeInterval)_currentTime;
+- (NSTimeInterval)_duration;
+@end
+
+@implementation MovieControllerLayer
+
+static CGImageRef createImageNamed(NSString *name)
+{
+ NSURL *url = [[NSBundle bundleForClass:[MovieControllerLayer class]] URLForResource:name withExtension:@"tiff"];
+
+ if (!url)
+ return NULL;
+
+ CGImageSourceRef imageSource = CGImageSourceCreateWithURL((CFURLRef)url, NULL);
+ if (!imageSource)
+ return NULL;
+
+ CGImageRef image = CGImageSourceCreateImageAtIndex(imageSource, 0, NULL);
+ CFRelease(imageSource);
+
+ return image;
+}
+
+- (id)init
+{
+ if (self = [super init]) {
+ self.needsDisplayOnBoundsChange = YES;
+ self.frame = CGRectMake(0, 0, 0, 25);
+ self.autoresizingMask = kCALayerWidthSizable;
+
+ _playImage = createImageNamed(@"Play");
+ _pauseImage = createImageNamed(@"Pause");
+ _sliderTrackLeft = createImageNamed(@"SliderTrackLeft");
+ _sliderTrackRight = createImageNamed(@"SliderTrackRight");
+ _sliderTrackCenter = createImageNamed(@"SliderTrackCenter");
+
+ _thumb = createImageNamed(@"Thumb");
+ }
+
+ return self;
+}
+
+- (void)dealloc
+{
+ CGImageRelease(_playImage);
+ CGImageRelease(_pauseImage);
+
+ CGImageRelease(_sliderTrackLeft);
+ CGImageRelease(_sliderTrackRight);
+ CGImageRelease(_sliderTrackCenter);
+
+ CGImageRelease(_thumb);
+
+ [self setMovie:nil];
+ [_updateTimeTimer invalidate];
+
+ [super dealloc];
+}
+
+#pragma mark Drawing
+
+- (CGRect)_playPauseButtonRect
+{
+ return CGRectMake(0, 0, 25, 25);
+}
+
+- (CGRect)_sliderRect
+{
+ CGFloat sliderYPosition = (self.bounds.size.height - CGImageGetHeight(_sliderTrackLeft)) / 2.0;
+ CGFloat playPauseButtonWidth = [self _playPauseButtonRect].size.width;
+
+ return CGRectMake(playPauseButtonWidth, sliderYPosition,
+ self.bounds.size.width - playPauseButtonWidth - 7, CGImageGetHeight(_sliderTrackLeft));
+}
+
+- (CGRect)_sliderThumbRect
+{
+ CGRect sliderRect = [self _sliderRect];
+
+ CGFloat fraction = 0.0;
+ if (_movie)
+ fraction = [self _currentTime] / [self _duration];
+
+ CGFloat x = fraction * (CGRectGetWidth(sliderRect) - CGImageGetWidth(_thumb));
+
+ return CGRectMake(CGRectGetMinX(sliderRect) + x, CGRectGetMinY(sliderRect) - 1,
+ CGImageGetWidth(_thumb), CGImageGetHeight(_thumb));
+}
+
+- (CGRect)_innerSliderRect
+{
+ return CGRectInset([self _sliderRect], CGRectGetWidth([self _sliderThumbRect]) / 2, 0);
+}
+
+- (void)_drawPlayPauseButtonInContext:(CGContextRef)context
+{
+ CGContextDrawImage(context, [self _playPauseButtonRect], [self _isPlaying] ? _pauseImage : _playImage);
+}
+
+- (void)_drawSliderInContext:(CGContextRef)context
+{
+ // Draw the thumb
+ CGRect sliderThumbRect = [self _sliderThumbRect];
+ CGContextDrawImage(context, sliderThumbRect, _thumb);
+
+ CGRect sliderRect = [self _sliderRect];
+
+ // Draw left part
+ CGRect sliderLeftTrackRect = CGRectMake(CGRectGetMinX(sliderRect), CGRectGetMinY(sliderRect),
+ CGImageGetWidth(_sliderTrackLeft), CGImageGetHeight(_sliderTrackLeft));
+ CGContextDrawImage(context, sliderLeftTrackRect, _sliderTrackLeft);
+
+ // Draw center part
+ CGRect sliderCenterTrackRect = CGRectInset(sliderRect, CGImageGetWidth(_sliderTrackLeft), 0);
+ CGContextDrawImage(context, sliderCenterTrackRect, _sliderTrackCenter);
+
+ // Draw right part
+ CGRect sliderRightTrackRect = CGRectMake(CGRectGetMaxX(sliderCenterTrackRect), CGRectGetMinY(sliderRect),
+ CGImageGetWidth(_sliderTrackRight), CGImageGetHeight(_sliderTrackRight));
+ CGContextDrawImage(context, sliderRightTrackRect, _sliderTrackRight);
+
+}
+
+- (void)drawInContext:(CGContextRef)context
+{
+ CGContextSaveGState(context);
+ CGContextSetFillColorWithColor(context, CGColorGetConstantColor(kCGColorBlack));
+ CGContextFillRect(context, self.bounds);
+ CGContextRestoreGState(context);
+
+ [self _drawPlayPauseButtonInContext:context];
+ [self _drawSliderInContext:context];
+}
+
+#pragma mark Movie handling
+
+- (NSTimeInterval)_currentTime
+{
+ if (!_movie)
+ return 0;
+
+ QTTime time = [_movie currentTime];
+ NSTimeInterval timeInterval;
+ if (!QTGetTimeInterval(time, &timeInterval))
+ return 0;
+
+ return timeInterval;
+}
+
+- (NSTimeInterval)_duration
+{
+ if (!_movie)
+ return 0;
+
+ QTTime time = [_movie duration];
+ NSTimeInterval timeInterval;
+ if (!QTGetTimeInterval(time, &timeInterval))
+ return 0;
+
+ return timeInterval;
+}
+
+- (BOOL)_isPlaying
+{
+ return [_movie rate] != 0.0;
+}
+
+- (void)_updateTime:(NSTimer *)timer
+{
+ [self setNeedsDisplay];
+}
+
+- (void)_rateDidChange:(NSNotification *)notification
+{
+ float rate = [[[notification userInfo] objectForKey:QTMovieRateDidChangeNotificationParameter] floatValue];
+
+ if (rate == 0.0) {
+ [_updateTimeTimer invalidate];
+ _updateTimeTimer = nil;
+ } else
+ _updateTimeTimer = [NSTimer scheduledTimerWithTimeInterval:0.035 target:self selector:@selector(_updateTime:) userInfo:nil repeats:YES];
+
+ [self setNeedsDisplay];
+}
+
+- (void)_timeDidChange:(NSNotification *)notification
+{
+ [self setNeedsDisplay];
+}
+
+- (id<CAAction>)actionForKey:(NSString *)key
+{
+ // We don't want to animate the contents of the layer.
+ if ([key isEqualToString:@"contents"])
+ return nil;
+
+ return [super actionForKey:key];
+}
+
+- (void)setMovie:(QTMovie *)movie
+{
+ if (_movie == movie)
+ return;
+
+ if (_movie) {
+ [[NSNotificationCenter defaultCenter] removeObserver:self
+ name:QTMovieRateDidChangeNotification
+ object:_movie];
+ [[NSNotificationCenter defaultCenter] removeObserver:self
+ name:QTMovieTimeDidChangeNotification
+ object:_movie];
+ [_movie release];
+ }
+
+ _movie = [movie retain];
+
+ if (_movie) {
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(_rateDidChange:)
+ name:QTMovieRateDidChangeNotification
+ object:_movie];
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(_timeDidChange:)
+ name:QTMovieTimeDidChangeNotification
+ object:_movie];
+ [self setNeedsDisplay];
+ }
+
+}
+
+# pragma mark Event handling
+
+- (void)_setNewTimeForThumbCenterX:(CGFloat)centerX
+{
+ CGRect innerRect = [self _innerSliderRect];
+
+ CGFloat fraction = (centerX - CGRectGetMinX(innerRect)) / CGRectGetWidth(innerRect);
+ if (fraction > 1.0)
+ fraction = 1.0;
+ else if (fraction < 0.0)
+ fraction = 0.0;
+
+ NSTimeInterval newTime = fraction * [self _duration];
+
+ [_movie setCurrentTime:QTMakeTimeWithTimeInterval(newTime)];
+ [self setNeedsDisplay];
+}
+
+- (void)handleMouseDown:(CGPoint)point
+{
+ if (!_movie)
+ return;
+
+ if (CGRectContainsPoint([self _sliderRect], point)) {
+ _wasPlayingBeforeMouseDown = [self _isPlaying];
+ _isScrubbing = YES;
+
+ [_movie stop];
+ if (CGRectContainsPoint([self _sliderThumbRect], point))
+ _mouseDownXDelta = point.x - CGRectGetMidX([self _sliderThumbRect]);
+ else {
+ [self _setNewTimeForThumbCenterX:point.x];
+ _mouseDownXDelta = 0;
+ }
+ }
+}
+
+- (void)handleMouseUp:(CGPoint)point
+{
+ if (!_movie)
+ return;
+
+ if (_isScrubbing) {
+ _isScrubbing = NO;
+ _mouseDownXDelta = 0;
+
+ if (_wasPlayingBeforeMouseDown)
+ [_movie play];
+ return;
+ }
+
+ if (CGRectContainsPoint([self _playPauseButtonRect], point)) {
+ if ([self _isPlaying])
+ [_movie stop];
+ else
+ [_movie play];
+ return;
+ }
+}
+
+- (void)handleMouseDragged:(CGPoint)point
+{
+ if (!_movie)
+ return;
+
+ if (!_isScrubbing)
+ return;
+
+ point.x -= _mouseDownXDelta;
+
+ [self _setNewTimeForThumbCenterX:point.x];
+}
+
+@end