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