1 /*
2 * Copyright (C) 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 "WebNodeHighlight.h"
31
32 #include "WebView.h"
33 #include <WebCore/BitmapInfo.h>
34 #include <WebCore/Color.h>
35 #include <WebCore/GraphicsContext.h>
36 #include <WebCore/InspectorController.h>
37 #include <WebCore/Page.h>
38 #include <WebCore/WindowMessageBroadcaster.h>
39 #include <wtf/OwnPtr.h>
40 #include <wtf/HashSet.h>
41
42 using namespace WebCore;
43
44 static LPCTSTR kOverlayWindowClassName = TEXT("WebNodeHighlightWindowClass");
45 static ATOM registerOverlayClass();
46 static LPCTSTR kWebNodeHighlightPointerProp = TEXT("WebNodeHighlightPointer");
47
WebNodeHighlight(WebView * webView)48 WebNodeHighlight::WebNodeHighlight(WebView* webView)
49 : m_inspectedWebView(webView)
50 , m_overlay(0)
51 , m_observedWindow(0)
52 , m_showsWhileWebViewIsVisible(false)
53 {
54 m_inspectedWebView->viewWindow(reinterpret_cast<OLE_HANDLE*>(&m_inspectedWebViewWindow));
55 }
56
~WebNodeHighlight()57 WebNodeHighlight::~WebNodeHighlight()
58 {
59 if (m_observedWindow)
60 WindowMessageBroadcaster::removeListener(m_observedWindow, this);
61 if (m_inspectedWebViewWindow)
62 WindowMessageBroadcaster::removeListener(m_inspectedWebViewWindow, this);
63
64 if (m_overlay)
65 ::DestroyWindow(m_overlay);
66 }
67
setShowsWhileWebViewIsVisible(bool shows)68 void WebNodeHighlight::setShowsWhileWebViewIsVisible(bool shows)
69 {
70 if (m_showsWhileWebViewIsVisible == shows)
71 return;
72 m_showsWhileWebViewIsVisible = shows;
73
74 if (!m_showsWhileWebViewIsVisible) {
75 hide();
76 return;
77 }
78
79 bool webViewVisible = isWebViewVisible();
80
81 if (isShowing() == webViewVisible)
82 return;
83
84 if (webViewVisible)
85 show();
86 else
87 hide();
88 }
89
isWebViewVisible() const90 bool WebNodeHighlight::isWebViewVisible() const
91 {
92 if (!m_inspectedWebViewWindow)
93 return false;
94
95 return IsWindowVisible(m_inspectedWebViewWindow);
96 }
97
show()98 void WebNodeHighlight::show()
99 {
100 if (!m_overlay) {
101 registerOverlayClass();
102
103 m_overlay = ::CreateWindowEx(WS_EX_LAYERED | WS_EX_TOOLWINDOW | WS_EX_TRANSPARENT, kOverlayWindowClassName, 0, WS_POPUP,
104 0, 0, 0, 0,
105 m_inspectedWebViewWindow, 0, 0, 0);
106 if (!m_overlay)
107 return;
108
109 ::SetProp(m_overlay, kWebNodeHighlightPointerProp, reinterpret_cast<HANDLE>(this));
110
111 m_observedWindow = GetAncestor(m_inspectedWebViewWindow, GA_ROOT);
112 WindowMessageBroadcaster::addListener(m_observedWindow, this);
113 WindowMessageBroadcaster::addListener(m_inspectedWebViewWindow, this);
114 }
115
116 ASSERT(m_showsWhileWebViewIsVisible);
117
118 update();
119 SetWindowPos(m_overlay, 0, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
120 }
121
hide()122 void WebNodeHighlight::hide()
123 {
124 if (m_overlay)
125 ::ShowWindow(m_overlay, SW_HIDE);
126 }
127
isShowing() const128 bool WebNodeHighlight::isShowing() const
129 {
130 return m_overlay && ::IsWindowVisible(m_overlay);
131 }
132
update()133 void WebNodeHighlight::update()
134 {
135 ASSERT(m_overlay);
136
137 HDC hdc = ::CreateCompatibleDC(::GetDC(m_overlay));
138 if (!hdc)
139 return;
140
141 RECT webViewRect;
142 ::GetWindowRect(m_inspectedWebViewWindow, &webViewRect);
143
144 SIZE size;
145 size.cx = webViewRect.right - webViewRect.left;
146 size.cy = webViewRect.bottom - webViewRect.top;
147
148 BitmapInfo bitmapInfo = BitmapInfo::createBottomUp(IntSize(size));
149
150 void* pixels = 0;
151 OwnPtr<HBITMAP> hbmp(::CreateDIBSection(hdc, &bitmapInfo, DIB_RGB_COLORS, &pixels, 0, 0));
152
153 ::SelectObject(hdc, hbmp.get());
154
155 GraphicsContext context(hdc);
156
157 m_inspectedWebView->page()->inspectorController()->drawNodeHighlight(context);
158
159 BLENDFUNCTION bf;
160 bf.BlendOp = AC_SRC_OVER;
161 bf.BlendFlags = 0;
162 bf.SourceConstantAlpha = 255;
163 bf.AlphaFormat = AC_SRC_ALPHA;
164
165 POINT srcPoint;
166 srcPoint.x = 0;
167 srcPoint.y = 0;
168
169 POINT dstPoint;
170 dstPoint.x = webViewRect.left;
171 dstPoint.y = webViewRect.top;
172
173 ::UpdateLayeredWindow(m_overlay, ::GetDC(0), &dstPoint, &size, hdc, &srcPoint, 0, &bf, ULW_ALPHA);
174
175 ::DeleteDC(hdc);
176 }
177
placeBehindWindow(HWND window)178 void WebNodeHighlight::placeBehindWindow(HWND window)
179 {
180 ASSERT(m_overlay);
181 SetWindowPos(m_overlay, window, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
182 }
183
registerOverlayClass()184 static ATOM registerOverlayClass()
185 {
186 static bool haveRegisteredWindowClass = false;
187
188 if (haveRegisteredWindowClass)
189 return true;
190
191 WNDCLASSEX wcex;
192
193 wcex.cbSize = sizeof(WNDCLASSEX);
194
195 wcex.style = 0;
196 wcex.lpfnWndProc = OverlayWndProc;
197 wcex.cbClsExtra = 0;
198 wcex.cbWndExtra = 0;
199 wcex.hInstance = 0;
200 wcex.hIcon = 0;
201 wcex.hCursor = LoadCursor(0, IDC_ARROW);
202 wcex.hbrBackground = 0;
203 wcex.lpszMenuName = 0;
204 wcex.lpszClassName = kOverlayWindowClassName;
205 wcex.hIconSm = 0;
206
207 haveRegisteredWindowClass = true;
208
209 return ::RegisterClassEx(&wcex);
210 }
211
OverlayWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)212 LRESULT CALLBACK OverlayWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
213 {
214 WebNodeHighlight* highlight = reinterpret_cast<WebNodeHighlight*>(::GetProp(hwnd, kWebNodeHighlightPointerProp));
215 if (!highlight)
216 return ::DefWindowProc(hwnd, msg, wParam, lParam);
217
218 return ::DefWindowProc(hwnd, msg, wParam, lParam);
219 }
220
onWebViewShowWindow(bool showing)221 void WebNodeHighlight::onWebViewShowWindow(bool showing)
222 {
223 if (!m_showsWhileWebViewIsVisible)
224 return;
225
226 if (isShowing() == showing)
227 return;
228
229 if (showing)
230 show();
231 else
232 hide();
233 }
234
onWebViewWindowPosChanged(WINDOWPOS * windowPos)235 void WebNodeHighlight::onWebViewWindowPosChanged(WINDOWPOS* windowPos)
236 {
237 bool sizing = !(windowPos->flags & SWP_NOSIZE);
238
239 if (!sizing)
240 return;
241
242 if (!isShowing())
243 return;
244
245 update();
246 }
247
onRootWindowPosChanged(WINDOWPOS * windowPos)248 void WebNodeHighlight::onRootWindowPosChanged(WINDOWPOS* windowPos)
249 {
250 bool moving = !(windowPos->flags & SWP_NOMOVE);
251 bool sizing = !(windowPos->flags & SWP_NOSIZE);
252
253 if (!moving)
254 return;
255
256 // Size changes are handled by onWebViewWindowPosChanged.
257 if (sizing)
258 return;
259
260 if (!isShowing())
261 return;
262
263 update();
264 }
265
windowReceivedMessage(HWND window,UINT msg,WPARAM wParam,LPARAM lParam)266 void WebNodeHighlight::windowReceivedMessage(HWND window, UINT msg, WPARAM wParam, LPARAM lParam)
267 {
268 if (window == m_inspectedWebViewWindow) {
269 switch (msg) {
270 case WM_SHOWWINDOW:
271 onWebViewShowWindow(wParam);
272 break;
273 case WM_WINDOWPOSCHANGED:
274 onWebViewWindowPosChanged(reinterpret_cast<WINDOWPOS*>(lParam));
275 break;
276 default:
277 break;
278 }
279
280 return;
281 }
282
283 ASSERT(window == m_observedWindow);
284 switch (msg) {
285 case WM_WINDOWPOSCHANGED:
286 onRootWindowPosChanged(reinterpret_cast<WINDOWPOS*>(lParam));
287 break;
288 default:
289 break;
290 }
291 }
292