Rename ENABLE_ASYNC_ITERATION to ENABLE_JS_ASYNC_ITERATION
[WebKit-https.git] / Source / WebKitLegacy / 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 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 #if PLATFORM(IOS)
37 #import "WebFramePrivate.h"
38 #import "WebHTMLView.h"
39 #import "WebView.h"
40 #import <WebCore/WAKWindow.h>
41 #import <pal/spi/cocoa/QuartzCoreSPI.h>
42 #endif
43
44 using namespace WebCore;
45
46 #if !PLATFORM(IOS)
47 @interface WebNodeHighlight (FileInternal)
48 - (NSRect)_computeHighlightWindowFrame;
49 - (void)_repositionHighlightWindow;
50 @end
51 #endif
52
53 #if PLATFORM(IOS)
54 @implementation WebHighlightLayer
55
56 - (id)initWithHighlightView:(WebNodeHighlightView *)view webView:(WebView *)webView
57 {
58     self = [super init];
59     if (!self)
60         return nil;
61     _view = view;
62     _webView = webView;
63     return self;
64 }
65
66 - (void)layoutSublayers
67 {
68     CGFloat documentScale = [[[_webView mainFrame] documentView] scale];
69     [self setTransform:CATransform3DMakeScale(documentScale, documentScale, 1.0)];
70
71     [_view layoutSublayers:self];
72 }
73
74 - (id<CAAction>)actionForKey:(NSString *)key
75 {
76     return nil; // Disable all default actions.
77 }
78
79 @end
80 #endif
81
82 @implementation WebNodeHighlight
83
84 - (id)initWithTargetView:(NSView *)targetView inspectorController:(InspectorController*)inspectorController
85 {
86     self = [super init];
87     if (!self)
88         return nil;
89
90     _targetView = [targetView retain];
91     _inspectorController = inspectorController;
92
93 #if !PLATFORM(IOS)
94     int styleMask = NSWindowStyleMaskBorderless;
95     NSRect contentRect = [NSWindow contentRectForFrameRect:[self _computeHighlightWindowFrame] styleMask:styleMask];
96     _highlightWindow = [[NSWindow alloc] initWithContentRect:contentRect styleMask:styleMask backing:NSBackingStoreBuffered defer:NO];
97     [_highlightWindow setBackgroundColor:[NSColor clearColor]];
98     [_highlightWindow setOpaque:NO];
99     [_highlightWindow setIgnoresMouseEvents:YES];
100     [_highlightWindow setReleasedWhenClosed:NO];
101
102     _highlightView = [[WebNodeHighlightView alloc] initWithWebNodeHighlight:self];
103     [_highlightWindow setContentView:_highlightView];
104     [_highlightView release];
105 #else
106     ASSERT([_targetView isKindOfClass:[WebView class]]);
107     WebView *webView = (WebView *)targetView;
108
109     _highlightView = [[WebNodeHighlightView alloc] initWithWebNodeHighlight:self];
110     _highlightLayer = [[WebHighlightLayer alloc] initWithHighlightView:_highlightView webView:webView];
111     [_highlightLayer setContentsScale:[[_targetView window] screenScale]]; // HiDPI.
112     [_highlightLayer setCanDrawConcurrently:NO];
113 #endif
114
115     return self;
116 }
117
118 - (void)dealloc
119 {
120 #if !PLATFORM(IOS)
121     ASSERT(!_highlightWindow);
122 #else
123     ASSERT(!_highlightLayer);
124 #endif
125     ASSERT(!_targetView);
126     ASSERT(!_highlightView);
127
128     [super dealloc];
129 }
130
131 - (void)attach
132 {
133     ASSERT(_targetView);
134     ASSERT([_targetView window]);
135
136 #if !PLATFORM(IOS)
137     ASSERT(_highlightWindow);
138
139     if (!_highlightWindow || !_targetView || ![_targetView window])
140         return;
141
142     [[_targetView window] addChildWindow:_highlightWindow ordered:NSWindowAbove];
143
144     // Observe both frame-changed and bounds-changed notifications because either one could leave
145     // the highlight incorrectly positioned with respect to the target view. We need to do this for
146     // the entire superview hierarchy to handle scrolling, bars coming and going, etc. 
147     // (without making concrete assumptions about the view hierarchy).
148     NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
149     for (NSView *v = _targetView; v; v = [v superview]) {
150         [notificationCenter addObserver:self selector:@selector(_repositionHighlightWindow) name:NSViewFrameDidChangeNotification object:v];
151         [notificationCenter addObserver:self selector:@selector(_repositionHighlightWindow) name:NSViewBoundsDidChangeNotification object:v];
152     }
153 #else
154     ASSERT(_highlightLayer);
155
156     WAKWindow *window = [_targetView window];
157     [[window hostLayer] addSublayer:_highlightLayer];
158     [self setNeedsDisplay];
159 #endif
160
161     if (_delegate && [_delegate respondsToSelector:@selector(didAttachWebNodeHighlight:)])
162         [_delegate didAttachWebNodeHighlight:self];
163 }
164
165 - (id)delegate
166 {
167     return _delegate;
168 }
169
170 - (void)detach
171 {
172 #if !PLATFORM(IOS)
173     if (!_highlightWindow) {
174 #else
175     if (!_highlightLayer) {
176 #endif
177         ASSERT(!_targetView);
178         return;
179     }
180
181     if (_delegate && [_delegate respondsToSelector:@selector(willDetachWebNodeHighlight:)])
182         [_delegate willDetachWebNodeHighlight:self];
183
184 #if !PLATFORM(IOS)
185     NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
186     [notificationCenter removeObserver:self name:NSViewFrameDidChangeNotification object:nil];
187     [notificationCenter removeObserver:self name:NSViewBoundsDidChangeNotification object:nil];
188
189     [[_highlightWindow parentWindow] removeChildWindow:_highlightWindow];
190     [_highlightWindow close];
191
192     [_highlightWindow release];
193     _highlightWindow = nil;
194 #else
195     [_highlightLayer removeFromSuperlayer];
196     [_highlightLayer release];
197     _highlightLayer = nil;
198 #endif
199
200     [_targetView release];
201     _targetView = nil;
202
203     // We didn't retain _highlightView, but we do need to tell it to forget about us, so it doesn't
204     // try to send our delegate messages after we've been dealloc'ed, e.g.
205     [_highlightView detachFromWebNodeHighlight];
206 #if PLATFORM(IOS)
207     // iOS did retain the highlightView, and we should release it here.
208     [_highlightView release];
209 #endif
210     _highlightView = nil;
211 }
212
213 - (WebNodeHighlightView *)highlightView
214 {
215     return _highlightView;
216 }
217
218 - (void)setDelegate:(id)delegate
219 {
220     // The delegate is not retained, as usual in Cocoa.
221     _delegate = delegate;
222 }
223
224 #if !PLATFORM(IOS)
225 - (void)setNeedsUpdateInTargetViewRect:(NSRect)rect
226 {
227     ASSERT(_targetView);
228
229     [[_targetView window] disableScreenUpdatesUntilFlush];
230
231     // Mark the whole highlight view as needing display since we don't know what areas
232     // need updated, since the highlight can be larger than the element to show margins.
233     [_highlightView setNeedsDisplay:YES];
234
235     // Redraw highlight view immediately so it updates in sync with the target view.
236     // This is especially visible when resizing the window, scrolling or with DHTML.
237     [_highlightView displayIfNeeded];
238 }
239 #else
240 - (void)setNeedsDisplay
241 {
242     [_highlightLayer setNeedsLayout];
243     [_highlightLayer setNeedsDisplay];
244     [_highlightLayer displayIfNeeded];
245 }
246 #endif
247
248 - (NSView *)targetView
249 {
250     return _targetView;
251 }
252
253 - (InspectorController*)inspectorController
254 {
255     return _inspectorController;
256 }
257
258 @end
259
260 #if !PLATFORM(IOS)
261 @implementation WebNodeHighlight (FileInternal)
262
263 - (NSRect)_computeHighlightWindowFrame
264 {
265     ASSERT(_targetView);
266     ASSERT([_targetView window]);
267
268     NSRect highlightWindowFrame = [_targetView convertRect:[_targetView visibleRect] toView:nil];
269 #pragma clang diagnostic push
270 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
271     highlightWindowFrame.origin = [[_targetView window] convertBaseToScreen:highlightWindowFrame.origin];
272 #pragma clang diagnostic pop
273
274     return highlightWindowFrame;
275 }
276
277 - (void)_repositionHighlightWindow
278 {
279     // This assertion fires in cases where a new tab is created while the highlight
280     // is showing (<http://bugs.webkit.org/show_bug.cgi?id=14254>)
281     ASSERT([_targetView window]);
282     
283     // Until that bug is fixed, bail out to avoid worse problems where the highlight
284     // moves to a nonsense location.
285     if (![_targetView window])
286         return;
287
288     // Disable screen updates so the highlight moves in sync with the view.
289     [[_targetView window] disableScreenUpdatesUntilFlush];
290
291     [_highlightWindow setFrame:[self _computeHighlightWindowFrame] display:YES];
292 }
293
294 @end
295 #endif