diff -r 000000000000 -r dd21522fd290 webengine/osswebengine/WebKit/WebInspector/WebNodeHighlight.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/webengine/osswebengine/WebKit/WebInspector/WebNodeHighlight.m Mon Mar 30 12:54:55 2009 +0300 @@ -0,0 +1,266 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "WebNodeHighlight.h" +#import "WebNodeHighlightView.h" +#import "WebNSViewExtras.h" + +#import + +#define FADE_ANIMATION_DURATION 0.2 + +@interface WebNodeHighlightFadeInAnimation : NSAnimation +@end + +@interface WebNodeHighlight (FileInternal) +- (NSRect)_computeHighlightWindowFrame; +- (void)_repositionHighlightWindow; +- (void)_animateFadeIn:(WebNodeHighlightFadeInAnimation *)animation; +@end + +@implementation WebNodeHighlightFadeInAnimation + +- (void)setCurrentProgress:(NSAnimationProgress)progress +{ + [super setCurrentProgress:progress]; + [(WebNodeHighlight *)[self delegate] _animateFadeIn:self]; +} + +@end + +@implementation WebNodeHighlight + +- (id)initWithTargetView:(NSView *)targetView +{ + self = [super init]; + if (!self) + return nil; + + _targetView = [targetView retain]; + + int styleMask = NSBorderlessWindowMask; + NSRect contentRect = [NSWindow contentRectForFrameRect:[self _computeHighlightWindowFrame] styleMask:styleMask]; + _highlightWindow = [[NSWindow alloc] initWithContentRect:contentRect styleMask:styleMask backing:NSBackingStoreBuffered defer:NO]; + [_highlightWindow setBackgroundColor:[NSColor clearColor]]; + [_highlightWindow setOpaque:NO]; + [_highlightWindow setIgnoresMouseEvents:YES]; + [_highlightWindow setReleasedWhenClosed:NO]; + + _highlightView = [[WebNodeHighlightView alloc] initWithWebNodeHighlight:self]; + [_highlightView setFractionFadedIn:0.0]; + [_highlightWindow setContentView:_highlightView]; + [_highlightView release]; + + return self; +} + +- (void)setHighlightedNode:(DOMNode *)node +{ + id old = _highlightNode; + _highlightNode = [node retain]; + [old release]; +} + +- (DOMNode *)highlightedNode +{ + return _highlightNode; +} + +- (void)dealloc +{ + // FIXME: Bad to do all this work in dealloc. What about under GC? + + [self detachHighlight]; + + ASSERT(!_highlightWindow); + ASSERT(!_targetView); + + [_fadeInAnimation setDelegate:nil]; + [_fadeInAnimation stopAnimation]; + [_fadeInAnimation release]; + + [_highlightNode release]; + + [super dealloc]; +} + +- (void)attachHighlight +{ + ASSERT(_targetView); + ASSERT([_targetView window]); + ASSERT(_highlightWindow); + + // Disable screen updates so the highlight moves in sync with the view. + [[_targetView window] disableScreenUpdatesUntilFlush]; + [[_targetView window] addChildWindow:_highlightWindow ordered:NSWindowAbove]; + + // Observe both frame-changed and bounds-changed notifications because either one could leave + // the highlight incorrectly positioned with respect to the target view. We need to do this for + // the entire superview hierarchy to handle scrolling, bars coming and going, etc. + // (without making concrete assumptions about the view hierarchy). + NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; + for (NSView *v = _targetView; v; v = [v superview]) { + [notificationCenter addObserver:self selector:@selector(_repositionHighlightWindow) name:NSViewFrameDidChangeNotification object:v]; + [notificationCenter addObserver:self selector:@selector(_repositionHighlightWindow) name:NSViewBoundsDidChangeNotification object:v]; + } + + if (_delegate && [_delegate respondsToSelector:@selector(didAttachWebNodeHighlight:)]) + [_delegate didAttachWebNodeHighlight:self]; +} + +- (id)delegate +{ + return _delegate; +} + +- (void)detachHighlight +{ + if (!_highlightWindow) { + ASSERT(!_targetView); + return; + } + + if (_delegate && [_delegate respondsToSelector:@selector(willDetachWebNodeHighlight:)]) + [_delegate willDetachWebNodeHighlight:self]; + + // FIXME: is this necessary while detaching? Should test. + [[_targetView window] disableScreenUpdatesUntilFlush]; + + NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; + [notificationCenter removeObserver:self name:NSViewFrameDidChangeNotification object:nil]; + [notificationCenter removeObserver:self name:NSViewBoundsDidChangeNotification object:nil]; + + [[_highlightWindow parentWindow] removeChildWindow:_highlightWindow]; + + [_highlightWindow release]; + _highlightWindow = nil; + + [_targetView release]; + _targetView = nil; + + // We didn't retain _highlightView, but we do need to tell it to forget about us, so it doesn't + // try to send our delegate messages after we've been dealloc'ed, e.g. + [_highlightView detachFromWebNodeHighlight]; + _highlightView = nil; +} + +- (void)show +{ + ASSERT(!_fadeInAnimation); + if (_fadeInAnimation || [_highlightView fractionFadedIn] == 1.0) + return; + + _fadeInAnimation = [[WebNodeHighlightFadeInAnimation alloc] initWithDuration:FADE_ANIMATION_DURATION animationCurve:NSAnimationEaseInOut]; + [_fadeInAnimation setAnimationBlockingMode:NSAnimationNonblocking]; + [_fadeInAnimation setDelegate:self]; + [_fadeInAnimation startAnimation]; +} + +- (void)hide +{ + [_highlightView setFractionFadedIn:0.0]; +} + +- (void)animationDidEnd:(NSAnimation *)animation +{ + ASSERT(animation == _fadeInAnimation); + [_fadeInAnimation release]; + _fadeInAnimation = nil; +} + +- (BOOL)ignoresMouseEvents +{ + ASSERT(_highlightWindow); + return [_highlightWindow ignoresMouseEvents]; +} + +- (WebNodeHighlightView *)highlightView +{ + return _highlightView; +} + +- (void)setDelegate:(id)delegate +{ + // The delegate is not retained, as usual in Cocoa. + _delegate = delegate; +} + +- (void)setHolesNeedUpdateInTargetViewRect:(NSRect)rect +{ + ASSERT(_targetView); + + [_highlightView setHolesNeedUpdateInRect:[_targetView _web_convertRect:rect toView:_highlightView]]; + + // Redraw highlight view immediately so it updates in sync with the target view + // if we called disableScreenUpdatesUntilFlush on the target view earlier. This + // is especially visible when resizing the window. + [_highlightView displayIfNeeded]; +} + +- (void)setIgnoresMouseEvents:(BOOL)newValue +{ + ASSERT(_highlightWindow); + [_highlightWindow setIgnoresMouseEvents:newValue]; +} + +- (NSView *)targetView +{ + return _targetView; +} + +@end + +@implementation WebNodeHighlight (FileInternal) + +- (NSRect)_computeHighlightWindowFrame +{ + ASSERT(_targetView); + ASSERT([_targetView window]); + + NSRect highlightWindowFrame = [_targetView convertRect:[_targetView visibleRect] toView:nil]; + highlightWindowFrame.origin = [[_targetView window] convertBaseToScreen:highlightWindowFrame.origin]; + + return highlightWindowFrame; +} + +- (void)_repositionHighlightWindow +{ + ASSERT([_targetView window]); + + // Disable screen updates so the highlight moves in sync with the view. + [[_targetView window] disableScreenUpdatesUntilFlush]; + + [_highlightWindow setFrame:[self _computeHighlightWindowFrame] display:YES]; +} + +- (void)_animateFadeIn:(WebNodeHighlightFadeInAnimation *)animation +{ + [_highlightView setFractionFadedIn:[animation currentValue]]; +} + +@end