Home | History | Annotate | Download | only in WebInspector
      1 /*
      2  * Copyright (C) 2007, 2008 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 <WebCore/InspectorController.h>
     34 #import <wtf/Assertions.h>
     35 
     36 using namespace WebCore;
     37 
     38 @interface WebNodeHighlight (FileInternal)
     39 - (NSRect)_computeHighlightWindowFrame;
     40 - (void)_repositionHighlightWindow;
     41 @end
     42 
     43 @implementation WebNodeHighlight
     44 
     45 - (id)initWithTargetView:(NSView *)targetView inspectorController:(InspectorController*)inspectorController
     46 {
     47     self = [super init];
     48     if (!self)
     49         return nil;
     50 
     51     _targetView = [targetView retain];
     52     _inspectorController = inspectorController;
     53 
     54     int styleMask = NSBorderlessWindowMask;
     55     NSRect contentRect = [NSWindow contentRectForFrameRect:[self _computeHighlightWindowFrame] styleMask:styleMask];
     56     _highlightWindow = [[NSWindow alloc] initWithContentRect:contentRect styleMask:styleMask backing:NSBackingStoreBuffered defer:NO];
     57     [_highlightWindow setBackgroundColor:[NSColor clearColor]];
     58     [_highlightWindow setOpaque:NO];
     59     [_highlightWindow setIgnoresMouseEvents:YES];
     60     [_highlightWindow setReleasedWhenClosed:NO];
     61 
     62     _highlightView = [[WebNodeHighlightView alloc] initWithWebNodeHighlight:self];
     63     [_highlightWindow setContentView:_highlightView];
     64     [_highlightView release];
     65 
     66     return self;
     67 }
     68 
     69 - (void)dealloc
     70 {
     71     ASSERT(!_highlightWindow);
     72     ASSERT(!_targetView);
     73     ASSERT(!_highlightView);
     74 
     75     [super dealloc];
     76 }
     77 
     78 - (void)attach
     79 {
     80     ASSERT(_targetView);
     81     ASSERT([_targetView window]);
     82     ASSERT(_highlightWindow);
     83 
     84     if (!_highlightWindow || !_targetView || ![_targetView window])
     85         return;
     86 
     87     [[_targetView window] addChildWindow:_highlightWindow ordered:NSWindowAbove];
     88 
     89     // Observe both frame-changed and bounds-changed notifications because either one could leave
     90     // the highlight incorrectly positioned with respect to the target view. We need to do this for
     91     // the entire superview hierarchy to handle scrolling, bars coming and going, etc.
     92     // (without making concrete assumptions about the view hierarchy).
     93     NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
     94     for (NSView *v = _targetView; v; v = [v superview]) {
     95         [notificationCenter addObserver:self selector:@selector(_repositionHighlightWindow) name:NSViewFrameDidChangeNotification object:v];
     96         [notificationCenter addObserver:self selector:@selector(_repositionHighlightWindow) name:NSViewBoundsDidChangeNotification object:v];
     97     }
     98 
     99     if (_delegate && [_delegate respondsToSelector:@selector(didAttachWebNodeHighlight:)])
    100         [_delegate didAttachWebNodeHighlight:self];
    101 }
    102 
    103 - (id)delegate
    104 {
    105     return _delegate;
    106 }
    107 
    108 - (void)detach
    109 {
    110     if (!_highlightWindow) {
    111         ASSERT(!_targetView);
    112         return;
    113     }
    114 
    115     if (_delegate && [_delegate respondsToSelector:@selector(willDetachWebNodeHighlight:)])
    116         [_delegate willDetachWebNodeHighlight:self];
    117 
    118     NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
    119     [notificationCenter removeObserver:self name:NSViewFrameDidChangeNotification object:nil];
    120     [notificationCenter removeObserver:self name:NSViewBoundsDidChangeNotification object:nil];
    121 
    122     [[_highlightWindow parentWindow] removeChildWindow:_highlightWindow];
    123 
    124     [_highlightWindow release];
    125     _highlightWindow = nil;
    126 
    127     [_targetView release];
    128     _targetView = nil;
    129 
    130     // We didn't retain _highlightView, but we do need to tell it to forget about us, so it doesn't
    131     // try to send our delegate messages after we've been dealloc'ed, e.g.
    132     [_highlightView detachFromWebNodeHighlight];
    133     _highlightView = nil;
    134 }
    135 
    136 - (WebNodeHighlightView *)highlightView
    137 {
    138     return _highlightView;
    139 }
    140 
    141 - (void)setDelegate:(id)delegate
    142 {
    143     // The delegate is not retained, as usual in Cocoa.
    144     _delegate = delegate;
    145 }
    146 
    147 - (void)setNeedsUpdateInTargetViewRect:(NSRect)rect
    148 {
    149     ASSERT(_targetView);
    150 
    151     [[_targetView window] disableScreenUpdatesUntilFlush];
    152 
    153     // Mark the whole highlight view as needing display since we don't know what areas
    154     // need updated, since the highlight can be larger than the element to show margins.
    155     [_highlightView setNeedsDisplay:YES];
    156 
    157     // Redraw highlight view immediately so it updates in sync with the target view.
    158     // This is especially visible when resizing the window, scrolling or with DHTML.
    159     [_highlightView displayIfNeeded];
    160 }
    161 
    162 - (NSView *)targetView
    163 {
    164     return _targetView;
    165 }
    166 
    167 - (InspectorController*)inspectorController
    168 {
    169     return _inspectorController;
    170 }
    171 
    172 @end
    173 
    174 @implementation WebNodeHighlight (FileInternal)
    175 
    176 - (NSRect)_computeHighlightWindowFrame
    177 {
    178     ASSERT(_targetView);
    179     ASSERT([_targetView window]);
    180 
    181     NSRect highlightWindowFrame = [_targetView convertRect:[_targetView visibleRect] toView:nil];
    182     highlightWindowFrame.origin = [[_targetView window] convertBaseToScreen:highlightWindowFrame.origin];
    183 
    184     return highlightWindowFrame;
    185 }
    186 
    187 - (void)_repositionHighlightWindow
    188 {
    189     // This assertion fires in cases where a new tab is created while the highlight
    190     // is showing (<http://bugs.webkit.org/show_bug.cgi?id=14254>)
    191     ASSERT([_targetView window]);
    192 
    193     // Until that bug is fixed, bail out to avoid worse problems where the highlight
    194     // moves to a nonsense location.
    195     if (![_targetView window])
    196         return;
    197 
    198     // Disable screen updates so the highlight moves in sync with the view.
    199     [[_targetView window] disableScreenUpdatesUntilFlush];
    200 
    201     [_highlightWindow setFrame:[self _computeHighlightWindowFrame] display:YES];
    202 }
    203 
    204 @end
    205