| OLD | NEW | 
 | (Empty) | 
|     1 /* |  | 
|     2  * Copyright (C) 2006, 2007, 2008, 2011 Apple Inc. All rights reserved. |  | 
|     3  * Copyright (C) 2007-2009 Torch Mobile Inc. |  | 
|     4  * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). |  | 
|     5  * |  | 
|     6  * This library is free software; you can redistribute it and/or |  | 
|     7  * modify it under the terms of the GNU Library General Public |  | 
|     8  * License as published by the Free Software Foundation; either |  | 
|     9  * version 2 of the License, or (at your option) any later version. |  | 
|    10  * |  | 
|    11  * This library is distributed in the hope that it will be useful, |  | 
|    12  * but WITHOUT ANY WARRANTY; without even the implied warranty of |  | 
|    13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU |  | 
|    14  * Library General Public License for more details. |  | 
|    15  * |  | 
|    16  * You should have received a copy of the GNU Library General Public License |  | 
|    17  * along with this library; see the file COPYING.LIB.  If not, write to |  | 
|    18  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |  | 
|    19  * Boston, MA 02110-1301, USA. |  | 
|    20  * |  | 
|    21  */ |  | 
|    22  |  | 
|    23 #include "config.h" |  | 
|    24 #include "PopupMenuWin.h" |  | 
|    25  |  | 
|    26 #include "BitmapInfo.h" |  | 
|    27 #include "Document.h" |  | 
|    28 #include "FloatRect.h" |  | 
|    29 #include "FontSelector.h" |  | 
|    30 #include "Frame.h" |  | 
|    31 #include "FrameView.h" |  | 
|    32 #include "GraphicsContext.h" |  | 
|    33 #include "HTMLNames.h" |  | 
|    34 #include "HWndDC.h" |  | 
|    35 #include "HostWindow.h" |  | 
|    36 #include "LengthFunctions.h" |  | 
|    37 #include "Page.h" |  | 
|    38 #include "PlatformMouseEvent.h" |  | 
|    39 #include "PlatformScreen.h" |  | 
|    40 #include "RenderMenuList.h" |  | 
|    41 #include "RenderTheme.h" |  | 
|    42 #include "RenderView.h" |  | 
|    43 #include "Scrollbar.h" |  | 
|    44 #include "ScrollbarTheme.h" |  | 
|    45 #include "SimpleFontData.h" |  | 
|    46 #include "TextRun.h" |  | 
|    47 #include "WebCoreInstanceHandle.h" |  | 
|    48 #include "WindowsExtras.h" |  | 
|    49  |  | 
|    50 #include <windows.h> |  | 
|    51 #include <windowsx.h> |  | 
|    52 #if OS(WINCE) |  | 
|    53 #include <ResDefCE.h> |  | 
|    54 #define MAKEPOINTS(l) (*((POINTS FAR *)&(l))) |  | 
|    55 #endif |  | 
|    56  |  | 
|    57 #define HIGH_BIT_MASK_SHORT 0x8000 |  | 
|    58  |  | 
|    59 using std::min; |  | 
|    60  |  | 
|    61 namespace WebCore { |  | 
|    62  |  | 
|    63 using namespace HTMLNames; |  | 
|    64  |  | 
|    65 // Default Window animation duration in milliseconds |  | 
|    66 static const int defaultAnimationDuration = 200; |  | 
|    67 // Maximum height of a popup window |  | 
|    68 static const int maxPopupHeight = 320; |  | 
|    69  |  | 
|    70 const int optionSpacingMiddle = 1; |  | 
|    71 const int popupWindowBorderWidth = 1; |  | 
|    72  |  | 
|    73 static LPCWSTR kPopupWindowClassName = L"PopupWindowClass"; |  | 
|    74  |  | 
|    75 // This is used from within our custom message pump when we want to send a |  | 
|    76 // message to the web view and not have our message stolen and sent to |  | 
|    77 // the popup window. |  | 
|    78 static const UINT WM_HOST_WINDOW_FIRST = WM_USER; |  | 
|    79 static const UINT WM_HOST_WINDOW_CHAR = WM_USER + WM_CHAR;  |  | 
|    80 static const UINT WM_HOST_WINDOW_MOUSEMOVE = WM_USER + WM_MOUSEMOVE; |  | 
|    81  |  | 
|    82 // FIXME: Remove this as soon as practical. |  | 
|    83 static inline bool isASCIIPrintable(unsigned c) |  | 
|    84 { |  | 
|    85     return c >= 0x20 && c <= 0x7E; |  | 
|    86 } |  | 
|    87  |  | 
|    88 static void translatePoint(LPARAM& lParam, HWND from, HWND to) |  | 
|    89 { |  | 
|    90     POINT pt; |  | 
|    91     pt.x = (short)GET_X_LPARAM(lParam); |  | 
|    92     pt.y = (short)GET_Y_LPARAM(lParam);     |  | 
|    93     ::MapWindowPoints(from, to, &pt, 1); |  | 
|    94     lParam = MAKELPARAM(pt.x, pt.y); |  | 
|    95 } |  | 
|    96  |  | 
|    97 static FloatRect monitorFromHwnd(HWND hwnd) |  | 
|    98 { |  | 
|    99     HMONITOR monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY); |  | 
|   100     MONITORINFOEX monitorInfo; |  | 
|   101     monitorInfo.cbSize = sizeof(MONITORINFOEX); |  | 
|   102     GetMonitorInfo(monitor, &monitorInfo); |  | 
|   103     return monitorInfo.rcWork; |  | 
|   104 } |  | 
|   105  |  | 
|   106 PopupMenuWin::PopupMenuWin(PopupMenuClient* client) |  | 
|   107     : m_popupClient(client) |  | 
|   108     , m_scrollbar(0) |  | 
|   109     , m_popup(0) |  | 
|   110     , m_DC(0) |  | 
|   111     , m_bmp(0) |  | 
|   112     , m_wasClicked(false) |  | 
|   113     , m_itemHeight(0) |  | 
|   114     , m_scrollOffset(0) |  | 
|   115     , m_wheelDelta(0) |  | 
|   116     , m_focusedIndex(0) |  | 
|   117     , m_scrollbarCapturingMouse(false) |  | 
|   118     , m_showPopup(false) |  | 
|   119 { |  | 
|   120 } |  | 
|   121  |  | 
|   122 PopupMenuWin::~PopupMenuWin() |  | 
|   123 { |  | 
|   124     if (m_bmp) |  | 
|   125         ::DeleteObject(m_bmp); |  | 
|   126     if (m_DC) |  | 
|   127         ::DeleteDC(m_DC); |  | 
|   128     if (m_popup) |  | 
|   129         ::DestroyWindow(m_popup); |  | 
|   130     if (m_scrollbar) |  | 
|   131         m_scrollbar->setParent(0); |  | 
|   132 } |  | 
|   133  |  | 
|   134 void PopupMenuWin::disconnectClient() |  | 
|   135 { |  | 
|   136     m_popupClient = 0; |  | 
|   137 } |  | 
|   138  |  | 
|   139 LPCWSTR PopupMenuWin::popupClassName() |  | 
|   140 { |  | 
|   141     return kPopupWindowClassName; |  | 
|   142 } |  | 
|   143  |  | 
|   144 void PopupMenuWin::show(const IntRect& r, FrameView* view, int index) |  | 
|   145 { |  | 
|   146     calculatePositionAndSize(r, view); |  | 
|   147     if (clientRect().isEmpty()) |  | 
|   148         return; |  | 
|   149  |  | 
|   150     HWND hostWindow = view->hostWindow()->platformPageClient(); |  | 
|   151  |  | 
|   152     if (!m_scrollbar && visibleItems() < client()->listSize()) { |  | 
|   153         // We need a scroll bar |  | 
|   154         m_scrollbar = client()->createScrollbar(this, VerticalScrollbar, SmallSc
      rollbar); |  | 
|   155         m_scrollbar->styleChanged(); |  | 
|   156     } |  | 
|   157  |  | 
|   158     // We need to reposition the popup window to its final coordinates. |  | 
|   159     // Before calling this, the popup hwnd is currently the size of and at the l
      ocation of the menu list client so it needs to be updated. |  | 
|   160     ::MoveWindow(m_popup, m_windowRect.x(), m_windowRect.y(), m_windowRect.width
      (), m_windowRect.height(), false); |  | 
|   161  |  | 
|   162     // Determine whether we should animate our popups |  | 
|   163     // Note: Must use 'BOOL' and 'FALSE' instead of 'bool' and 'false' to avoid 
      stack corruption with SystemParametersInfo |  | 
|   164     BOOL shouldAnimate = FALSE; |  | 
|   165 #if !OS(WINCE) |  | 
|   166     ::SystemParametersInfo(SPI_GETCOMBOBOXANIMATION, 0, &shouldAnimate, 0); |  | 
|   167  |  | 
|   168     if (shouldAnimate) { |  | 
|   169         RECT viewRect = {0}; |  | 
|   170         ::GetWindowRect(hostWindow, &viewRect); |  | 
|   171         if (!::IsRectEmpty(&viewRect)) |  | 
|   172             ::AnimateWindow(m_popup, defaultAnimationDuration, AW_BLEND); |  | 
|   173     } else |  | 
|   174 #endif |  | 
|   175         ::ShowWindow(m_popup, SW_SHOWNOACTIVATE); |  | 
|   176  |  | 
|   177     if (client()) { |  | 
|   178         int index = client()->selectedIndex(); |  | 
|   179         if (index >= 0) |  | 
|   180             setFocusedIndex(index); |  | 
|   181     } |  | 
|   182  |  | 
|   183     m_showPopup = true; |  | 
|   184  |  | 
|   185     // Protect the popup menu in case its owner is destroyed while we're running
       the message pump. |  | 
|   186     RefPtr<PopupMenu> protect(this); |  | 
|   187  |  | 
|   188     ::SetCapture(hostWindow); |  | 
|   189  |  | 
|   190     MSG msg; |  | 
|   191     HWND activeWindow; |  | 
|   192  |  | 
|   193     while (::GetMessage(&msg, 0, 0, 0)) { |  | 
|   194         switch (msg.message) { |  | 
|   195             case WM_HOST_WINDOW_MOUSEMOVE: |  | 
|   196             case WM_HOST_WINDOW_CHAR:  |  | 
|   197                 if (msg.hwnd == m_popup) { |  | 
|   198                     // This message should be sent to the host window. |  | 
|   199                     msg.hwnd = hostWindow; |  | 
|   200                     msg.message -= WM_HOST_WINDOW_FIRST; |  | 
|   201                 } |  | 
|   202                 break; |  | 
|   203  |  | 
|   204             // Steal mouse messages. |  | 
|   205 #if !OS(WINCE) |  | 
|   206             case WM_NCMOUSEMOVE: |  | 
|   207             case WM_NCLBUTTONDOWN: |  | 
|   208             case WM_NCLBUTTONUP: |  | 
|   209             case WM_NCLBUTTONDBLCLK: |  | 
|   210             case WM_NCRBUTTONDOWN: |  | 
|   211             case WM_NCRBUTTONUP: |  | 
|   212             case WM_NCRBUTTONDBLCLK: |  | 
|   213             case WM_NCMBUTTONDOWN: |  | 
|   214             case WM_NCMBUTTONUP: |  | 
|   215             case WM_NCMBUTTONDBLCLK: |  | 
|   216 #endif |  | 
|   217             case WM_MOUSEWHEEL: |  | 
|   218                 msg.hwnd = m_popup; |  | 
|   219                 break; |  | 
|   220  |  | 
|   221             // These mouse messages use client coordinates so we need to convert
       them. |  | 
|   222             case WM_MOUSEMOVE: |  | 
|   223             case WM_LBUTTONDOWN: |  | 
|   224             case WM_LBUTTONUP: |  | 
|   225             case WM_LBUTTONDBLCLK: |  | 
|   226             case WM_RBUTTONDOWN: |  | 
|   227             case WM_RBUTTONUP: |  | 
|   228             case WM_RBUTTONDBLCLK: |  | 
|   229             case WM_MBUTTONDOWN: |  | 
|   230             case WM_MBUTTONUP: |  | 
|   231             case WM_MBUTTONDBLCLK: { |  | 
|   232                 // Translate the coordinate. |  | 
|   233                 translatePoint(msg.lParam, msg.hwnd, m_popup); |  | 
|   234  |  | 
|   235                 msg.hwnd = m_popup; |  | 
|   236                 break; |  | 
|   237             } |  | 
|   238  |  | 
|   239             // Steal all keyboard messages. |  | 
|   240             case WM_KEYDOWN: |  | 
|   241             case WM_KEYUP: |  | 
|   242             case WM_CHAR: |  | 
|   243             case WM_DEADCHAR: |  | 
|   244             case WM_SYSKEYDOWN: |  | 
|   245             case WM_SYSKEYUP: |  | 
|   246             case WM_SYSCHAR: |  | 
|   247             case WM_SYSDEADCHAR: |  | 
|   248                 msg.hwnd = m_popup; |  | 
|   249                 break; |  | 
|   250         } |  | 
|   251  |  | 
|   252         ::TranslateMessage(&msg); |  | 
|   253         ::DispatchMessage(&msg); |  | 
|   254  |  | 
|   255         if (!m_popupClient) |  | 
|   256             break; |  | 
|   257  |  | 
|   258         if (!m_showPopup) |  | 
|   259             break; |  | 
|   260         activeWindow = ::GetActiveWindow(); |  | 
|   261         if (activeWindow != hostWindow && !::IsChild(activeWindow, hostWindow)) |  | 
|   262             break; |  | 
|   263         if (::GetCapture() != hostWindow) |  | 
|   264             break; |  | 
|   265     } |  | 
|   266  |  | 
|   267     if (::GetCapture() == hostWindow) |  | 
|   268         ::ReleaseCapture(); |  | 
|   269  |  | 
|   270     // We're done, hide the popup if necessary. |  | 
|   271     hide(); |  | 
|   272 } |  | 
|   273  |  | 
|   274 void PopupMenuWin::hide() |  | 
|   275 { |  | 
|   276     if (!m_showPopup) |  | 
|   277         return; |  | 
|   278  |  | 
|   279     m_showPopup = false; |  | 
|   280  |  | 
|   281     ::ShowWindow(m_popup, SW_HIDE); |  | 
|   282  |  | 
|   283     if (client()) |  | 
|   284         client()->popupDidHide(); |  | 
|   285  |  | 
|   286     // Post a WM_NULL message to wake up the message pump if necessary. |  | 
|   287     ::PostMessage(m_popup, WM_NULL, 0, 0); |  | 
|   288 } |  | 
|   289  |  | 
|   290 // The screen that the popup is placed on should be whichever one the popup menu
       button lies on. |  | 
|   291 // We fake an hwnd (here we use the popup's hwnd) on top of the button which we 
      can then use to determine the screen. |  | 
|   292 // We can then proceed with our final position/size calculations. |  | 
|   293 void PopupMenuWin::calculatePositionAndSize(const IntRect& r, FrameView* v) |  | 
|   294 { |  | 
|   295     // First get the screen coordinates of the popup menu client. |  | 
|   296     HWND hostWindow = v->hostWindow()->platformPageClient(); |  | 
|   297     IntRect absoluteBounds = ((RenderMenuList*)m_popupClient)->absoluteBoundingB
      oxRect(); |  | 
|   298     IntRect absoluteScreenCoords(v->contentsToWindow(absoluteBounds.location()),
       absoluteBounds.size()); |  | 
|   299     POINT absoluteLocation(absoluteScreenCoords.location()); |  | 
|   300     if (!::ClientToScreen(v->hostWindow()->platformPageClient(), &absoluteLocati
      on)) |  | 
|   301         return; |  | 
|   302     absoluteScreenCoords.setLocation(absoluteLocation); |  | 
|   303  |  | 
|   304     // Now set the popup menu's location temporarily to these coordinates so we 
      can determine which screen the popup should lie on. |  | 
|   305     // We create or move m_popup as necessary. |  | 
|   306     if (!m_popup) { |  | 
|   307         registerClass(); |  | 
|   308         DWORD exStyle = WS_EX_LTRREADING; |  | 
|   309         m_popup = ::CreateWindowExW(exStyle, kPopupWindowClassName, L"PopupMenu"
      , |  | 
|   310             WS_POPUP | WS_BORDER, |  | 
|   311             absoluteScreenCoords.x(), absoluteScreenCoords.y(), absoluteScreenCo
      ords.width(), absoluteScreenCoords.height(), |  | 
|   312             hostWindow, 0, WebCore::instanceHandle(), this); |  | 
|   313  |  | 
|   314         if (!m_popup) |  | 
|   315             return; |  | 
|   316     } else |  | 
|   317         ::MoveWindow(m_popup, absoluteScreenCoords.x(), absoluteScreenCoords.y()
      , absoluteScreenCoords.width(), absoluteScreenCoords.height(), false); |  | 
|   318  |  | 
|   319     FloatRect screen = monitorFromHwnd(m_popup); |  | 
|   320      |  | 
|   321     // Now we determine the actual location and measurements of the popup itself
      . |  | 
|   322     // r is in absolute document coordinates, but we want to be in screen coordi
      nates. |  | 
|   323  |  | 
|   324     // First, move to WebView coordinates |  | 
|   325     IntRect rScreenCoords(v->contentsToWindow(r.location()), r.size()); |  | 
|   326  |  | 
|   327     // Then, translate to screen coordinates |  | 
|   328     POINT location(rScreenCoords.location()); |  | 
|   329     if (!::ClientToScreen(v->hostWindow()->platformPageClient(), &location)) |  | 
|   330         return; |  | 
|   331  |  | 
|   332     rScreenCoords.setLocation(location); |  | 
|   333  |  | 
|   334     // First, determine the popup's height |  | 
|   335     int itemCount = client()->listSize(); |  | 
|   336     m_itemHeight = client()->menuStyle().font().fontMetrics().height() + optionS
      pacingMiddle; |  | 
|   337     int naturalHeight = m_itemHeight * itemCount; |  | 
|   338     int popupHeight = min(maxPopupHeight, naturalHeight); |  | 
|   339     // The popup should show an integral number of items (i.e. no partial items 
      should be visible) |  | 
|   340     popupHeight -= popupHeight % m_itemHeight; |  | 
|   341      |  | 
|   342     // Next determine its width |  | 
|   343     int popupWidth = 0; |  | 
|   344     for (int i = 0; i < itemCount; ++i) { |  | 
|   345         String text = client()->itemText(i); |  | 
|   346         if (text.isEmpty()) |  | 
|   347             continue; |  | 
|   348  |  | 
|   349         Font itemFont = client()->menuStyle().font(); |  | 
|   350         if (client()->itemIsLabel(i)) { |  | 
|   351             FontDescription d = itemFont.fontDescription(); |  | 
|   352             d.setWeight(d.bolderWeight()); |  | 
|   353             itemFont = Font(d, itemFont.letterSpacing(), itemFont.wordSpacing())
      ; |  | 
|   354             itemFont.update(m_popupClient->fontSelector()); |  | 
|   355         } |  | 
|   356  |  | 
|   357         popupWidth = max(popupWidth, static_cast<int>(ceilf(itemFont.width(TextR
      un(text.characters(), text.length()))))); |  | 
|   358     } |  | 
|   359  |  | 
|   360     if (naturalHeight > maxPopupHeight) |  | 
|   361         // We need room for a scrollbar |  | 
|   362         popupWidth += ScrollbarTheme::theme()->scrollbarThickness(SmallScrollbar
      ); |  | 
|   363  |  | 
|   364     // Add padding to align the popup text with the <select> text |  | 
|   365     popupWidth += max<int>(0, client()->clientPaddingRight() - client()->clientI
      nsetRight()) + max<int>(0, client()->clientPaddingLeft() - client()->clientInset
      Left()); |  | 
|   366  |  | 
|   367     // Leave room for the border |  | 
|   368     popupWidth += 2 * popupWindowBorderWidth; |  | 
|   369     popupHeight += 2 * popupWindowBorderWidth; |  | 
|   370  |  | 
|   371     // The popup should be at least as wide as the control on the page |  | 
|   372     popupWidth = max(rScreenCoords.width() - client()->clientInsetLeft() - clien
      t()->clientInsetRight(), popupWidth); |  | 
|   373  |  | 
|   374     // Always left-align items in the popup.  This matches popup menus on the ma
      c. |  | 
|   375     int popupX = rScreenCoords.x() + client()->clientInsetLeft(); |  | 
|   376  |  | 
|   377     IntRect popupRect(popupX, rScreenCoords.maxY(), popupWidth, popupHeight); |  | 
|   378  |  | 
|   379     // Check that we don't go off the screen vertically |  | 
|   380     if (popupRect.maxY() > screen.height()) { |  | 
|   381         // The popup will go off the screen, so try placing it above the client |  | 
|   382         if (rScreenCoords.y() - popupRect.height() < 0) { |  | 
|   383             // The popup won't fit above, either, so place it whereever's bigger
       and resize it to fit |  | 
|   384             if ((rScreenCoords.y() + rScreenCoords.height() / 2) < (screen.heigh
      t() / 2)) { |  | 
|   385                 // Below is bigger |  | 
|   386                 popupRect.setHeight(screen.height() - popupRect.y()); |  | 
|   387             } else { |  | 
|   388                 // Above is bigger |  | 
|   389                 popupRect.setY(0); |  | 
|   390                 popupRect.setHeight(rScreenCoords.y()); |  | 
|   391             } |  | 
|   392         } else { |  | 
|   393             // The popup fits above, so reposition it |  | 
|   394             popupRect.setY(rScreenCoords.y() - popupRect.height()); |  | 
|   395         } |  | 
|   396     } |  | 
|   397  |  | 
|   398     // Check that we don't go off the screen horizontally |  | 
|   399     if (popupRect.x() + popupRect.width() > screen.width() + screen.x()) |  | 
|   400         popupRect.setX(screen.x() + screen.width() - popupRect.width()); |  | 
|   401     if (popupRect.x() < screen.x()) |  | 
|   402         popupRect.setX(screen.x()); |  | 
|   403  |  | 
|   404     m_windowRect = popupRect; |  | 
|   405     return; |  | 
|   406 } |  | 
|   407  |  | 
|   408 bool PopupMenuWin::setFocusedIndex(int i, bool hotTracking) |  | 
|   409 { |  | 
|   410     if (i < 0 || i >= client()->listSize() || i == focusedIndex()) |  | 
|   411         return false; |  | 
|   412  |  | 
|   413     if (!client()->itemIsEnabled(i)) |  | 
|   414         return false; |  | 
|   415  |  | 
|   416     invalidateItem(focusedIndex()); |  | 
|   417     invalidateItem(i); |  | 
|   418  |  | 
|   419     m_focusedIndex = i; |  | 
|   420  |  | 
|   421     if (!hotTracking) |  | 
|   422         client()->setTextFromItem(i); |  | 
|   423  |  | 
|   424     if (!scrollToRevealSelection()) |  | 
|   425         ::UpdateWindow(m_popup); |  | 
|   426  |  | 
|   427     return true; |  | 
|   428 } |  | 
|   429  |  | 
|   430 int PopupMenuWin::visibleItems() const |  | 
|   431 { |  | 
|   432     return clientRect().height() / m_itemHeight; |  | 
|   433 } |  | 
|   434  |  | 
|   435 int PopupMenuWin::listIndexAtPoint(const IntPoint& point) const |  | 
|   436 { |  | 
|   437     return m_scrollOffset + point.y() / m_itemHeight; |  | 
|   438 } |  | 
|   439  |  | 
|   440 int PopupMenuWin::focusedIndex() const |  | 
|   441 { |  | 
|   442     return m_focusedIndex; |  | 
|   443 } |  | 
|   444  |  | 
|   445 void PopupMenuWin::focusFirst() |  | 
|   446 { |  | 
|   447     if (!client()) |  | 
|   448         return; |  | 
|   449  |  | 
|   450     int size = client()->listSize(); |  | 
|   451  |  | 
|   452     for (int i = 0; i < size; ++i) |  | 
|   453         if (client()->itemIsEnabled(i)) { |  | 
|   454             setFocusedIndex(i); |  | 
|   455             break; |  | 
|   456         } |  | 
|   457 } |  | 
|   458  |  | 
|   459 void PopupMenuWin::focusLast() |  | 
|   460 { |  | 
|   461     if (!client()) |  | 
|   462         return; |  | 
|   463  |  | 
|   464     int size = client()->listSize(); |  | 
|   465  |  | 
|   466     for (int i = size - 1; i > 0; --i) |  | 
|   467         if (client()->itemIsEnabled(i)) { |  | 
|   468             setFocusedIndex(i); |  | 
|   469             break; |  | 
|   470         } |  | 
|   471 } |  | 
|   472  |  | 
|   473 bool PopupMenuWin::down(unsigned lines) |  | 
|   474 { |  | 
|   475     if (!client()) |  | 
|   476         return false; |  | 
|   477  |  | 
|   478     int size = client()->listSize(); |  | 
|   479  |  | 
|   480     int lastSelectableIndex, selectedListIndex; |  | 
|   481     lastSelectableIndex = selectedListIndex = focusedIndex(); |  | 
|   482     for (int i = selectedListIndex + 1; i >= 0 && i < size; ++i) |  | 
|   483         if (client()->itemIsEnabled(i)) { |  | 
|   484             lastSelectableIndex = i; |  | 
|   485             if (i >= selectedListIndex + (int)lines) |  | 
|   486                 break; |  | 
|   487         } |  | 
|   488  |  | 
|   489     return setFocusedIndex(lastSelectableIndex); |  | 
|   490 } |  | 
|   491  |  | 
|   492 bool PopupMenuWin::up(unsigned lines) |  | 
|   493 { |  | 
|   494     if (!client()) |  | 
|   495         return false; |  | 
|   496  |  | 
|   497     int size = client()->listSize(); |  | 
|   498  |  | 
|   499     int lastSelectableIndex, selectedListIndex; |  | 
|   500     lastSelectableIndex = selectedListIndex = focusedIndex(); |  | 
|   501     for (int i = selectedListIndex - 1; i >= 0 && i < size; --i) |  | 
|   502         if (client()->itemIsEnabled(i)) { |  | 
|   503             lastSelectableIndex = i; |  | 
|   504             if (i <= selectedListIndex - (int)lines) |  | 
|   505                 break; |  | 
|   506         } |  | 
|   507  |  | 
|   508     return setFocusedIndex(lastSelectableIndex); |  | 
|   509 } |  | 
|   510  |  | 
|   511 void PopupMenuWin::invalidateItem(int index) |  | 
|   512 { |  | 
|   513     if (!m_popup) |  | 
|   514         return; |  | 
|   515  |  | 
|   516     IntRect damageRect(clientRect()); |  | 
|   517     damageRect.setY(m_itemHeight * (index - m_scrollOffset)); |  | 
|   518     damageRect.setHeight(m_itemHeight); |  | 
|   519     if (m_scrollbar) |  | 
|   520         damageRect.setWidth(damageRect.width() - m_scrollbar->frameRect().width(
      )); |  | 
|   521  |  | 
|   522     RECT r = damageRect; |  | 
|   523     ::InvalidateRect(m_popup, &r, TRUE); |  | 
|   524 } |  | 
|   525  |  | 
|   526 IntRect PopupMenuWin::clientRect() const |  | 
|   527 { |  | 
|   528     IntRect clientRect = m_windowRect; |  | 
|   529     clientRect.inflate(-popupWindowBorderWidth); |  | 
|   530     clientRect.setLocation(IntPoint(0, 0)); |  | 
|   531     return clientRect; |  | 
|   532 } |  | 
|   533  |  | 
|   534 void PopupMenuWin::incrementWheelDelta(int delta) |  | 
|   535 { |  | 
|   536     m_wheelDelta += delta; |  | 
|   537 } |  | 
|   538  |  | 
|   539 void PopupMenuWin::reduceWheelDelta(int delta) |  | 
|   540 { |  | 
|   541     ASSERT(delta >= 0); |  | 
|   542     ASSERT(delta <= abs(m_wheelDelta)); |  | 
|   543  |  | 
|   544     if (m_wheelDelta > 0) |  | 
|   545         m_wheelDelta -= delta; |  | 
|   546     else if (m_wheelDelta < 0) |  | 
|   547         m_wheelDelta += delta; |  | 
|   548     else |  | 
|   549         return; |  | 
|   550 } |  | 
|   551  |  | 
|   552 bool PopupMenuWin::scrollToRevealSelection() |  | 
|   553 { |  | 
|   554     if (!m_scrollbar) |  | 
|   555         return false; |  | 
|   556  |  | 
|   557     int index = focusedIndex(); |  | 
|   558  |  | 
|   559     if (index < m_scrollOffset) { |  | 
|   560         ScrollableArea::scrollToOffsetWithoutAnimation(VerticalScrollbar, index)
      ; |  | 
|   561         return true; |  | 
|   562     } |  | 
|   563  |  | 
|   564     if (index >= m_scrollOffset + visibleItems()) { |  | 
|   565         ScrollableArea::scrollToOffsetWithoutAnimation(VerticalScrollbar, index 
      - visibleItems() + 1); |  | 
|   566         return true; |  | 
|   567     } |  | 
|   568  |  | 
|   569     return false; |  | 
|   570 } |  | 
|   571  |  | 
|   572 void PopupMenuWin::updateFromElement() |  | 
|   573 { |  | 
|   574     if (!m_popup) |  | 
|   575         return; |  | 
|   576  |  | 
|   577     m_focusedIndex = client()->selectedIndex(); |  | 
|   578  |  | 
|   579     ::InvalidateRect(m_popup, 0, TRUE); |  | 
|   580     if (!scrollToRevealSelection()) |  | 
|   581         ::UpdateWindow(m_popup); |  | 
|   582 } |  | 
|   583  |  | 
|   584 const int separatorPadding = 4; |  | 
|   585 const int separatorHeight = 1; |  | 
|   586 void PopupMenuWin::paint(const IntRect& damageRect, HDC hdc) |  | 
|   587 { |  | 
|   588     if (!m_popup) |  | 
|   589         return; |  | 
|   590  |  | 
|   591     if (!m_DC) { |  | 
|   592         m_DC = ::CreateCompatibleDC(HWndDC(m_popup)); |  | 
|   593         if (!m_DC) |  | 
|   594             return; |  | 
|   595     } |  | 
|   596  |  | 
|   597     if (m_bmp) { |  | 
|   598         bool keepBitmap = false; |  | 
|   599         BITMAP bitmap; |  | 
|   600         if (GetObject(m_bmp, sizeof(bitmap), &bitmap)) |  | 
|   601             keepBitmap = bitmap.bmWidth == clientRect().width() |  | 
|   602                 && bitmap.bmHeight == clientRect().height(); |  | 
|   603         if (!keepBitmap) { |  | 
|   604             DeleteObject(m_bmp); |  | 
|   605             m_bmp = 0; |  | 
|   606         } |  | 
|   607     } |  | 
|   608     if (!m_bmp) { |  | 
|   609 #if OS(WINCE) |  | 
|   610         BitmapInfo bitmapInfo = BitmapInfo::createBottomUp(clientRect().size(), 
      BitmapInfo::BitCount16); |  | 
|   611 #else |  | 
|   612         BitmapInfo bitmapInfo = BitmapInfo::createBottomUp(clientRect().size()); |  | 
|   613 #endif |  | 
|   614         void* pixels = 0; |  | 
|   615         m_bmp = ::CreateDIBSection(m_DC, &bitmapInfo, DIB_RGB_COLORS, &pixels, 0
      , 0); |  | 
|   616         if (!m_bmp) |  | 
|   617             return; |  | 
|   618  |  | 
|   619         ::SelectObject(m_DC, m_bmp); |  | 
|   620     } |  | 
|   621  |  | 
|   622     GraphicsContext context(m_DC); |  | 
|   623  |  | 
|   624     int itemCount = client()->listSize(); |  | 
|   625  |  | 
|   626     // listRect is the damageRect translated into the coordinates of the entire 
      menu list (which is itemCount * m_itemHeight pixels tall) |  | 
|   627     IntRect listRect = damageRect; |  | 
|   628     listRect.move(IntSize(0, m_scrollOffset * m_itemHeight)); |  | 
|   629  |  | 
|   630     for (int y = listRect.y(); y < listRect.maxY(); y += m_itemHeight) { |  | 
|   631         int index = y / m_itemHeight; |  | 
|   632  |  | 
|   633         Color optionBackgroundColor, optionTextColor; |  | 
|   634         PopupMenuStyle itemStyle = client()->itemStyle(index); |  | 
|   635         if (index == focusedIndex()) { |  | 
|   636             optionBackgroundColor = RenderTheme::defaultTheme()->activeListBoxSe
      lectionBackgroundColor(); |  | 
|   637             optionTextColor = RenderTheme::defaultTheme()->activeListBoxSelectio
      nForegroundColor(); |  | 
|   638         } else { |  | 
|   639             optionBackgroundColor = itemStyle.backgroundColor(); |  | 
|   640             optionTextColor = itemStyle.foregroundColor(); |  | 
|   641         } |  | 
|   642  |  | 
|   643         // itemRect is in client coordinates |  | 
|   644         IntRect itemRect(0, (index - m_scrollOffset) * m_itemHeight, damageRect.
      width(), m_itemHeight); |  | 
|   645  |  | 
|   646         // Draw the background for this menu item |  | 
|   647         if (itemStyle.isVisible()) |  | 
|   648             context.fillRect(itemRect, optionBackgroundColor, ColorSpaceDeviceRG
      B); |  | 
|   649  |  | 
|   650         if (client()->itemIsSeparator(index)) { |  | 
|   651             IntRect separatorRect(itemRect.x() + separatorPadding, itemRect.y() 
      + (itemRect.height() - separatorHeight) / 2, itemRect.width() - 2 * separatorPad
      ding, separatorHeight); |  | 
|   652             context.fillRect(separatorRect, optionTextColor, ColorSpaceDeviceRGB
      ); |  | 
|   653             continue; |  | 
|   654         } |  | 
|   655  |  | 
|   656         String itemText = client()->itemText(index); |  | 
|   657              |  | 
|   658         TextDirection direction = (itemText.defaultWritingDirection() == WTF::Un
      icode::RightToLeft) ? RTL : LTR; |  | 
|   659         TextRun textRun(itemText, 0, 0, TextRun::AllowTrailingExpansion, directi
      on); |  | 
|   660  |  | 
|   661         context.setFillColor(optionTextColor, ColorSpaceDeviceRGB); |  | 
|   662          |  | 
|   663         Font itemFont = client()->menuStyle().font(); |  | 
|   664         if (client()->itemIsLabel(index)) { |  | 
|   665             FontDescription d = itemFont.fontDescription(); |  | 
|   666             d.setWeight(d.bolderWeight()); |  | 
|   667             itemFont = Font(d, itemFont.letterSpacing(), itemFont.wordSpacing())
      ; |  | 
|   668             itemFont.update(m_popupClient->fontSelector()); |  | 
|   669         } |  | 
|   670          |  | 
|   671         // Draw the item text |  | 
|   672         if (itemStyle.isVisible()) { |  | 
|   673             int textX = max<int>(0, client()->clientPaddingLeft() - client()->cl
      ientInsetLeft()); |  | 
|   674             if (RenderTheme::defaultTheme()->popupOptionSupportsTextIndent() && 
      itemStyle.textDirection() == LTR) |  | 
|   675                 textX += minimumIntValueForLength(itemStyle.textIndent(), itemRe
      ct.width()); |  | 
|   676             int textY = itemRect.y() + itemFont.fontMetrics().ascent() + (itemRe
      ct.height() - itemFont.fontMetrics().height()) / 2; |  | 
|   677             context.drawBidiText(itemFont, textRun, IntPoint(textX, textY)); |  | 
|   678         } |  | 
|   679     } |  | 
|   680  |  | 
|   681     if (m_scrollbar) |  | 
|   682         m_scrollbar->paint(&context, damageRect); |  | 
|   683  |  | 
|   684     HWndDC hWndDC; |  | 
|   685     HDC localDC = hdc ? hdc : hWndDC.setHWnd(m_popup); |  | 
|   686  |  | 
|   687     ::BitBlt(localDC, damageRect.x(), damageRect.y(), damageRect.width(), damage
      Rect.height(), m_DC, damageRect.x(), damageRect.y(), SRCCOPY); |  | 
|   688 } |  | 
|   689  |  | 
|   690 int PopupMenuWin::scrollSize(ScrollbarOrientation orientation) const |  | 
|   691 { |  | 
|   692     return ((orientation == VerticalScrollbar) && m_scrollbar) ? (m_scrollbar->t
      otalSize() - m_scrollbar->visibleSize()) : 0; |  | 
|   693 } |  | 
|   694  |  | 
|   695 int PopupMenuWin::scrollPosition(Scrollbar*) const |  | 
|   696 { |  | 
|   697     return m_scrollOffset; |  | 
|   698 } |  | 
|   699  |  | 
|   700 void PopupMenuWin::setScrollOffset(const IntPoint& offset) |  | 
|   701 { |  | 
|   702     scrollTo(offset.y()); |  | 
|   703 } |  | 
|   704  |  | 
|   705 void PopupMenuWin::scrollTo(int offset) |  | 
|   706 { |  | 
|   707     ASSERT(m_scrollbar); |  | 
|   708  |  | 
|   709     if (!m_popup) |  | 
|   710         return; |  | 
|   711  |  | 
|   712     if (m_scrollOffset == offset) |  | 
|   713         return; |  | 
|   714  |  | 
|   715     int scrolledLines = m_scrollOffset - offset; |  | 
|   716     m_scrollOffset = offset; |  | 
|   717  |  | 
|   718     UINT flags = SW_INVALIDATE; |  | 
|   719  |  | 
|   720 #ifdef CAN_SET_SMOOTH_SCROLLING_DURATION |  | 
|   721     BOOL shouldSmoothScroll = FALSE; |  | 
|   722     ::SystemParametersInfo(SPI_GETLISTBOXSMOOTHSCROLLING, 0, &shouldSmoothScroll
      , 0); |  | 
|   723     if (shouldSmoothScroll) |  | 
|   724         flags |= MAKEWORD(SW_SMOOTHSCROLL, smoothScrollAnimationDuration); |  | 
|   725 #endif |  | 
|   726  |  | 
|   727     IntRect listRect = clientRect(); |  | 
|   728     if (m_scrollbar) |  | 
|   729         listRect.setWidth(listRect.width() - m_scrollbar->frameRect().width()); |  | 
|   730     RECT r = listRect; |  | 
|   731     ::ScrollWindowEx(m_popup, 0, scrolledLines * m_itemHeight, &r, 0, 0, 0, flag
      s); |  | 
|   732     if (m_scrollbar) { |  | 
|   733         r = m_scrollbar->frameRect(); |  | 
|   734         ::InvalidateRect(m_popup, &r, TRUE); |  | 
|   735     } |  | 
|   736     ::UpdateWindow(m_popup); |  | 
|   737 } |  | 
|   738  |  | 
|   739 void PopupMenuWin::invalidateScrollbarRect(Scrollbar* scrollbar, const IntRect& 
      rect) |  | 
|   740 { |  | 
|   741     IntRect scrollRect = rect; |  | 
|   742     scrollRect.move(scrollbar->x(), scrollbar->y()); |  | 
|   743     RECT r = scrollRect; |  | 
|   744     ::InvalidateRect(m_popup, &r, false); |  | 
|   745 } |  | 
|   746  |  | 
|   747 int PopupMenuWin::visibleHeight() const |  | 
|   748 { |  | 
|   749     return m_scrollbar ? m_scrollbar->visibleSize() : m_windowRect.height(); |  | 
|   750 } |  | 
|   751  |  | 
|   752 int PopupMenuWin::visibleWidth() const |  | 
|   753 { |  | 
|   754     return m_windowRect.width(); |  | 
|   755 } |  | 
|   756  |  | 
|   757 IntSize PopupMenuWin::contentsSize() const |  | 
|   758 { |  | 
|   759     return m_windowRect.size(); |  | 
|   760 } |  | 
|   761  |  | 
|   762 bool PopupMenuWin::scrollbarsCanBeActive() const |  | 
|   763 { |  | 
|   764     return m_showPopup; |  | 
|   765 } |  | 
|   766  |  | 
|   767 IntRect PopupMenuWin::scrollableAreaBoundingBox() const |  | 
|   768 { |  | 
|   769     return m_windowRect; |  | 
|   770 } |  | 
|   771  |  | 
|   772 void PopupMenuWin::registerClass() |  | 
|   773 { |  | 
|   774     static bool haveRegisteredWindowClass = false; |  | 
|   775  |  | 
|   776     if (haveRegisteredWindowClass) |  | 
|   777         return; |  | 
|   778  |  | 
|   779 #if OS(WINCE) |  | 
|   780     WNDCLASS wcex; |  | 
|   781 #else |  | 
|   782     WNDCLASSEX wcex; |  | 
|   783     wcex.cbSize = sizeof(WNDCLASSEX); |  | 
|   784     wcex.hIconSm        = 0; |  | 
|   785     wcex.style          = CS_DROPSHADOW; |  | 
|   786 #endif |  | 
|   787  |  | 
|   788     wcex.lpfnWndProc    = PopupMenuWndProc; |  | 
|   789     wcex.cbClsExtra     = 0; |  | 
|   790     wcex.cbWndExtra     = sizeof(PopupMenu*); // For the PopupMenu pointer |  | 
|   791     wcex.hInstance      = WebCore::instanceHandle(); |  | 
|   792     wcex.hIcon          = 0; |  | 
|   793     wcex.hCursor        = LoadCursor(0, IDC_ARROW); |  | 
|   794     wcex.hbrBackground  = 0; |  | 
|   795     wcex.lpszMenuName   = 0; |  | 
|   796     wcex.lpszClassName  = kPopupWindowClassName; |  | 
|   797  |  | 
|   798     haveRegisteredWindowClass = true; |  | 
|   799  |  | 
|   800 #if OS(WINCE) |  | 
|   801     RegisterClass(&wcex); |  | 
|   802 #else |  | 
|   803     RegisterClassEx(&wcex); |  | 
|   804 #endif |  | 
|   805 } |  | 
|   806  |  | 
|   807  |  | 
|   808 LRESULT CALLBACK PopupMenuWin::PopupMenuWndProc(HWND hWnd, UINT message, WPARAM 
      wParam, LPARAM lParam) |  | 
|   809 { |  | 
|   810     if (PopupMenuWin* popup = static_cast<PopupMenuWin*>(getWindowPointer(hWnd, 
      0))) |  | 
|   811         return popup->wndProc(hWnd, message, wParam, lParam); |  | 
|   812  |  | 
|   813     if (message == WM_CREATE) { |  | 
|   814         LPCREATESTRUCT createStruct = reinterpret_cast<LPCREATESTRUCT>(lParam); |  | 
|   815  |  | 
|   816         // Associate the PopupMenu with the window. |  | 
|   817         setWindowPointer(hWnd, 0, createStruct->lpCreateParams); |  | 
|   818         return 0; |  | 
|   819     } |  | 
|   820  |  | 
|   821     return ::DefWindowProc(hWnd, message, wParam, lParam); |  | 
|   822 } |  | 
|   823  |  | 
|   824 const int smoothScrollAnimationDuration = 5000; |  | 
|   825  |  | 
|   826 LRESULT PopupMenuWin::wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lPa
      ram) |  | 
|   827 { |  | 
|   828     LRESULT lResult = 0; |  | 
|   829  |  | 
|   830     switch (message) { |  | 
|   831 #if !OS(WINCE) |  | 
|   832         case WM_MOUSEACTIVATE: |  | 
|   833             return MA_NOACTIVATE; |  | 
|   834 #endif |  | 
|   835         case WM_SIZE: { |  | 
|   836             if (!scrollbar()) |  | 
|   837                 break; |  | 
|   838  |  | 
|   839             IntSize size(LOWORD(lParam), HIWORD(lParam)); |  | 
|   840             scrollbar()->setFrameRect(IntRect(size.width() - scrollbar()->width(
      ), 0, scrollbar()->width(), size.height())); |  | 
|   841  |  | 
|   842             int visibleItems = this->visibleItems(); |  | 
|   843             scrollbar()->setEnabled(visibleItems < client()->listSize()); |  | 
|   844             scrollbar()->setSteps(1, max(1, visibleItems - 1)); |  | 
|   845             scrollbar()->setProportion(visibleItems, client()->listSize()); |  | 
|   846  |  | 
|   847             break; |  | 
|   848         } |  | 
|   849         case WM_SYSKEYDOWN: |  | 
|   850         case WM_KEYDOWN: { |  | 
|   851             if (!client()) |  | 
|   852                 break; |  | 
|   853  |  | 
|   854             bool altKeyPressed = GetKeyState(VK_MENU) & HIGH_BIT_MASK_SHORT; |  | 
|   855             bool ctrlKeyPressed = GetKeyState(VK_CONTROL) & HIGH_BIT_MASK_SHORT; |  | 
|   856  |  | 
|   857             lResult = 0; |  | 
|   858             switch (LOWORD(wParam)) { |  | 
|   859                 case VK_F4: { |  | 
|   860                     if (!altKeyPressed && !ctrlKeyPressed) { |  | 
|   861                         int index = focusedIndex(); |  | 
|   862                         ASSERT(index >= 0); |  | 
|   863                         client()->valueChanged(index); |  | 
|   864                         hide(); |  | 
|   865                     } |  | 
|   866                     break; |  | 
|   867                 } |  | 
|   868                 case VK_DOWN: |  | 
|   869                     if (altKeyPressed) { |  | 
|   870                         int index = focusedIndex(); |  | 
|   871                         ASSERT(index >= 0); |  | 
|   872                         client()->valueChanged(index); |  | 
|   873                         hide(); |  | 
|   874                     } else |  | 
|   875                         down(); |  | 
|   876                     break; |  | 
|   877                 case VK_RIGHT: |  | 
|   878                     down(); |  | 
|   879                     break; |  | 
|   880                 case VK_UP: |  | 
|   881                     if (altKeyPressed) { |  | 
|   882                         int index = focusedIndex(); |  | 
|   883                         ASSERT(index >= 0); |  | 
|   884                         client()->valueChanged(index); |  | 
|   885                         hide(); |  | 
|   886                     } else |  | 
|   887                         up(); |  | 
|   888                     break; |  | 
|   889                 case VK_LEFT: |  | 
|   890                     up(); |  | 
|   891                     break; |  | 
|   892                 case VK_HOME: |  | 
|   893                     focusFirst(); |  | 
|   894                     break; |  | 
|   895                 case VK_END: |  | 
|   896                     focusLast(); |  | 
|   897                     break; |  | 
|   898                 case VK_PRIOR: |  | 
|   899                     if (focusedIndex() != scrollOffset()) { |  | 
|   900                         // Set the selection to the first visible item |  | 
|   901                         int firstVisibleItem = scrollOffset(); |  | 
|   902                         up(focusedIndex() - firstVisibleItem); |  | 
|   903                     } else { |  | 
|   904                         // The first visible item is selected, so move the selec
      tion back one page |  | 
|   905                         up(visibleItems()); |  | 
|   906                     } |  | 
|   907                     break; |  | 
|   908                 case VK_NEXT: { |  | 
|   909                     int lastVisibleItem = scrollOffset() + visibleItems() - 1; |  | 
|   910                     if (focusedIndex() != lastVisibleItem) { |  | 
|   911                         // Set the selection to the last visible item |  | 
|   912                         down(lastVisibleItem - focusedIndex()); |  | 
|   913                     } else { |  | 
|   914                         // The last visible item is selected, so move the select
      ion forward one page |  | 
|   915                         down(visibleItems()); |  | 
|   916                     } |  | 
|   917                     break; |  | 
|   918                 } |  | 
|   919                 case VK_TAB: |  | 
|   920                     ::SendMessage(client()->hostWindow()->platformPageClient(), 
      message, wParam, lParam); |  | 
|   921                     hide(); |  | 
|   922                     break; |  | 
|   923                 case VK_ESCAPE: |  | 
|   924                     hide(); |  | 
|   925                     break; |  | 
|   926                 default: |  | 
|   927                     if (isASCIIPrintable(wParam)) |  | 
|   928                         // Send the keydown to the WebView so it can be used for
       type-to-select. |  | 
|   929                         // Since we know that the virtual key is ASCII printable
      , it's OK to convert this to |  | 
|   930                         // a WM_CHAR message. (We don't want to call TranslateMe
      ssage because that will post a |  | 
|   931                         // WM_CHAR message that will be stolen and redirected to
       the popup HWND. |  | 
|   932                         ::PostMessage(m_popup, WM_HOST_WINDOW_CHAR, wParam, lPar
      am); |  | 
|   933                     else |  | 
|   934                         lResult = 1; |  | 
|   935                     break; |  | 
|   936             } |  | 
|   937             break; |  | 
|   938         } |  | 
|   939         case WM_CHAR: { |  | 
|   940             if (!client()) |  | 
|   941                 break; |  | 
|   942  |  | 
|   943             lResult = 0; |  | 
|   944             int index; |  | 
|   945             switch (wParam) { |  | 
|   946                 case 0x0D:   // Enter/Return |  | 
|   947                     hide(); |  | 
|   948                     index = focusedIndex(); |  | 
|   949                     ASSERT(index >= 0); |  | 
|   950                     client()->valueChanged(index); |  | 
|   951                     break; |  | 
|   952                 case 0x1B:   // Escape |  | 
|   953                     hide(); |  | 
|   954                     break; |  | 
|   955                 case 0x09:   // TAB |  | 
|   956                 case 0x08:   // Backspace |  | 
|   957                 case 0x0A:   // Linefeed |  | 
|   958                 default:     // Character |  | 
|   959                     lResult = 1; |  | 
|   960                     break; |  | 
|   961             } |  | 
|   962             break; |  | 
|   963         } |  | 
|   964         case WM_MOUSEMOVE: { |  | 
|   965             IntPoint mousePoint(MAKEPOINTS(lParam)); |  | 
|   966             if (scrollbar()) { |  | 
|   967                 IntRect scrollBarRect = scrollbar()->frameRect(); |  | 
|   968                 if (scrollbarCapturingMouse() || scrollBarRect.contains(mousePoi
      nt)) { |  | 
|   969                     // Put the point into coordinates relative to the scroll bar |  | 
|   970                     mousePoint.move(-scrollBarRect.x(), -scrollBarRect.y()); |  | 
|   971                     PlatformMouseEvent event(hWnd, message, wParam, MAKELPARAM(m
      ousePoint.x(), mousePoint.y())); |  | 
|   972                     scrollbar()->mouseMoved(event); |  | 
|   973                     break; |  | 
|   974                 } |  | 
|   975             } |  | 
|   976  |  | 
|   977             BOOL shouldHotTrack = FALSE; |  | 
|   978 #if !OS(WINCE) |  | 
|   979             ::SystemParametersInfo(SPI_GETHOTTRACKING, 0, &shouldHotTrack, 0); |  | 
|   980 #endif |  | 
|   981  |  | 
|   982             RECT bounds; |  | 
|   983             GetClientRect(popupHandle(), &bounds); |  | 
|   984             if (!::PtInRect(&bounds, mousePoint) && !(wParam & MK_LBUTTON) && cl
      ient()) { |  | 
|   985                 // When the mouse is not inside the popup menu and the left butt
      on isn't down, just |  | 
|   986                 // repost the message to the web view. |  | 
|   987  |  | 
|   988                 // Translate the coordinate. |  | 
|   989                 translatePoint(lParam, m_popup, client()->hostWindow()->platform
      PageClient()); |  | 
|   990  |  | 
|   991                 ::PostMessage(m_popup, WM_HOST_WINDOW_MOUSEMOVE, wParam, lParam)
      ; |  | 
|   992                 break; |  | 
|   993             } |  | 
|   994  |  | 
|   995             if ((shouldHotTrack || wParam & MK_LBUTTON) && ::PtInRect(&bounds, m
      ousePoint)) |  | 
|   996                 setFocusedIndex(listIndexAtPoint(mousePoint), true); |  | 
|   997  |  | 
|   998             break; |  | 
|   999         } |  | 
|  1000         case WM_LBUTTONDOWN: { |  | 
|  1001             IntPoint mousePoint(MAKEPOINTS(lParam)); |  | 
|  1002             if (scrollbar()) { |  | 
|  1003                 IntRect scrollBarRect = scrollbar()->frameRect(); |  | 
|  1004                 if (scrollBarRect.contains(mousePoint)) { |  | 
|  1005                     // Put the point into coordinates relative to the scroll bar |  | 
|  1006                     mousePoint.move(-scrollBarRect.x(), -scrollBarRect.y()); |  | 
|  1007                     PlatformMouseEvent event(hWnd, message, wParam, MAKELPARAM(m
      ousePoint.x(), mousePoint.y())); |  | 
|  1008                     scrollbar()->mouseDown(event); |  | 
|  1009                     setScrollbarCapturingMouse(true); |  | 
|  1010                     break; |  | 
|  1011                 } |  | 
|  1012             } |  | 
|  1013  |  | 
|  1014             // If the mouse is inside the window, update the focused index. Othe
      rwise,  |  | 
|  1015             // hide the popup. |  | 
|  1016             RECT bounds; |  | 
|  1017             GetClientRect(m_popup, &bounds); |  | 
|  1018             if (::PtInRect(&bounds, mousePoint)) |  | 
|  1019                 setFocusedIndex(listIndexAtPoint(mousePoint), true); |  | 
|  1020             else |  | 
|  1021                 hide(); |  | 
|  1022             break; |  | 
|  1023         } |  | 
|  1024         case WM_LBUTTONUP: { |  | 
|  1025             IntPoint mousePoint(MAKEPOINTS(lParam)); |  | 
|  1026             if (scrollbar()) { |  | 
|  1027                 IntRect scrollBarRect = scrollbar()->frameRect(); |  | 
|  1028                 if (scrollbarCapturingMouse() || scrollBarRect.contains(mousePoi
      nt)) { |  | 
|  1029                     setScrollbarCapturingMouse(false); |  | 
|  1030                     // Put the point into coordinates relative to the scroll bar |  | 
|  1031                     mousePoint.move(-scrollBarRect.x(), -scrollBarRect.y()); |  | 
|  1032                     PlatformMouseEvent event(hWnd, message, wParam, MAKELPARAM(m
      ousePoint.x(), mousePoint.y())); |  | 
|  1033                     scrollbar()->mouseUp(event); |  | 
|  1034                     // FIXME: This is a hack to work around Scrollbar not invali
      dating correctly when it doesn't have a parent widget |  | 
|  1035                     RECT r = scrollBarRect; |  | 
|  1036                     ::InvalidateRect(popupHandle(), &r, TRUE); |  | 
|  1037                     break; |  | 
|  1038                 } |  | 
|  1039             } |  | 
|  1040             // Only hide the popup if the mouse is inside the popup window. |  | 
|  1041             RECT bounds; |  | 
|  1042             GetClientRect(popupHandle(), &bounds); |  | 
|  1043             if (client() && ::PtInRect(&bounds, mousePoint)) { |  | 
|  1044                 hide(); |  | 
|  1045                 int index = focusedIndex(); |  | 
|  1046                 if (index >= 0) |  | 
|  1047                     client()->valueChanged(index); |  | 
|  1048             } |  | 
|  1049             break; |  | 
|  1050         } |  | 
|  1051  |  | 
|  1052         case WM_MOUSEWHEEL: { |  | 
|  1053             if (!scrollbar()) |  | 
|  1054                 break; |  | 
|  1055  |  | 
|  1056             int i = 0; |  | 
|  1057             for (incrementWheelDelta(GET_WHEEL_DELTA_WPARAM(wParam)); abs(wheelD
      elta()) >= WHEEL_DELTA; reduceWheelDelta(WHEEL_DELTA)) { |  | 
|  1058                 if (wheelDelta() > 0) |  | 
|  1059                     ++i; |  | 
|  1060                 else |  | 
|  1061                     --i; |  | 
|  1062             } |  | 
|  1063  |  | 
|  1064             ScrollableArea::scroll(i > 0 ? ScrollUp : ScrollDown, ScrollByLine, 
      abs(i)); |  | 
|  1065             break; |  | 
|  1066         } |  | 
|  1067  |  | 
|  1068         case WM_PAINT: { |  | 
|  1069             PAINTSTRUCT paintInfo; |  | 
|  1070             ::BeginPaint(popupHandle(), &paintInfo); |  | 
|  1071             paint(paintInfo.rcPaint, paintInfo.hdc); |  | 
|  1072             ::EndPaint(popupHandle(), &paintInfo); |  | 
|  1073             lResult = 0; |  | 
|  1074             break; |  | 
|  1075         } |  | 
|  1076 #if !OS(WINCE) |  | 
|  1077         case WM_PRINTCLIENT: |  | 
|  1078             paint(clientRect(), (HDC)wParam); |  | 
|  1079             break; |  | 
|  1080 #endif |  | 
|  1081         default: |  | 
|  1082             lResult = DefWindowProc(hWnd, message, wParam, lParam); |  | 
|  1083     } |  | 
|  1084  |  | 
|  1085     return lResult; |  | 
|  1086 } |  | 
|  1087  |  | 
|  1088 } |  | 
| OLD | NEW |