2 * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
29 #import "WebNodeHighlight.h"
30 #import "WebNodeHighlightView.h"
31 #import "WebNSViewExtras.h"
33 #import <WebCore/InspectorController.h>
34 #import <wtf/Assertions.h>
36 using namespace WebCore;
38 @interface WebNodeHighlight (FileInternal)
39 - (NSRect)_computeHighlightWindowFrame;
40 - (void)_repositionHighlightWindow;
43 @implementation WebNodeHighlight
45 - (id)initWithTargetView:(NSView *)targetView inspectorController:(InspectorController*)inspectorController
51 _targetView = [targetView retain];
52 _inspectorController = inspectorController;
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];
62 _highlightView = [[WebNodeHighlightView alloc] initWithWebNodeHighlight:self];
63 [_highlightWindow setContentView:_highlightView];
64 [_highlightView release];
71 ASSERT(!_highlightWindow);
73 ASSERT(!_highlightView);
81 ASSERT([_targetView window]);
82 ASSERT(_highlightWindow);
84 if (!_highlightWindow || !_targetView || ![_targetView window])
87 [[_targetView window] addChildWindow:_highlightWindow ordered:NSWindowAbove];
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];
99 if (_delegate && [_delegate respondsToSelector:@selector(didAttachWebNodeHighlight:)])
100 [_delegate didAttachWebNodeHighlight:self];
110 if (!_highlightWindow) {
111 ASSERT(!_targetView);
115 if (_delegate && [_delegate respondsToSelector:@selector(willDetachWebNodeHighlight:)])
116 [_delegate willDetachWebNodeHighlight:self];
118 NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
119 [notificationCenter removeObserver:self name:NSViewFrameDidChangeNotification object:nil];
120 [notificationCenter removeObserver:self name:NSViewBoundsDidChangeNotification object:nil];
122 [[_highlightWindow parentWindow] removeChildWindow:_highlightWindow];
124 [_highlightWindow release];
125 _highlightWindow = nil;
127 [_targetView release];
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;
136 - (WebNodeHighlightView *)highlightView
138 return _highlightView;
141 - (void)setDelegate:(id)delegate
143 // The delegate is not retained, as usual in Cocoa.
144 _delegate = delegate;
147 - (void)setNeedsUpdateInTargetViewRect:(NSRect)rect
151 [[_targetView window] disableScreenUpdatesUntilFlush];
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];
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];
162 - (NSView *)targetView
167 - (InspectorController*)inspectorController
169 return _inspectorController;
174 @implementation WebNodeHighlight (FileInternal)
176 - (NSRect)_computeHighlightWindowFrame
179 ASSERT([_targetView window]);
181 NSRect highlightWindowFrame = [_targetView convertRect:[_targetView visibleRect] toView:nil];
182 highlightWindowFrame.origin = [[_targetView window] convertBaseToScreen:highlightWindowFrame.origin];
184 return highlightWindowFrame;
187 - (void)_repositionHighlightWindow
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]);
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])
198 // Disable screen updates so the highlight moves in sync with the view.
199 [[_targetView window] disableScreenUpdatesUntilFlush];
201 [_highlightWindow setFrame:[self _computeHighlightWindowFrame] display:YES];