Home | History | Annotate | Download | only in win
      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