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 #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 
     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 
     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 
     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 
     90 bool WebNodeHighlight::isWebViewVisible() const
     91 {
     92     if (!m_inspectedWebViewWindow)
     93         return false;
     94 
     95     return IsWindowVisible(m_inspectedWebViewWindow);
     96 }
     97 
     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 
    122 void WebNodeHighlight::hide()
    123 {
    124     if (m_overlay)
    125         ::ShowWindow(m_overlay, SW_HIDE);
    126 }
    127 
    128 bool WebNodeHighlight::isShowing() const
    129 {
    130     return m_overlay && ::IsWindowVisible(m_overlay);
    131 }
    132 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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