[Win] Popup menu is not accessible.
authorpeavo@outlook.com <peavo@outlook.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 24 Apr 2015 11:42:43 +0000 (11:42 +0000)
committerpeavo@outlook.com <peavo@outlook.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 24 Apr 2015 11:42:43 +0000 (11:42 +0000)
https://bugs.webkit.org/show_bug.cgi?id=141704

Reviewed by Brent Fulgham.

Get accessibility information for items in popup menus.

* platform/win/PopupMenuWin.cpp:
(WebCore::PopupMenuWin::onGetObject):
(WebCore::PopupMenuWin::wndProc):
(WebCore::AccessiblePopupMenu::AccessiblePopupMenu):
(WebCore::AccessiblePopupMenu::~AccessiblePopupMenu):
(WebCore::AccessiblePopupMenu::QueryInterface):
(WebCore::AccessiblePopupMenu::AddRef):
(WebCore::AccessiblePopupMenu::Release):
(WebCore::AccessiblePopupMenu::GetTypeInfoCount):
(WebCore::AccessiblePopupMenu::GetTypeInfo):
(WebCore::AccessiblePopupMenu::GetIDsOfNames):
(WebCore::AccessiblePopupMenu::Invoke):
(WebCore::AccessiblePopupMenu::get_accParent):
(WebCore::AccessiblePopupMenu::get_accChildCount):
(WebCore::AccessiblePopupMenu::get_accChild):
(WebCore::AccessiblePopupMenu::get_accName):
(WebCore::AccessiblePopupMenu::get_accValue):
(WebCore::AccessiblePopupMenu::get_accDescription):
(WebCore::AccessiblePopupMenu::get_accRole):
(WebCore::AccessiblePopupMenu::get_accState):
(WebCore::AccessiblePopupMenu::get_accHelp):
(WebCore::AccessiblePopupMenu::get_accKeyboardShortcut):
(WebCore::AccessiblePopupMenu::get_accFocus):
(WebCore::AccessiblePopupMenu::get_accSelection):
(WebCore::AccessiblePopupMenu::get_accDefaultAction):
(WebCore::AccessiblePopupMenu::accSelect):
(WebCore::AccessiblePopupMenu::accLocation):
(WebCore::AccessiblePopupMenu::accNavigate):
(WebCore::AccessiblePopupMenu::accHitTest):
(WebCore::AccessiblePopupMenu::accDoDefaultAction):
(WebCore::AccessiblePopupMenu::put_accName):
(WebCore::AccessiblePopupMenu::put_accValue):
(WebCore::AccessiblePopupMenu::get_accHelpTopic):
* platform/win/PopupMenuWin.h:
* platform/win/ScrollbarThemeWin.h:
(WebCore::ScrollbarThemeWin::hasButtons): Deleted.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@183262 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebCore/ChangeLog
Source/WebCore/platform/win/PopupMenuWin.cpp
Source/WebCore/platform/win/PopupMenuWin.h
Source/WebCore/platform/win/ScrollbarThemeWin.h

index bd7d5a8848eafd13e703dd5570543edfdb912e70..cdd9527e19a7067c69979a590fe0d4177618e291 100644 (file)
@@ -1,3 +1,49 @@
+2015-04-24  Per Arne Vollan  <peavo@outlook.com>
+
+        [Win] Popup menu is not accessible.
+        https://bugs.webkit.org/show_bug.cgi?id=141704
+
+        Reviewed by Brent Fulgham.
+
+        Get accessibility information for items in popup menus.
+
+        * platform/win/PopupMenuWin.cpp:
+        (WebCore::PopupMenuWin::onGetObject):
+        (WebCore::PopupMenuWin::wndProc):
+        (WebCore::AccessiblePopupMenu::AccessiblePopupMenu):
+        (WebCore::AccessiblePopupMenu::~AccessiblePopupMenu):
+        (WebCore::AccessiblePopupMenu::QueryInterface):
+        (WebCore::AccessiblePopupMenu::AddRef):
+        (WebCore::AccessiblePopupMenu::Release):
+        (WebCore::AccessiblePopupMenu::GetTypeInfoCount):
+        (WebCore::AccessiblePopupMenu::GetTypeInfo):
+        (WebCore::AccessiblePopupMenu::GetIDsOfNames):
+        (WebCore::AccessiblePopupMenu::Invoke):
+        (WebCore::AccessiblePopupMenu::get_accParent):
+        (WebCore::AccessiblePopupMenu::get_accChildCount):
+        (WebCore::AccessiblePopupMenu::get_accChild):
+        (WebCore::AccessiblePopupMenu::get_accName):
+        (WebCore::AccessiblePopupMenu::get_accValue):
+        (WebCore::AccessiblePopupMenu::get_accDescription):
+        (WebCore::AccessiblePopupMenu::get_accRole):
+        (WebCore::AccessiblePopupMenu::get_accState):
+        (WebCore::AccessiblePopupMenu::get_accHelp):
+        (WebCore::AccessiblePopupMenu::get_accKeyboardShortcut):
+        (WebCore::AccessiblePopupMenu::get_accFocus):
+        (WebCore::AccessiblePopupMenu::get_accSelection):
+        (WebCore::AccessiblePopupMenu::get_accDefaultAction):
+        (WebCore::AccessiblePopupMenu::accSelect):
+        (WebCore::AccessiblePopupMenu::accLocation):
+        (WebCore::AccessiblePopupMenu::accNavigate):
+        (WebCore::AccessiblePopupMenu::accHitTest):
+        (WebCore::AccessiblePopupMenu::accDoDefaultAction):
+        (WebCore::AccessiblePopupMenu::put_accName):
+        (WebCore::AccessiblePopupMenu::put_accValue):
+        (WebCore::AccessiblePopupMenu::get_accHelpTopic):
+        * platform/win/PopupMenuWin.h:
+        * platform/win/ScrollbarThemeWin.h:
+        (WebCore::ScrollbarThemeWin::hasButtons): Deleted.
+
 2015-04-23  Antti Koivisto  <antti@apple.com>
 
         Memory cache live resources repeatedly purged during painting
index 8d199c9dacb9cace6045176db881892a34094b11..d0e0c3ff624a6f6edb5fc3743a4fed558af9b712 100644 (file)
@@ -23,6 +23,7 @@
 #include "config.h"
 #include "PopupMenuWin.h"
 
+#include "BString.h"
 #include "BitmapInfo.h"
 #include "Document.h"
 #include "FloatRect.h"
@@ -43,6 +44,7 @@
 #include "RenderView.h"
 #include "Scrollbar.h"
 #include "ScrollbarTheme.h"
+#include "ScrollbarThemeWin.h"
 #include "TextRun.h"
 #include "WebCoreInstanceHandle.h"
 #include <wtf/WindowsExtras.h>
@@ -748,6 +750,32 @@ IntRect PopupMenuWin::scrollableAreaBoundingBox() const
     return m_windowRect;
 }
 
+bool PopupMenuWin::onGetObject(WPARAM wParam, LPARAM lParam, LRESULT& lResult)
+{
+    lResult = 0;
+
+    if (static_cast<LONG>(lParam) != OBJID_CLIENT)
+        return false;
+
+    if (!m_accessiblePopupMenu)
+        m_accessiblePopupMenu = new AccessiblePopupMenu(*this);
+
+    static HMODULE accessibilityLib = nullptr;
+    if (!accessibilityLib) {
+        if (!(accessibilityLib = ::LoadLibraryW(L"oleacc.dll")))
+            return false;
+    }
+
+    static LPFNLRESULTFROMOBJECT procPtr = reinterpret_cast<LPFNLRESULTFROMOBJECT>(::GetProcAddress(accessibilityLib, "LresultFromObject"));
+    if (!procPtr)
+        return false;
+
+    // LresultFromObject returns a reference to the accessible object, stored
+    // in an LRESULT. If this call is not successful, Windows will handle the
+    // request through DefWindowProc.
+    return SUCCEEDED(lResult = procPtr(__uuidof(IAccessible), wParam, m_accessiblePopupMenu.get()));
+}
+
 void PopupMenuWin::registerClass()
 {
     static bool haveRegisteredWindowClass = false;
@@ -1050,6 +1078,9 @@ LRESULT PopupMenuWin::wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lPa
         case WM_PRINTCLIENT:
             paint(clientRect(), (HDC)wParam);
             break;
+        case WM_GETOBJECT:
+            onGetObject(wParam, lParam, lResult);
+            break;
         default:
             lResult = DefWindowProc(hWnd, message, wParam, lParam);
     }
@@ -1057,4 +1088,315 @@ LRESULT PopupMenuWin::wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lPa
     return lResult;
 }
 
+AccessiblePopupMenu::AccessiblePopupMenu(const PopupMenuWin& popupMenu)
+    : m_refCount(0)
+    , m_popupMenu(popupMenu)
+{
+}
+
+AccessiblePopupMenu::~AccessiblePopupMenu()
+{
+}
+
+HRESULT AccessiblePopupMenu::QueryInterface(REFIID riid, __RPC__deref_out void __RPC_FAR *__RPC_FAR *ppvObject)
+{
+    if (IsEqualGUID(riid, __uuidof(IAccessible)))
+        *ppvObject = static_cast<IAccessible*>(this);
+    else if (IsEqualGUID(riid, __uuidof(IDispatch)))
+        *ppvObject = static_cast<IAccessible*>(this);
+    else if (IsEqualGUID(riid, __uuidof(IUnknown)))
+        *ppvObject = static_cast<IAccessible*>(this);
+    else {
+        *ppvObject = 0;
+        return E_NOINTERFACE;
+    }
+    AddRef();
+    return S_OK;
+}
+
+ULONG AccessiblePopupMenu::AddRef()
+{
+    return ++m_refCount;
+}
+
+ULONG AccessiblePopupMenu::Release()
+{
+    int refCount = --m_refCount;
+    if (!refCount)
+        delete this;
+    return refCount;
+}
+
+HRESULT AccessiblePopupMenu::GetTypeInfoCount(UINT* count)
+{
+    return E_NOTIMPL;
+}
+
+HRESULT AccessiblePopupMenu::GetTypeInfo(UINT, LCID, ITypeInfo** ppTInfo)
+{
+    return E_NOTIMPL;
+}
+
+HRESULT AccessiblePopupMenu::GetIDsOfNames(REFIID, LPOLESTR*, UINT, LCID, DISPID*)
+{
+    return E_NOTIMPL;
+}
+
+HRESULT AccessiblePopupMenu::Invoke(DISPID, REFIID, LCID, WORD, DISPPARAMS*, VARIANT*, EXCEPINFO*, UINT*)
+{
+    return E_NOTIMPL;
+}
+
+HRESULT AccessiblePopupMenu::get_accParent(IDispatch**)
+{
+    return E_NOTIMPL;
+}
+
+HRESULT AccessiblePopupMenu::get_accChildCount(long* count)
+{
+    if (!count)
+        return E_POINTER;
+
+    *count = m_popupMenu.visibleItems();
+    return S_OK;
+}
+
+HRESULT AccessiblePopupMenu::get_accChild(VARIANT vChild, IDispatch** ppChild)
+{
+    if (!ppChild)
+        return E_POINTER;
+
+    if (vChild.vt != VT_I4) {
+        *ppChild = nullptr;
+        return E_INVALIDARG;
+    }
+    *ppChild = nullptr;
+    return S_FALSE;
+}
+
+HRESULT AccessiblePopupMenu::get_accName(VARIANT vChild, BSTR* name)
+{
+    return get_accValue(vChild, name);
+}
+
+HRESULT AccessiblePopupMenu::get_accValue(VARIANT vChild, BSTR* value)
+{
+    if (!value)
+        return E_POINTER;
+
+    if (vChild.vt != VT_I4)
+        return E_INVALIDARG;
+
+    int index = vChild.lVal - 1;
+
+    if (index < 0)
+        return E_INVALIDARG;
+
+    BString itemText(m_popupMenu.client()->itemText(index));
+    *value = itemText.release();
+
+    return S_OK;
+}
+
+HRESULT AccessiblePopupMenu::get_accDescription(VARIANT, BSTR*)
+{
+    return E_NOTIMPL;
+}
+
+HRESULT AccessiblePopupMenu::get_accRole(VARIANT vChild, VARIANT* pvRole)
+{
+    if (!pvRole)
+        return E_POINTER;
+
+    if (vChild.vt != VT_I4)
+        return E_INVALIDARG;
+
+    // Scrollbar parts are encoded as negative values.
+    if (vChild.lVal < 0) {
+        V_VT(pvRole) = VT_I4;
+        V_I4(pvRole) = ROLE_SYSTEM_SCROLLBAR;
+    } else {
+        V_VT(pvRole) = VT_I4;
+        V_I4(pvRole) = ROLE_SYSTEM_LISTITEM;
+    }
+
+    return S_OK;
+}
+
+HRESULT AccessiblePopupMenu::get_accState(VARIANT vChild, VARIANT* pvState)
+{
+    if (!pvState)
+        return E_POINTER;
+
+    if (vChild.vt != VT_I4)
+        return E_INVALIDARG;
+
+    V_VT(pvState) = VT_I4;
+    V_I4(pvState) = 0; // STATE_SYSTEM_NORMAL
+    
+    return S_OK;
+}
+
+HRESULT AccessiblePopupMenu::get_accHelp(VARIANT vChild, BSTR* helpText)
+{
+    return E_NOTIMPL;
+}
+
+HRESULT AccessiblePopupMenu::get_accKeyboardShortcut(VARIANT vChild, BSTR*)
+{
+    return E_NOTIMPL;
+}
+
+HRESULT AccessiblePopupMenu::get_accFocus(VARIANT* pvFocusedChild)
+{
+    return E_NOTIMPL;
+}
+
+HRESULT AccessiblePopupMenu::get_accSelection(VARIANT* pvSelectedChild)
+{
+    return E_NOTIMPL;
+}
+
+HRESULT AccessiblePopupMenu::get_accDefaultAction(VARIANT vChild, BSTR* actionDescription)
+{
+    return E_NOTIMPL;
+}
+
+HRESULT AccessiblePopupMenu::accSelect(long selectionFlags, VARIANT vChild)
+{
+    return E_NOTIMPL;
+}
+
+HRESULT AccessiblePopupMenu::accLocation(long* left, long* top, long* width, long* height, VARIANT vChild)
+{
+    if (!left || !top || !width || !height)
+        return E_POINTER;
+
+    if (vChild.vt != VT_I4)
+        return E_INVALIDARG;
+
+    const IntRect& windowRect = m_popupMenu.windowRect();
+
+    // Scrollbar parts are encoded as negative values.
+    if (vChild.lVal < 0) {
+        if (!m_popupMenu.scrollbar())
+            return E_FAIL;
+
+        WebCore::ScrollbarPart part = static_cast<WebCore::ScrollbarPart>(-vChild.lVal);
+
+        ScrollbarThemeWin* theme = static_cast<ScrollbarThemeWin*>(m_popupMenu.scrollbar()->theme());
+        if (!theme)
+            return E_FAIL;
+
+        IntRect partRect;
+
+        switch (part) {
+        case BackTrackPart:
+        case BackButtonStartPart:
+            partRect = theme->backButtonRect(m_popupMenu.scrollbar(), WebCore::BackTrackPart);
+            break;
+        case ThumbPart:
+            partRect = theme->thumbRect(m_popupMenu.scrollbar());
+            break;
+        case ForwardTrackPart:
+        case ForwardButtonEndPart:
+            partRect = theme->forwardButtonRect(m_popupMenu.scrollbar(), WebCore::ForwardTrackPart);
+            break;
+        case ScrollbarBGPart:
+            partRect = theme->trackRect(m_popupMenu.scrollbar());
+            break;
+        default:
+            return E_FAIL;
+        }
+
+        partRect.move(windowRect.x(), windowRect.y());
+
+        *left = partRect.x();
+        *top = partRect.y();
+        *width = partRect.width();
+        *height = partRect.height();
+
+        return S_OK;
+    }
+
+    int index = vChild.lVal - 1;
+
+    if (index < 0)
+        return E_INVALIDARG;
+
+    *left = windowRect.x();
+    *top = windowRect.y() + (index - m_popupMenu.m_scrollOffset) * m_popupMenu.itemHeight();
+    *width = windowRect.width();
+    *height = m_popupMenu.itemHeight();
+
+    return S_OK;
+}
+
+HRESULT AccessiblePopupMenu::accNavigate(long direction, VARIANT vFromChild, VARIANT* pvNavigatedTo)
+{
+    return E_NOTIMPL;
+}
+
+HRESULT AccessiblePopupMenu::accHitTest(long x, long y, VARIANT* pvChildAtPoint)
+{
+    if (!pvChildAtPoint)
+        return E_POINTER;
+
+    ::VariantInit(pvChildAtPoint);
+
+    IntRect windowRect = m_popupMenu.windowRect();
+
+    IntPoint pt(x - windowRect.x(), y - windowRect.y());
+
+    IntRect scrollRect;
+
+    if (m_popupMenu.scrollbar())
+        scrollRect = m_popupMenu.scrollbar()->frameRect();
+
+    if (m_popupMenu.scrollbar() && scrollRect.contains(pt)) {
+        if (!m_popupMenu.scrollbar()->theme())
+            return E_FAIL;
+
+        pt.move(-scrollRect.x(), -scrollRect.y());
+
+        WebCore::ScrollbarPart part = m_popupMenu.scrollbar()->theme()->hitTest(m_popupMenu.scrollbar(), pt);
+
+        V_VT(pvChildAtPoint) = VT_I4;
+        V_I4(pvChildAtPoint) = -part; // Scrollbar parts are encoded as negative, to avoid mixup with item indexes.
+        return S_OK;
+    }
+
+    int index = m_popupMenu.listIndexAtPoint(pt);
+
+    if (index < 0) {
+        V_VT(pvChildAtPoint) = VT_EMPTY;
+        return S_OK;
+    }
+
+    V_VT(pvChildAtPoint) = VT_I4;
+    V_I4(pvChildAtPoint) = index + 1; // CHILDID_SELF is 0, need to add 1.
+
+    return S_OK;
+}
+
+HRESULT AccessiblePopupMenu::accDoDefaultAction(VARIANT vChild)
+{
+    return E_NOTIMPL;
+}
+
+HRESULT AccessiblePopupMenu::put_accName(VARIANT, BSTR)
+{
+    return E_NOTIMPL;
+}
+
+HRESULT AccessiblePopupMenu::put_accValue(VARIANT, BSTR)
+{
+    return E_NOTIMPL;
+}
+
+HRESULT AccessiblePopupMenu::get_accHelpTopic(BSTR* helpFile, VARIANT, long* topicID)
+{
+    return E_NOTIMPL;
+}
+
 }
index 9b6bd8d49ea931f33cfcfc9b54fb306320918aca..b8d60c2c9734d8cb6e69d0ea98e45cdbc4076b30 100644 (file)
 #ifndef PopupMenuWin_h
 #define PopupMenuWin_h
 
+#include "COMPtr.h"
 #include "IntRect.h"
 #include "PopupMenu.h"
 #include "PopupMenuClient.h"
 #include "ScrollableArea.h"
 #include "Scrollbar.h"
+#include <OleAcc.h>
 #include <wtf/PassRefPtr.h>
 #include <wtf/RefCounted.h>
 #include <wtf/RefPtr.h>
@@ -35,6 +37,7 @@ namespace WebCore {
 
 class FrameView;
 class Scrollbar;
+class AccessiblePopupMenu;
 
 class PopupMenuWin : public PopupMenu, private ScrollableArea {
 public:
@@ -112,6 +115,8 @@ private:
     void calculatePositionAndSize(const IntRect&, FrameView*);
     void invalidateItem(int index);
 
+    bool onGetObject(WPARAM wParam, LPARAM lParam, LRESULT& lResult);
+
     static LRESULT CALLBACK PopupMenuWndProc(HWND, UINT, WPARAM, LPARAM);
     LRESULT wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
     static void registerClass();
@@ -130,6 +135,53 @@ private:
     int m_hoveredIndex;
     bool m_scrollbarCapturingMouse;
     bool m_showPopup;
+    COMPtr<IAccessible> m_accessiblePopupMenu;
+
+    friend class AccessiblePopupMenu;
+};
+
+class AccessiblePopupMenu : public IAccessible {
+public:
+    AccessiblePopupMenu(const PopupMenuWin&);
+    ~AccessiblePopupMenu();
+
+    // IUnknown
+    virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, __RPC__deref_out void __RPC_FAR *__RPC_FAR *ppvObject);
+    virtual ULONG STDMETHODCALLTYPE AddRef();
+    virtual ULONG STDMETHODCALLTYPE Release();
+
+    // IDispatch - Not to be implemented.
+    virtual HRESULT STDMETHODCALLTYPE GetTypeInfoCount(UINT* count);
+    virtual HRESULT STDMETHODCALLTYPE GetTypeInfo(UINT, LCID, ITypeInfo** ppTInfo);
+    virtual HRESULT STDMETHODCALLTYPE GetIDsOfNames(REFIID, LPOLESTR*, UINT, LCID, DISPID*);
+    virtual HRESULT STDMETHODCALLTYPE Invoke(DISPID, REFIID, LCID, WORD, DISPPARAMS*, VARIANT*, EXCEPINFO*, UINT*);
+
+    // IAccessible
+    virtual HRESULT STDMETHODCALLTYPE get_accParent(IDispatch**);
+    virtual HRESULT STDMETHODCALLTYPE get_accChildCount(long*);
+    virtual HRESULT STDMETHODCALLTYPE get_accChild(VARIANT vChild, IDispatch** ppChild);
+    virtual HRESULT STDMETHODCALLTYPE get_accName(VARIANT vChild, BSTR*);
+    virtual HRESULT STDMETHODCALLTYPE get_accValue(VARIANT vChild, BSTR*);
+    virtual HRESULT STDMETHODCALLTYPE get_accDescription(VARIANT, BSTR*);
+    virtual HRESULT STDMETHODCALLTYPE get_accRole(VARIANT vChild, VARIANT* pvRole);
+    virtual HRESULT STDMETHODCALLTYPE get_accState(VARIANT vChild, VARIANT* pvState);
+    virtual HRESULT STDMETHODCALLTYPE get_accHelp(VARIANT vChild, BSTR* helpText);
+    virtual HRESULT STDMETHODCALLTYPE get_accKeyboardShortcut(VARIANT vChild, BSTR*);
+    virtual HRESULT STDMETHODCALLTYPE get_accFocus(VARIANT* pvFocusedChild);
+    virtual HRESULT STDMETHODCALLTYPE get_accSelection(VARIANT* pvSelectedChild);
+    virtual HRESULT STDMETHODCALLTYPE get_accDefaultAction(VARIANT vChild, BSTR* actionDescription);
+    virtual HRESULT STDMETHODCALLTYPE accSelect(long selectionFlags, VARIANT vChild);
+    virtual HRESULT STDMETHODCALLTYPE accLocation(long* left, long* top, long* width, long* height, VARIANT vChild);
+    virtual HRESULT STDMETHODCALLTYPE accNavigate(long direction, VARIANT vFromChild, VARIANT* pvNavigatedTo);
+    virtual HRESULT STDMETHODCALLTYPE accHitTest(long x, long y, VARIANT* pvChildAtPoint);
+    virtual HRESULT STDMETHODCALLTYPE accDoDefaultAction(VARIANT vChild);
+    virtual HRESULT STDMETHODCALLTYPE put_accName(VARIANT, BSTR);
+    virtual HRESULT STDMETHODCALLTYPE put_accValue(VARIANT, BSTR);
+    virtual HRESULT STDMETHODCALLTYPE get_accHelpTopic(BSTR* helpFile, VARIANT, long* topicID);
+
+private:
+    int m_refCount;
+    const PopupMenuWin& m_popupMenu;
 };
 
 } // namespace WebCore
index 870240c16558cf0f62574196eeb69aaa806a7a24..f44e92bcb9644bd8cf7d03140aa6e28efa03d4b0 100644 (file)
@@ -35,27 +35,27 @@ public:
     ScrollbarThemeWin();
     virtual ~ScrollbarThemeWin();
 
-    virtual int scrollbarThickness(ScrollbarControlSize = RegularScrollbar);
+    int scrollbarThickness(ScrollbarControlSize = RegularScrollbar) override;
 
-    virtual void themeChanged();
+    void themeChanged() override;
     
-    virtual bool invalidateOnMouseEnterExit();
+    bool invalidateOnMouseEnterExit() override;
 
-protected:
-    virtual bool hasButtons(ScrollbarThemeClient*) { return true; }
-    virtual bool hasThumb(ScrollbarThemeClient*);
+    IntRect backButtonRect(ScrollbarThemeClient*, ScrollbarPart, bool painting = false) override;
+    IntRect forwardButtonRect(ScrollbarThemeClient*, ScrollbarPart, bool painting = false) override;
+    IntRect trackRect(ScrollbarThemeClient*, bool painting = false) override;
 
-    virtual IntRect backButtonRect(ScrollbarThemeClient*, ScrollbarPart, bool painting = false);
-    virtual IntRect forwardButtonRect(ScrollbarThemeClient*, ScrollbarPart, bool painting = false);
-    virtual IntRect trackRect(ScrollbarThemeClient*, bool painting = false);
+protected:
+    bool hasButtons(ScrollbarThemeClient*) override { return true; }
+    bool hasThumb(ScrollbarThemeClient*) override;
 
-    virtual bool shouldCenterOnThumb(ScrollbarThemeClient*, const PlatformMouseEvent&);
-    virtual bool shouldSnapBackToDragOrigin(ScrollbarThemeClient*, const PlatformMouseEvent&);
+    bool shouldCenterOnThumb(ScrollbarThemeClient*, const PlatformMouseEvent&) override;
+    bool shouldSnapBackToDragOrigin(ScrollbarThemeClient*, const PlatformMouseEvent&) override;
 
-    virtual void paintTrackBackground(GraphicsContext*, ScrollbarThemeClient*, const IntRect&);
-    virtual void paintTrackPiece(GraphicsContext*, ScrollbarThemeClient*, const IntRect&, ScrollbarPart);
-    virtual void paintButton(GraphicsContext*, ScrollbarThemeClient*, const IntRect&, ScrollbarPart);
-    virtual void paintThumb(GraphicsContext*, ScrollbarThemeClient*, const IntRect&);
+    void paintTrackBackground(GraphicsContext*, ScrollbarThemeClient*, const IntRect&) override;
+    void paintTrackPiece(GraphicsContext*, ScrollbarThemeClient*, const IntRect&, ScrollbarPart) override;
+    void paintButton(GraphicsContext*, ScrollbarThemeClient*, const IntRect&, ScrollbarPart) override;
+    void paintThumb(GraphicsContext*, ScrollbarThemeClient*, const IntRect&) override;
 };
 
 }