• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2006, 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 #include "config.h"
30 #include "WebInspectorClient.h"
31 
32 #include "WebInspectorDelegate.h"
33 #include "WebKit.h"
34 #include "WebMutableURLRequest.h"
35 #include "WebNodeHighlight.h"
36 #include "WebView.h"
37 
38 #pragma warning(push, 0)
39 #include <WebCore/BString.h>
40 #include <WebCore/Element.h>
41 #include <WebCore/FloatRect.h>
42 #include <WebCore/FrameView.h>
43 #include <WebCore/InspectorController.h>
44 #include <WebCore/NotImplemented.h>
45 #include <WebCore/Page.h>
46 #include <WebCore/RenderObject.h>
47 #include <WebCore/WindowMessageBroadcaster.h>
48 #pragma warning(pop)
49 
50 #include <tchar.h>
51 #include <wtf/RetainPtr.h>
52 
53 using namespace WebCore;
54 
55 static const char* const inspectorStartsAttachedName = "inspectorStartsAttached";
56 
57 static LPCTSTR kWebInspectorWindowClassName = TEXT("WebInspectorWindowClass");
58 static ATOM registerWindowClass();
59 static LPCTSTR kWebInspectorPointerProp = TEXT("WebInspectorPointer");
60 
defaultWindowRect()61 static const IntRect& defaultWindowRect()
62 {
63     static IntRect rect(60, 200, 750, 650);
64     return rect;
65 }
66 
getWebKitBundle()67 static CFBundleRef getWebKitBundle()
68 {
69     return CFBundleGetBundleWithIdentifier(CFSTR("com.apple.WebKit"));
70 }
71 
WebInspectorClient(WebView * webView)72 WebInspectorClient::WebInspectorClient(WebView* webView)
73     : m_inspectedWebView(webView)
74     , m_hwnd(0)
75     , m_webViewHwnd(0)
76     , m_shouldAttachWhenShown(false)
77     , m_attached(false)
78 {
79     ASSERT(m_inspectedWebView);
80 
81     m_inspectedWebView->viewWindow((OLE_HANDLE*)&m_inspectedWebViewHwnd);
82 
83     // FIXME: Implement window size/position save/restore
84 #if 0
85     [self setWindowFrameAutosaveName:@"Web Inspector"];
86 #endif
87 }
88 
~WebInspectorClient()89 WebInspectorClient::~WebInspectorClient()
90 {
91     if (m_hwnd)
92         ::DestroyWindow(m_hwnd);
93 }
94 
inspectorDestroyed()95 void WebInspectorClient::inspectorDestroyed()
96 {
97     delete this;
98 }
99 
createPage()100 Page* WebInspectorClient::createPage()
101 {
102     if (m_webView)
103         return core(m_webView.get());
104 
105     ASSERT(!m_hwnd);
106 
107     registerWindowClass();
108 
109     m_hwnd = ::CreateWindowEx(0, kWebInspectorWindowClassName, 0, WS_OVERLAPPEDWINDOW,
110         defaultWindowRect().x(), defaultWindowRect().y(), defaultWindowRect().width(), defaultWindowRect().height(),
111         0, 0, 0, 0);
112 
113     if (!m_hwnd)
114         return 0;
115 
116     ::SetProp(m_hwnd, kWebInspectorPointerProp, reinterpret_cast<HANDLE>(this));
117 
118     m_webView.adoptRef(WebView::createInstance());
119 
120     if (FAILED(m_webView->setHostWindow((OLE_HANDLE)(ULONG64)m_hwnd)))
121         return 0;
122 
123     RECT rect;
124     GetClientRect(m_hwnd, &rect);
125     if (FAILED(m_webView->initWithFrame(rect, 0, 0)))
126         return 0;
127 
128     COMPtr<WebInspectorDelegate> delegate(AdoptCOM, WebInspectorDelegate::createInstance());
129     if (FAILED(m_webView->setUIDelegate(delegate.get())))
130         return 0;
131 
132     // Keep preferences separate from the rest of the client, making sure we are using expected preference values.
133     // One reason this is good is that it keeps the inspector out of history via "private browsing".
134     // FIXME: It's crazy that we have to do this song and dance to end up with
135     // a private WebPreferences object, even within WebKit. We should make this
136     // process simpler, and consider whether we can make it simpler for WebKit
137     // clients as well.
138     COMPtr<WebPreferences> tempPreferences(AdoptCOM, WebPreferences::createInstance());
139     COMPtr<IWebPreferences> iPreferences;
140     if (FAILED(tempPreferences->initWithIdentifier(BString(L"WebInspectorPreferences"), &iPreferences)))
141         return 0;
142     COMPtr<WebPreferences> preferences(Query, iPreferences);
143     if (!preferences)
144         return 0;
145     if (FAILED(preferences->setAutosaves(FALSE)))
146         return 0;
147     if (FAILED(preferences->setPrivateBrowsingEnabled(TRUE)))
148         return 0;
149     if (FAILED(preferences->setLoadsImagesAutomatically(TRUE)))
150         return 0;
151     if (FAILED(preferences->setAuthorAndUserStylesEnabled(TRUE)))
152         return 0;
153     if (FAILED(preferences->setAllowsAnimatedImages(TRUE)))
154         return 0;
155     if (FAILED(preferences->setLoadsImagesAutomatically(TRUE)))
156         return 0;
157     if (FAILED(preferences->setPlugInsEnabled(FALSE)))
158         return 0;
159     if (FAILED(preferences->setJavaEnabled(FALSE)))
160         return 0;
161     if (FAILED(preferences->setUserStyleSheetEnabled(FALSE)))
162         return 0;
163     if (FAILED(preferences->setTabsToLinks(FALSE)))
164         return 0;
165     if (FAILED(preferences->setMinimumFontSize(0)))
166         return 0;
167     if (FAILED(preferences->setMinimumLogicalFontSize(9)))
168         return 0;
169     if (FAILED(preferences->setFixedFontFamily(BString(L"Courier New"))))
170         return 0;
171     if (FAILED(preferences->setDefaultFixedFontSize(13)))
172         return 0;
173 
174     if (FAILED(m_webView->setPreferences(preferences.get())))
175         return 0;
176 
177     m_webView->setProhibitsMainFrameScrolling(TRUE);
178 
179     if (FAILED(m_webView->viewWindow(reinterpret_cast<OLE_HANDLE*>(&m_webViewHwnd))))
180         return 0;
181 
182     COMPtr<WebMutableURLRequest> request;
183     request.adoptRef(WebMutableURLRequest::createInstance());
184 
185     RetainPtr<CFURLRef> htmlURLRef(AdoptCF, CFBundleCopyResourceURL(getWebKitBundle(), CFSTR("inspector"), CFSTR("html"), CFSTR("inspector")));
186     if (!htmlURLRef)
187         return 0;
188 
189     CFStringRef urlStringRef = ::CFURLGetString(htmlURLRef.get());
190     if (FAILED(request->initWithURL(BString(urlStringRef), WebURLRequestUseProtocolCachePolicy, 60)))
191         return 0;
192 
193     if (FAILED(m_webView->topLevelFrame()->loadRequest(request.get())))
194         return 0;
195 
196     return core(m_webView.get());
197 }
198 
199 
localizedStringsURL()200 String WebInspectorClient::localizedStringsURL()
201 {
202     RetainPtr<CFURLRef> url(AdoptCF, CFBundleCopyResourceURL(getWebKitBundle(), CFSTR("localizedStrings"), CFSTR("js"), 0));
203     if (!url)
204         return String();
205 
206     return CFURLGetString(url.get());
207 }
208 
209 
hiddenPanels()210 String WebInspectorClient::hiddenPanels()
211 {
212     // FIXME: implement this
213     return String();
214 }
215 
showWindow()216 void WebInspectorClient::showWindow()
217 {
218     showWindowWithoutNotifications();
219     m_inspectedWebView->page()->inspectorController()->setWindowVisible(true, m_shouldAttachWhenShown);
220 }
221 
closeWindow()222 void WebInspectorClient::closeWindow()
223 {
224     closeWindowWithoutNotifications();
225     m_inspectedWebView->page()->inspectorController()->setWindowVisible(false, m_shouldAttachWhenShown);
226 }
227 
windowVisible()228 bool WebInspectorClient::windowVisible()
229 {
230     return !!::IsWindowVisible(m_hwnd);
231 }
232 
attachWindow()233 void WebInspectorClient::attachWindow()
234 {
235     if (m_attached)
236         return;
237 
238     m_inspectedWebView->page()->inspectorController()->setSetting(inspectorStartsAttachedName, InspectorController::Setting(true));
239 
240     closeWindowWithoutNotifications();
241     showWindowWithoutNotifications();
242 }
243 
detachWindow()244 void WebInspectorClient::detachWindow()
245 {
246     if (!m_attached)
247         return;
248 
249     m_inspectedWebView->page()->inspectorController()->setSetting(inspectorStartsAttachedName, InspectorController::Setting(false));
250 
251     closeWindowWithoutNotifications();
252     showWindowWithoutNotifications();
253 }
254 
setAttachedWindowHeight(unsigned height)255 void WebInspectorClient::setAttachedWindowHeight(unsigned height)
256 {
257     if (!m_attached)
258         return;
259 
260     HWND hostWindow;
261     if (!SUCCEEDED(m_inspectedWebView->hostWindow((OLE_HANDLE*)&hostWindow)))
262         return;
263 
264     RECT hostWindowRect;
265     GetClientRect(hostWindow, &hostWindowRect);
266 
267     RECT inspectedRect;
268     GetClientRect(m_inspectedWebViewHwnd, &inspectedRect);
269 
270     int totalHeight = hostWindowRect.bottom - hostWindowRect.top;
271     int webViewWidth = inspectedRect.right - inspectedRect.left;
272 
273     SetWindowPos(m_webViewHwnd, 0, 0, totalHeight - height, webViewWidth, height, SWP_NOZORDER);
274 
275     // We want to set the inspected web view height to the totalHeight, because the height adjustment
276     // of the inspected web view happens in onWebViewWindowPosChanging, not here.
277     SetWindowPos(m_inspectedWebViewHwnd, 0, 0, 0, webViewWidth, totalHeight, SWP_NOZORDER);
278 
279     RedrawWindow(m_webViewHwnd, 0, 0, RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_UPDATENOW);
280     RedrawWindow(m_inspectedWebViewHwnd, 0, 0, RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_UPDATENOW);
281 }
282 
highlight(Node *)283 void WebInspectorClient::highlight(Node*)
284 {
285     bool creatingHighlight = !m_highlight;
286 
287     if (creatingHighlight)
288         m_highlight.set(new WebNodeHighlight(m_inspectedWebView));
289 
290     if (m_highlight->isShowing())
291         m_highlight->update();
292     else
293         m_highlight->setShowsWhileWebViewIsVisible(true);
294 
295     if (creatingHighlight && IsWindowVisible(m_hwnd))
296         m_highlight->placeBehindWindow(m_hwnd);
297 }
298 
hideHighlight()299 void WebInspectorClient::hideHighlight()
300 {
301     if (m_highlight)
302         m_highlight->setShowsWhileWebViewIsVisible(false);
303 }
304 
inspectedURLChanged(const String & newURL)305 void WebInspectorClient::inspectedURLChanged(const String& newURL)
306 {
307     m_inspectedURL = newURL;
308     updateWindowTitle();
309 }
310 
inspectorWindowObjectCleared()311 void WebInspectorClient::inspectorWindowObjectCleared()
312 {
313     notImplemented();
314 }
315 
closeWindowWithoutNotifications()316 void WebInspectorClient::closeWindowWithoutNotifications()
317 {
318     if (!m_hwnd)
319         return;
320 
321     if (!m_attached) {
322         ShowWindow(m_hwnd, SW_HIDE);
323         return;
324     }
325 
326     ASSERT(m_webView);
327     ASSERT(m_inspectedWebViewHwnd);
328     ASSERT(!IsWindowVisible(m_hwnd));
329 
330     // Remove the Inspector's WebView from the inspected WebView's parent window.
331     WindowMessageBroadcaster::removeListener(m_inspectedWebViewHwnd, this);
332 
333     m_attached = false;
334 
335     m_webView->setHostWindow(reinterpret_cast<OLE_HANDLE>(m_hwnd));
336 
337     // Make sure everything has the right size/position.
338     HWND hostWindow;
339     if (SUCCEEDED(m_inspectedWebView->hostWindow((OLE_HANDLE*)&hostWindow)))
340         SendMessage(hostWindow, WM_SIZE, 0, 0);
341 
342     if (m_highlight && m_highlight->isShowing())
343         m_highlight->update();
344 }
345 
showWindowWithoutNotifications()346 void WebInspectorClient::showWindowWithoutNotifications()
347 {
348     if (!m_hwnd)
349         return;
350 
351     ASSERT(m_webView);
352     ASSERT(m_inspectedWebViewHwnd);
353 
354     InspectorController::Setting shouldAttach = m_inspectedWebView->page()->inspectorController()->setting(inspectorStartsAttachedName);
355     m_shouldAttachWhenShown = shouldAttach.type() == InspectorController::Setting::BooleanType ? shouldAttach.booleanValue() : false;
356 
357     if (!m_shouldAttachWhenShown) {
358         // Put the Inspector's WebView inside our window and show it.
359         m_webView->setHostWindow(reinterpret_cast<OLE_HANDLE>(m_hwnd));
360         SendMessage(m_hwnd, WM_SIZE, 0, 0);
361         updateWindowTitle();
362 
363         SetWindowPos(m_hwnd, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
364         return;
365     }
366 
367     // Put the Inspector's WebView inside the inspected WebView's parent window.
368     WindowMessageBroadcaster::addListener(m_inspectedWebViewHwnd, this);
369 
370     HWND hostWindow;
371     if (FAILED(m_inspectedWebView->hostWindow(reinterpret_cast<OLE_HANDLE*>(&hostWindow))))
372         return;
373 
374     m_webView->setHostWindow(reinterpret_cast<OLE_HANDLE>(hostWindow));
375 
376     // Then hide our own window.
377     ShowWindow(m_hwnd, SW_HIDE);
378 
379     m_attached = true;
380 
381     // Make sure everything has the right size/position.
382     SendMessage(hostWindow, WM_SIZE, 0, 0);
383     if (m_highlight && m_highlight->isShowing())
384         m_highlight->update();
385 }
386 
updateWindowTitle()387 void WebInspectorClient::updateWindowTitle()
388 {
389     // FIXME: The series of appends should be replaced with a call to String::format()
390     // when it can be figured out how to get the unicode em-dash to show up.
391     String title = "Web Inspector ";
392     title.append((UChar)0x2014); // em-dash
393     title.append(' ');
394     title.append(m_inspectedURL);
395     ::SetWindowText(m_hwnd, title.charactersWithNullTermination());
396 }
397 
onGetMinMaxInfo(WPARAM,LPARAM lParam)398 LRESULT WebInspectorClient::onGetMinMaxInfo(WPARAM, LPARAM lParam)
399 {
400     MINMAXINFO* info = reinterpret_cast<MINMAXINFO*>(lParam);
401     POINT size = {400, 400};
402     info->ptMinTrackSize = size;
403 
404     return 0;
405 }
406 
onSize(WPARAM,LPARAM)407 LRESULT WebInspectorClient::onSize(WPARAM, LPARAM)
408 {
409     RECT rect;
410     ::GetClientRect(m_hwnd, &rect);
411 
412     ::SetWindowPos(m_webViewHwnd, 0, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
413 
414     return 0;
415 }
416 
onClose(WPARAM,LPARAM)417 LRESULT WebInspectorClient::onClose(WPARAM, LPARAM)
418 {
419     ::ShowWindow(m_hwnd, SW_HIDE);
420     m_inspectedWebView->page()->inspectorController()->setWindowVisible(false, m_shouldAttachWhenShown);
421 
422     hideHighlight();
423 
424     return 0;
425 }
426 
onSetFocus()427 LRESULT WebInspectorClient::onSetFocus()
428 {
429     SetFocus(m_webViewHwnd);
430     return 0;
431 }
432 
onWebViewWindowPosChanging(WPARAM,LPARAM lParam)433 void WebInspectorClient::onWebViewWindowPosChanging(WPARAM, LPARAM lParam)
434 {
435     ASSERT(m_attached);
436 
437     WINDOWPOS* windowPos = reinterpret_cast<WINDOWPOS*>(lParam);
438     ASSERT_ARG(lParam, windowPos);
439 
440     if (windowPos->flags & SWP_NOSIZE)
441         return;
442 
443     RECT inspectorRect;
444     GetClientRect(m_webViewHwnd, &inspectorRect);
445     unsigned inspectorHeight = inspectorRect.bottom - inspectorRect.top;
446 
447     windowPos->cy -= inspectorHeight;
448 
449     SetWindowPos(m_webViewHwnd, 0, windowPos->x, windowPos->y + windowPos->cy, windowPos->cx, inspectorHeight, SWP_NOZORDER);
450 }
451 
WebInspectorWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)452 static LRESULT CALLBACK WebInspectorWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
453 {
454     WebInspectorClient* client = reinterpret_cast<WebInspectorClient*>(::GetProp(hwnd, kWebInspectorPointerProp));
455     if (!client)
456         return ::DefWindowProc(hwnd, msg, wParam, lParam);
457 
458     switch (msg) {
459         case WM_GETMINMAXINFO:
460             return client->onGetMinMaxInfo(wParam, lParam);
461         case WM_SIZE:
462             return client->onSize(wParam, lParam);
463         case WM_CLOSE:
464             return client->onClose(wParam, lParam);
465         case WM_SETFOCUS:
466             return client->onSetFocus();
467         default:
468             break;
469     }
470 
471     return ::DefWindowProc(hwnd, msg, wParam, lParam);
472 }
473 
windowReceivedMessage(HWND,UINT msg,WPARAM wParam,LPARAM lParam)474 void WebInspectorClient::windowReceivedMessage(HWND, UINT msg, WPARAM wParam, LPARAM lParam)
475 {
476     switch (msg) {
477         case WM_WINDOWPOSCHANGING:
478             onWebViewWindowPosChanging(wParam, lParam);
479             break;
480         default:
481             break;
482     }
483 }
484 
registerWindowClass()485 static ATOM registerWindowClass()
486 {
487     static bool haveRegisteredWindowClass = false;
488 
489     if (haveRegisteredWindowClass)
490         return true;
491 
492     WNDCLASSEX wcex;
493 
494     wcex.cbSize = sizeof(WNDCLASSEX);
495 
496     wcex.style          = 0;
497     wcex.lpfnWndProc    = WebInspectorWndProc;
498     wcex.cbClsExtra     = 0;
499     wcex.cbWndExtra     = 0;
500     wcex.hInstance      = 0;
501     wcex.hIcon          = 0;
502     wcex.hCursor        = LoadCursor(0, IDC_ARROW);
503     wcex.hbrBackground  = 0;
504     wcex.lpszMenuName   = 0;
505     wcex.lpszClassName  = kWebInspectorWindowClassName;
506     wcex.hIconSm        = 0;
507 
508     haveRegisteredWindowClass = true;
509 
510     return ::RegisterClassEx(&wcex);
511 }
512