webengine/osswebengine/WebKit/WebInspector/WebNodeHighlight.m
changeset 0 dd21522fd290
equal deleted inserted replaced
-1:000000000000 0:dd21522fd290
       
     1 /*
       
     2  * Copyright (C) 2007 Apple Inc.  All rights reserved.
       
     3  *
       
     4  * Redistribution and use in source and binary forms, with or without
       
     5  * modification, are permitted provided that the following conditions
       
     6  * are met:
       
     7  *
       
     8  * 1.  Redistributions of source code must retain the above copyright
       
     9  *     notice, this list of conditions and the following disclaimer. 
       
    10  * 2.  Redistributions in binary form must reproduce the above copyright
       
    11  *     notice, this list of conditions and the following disclaimer in the
       
    12  *     documentation and/or other materials provided with the distribution. 
       
    13  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
       
    14  *     its contributors may be used to endorse or promote products derived
       
    15  *     from this software without specific prior written permission. 
       
    16  *
       
    17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
       
    18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
       
    19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
       
    20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
       
    21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
       
    22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
       
    23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
       
    24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
       
    25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
       
    26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
       
    27  */
       
    28 
       
    29 #import "WebNodeHighlight.h"
       
    30 #import "WebNodeHighlightView.h"
       
    31 #import "WebNSViewExtras.h"
       
    32 
       
    33 #import <JavaScriptCore/Assertions.h>
       
    34 
       
    35 #define FADE_ANIMATION_DURATION 0.2
       
    36 
       
    37 @interface WebNodeHighlightFadeInAnimation : NSAnimation
       
    38 @end
       
    39 
       
    40 @interface WebNodeHighlight (FileInternal)
       
    41 - (NSRect)_computeHighlightWindowFrame;
       
    42 - (void)_repositionHighlightWindow;
       
    43 - (void)_animateFadeIn:(WebNodeHighlightFadeInAnimation *)animation;
       
    44 @end
       
    45 
       
    46 @implementation WebNodeHighlightFadeInAnimation
       
    47 
       
    48 - (void)setCurrentProgress:(NSAnimationProgress)progress
       
    49 {
       
    50     [super setCurrentProgress:progress];
       
    51     [(WebNodeHighlight *)[self delegate] _animateFadeIn:self];
       
    52 }
       
    53 
       
    54 @end
       
    55 
       
    56 @implementation WebNodeHighlight
       
    57 
       
    58 - (id)initWithTargetView:(NSView *)targetView
       
    59 {
       
    60     self = [super init];
       
    61     if (!self)
       
    62         return nil;
       
    63 
       
    64     _targetView = [targetView retain];
       
    65 
       
    66     int styleMask = NSBorderlessWindowMask;
       
    67     NSRect contentRect = [NSWindow contentRectForFrameRect:[self _computeHighlightWindowFrame] styleMask:styleMask];
       
    68     _highlightWindow = [[NSWindow alloc] initWithContentRect:contentRect styleMask:styleMask backing:NSBackingStoreBuffered defer:NO];
       
    69     [_highlightWindow setBackgroundColor:[NSColor clearColor]];
       
    70     [_highlightWindow setOpaque:NO];
       
    71     [_highlightWindow setIgnoresMouseEvents:YES];
       
    72     [_highlightWindow setReleasedWhenClosed:NO];
       
    73 
       
    74     _highlightView = [[WebNodeHighlightView alloc] initWithWebNodeHighlight:self];
       
    75     [_highlightView setFractionFadedIn:0.0];
       
    76     [_highlightWindow setContentView:_highlightView];
       
    77     [_highlightView release];
       
    78 
       
    79     return self;
       
    80 }
       
    81 
       
    82 - (void)setHighlightedNode:(DOMNode *)node
       
    83 {
       
    84     id old = _highlightNode;
       
    85     _highlightNode = [node retain];
       
    86     [old release];
       
    87 }
       
    88 
       
    89 - (DOMNode *)highlightedNode
       
    90 {
       
    91     return _highlightNode;
       
    92 }
       
    93 
       
    94 - (void)dealloc
       
    95 {
       
    96     // FIXME: Bad to do all this work in dealloc. What about under GC?
       
    97 
       
    98     [self detachHighlight];
       
    99 
       
   100     ASSERT(!_highlightWindow);
       
   101     ASSERT(!_targetView);
       
   102 
       
   103     [_fadeInAnimation setDelegate:nil];
       
   104     [_fadeInAnimation stopAnimation];
       
   105     [_fadeInAnimation release];
       
   106 
       
   107     [_highlightNode release];
       
   108 
       
   109     [super dealloc];
       
   110 }
       
   111 
       
   112 - (void)attachHighlight
       
   113 {
       
   114     ASSERT(_targetView);
       
   115     ASSERT([_targetView window]);
       
   116     ASSERT(_highlightWindow);
       
   117 
       
   118     // Disable screen updates so the highlight moves in sync with the view.
       
   119     [[_targetView window] disableScreenUpdatesUntilFlush];
       
   120     [[_targetView window] addChildWindow:_highlightWindow ordered:NSWindowAbove];
       
   121 
       
   122     // Observe both frame-changed and bounds-changed notifications because either one could leave
       
   123     // the highlight incorrectly positioned with respect to the target view. We need to do this for
       
   124     // the entire superview hierarchy to handle scrolling, bars coming and going, etc. 
       
   125     // (without making concrete assumptions about the view hierarchy).
       
   126     NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
       
   127     for (NSView *v = _targetView; v; v = [v superview]) {
       
   128         [notificationCenter addObserver:self selector:@selector(_repositionHighlightWindow) name:NSViewFrameDidChangeNotification object:v];
       
   129         [notificationCenter addObserver:self selector:@selector(_repositionHighlightWindow) name:NSViewBoundsDidChangeNotification object:v];
       
   130     }
       
   131 
       
   132     if (_delegate && [_delegate respondsToSelector:@selector(didAttachWebNodeHighlight:)])
       
   133         [_delegate didAttachWebNodeHighlight:self];
       
   134 }
       
   135 
       
   136 - (id)delegate
       
   137 {
       
   138     return _delegate;
       
   139 }
       
   140 
       
   141 - (void)detachHighlight
       
   142 {
       
   143     if (!_highlightWindow) {
       
   144         ASSERT(!_targetView);
       
   145         return;
       
   146     }
       
   147 
       
   148     if (_delegate && [_delegate respondsToSelector:@selector(willDetachWebNodeHighlight:)])
       
   149         [_delegate willDetachWebNodeHighlight:self];
       
   150 
       
   151     // FIXME: is this necessary while detaching? Should test.
       
   152     [[_targetView window] disableScreenUpdatesUntilFlush];
       
   153 
       
   154     NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
       
   155     [notificationCenter removeObserver:self name:NSViewFrameDidChangeNotification object:nil];
       
   156     [notificationCenter removeObserver:self name:NSViewBoundsDidChangeNotification object:nil];
       
   157 
       
   158     [[_highlightWindow parentWindow] removeChildWindow:_highlightWindow];
       
   159 
       
   160     [_highlightWindow release];
       
   161     _highlightWindow = nil;
       
   162 
       
   163     [_targetView release];
       
   164     _targetView = nil;
       
   165 
       
   166     // We didn't retain _highlightView, but we do need to tell it to forget about us, so it doesn't
       
   167     // try to send our delegate messages after we've been dealloc'ed, e.g.
       
   168     [_highlightView detachFromWebNodeHighlight];
       
   169     _highlightView = nil;
       
   170 }
       
   171 
       
   172 - (void)show
       
   173 {
       
   174     ASSERT(!_fadeInAnimation);
       
   175     if (_fadeInAnimation || [_highlightView fractionFadedIn] == 1.0)
       
   176         return;
       
   177 
       
   178     _fadeInAnimation = [[WebNodeHighlightFadeInAnimation alloc] initWithDuration:FADE_ANIMATION_DURATION animationCurve:NSAnimationEaseInOut];
       
   179     [_fadeInAnimation setAnimationBlockingMode:NSAnimationNonblocking];
       
   180     [_fadeInAnimation setDelegate:self];
       
   181     [_fadeInAnimation startAnimation];
       
   182 }
       
   183 
       
   184 - (void)hide
       
   185 {
       
   186     [_highlightView setFractionFadedIn:0.0];
       
   187 }
       
   188 
       
   189 - (void)animationDidEnd:(NSAnimation *)animation
       
   190 {
       
   191     ASSERT(animation == _fadeInAnimation);
       
   192     [_fadeInAnimation release];
       
   193     _fadeInAnimation = nil;
       
   194 }
       
   195 
       
   196 - (BOOL)ignoresMouseEvents
       
   197 {
       
   198     ASSERT(_highlightWindow);
       
   199     return [_highlightWindow ignoresMouseEvents];
       
   200 }
       
   201 
       
   202 - (WebNodeHighlightView *)highlightView
       
   203 {
       
   204     return _highlightView;
       
   205 }
       
   206 
       
   207 - (void)setDelegate:(id)delegate
       
   208 {
       
   209     // The delegate is not retained, as usual in Cocoa.
       
   210     _delegate = delegate;
       
   211 }
       
   212 
       
   213 - (void)setHolesNeedUpdateInTargetViewRect:(NSRect)rect
       
   214 {
       
   215     ASSERT(_targetView);
       
   216 
       
   217     [_highlightView setHolesNeedUpdateInRect:[_targetView _web_convertRect:rect toView:_highlightView]];
       
   218 
       
   219     // Redraw highlight view immediately so it updates in sync with the target view
       
   220     // if we called disableScreenUpdatesUntilFlush on the target view earlier. This
       
   221     // is especially visible when resizing the window.
       
   222     [_highlightView displayIfNeeded];
       
   223 }
       
   224 
       
   225 - (void)setIgnoresMouseEvents:(BOOL)newValue
       
   226 {
       
   227     ASSERT(_highlightWindow);
       
   228     [_highlightWindow setIgnoresMouseEvents:newValue];
       
   229 }
       
   230 
       
   231 - (NSView *)targetView
       
   232 {
       
   233     return _targetView;
       
   234 }
       
   235 
       
   236 @end
       
   237 
       
   238 @implementation WebNodeHighlight (FileInternal)
       
   239 
       
   240 - (NSRect)_computeHighlightWindowFrame
       
   241 {
       
   242     ASSERT(_targetView);
       
   243     ASSERT([_targetView window]);
       
   244 
       
   245     NSRect highlightWindowFrame = [_targetView convertRect:[_targetView visibleRect] toView:nil];
       
   246     highlightWindowFrame.origin = [[_targetView window] convertBaseToScreen:highlightWindowFrame.origin];
       
   247 
       
   248     return highlightWindowFrame;
       
   249 }
       
   250 
       
   251 - (void)_repositionHighlightWindow
       
   252 {
       
   253     ASSERT([_targetView window]);
       
   254 
       
   255     // Disable screen updates so the highlight moves in sync with the view.
       
   256     [[_targetView window] disableScreenUpdatesUntilFlush];
       
   257 
       
   258     [_highlightWindow setFrame:[self _computeHighlightWindowFrame] display:YES];
       
   259 }
       
   260 
       
   261 - (void)_animateFadeIn:(WebNodeHighlightFadeInAnimation *)animation
       
   262 {
       
   263     [_highlightView setFractionFadedIn:[animation currentValue]];
       
   264 }
       
   265 
       
   266 @end