diff options
Diffstat (limited to 'WebKitExamplePlugins/NetscapeCoreAnimationMoviePlugin/MovieControllerLayer.m')
-rw-r--r-- | WebKitExamplePlugins/NetscapeCoreAnimationMoviePlugin/MovieControllerLayer.m | 355 |
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 |