[Release] Webkit-EFL Ver. 2.0_beta_118996_0.6.24
[framework/web/webkit-efl.git] / Source / WebKit / mac / WebInspector / WebNodeHighlight.mm
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