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