15c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/* 25c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Copyright (c) 2011, Google Inc. All rights reserved. 35c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * 45c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Redistribution and use in source and binary forms, with or without 55c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * modification, are permitted provided that the following conditions are 65c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * met: 75c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * 85c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * * Redistributions of source code must retain the above copyright 95c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * notice, this list of conditions and the following disclaimer. 105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * * Redistributions in binary form must reproduce the above 115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * copyright notice, this list of conditions and the following disclaimer 125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * in the documentation and/or other materials provided with the 135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * distribution. 145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * * Neither the name of Google Inc. nor the names of its 155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * contributors may be used to endorse or promote products derived from 165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * this software without specific prior written permission. 175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * 185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */ 3093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) 315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "config.h" 3293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)#include "PopupListBox.h" 335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 3453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "CSSValueKeywords.h" 3593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)#include "PopupContainer.h" 3693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)#include "PopupMenuChromium.h" 3753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "RuntimeEnabledFeatures.h" 3853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/platform/PlatformGestureEvent.h" 3953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/platform/PlatformKeyboardEvent.h" 4053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/platform/PlatformMouseEvent.h" 4153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/platform/PlatformScreen.h" 4253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/platform/PlatformTouchEvent.h" 4353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/platform/PlatformWheelEvent.h" 4453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/platform/PopupMenuClient.h" 4553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/platform/ScrollbarTheme.h" 4653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/platform/chromium/FramelessScrollViewClient.h" 4753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/platform/chromium/KeyboardCodes.h" 4853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/platform/graphics/Font.h" 495267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)#include "core/platform/graphics/FontCache.h" 5053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/platform/graphics/FontSelector.h" 5153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/platform/graphics/GraphicsContext.h" 5253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/platform/graphics/IntRect.h" 5353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/platform/graphics/StringTruncator.h" 5453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/platform/graphics/TextRun.h" 5553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/rendering/RenderTheme.h" 5693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)#include "wtf/ASCIICType.h" 5793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)#include "wtf/CurrentTime.h" 5893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)#include <limits> 595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)namespace WebCore { 615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 6293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)using namespace WTF::Unicode; 6393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) 6493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)static const int labelToIconPadding = 5; 6593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)// Padding height put at the top and bottom of each line. 6693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)static const int autofillLinePaddingHeight = 3; 6793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)const int PopupListBox::defaultMaxHeight = 500; 6893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)static const int maxVisibleRows = 20; 6993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)static const int minEndOfLinePadding = 2; 7093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)static const int textToLabelPadding = 10; 7193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)static const TimeStamp typeAheadTimeoutMs = 1000; 725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)PopupListBox::PopupListBox(PopupMenuClient* client, const PopupContainerSettings& settings) 745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) : m_settings(settings) 755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) , m_originalIndex(0) 765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) , m_selectedIndex(0) 775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) , m_acceptedIndexOnAbandon(-1) 785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) , m_visibleRows(0) 795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) , m_baseWidth(0) 8093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) , m_maxHeight(defaultMaxHeight) 815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) , m_popupClient(client) 825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) , m_repeatingChar(0) 835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) , m_lastCharTime(0) 845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) , m_maxWindowWidth(std::numeric_limits<int>::max()) 855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) setScrollbarModes(ScrollbarAlwaysOff, ScrollbarAlwaysOff); 875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)bool PopupListBox::handleMouseDownEvent(const PlatformMouseEvent& event) 905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) Scrollbar* scrollbar = scrollbarAtPoint(event.position()); 925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (scrollbar) { 935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_capturingScrollbar = scrollbar; 945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_capturingScrollbar->mouseDown(event); 955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return true; 965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!isPointInBounds(event.position())) 995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) abandon(); 1005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return true; 1025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 1035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)bool PopupListBox::handleMouseMoveEvent(const PlatformMouseEvent& event) 1055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 1065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (m_capturingScrollbar) { 1075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_capturingScrollbar->mouseMoved(event); 1085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return true; 1095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 1105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) Scrollbar* scrollbar = scrollbarAtPoint(event.position()); 1125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (m_lastScrollbarUnderMouse != scrollbar) { 1135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Send mouse exited to the old scrollbar. 1145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (m_lastScrollbarUnderMouse) 1155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_lastScrollbarUnderMouse->mouseExited(); 1165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_lastScrollbarUnderMouse = scrollbar; 1175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 1185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (scrollbar) { 1205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) scrollbar->mouseMoved(event); 1215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return true; 1225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 1235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!isPointInBounds(event.position())) 1255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return false; 1265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) selectIndex(pointToRowIndex(event.position())); 1285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return true; 1295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 1305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)bool PopupListBox::handleMouseReleaseEvent(const PlatformMouseEvent& event) 1325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 1335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (m_capturingScrollbar) { 1345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_capturingScrollbar->mouseUp(event); 1355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_capturingScrollbar = 0; 1365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return true; 1375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 1385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!isPointInBounds(event.position())) 1405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return true; 1415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 14293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) // Need to check before calling acceptIndex(), because m_popupClient might 14393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) // be removed in acceptIndex() calling because of event handler. 1445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) bool isSelectPopup = m_popupClient->menuStyle().menuType() == PopupMenuStyle::SelectPopup; 1457757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch if (acceptIndex(pointToRowIndex(event.position())) && m_focusedElement && isSelectPopup) { 1467757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch m_focusedElement->dispatchMouseEvent(event, eventNames().mouseupEvent); 1477757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch m_focusedElement->dispatchMouseEvent(event, eventNames().clickEvent); 1485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1497757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch // Clear m_focusedElement here, because we cannot clear in hidePopup() 15093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) // which is called before dispatchMouseEvent() is called. 1517757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch m_focusedElement = 0; 1525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 1535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return true; 1555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 1565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)bool PopupListBox::handleWheelEvent(const PlatformWheelEvent& event) 1585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 1595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!isPointInBounds(event.position())) { 1605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) abandon(); 1615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return true; 1625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 1635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) ScrollableArea::handleWheelEvent(event); 1655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return true; 1665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 1675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// Should be kept in sync with handleKeyEvent(). 1695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)bool PopupListBox::isInterestedInEventForKey(int keyCode) 1705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 1715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) switch (keyCode) { 1725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) case VKEY_ESCAPE: 1735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) case VKEY_RETURN: 1745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) case VKEY_UP: 1755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) case VKEY_DOWN: 1765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) case VKEY_PRIOR: 1775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) case VKEY_NEXT: 1785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) case VKEY_HOME: 1795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) case VKEY_END: 1805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) case VKEY_TAB: 1815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return true; 1825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) default: 1835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return false; 1845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 1855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 1865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)bool PopupListBox::handleTouchEvent(const PlatformTouchEvent&) 1885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 1895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return false; 1905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 1915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)bool PopupListBox::handleGestureEvent(const PlatformGestureEvent&) 1935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 1945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return false; 1955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 1965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static bool isCharacterTypeEvent(const PlatformKeyboardEvent& event) 1985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 1995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Check whether the event is a character-typed event or not. 2005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // We use RawKeyDown/Char/KeyUp event scheme on all platforms, 2015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // so PlatformKeyboardEvent::Char (not RawKeyDown) type event 2025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // is considered as character type event. 2035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return event.type() == PlatformEvent::Char; 2045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 2055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)bool PopupListBox::handleKeyEvent(const PlatformKeyboardEvent& event) 2075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 2085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (event.type() == PlatformEvent::KeyUp) 2095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return true; 2105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!numItems() && event.windowsVirtualKeyCode() != VKEY_ESCAPE) 2125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return true; 2135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) switch (event.windowsVirtualKeyCode()) { 2155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) case VKEY_ESCAPE: 2165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) abandon(); // may delete this 2175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return true; 2185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) case VKEY_RETURN: 2195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (m_selectedIndex == -1) { 2205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) hidePopup(); 2215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Don't eat the enter if nothing is selected. 2225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return false; 2235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 2245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) acceptIndex(m_selectedIndex); // may delete this 2255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return true; 2265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) case VKEY_UP: 2275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) case VKEY_DOWN: 22893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) // We have to forward only shift + up combination to focused node when 22993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) // autofill popup. Because all characters from the cursor to the start 23093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) // of the text area should selected when you press shift + up arrow. 2315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // shift + down should be the similar way to shift + up. 2325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (event.modifiers() && m_popupClient->menuStyle().menuType() == PopupMenuStyle::AutofillPopup) 2337757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch m_focusedElement->dispatchKeyEvent(event); 2345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) else if (event.windowsVirtualKeyCode() == VKEY_UP) 2355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) selectPreviousRow(); 2365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) else 2375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) selectNextRow(); 2385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) break; 2395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) case VKEY_PRIOR: 2405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) adjustSelectedIndex(-m_visibleRows); 2415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) break; 2425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) case VKEY_NEXT: 2435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) adjustSelectedIndex(m_visibleRows); 2445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) break; 2455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) case VKEY_HOME: 2465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) adjustSelectedIndex(-m_selectedIndex); 2475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) break; 2485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) case VKEY_END: 2495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) adjustSelectedIndex(m_items.size()); 2505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) break; 2515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) default: 2525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!event.ctrlKey() && !event.altKey() && !event.metaKey() 2535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) && isPrintableChar(event.windowsVirtualKeyCode()) 2545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) && isCharacterTypeEvent(event)) 2555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) typeAheadFind(event); 2565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) break; 2575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 2585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (m_originalIndex != m_selectedIndex) { 2605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Keyboard events should update the selection immediately (but we don't 2615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // want to fire the onchange event until the popup is closed, to match 2625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // IE). We change the original index so we revert to that when the 2635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // popup is closed. 2645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (m_settings.acceptOnAbandon) 2655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_acceptedIndexOnAbandon = m_selectedIndex; 2665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) setOriginalIndex(m_selectedIndex); 2685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (m_settings.setTextOnIndexChange) 2695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_popupClient->setTextFromItem(m_selectedIndex); 2705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 2715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (event.windowsVirtualKeyCode() == VKEY_TAB) { 2725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // TAB is a special case as it should select the current item if any and 2735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // advance focus. 2745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (m_selectedIndex >= 0) { 2755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) acceptIndex(m_selectedIndex); // May delete us. 2765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Return false so the TAB key event is propagated to the page. 2775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return false; 2785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 2795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Call abandon() so we honor m_acceptedIndexOnAbandon if set. 2805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) abandon(); 2815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Return false so the TAB key event is propagated to the page. 2825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return false; 2835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 2845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return true; 2865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 2875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)HostWindow* PopupListBox::hostWindow() const 2895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 2905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Our parent is the root ScrollView, so it is the one that has a 2915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // HostWindow. FrameView::hostWindow() works similarly. 2925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return parent() ? parent()->hostWindow() : 0; 2935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 2945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// From HTMLSelectElement.cpp 2965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static String stripLeadingWhiteSpace(const String& string) 2975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 2985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) int length = string.length(); 2995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) int i; 3005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) for (i = 0; i < length; ++i) 3015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (string[i] != noBreakSpace 30293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) && (string[i] <= 0x7F ? !isASCIISpace(string[i]) : (direction(string[i]) != WhiteSpaceNeutral))) 3035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) break; 3045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 3055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return string.substring(i, length - i); 3065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 3075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 3085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// From HTMLSelectElement.cpp, with modifications 3095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void PopupListBox::typeAheadFind(const PlatformKeyboardEvent& event) 3105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 3115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) TimeStamp now = static_cast<TimeStamp>(currentTime() * 1000.0f); 3125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) TimeStamp delta = now - m_lastCharTime; 3135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 3145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Reset the time when user types in a character. The time gap between 3155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // last character and the current character is used to indicate whether 3165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // user typed in a string or just a character as the search prefix. 3175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_lastCharTime = now; 3185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 3195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) UChar c = event.windowsVirtualKeyCode(); 3205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 3215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) String prefix; 3225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) int searchStartOffset = 1; 32393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) if (delta > typeAheadTimeoutMs) { 3245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_typedString = prefix = String(&c, 1); 3255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_repeatingChar = c; 3265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } else { 3275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_typedString.append(c); 3285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 32993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) if (c == m_repeatingChar) { 33093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) // The user is likely trying to cycle through all the items starting 33193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) // with this character, so just search on the character. 3325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) prefix = String(&c, 1); 33393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) } else { 3345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_repeatingChar = 0; 3355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) prefix = m_typedString; 3365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) searchStartOffset = 0; 3375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 3385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 3395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 34093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) // Compute a case-folded copy of the prefix string before beginning the 34193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) // search for a matching element. This code uses foldCase to work around the 34293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) // fact that String::startWith does not fold non-ASCII characters. This code 34393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) // can be changed to use startWith once that is fixed. 3445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) String prefixWithCaseFolded(prefix.foldCase()); 3455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) int itemCount = numItems(); 3465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) int index = (max(0, m_selectedIndex) + searchStartOffset) % itemCount; 3475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) for (int i = 0; i < itemCount; i++, index = (index + 1) % itemCount) { 3485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!isSelectableItem(index)) 3495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) continue; 3505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 3515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (stripLeadingWhiteSpace(m_items[index]->label).foldCase().startsWith(prefixWithCaseFolded)) { 3525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) selectIndex(index); 3535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return; 3545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 3555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 3565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 3575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 3585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void PopupListBox::paint(GraphicsContext* gc, const IntRect& rect) 3595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 36093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) // Adjust coords for scrolled frame. 3615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) IntRect r = intersection(rect, frameRect()); 3625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) int tx = x() - scrollX(); 3635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) int ty = y() - scrollY(); 3645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 3655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) r.move(-tx, -ty); 3665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 36793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) // Set clip rect to match revised damage rect. 3685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) gc->save(); 3695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) gc->translate(static_cast<float>(tx), static_cast<float>(ty)); 3705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) gc->clip(r); 3715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 3725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // FIXME: Can we optimize scrolling to not require repainting the entire 3735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // window? Should we? 3745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) for (int i = 0; i < numItems(); ++i) 3755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) paintRow(gc, r, i); 3765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 3775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Special case for an empty popup. 3785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!numItems()) 3795267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) gc->fillRect(r, Color::white); 3805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 3815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) gc->restore(); 3825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 3835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) ScrollView::paint(gc, rect); 3845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 3855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 3865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static const int separatorPadding = 4; 3875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static const int separatorHeight = 1; 3885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 3895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void PopupListBox::paintRow(GraphicsContext* gc, const IntRect& rect, int rowIndex) 3905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 3915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // This code is based largely on RenderListBox::paint* methods. 3925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 3935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) IntRect rowRect = getRowBounds(rowIndex); 3945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!rowRect.intersects(rect)) 3955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return; 3965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 3975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) PopupMenuStyle style = m_popupClient->itemStyle(rowIndex); 3985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 3995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Paint background 4005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) Color backColor, textColor, labelColor; 4015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (rowIndex == m_selectedIndex) { 4025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) backColor = RenderTheme::defaultTheme()->activeListBoxSelectionBackgroundColor(); 4035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) textColor = RenderTheme::defaultTheme()->activeListBoxSelectionForegroundColor(); 4045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) labelColor = textColor; 4055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } else { 4065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) backColor = style.backgroundColor(); 4075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) textColor = style.foregroundColor(); 408926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) 409926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)#if OS(LINUX) 410926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) // On other platforms, the <option> background color is the same as the 411926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) // <select> background color. On Linux, that makes the <option> 412926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) // background color very dark, so by default, try to use a lighter 413926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) // background color for <option>s. 414926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) if (style.backgroundColorType() == PopupMenuStyle::DefaultBackgroundColor && RenderTheme::defaultTheme()->systemColor(CSSValueButtonface) == backColor) 415926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) backColor = RenderTheme::defaultTheme()->systemColor(CSSValueMenu); 416926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)#endif 417926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) 4185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // FIXME: for now the label color is hard-coded. It should be added to 4195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // the PopupMenuStyle. 4205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) labelColor = Color(115, 115, 115); 4215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 4225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 4235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // If we have a transparent background, make sure it has a color to blend 4245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // against. 4255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (backColor.hasAlpha()) 4265267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) gc->fillRect(rowRect, Color::white); 4275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 4285267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) gc->fillRect(rowRect, backColor); 4295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 4305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // It doesn't look good but Autofill requires special style for separator. 4315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Autofill doesn't have padding and #dcdcdc color. 4325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (m_popupClient->itemIsSeparator(rowIndex)) { 4335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) int padding = style.menuType() == PopupMenuStyle::AutofillPopup ? 0 : separatorPadding; 4345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) IntRect separatorRect( 4355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) rowRect.x() + padding, 4365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) rowRect.y() + (rowRect.height() - separatorHeight) / 2, 4375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) rowRect.width() - 2 * padding, separatorHeight); 4385267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) gc->fillRect(separatorRect, style.menuType() == PopupMenuStyle::AutofillPopup ? Color(0xdc, 0xdc, 0xdc) : textColor); 4395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return; 4405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 4415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 4425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!style.isVisible()) 4435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return; 4445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 4455267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) gc->setFillColor(textColor); 4465267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) 4475267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) FontCachePurgePreventer fontCachePurgePreventer; 4485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 4495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) Font itemFont = getRowFont(rowIndex); 4505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // FIXME: http://crbug.com/19872 We should get the padding of individual option 4515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // elements. This probably implies changes to PopupMenuClient. 4525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) bool rightAligned = m_popupClient->menuStyle().textDirection() == RTL; 4535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) int textX = 0; 4545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) int maxWidth = 0; 4555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (rightAligned) 4565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) maxWidth = rowRect.width() - max<int>(0, m_popupClient->clientPaddingRight() - m_popupClient->clientInsetRight()); 4575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) else { 4585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) textX = max<int>(0, m_popupClient->clientPaddingLeft() - m_popupClient->clientInsetLeft()); 4595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) maxWidth = rowRect.width() - textX; 4605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 4615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Prepare text to be drawn. 4625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) String itemText = m_popupClient->itemText(rowIndex); 4635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) String itemLabel = m_popupClient->itemLabel(rowIndex); 4645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) String itemIcon = m_popupClient->itemIcon(rowIndex); 4655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (m_settings.restrictWidthOfListBox) { // Truncate strings to fit in. 4665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // FIXME: We should leftTruncate for the rtl case. 4675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // StringTruncator::leftTruncate would have to be implemented. 4685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) String str = StringTruncator::rightTruncate(itemText, maxWidth, itemFont); 4695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (str != itemText) { 4705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) itemText = str; 47193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) // Don't display the label or icon, we already don't have enough 47293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) // room for the item text. 4735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) itemLabel = ""; 4745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) itemIcon = ""; 4755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } else if (!itemLabel.isEmpty()) { 47693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) int availableWidth = maxWidth - textToLabelPadding - StringTruncator::width(itemText, itemFont); 4775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) itemLabel = StringTruncator::rightTruncate(itemLabel, availableWidth, itemFont); 4785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 4795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 4805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 4815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Prepare the directionality to draw text. 4825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) TextRun textRun(itemText, 0, 0, TextRun::AllowTrailingExpansion, style.textDirection(), style.hasTextDirectionOverride()); 4835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // If the text is right-to-left, make it right-aligned by adjusting its 4845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // beginning position. 4855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (rightAligned) 4865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) textX += maxWidth - itemFont.width(textRun); 4875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 4885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Draw the item text. 4895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) int textY = rowRect.y() + itemFont.fontMetrics().ascent() + (rowRect.height() - itemFont.fontMetrics().height()) / 2; 49093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) TextRunPaintInfo textRunPaintInfo(textRun); 49193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) textRunPaintInfo.bounds = rowRect; 49293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) gc->drawBidiText(itemFont, textRunPaintInfo, IntPoint(textX, textY)); 4935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 4945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // We are using the left padding as the right padding includes room for the scroll-bar which 4955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // does not show in this case. 4965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) int rightPadding = max<int>(0, m_popupClient->clientPaddingLeft() - m_popupClient->clientInsetLeft()); 4975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) int remainingWidth = rowRect.width() - rightPadding; 4985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 4995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Draw the icon if applicable. 5005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) RefPtr<Image> image(Image::loadPlatformResource(itemIcon.utf8().data())); 5015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (image && !image->isNull()) { 5025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) IntRect imageRect = image->rect(); 50393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) remainingWidth -= (imageRect.width() + labelToIconPadding); 5045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) imageRect.setX(rowRect.width() - rightPadding - imageRect.width()); 5055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) imageRect.setY(rowRect.y() + (rowRect.height() - imageRect.height()) / 2); 5065267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) gc->drawImage(image.get(), imageRect); 5075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 5085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 5095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Draw the the label if applicable. 5105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (itemLabel.isEmpty()) 5115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return; 5125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 5135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Autofill label is 0.9 smaller than regular font size. 5145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (style.menuType() == PopupMenuStyle::AutofillPopup) { 5155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) itemFont = m_popupClient->itemStyle(rowIndex).font(); 5165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) FontDescription d = itemFont.fontDescription(); 5175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) d.setComputedSize(d.computedSize() * 0.9); 5185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) itemFont = Font(d, itemFont.letterSpacing(), itemFont.wordSpacing()); 5195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) itemFont.update(0); 5205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 5215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 5225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) TextRun labelTextRun(itemLabel, 0, 0, TextRun::AllowTrailingExpansion, style.textDirection(), style.hasTextDirectionOverride()); 5235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (rightAligned) 5245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) textX = max<int>(0, m_popupClient->clientPaddingLeft() - m_popupClient->clientInsetLeft()); 5255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) else 5265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) textX = remainingWidth - itemFont.width(labelTextRun); 52793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) TextRunPaintInfo labelTextRunPaintInfo(labelTextRun); 52893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) labelTextRunPaintInfo.bounds = rowRect; 5295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 5305267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) gc->setFillColor(labelColor); 53193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) gc->drawBidiText(itemFont, labelTextRunPaintInfo, IntPoint(textX, textY)); 5325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 5335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 5345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)Font PopupListBox::getRowFont(int rowIndex) 5355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 5365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) Font itemFont = m_popupClient->itemStyle(rowIndex).font(); 5375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (m_popupClient->itemIsLabel(rowIndex)) { 5385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Bold-ify labels (ie, an <optgroup> heading). 5395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) FontDescription d = itemFont.fontDescription(); 5405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) d.setWeight(FontWeightBold); 5415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) Font font(d, itemFont.letterSpacing(), itemFont.wordSpacing()); 5425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) font.update(0); 5435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return font; 5445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 5455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 5465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return itemFont; 5475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 5485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 5495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void PopupListBox::abandon() 5505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 5515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) RefPtr<PopupListBox> keepAlive(this); 5525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 5535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_selectedIndex = m_originalIndex; 5545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 5555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) hidePopup(); 5565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 5575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (m_acceptedIndexOnAbandon >= 0) { 5585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (m_popupClient) 5595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_popupClient->valueChanged(m_acceptedIndexOnAbandon); 5605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_acceptedIndexOnAbandon = -1; 5615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 5625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 5635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 5645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)int PopupListBox::pointToRowIndex(const IntPoint& point) 5655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 5665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) int y = scrollY() + point.y(); 5675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 5685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // FIXME: binary search if perf matters. 5695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) for (int i = 0; i < numItems(); ++i) { 5705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (y < m_items[i]->yOffset) 5715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return i-1; 5725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 5735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 5745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Last item? 5755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (y < contentsHeight()) 5765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return m_items.size()-1; 5775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 5785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return -1; 5795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 5805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 5815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)bool PopupListBox::acceptIndex(int index) 5825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 5835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Clear m_acceptedIndexOnAbandon once user accepts the selected index. 5845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (m_acceptedIndexOnAbandon >= 0) 5855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_acceptedIndexOnAbandon = -1; 5865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 5875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (index >= numItems()) 5885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return false; 5895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 5905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (index < 0) { 5915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (m_popupClient) { 5925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Enter pressed with no selection, just close the popup. 5935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) hidePopup(); 5945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 5955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return false; 5965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 5975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 5985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (isSelectableItem(index)) { 5995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) RefPtr<PopupListBox> keepAlive(this); 6005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 6015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Hide ourselves first since valueChanged may have numerous side-effects. 6025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) hidePopup(); 6035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 6045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Tell the <select> PopupMenuClient what index was selected. 6055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_popupClient->valueChanged(index); 6065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 6075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return true; 6085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 6095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 6105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return false; 6115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 6125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 6135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void PopupListBox::selectIndex(int index) 6145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 6155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (index < 0 || index >= numItems()) 6165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return; 6175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 6185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) bool isSelectable = isSelectableItem(index); 6195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (index != m_selectedIndex && isSelectable) { 6205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) invalidateRow(m_selectedIndex); 6215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_selectedIndex = index; 6225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) invalidateRow(m_selectedIndex); 6235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 6245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) scrollToRevealSelection(); 6255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_popupClient->selectionChanged(m_selectedIndex); 6265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } else if (!isSelectable) 6275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) clearSelection(); 6285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 6295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 6305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void PopupListBox::setOriginalIndex(int index) 6315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 6325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_originalIndex = m_selectedIndex = index; 6335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 6345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 6355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)int PopupListBox::getRowHeight(int index) 6365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 6375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) int minimumHeight = PopupMenuChromium::minimumRowHeight(); 6385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (m_settings.deviceSupportsTouch) 6395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) minimumHeight = max(minimumHeight, PopupMenuChromium::optionRowHeightForTouch()); 6405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 6415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (index < 0 || m_popupClient->itemStyle(index).isDisplayNone()) 6425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return minimumHeight; 6435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 6445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Separator row height is the same size as itself. 6455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (m_popupClient->itemIsSeparator(index)) 6465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return max(separatorHeight, minimumHeight); 6475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 6485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) String icon = m_popupClient->itemIcon(index); 6495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) RefPtr<Image> image(Image::loadPlatformResource(icon.utf8().data())); 6505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 6515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) int fontHeight = getRowFont(index).fontMetrics().height(); 6525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) int iconHeight = (image && !image->isNull()) ? image->rect().height() : 0; 6535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 65493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) int linePaddingHeight = m_popupClient->menuStyle().menuType() == PopupMenuStyle::AutofillPopup ? autofillLinePaddingHeight : 0; 6555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) int calculatedRowHeight = max(fontHeight, iconHeight) + linePaddingHeight * 2; 6565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return max(calculatedRowHeight, minimumHeight); 6575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 6585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 6595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)IntRect PopupListBox::getRowBounds(int index) 6605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 6615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (index < 0) 6625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return IntRect(0, 0, visibleWidth(), getRowHeight(index)); 6635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 6645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return IntRect(0, m_items[index]->yOffset, visibleWidth(), getRowHeight(index)); 6655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 6665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 6675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void PopupListBox::invalidateRow(int index) 6685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 6695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (index < 0) 6705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return; 6715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 6725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Invalidate in the window contents, as FramelessScrollView::invalidateRect 6735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // paints in the window coordinates. 6745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) invalidateRect(contentsToWindow(getRowBounds(index))); 6755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 6765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 6775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void PopupListBox::scrollToRevealRow(int index) 6785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 6795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (index < 0) 6805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return; 6815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 6825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) IntRect rowRect = getRowBounds(index); 6835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 6845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (rowRect.y() < scrollY()) { 6855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Row is above current scroll position, scroll up. 6865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) ScrollView::setScrollPosition(IntPoint(0, rowRect.y())); 6875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } else if (rowRect.maxY() > scrollY() + visibleHeight()) { 6885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Row is below current scroll position, scroll down. 6895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) ScrollView::setScrollPosition(IntPoint(0, rowRect.maxY() - visibleHeight())); 6905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 6915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 6925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 6935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)bool PopupListBox::isSelectableItem(int index) 6945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 6955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) ASSERT(index >= 0 && index < numItems()); 6965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return m_items[index]->type == PopupItem::TypeOption && m_popupClient->itemIsEnabled(index); 6975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 6985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 6995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void PopupListBox::clearSelection() 7005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 7015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (m_selectedIndex != -1) { 7025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) invalidateRow(m_selectedIndex); 7035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_selectedIndex = -1; 7045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_popupClient->selectionCleared(); 7055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 7065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 7075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 7085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void PopupListBox::selectNextRow() 7095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 7105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!m_settings.loopSelectionNavigation || m_selectedIndex != numItems() - 1) { 7115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) adjustSelectedIndex(1); 7125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return; 7135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 7145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 7155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // We are moving past the last item, no row should be selected. 7165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) clearSelection(); 7175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 7185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 7195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void PopupListBox::selectPreviousRow() 7205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 7215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!m_settings.loopSelectionNavigation || m_selectedIndex > 0) { 7225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) adjustSelectedIndex(-1); 7235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return; 7245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 7255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 7265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!m_selectedIndex) { 7275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // We are moving past the first item, clear the selection. 7285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) clearSelection(); 7295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return; 7305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 7315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 7325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // No row is selected, jump to the last item. 7335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) selectIndex(numItems() - 1); 7345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) scrollToRevealSelection(); 7355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 7365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 7375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void PopupListBox::adjustSelectedIndex(int delta) 7385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 7395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) int targetIndex = m_selectedIndex + delta; 74093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) targetIndex = std::min(std::max(targetIndex, 0), numItems() - 1); 7415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!isSelectableItem(targetIndex)) { 7425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // We didn't land on an option. Try to find one. 7435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // We try to select the closest index to target, prioritizing any in 7445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // the range [current, target]. 7455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 7465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) int dir = delta > 0 ? 1 : -1; 7475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) int testIndex = m_selectedIndex; 7485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) int bestIndex = m_selectedIndex; 7495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) bool passedTarget = false; 7505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) while (testIndex >= 0 && testIndex < numItems()) { 7515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (isSelectableItem(testIndex)) 7525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) bestIndex = testIndex; 7535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (testIndex == targetIndex) 7545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) passedTarget = true; 7555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (passedTarget && bestIndex != m_selectedIndex) 7565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) break; 7575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 7585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) testIndex += dir; 7595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 7605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 7615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Pick the best index, which may mean we don't change. 7625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) targetIndex = bestIndex; 7635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 7645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 7655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Select the new index, and ensure its visible. We do this regardless of 7665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // whether the selection changed to ensure keyboard events always bring the 7675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // selection into view. 7685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) selectIndex(targetIndex); 7695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) scrollToRevealSelection(); 7705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 7715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 7725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void PopupListBox::hidePopup() 7735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 7745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (parent()) { 7755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) PopupContainer* container = static_cast<PopupContainer*>(parent()); 7765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (container->client()) 7775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) container->client()->popupClosed(container); 7785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) container->notifyPopupHidden(); 7795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 7805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 7815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (m_popupClient) 7825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_popupClient->popupDidHide(); 7835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 7845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 7855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void PopupListBox::updateFromElement() 7865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 7875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) clear(); 7885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 7895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) int size = m_popupClient->listSize(); 7905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) for (int i = 0; i < size; ++i) { 7915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) PopupItem::Type type; 7925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (m_popupClient->itemIsSeparator(i)) 7935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) type = PopupItem::TypeSeparator; 7945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) else if (m_popupClient->itemIsLabel(i)) 7955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) type = PopupItem::TypeGroup; 7965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) else 7975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) type = PopupItem::TypeOption; 7985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_items.append(new PopupItem(m_popupClient->itemText(i), type)); 7995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_items[i]->enabled = isSelectableItem(i); 8005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) PopupMenuStyle style = m_popupClient->itemStyle(i); 8015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_items[i]->textDirection = style.textDirection(); 8025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_items[i]->hasTextDirectionOverride = style.hasTextDirectionOverride(); 8035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 8045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 8055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_selectedIndex = m_popupClient->selectedIndex(); 8065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) setOriginalIndex(m_selectedIndex); 8075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 8085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) layout(); 8095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 8105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 8115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void PopupListBox::setMaxWidthAndLayout(int maxWidth) 8125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 8135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_maxWindowWidth = maxWidth; 8145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) layout(); 8155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 8165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 8175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void PopupListBox::layout() 8185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 8195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) bool isRightAligned = m_popupClient->menuStyle().textDirection() == RTL; 8205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 8215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Size our child items. 8225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) int baseWidth = 0; 8235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) int paddingWidth = 0; 8245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) int lineEndPaddingWidth = 0; 8255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) int y = 0; 8265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) for (int i = 0; i < numItems(); ++i) { 8275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Place the item vertically. 8285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_items[i]->yOffset = y; 8295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (m_popupClient->itemStyle(i).isDisplayNone()) 8305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) continue; 8315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) y += getRowHeight(i); 8325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 8335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Ensure the popup is wide enough to fit this item. 8345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) Font itemFont = getRowFont(i); 8355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) String text = m_popupClient->itemText(i); 8365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) String label = m_popupClient->itemLabel(i); 8375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) String icon = m_popupClient->itemIcon(i); 8385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) RefPtr<Image> iconImage(Image::loadPlatformResource(icon.utf8().data())); 8395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) int width = 0; 8405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!text.isEmpty()) 8415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) width = itemFont.width(TextRun(text)); 8425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!label.isEmpty()) { 8435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (width > 0) 84493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) width += textToLabelPadding; 8455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) width += itemFont.width(TextRun(label)); 8465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 8475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (iconImage && !iconImage->isNull()) { 8485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (width > 0) 84993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) width += labelToIconPadding; 8505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) width += iconImage->rect().width(); 8515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 8525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 8535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) baseWidth = max(baseWidth, width); 85493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) // FIXME: http://b/1210481 We should get the padding of individual 85593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) // option elements. 8565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) paddingWidth = max<int>(paddingWidth, 8575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_popupClient->clientPaddingLeft() + m_popupClient->clientPaddingRight()); 8585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) lineEndPaddingWidth = max<int>(lineEndPaddingWidth, 8595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) isRightAligned ? m_popupClient->clientPaddingLeft() : m_popupClient->clientPaddingRight()); 8605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 8615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 8625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Calculate scroll bar width. 8635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) int windowHeight = 0; 86493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) m_visibleRows = std::min(numItems(), maxVisibleRows); 8655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 8665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) for (int i = 0; i < m_visibleRows; ++i) { 8675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) int rowHeight = getRowHeight(i); 8685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 8695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Only clip the window height for non-Mac platforms. 8705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (windowHeight + rowHeight > m_maxHeight) { 8715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_visibleRows = i; 8725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) break; 8735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 8745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 8755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) windowHeight += rowHeight; 8765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 8775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 8785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Set our widget and scrollable contents sizes. 8795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) int scrollbarWidth = 0; 8805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (m_visibleRows < numItems()) { 8815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) scrollbarWidth = ScrollbarTheme::theme()->scrollbarThickness(); 8825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 88393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) // Use minEndOfLinePadding when there is a scrollbar so that we use 88493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) // as much as (lineEndPaddingWidth - minEndOfLinePadding) padding 8855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // space for scrollbar and allow user to use CSS padding to make the 8865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // popup listbox align with the select element. 88793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) paddingWidth = paddingWidth - lineEndPaddingWidth + minEndOfLinePadding; 8885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 8895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 8905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) int windowWidth; 8915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) int contentWidth; 8925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (m_settings.restrictWidthOfListBox) { 8935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) windowWidth = m_baseWidth; 8945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) contentWidth = m_baseWidth - scrollbarWidth; 8955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } else { 8965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) windowWidth = baseWidth + scrollbarWidth + paddingWidth; 8975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (windowWidth > m_maxWindowWidth) { 8985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // windowWidth exceeds m_maxWindowWidth, so we have to clip. 8995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) windowWidth = m_maxWindowWidth; 9005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) baseWidth = windowWidth - scrollbarWidth - paddingWidth; 9015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_baseWidth = baseWidth; 9025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 9035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) contentWidth = windowWidth - scrollbarWidth; 9045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 9055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (windowWidth < m_baseWidth) { 9065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) windowWidth = m_baseWidth; 9075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) contentWidth = m_baseWidth - scrollbarWidth; 9085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } else 9095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_baseWidth = baseWidth; 9105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 9115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 9125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) resize(windowWidth, windowHeight); 9135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) setContentsSize(IntSize(contentWidth, getRowBounds(numItems() - 1).maxY())); 9145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 9155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (hostWindow()) 9165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) scrollToRevealSelection(); 9175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 9185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) invalidate(); 9195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 9205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 9215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void PopupListBox::clear() 9225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 9235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) for (Vector<PopupItem*>::iterator it = m_items.begin(); it != m_items.end(); ++it) 9245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) delete *it; 9255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_items.clear(); 9265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 9275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 9285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)bool PopupListBox::isPointInBounds(const IntPoint& point) 9295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 9305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return numItems() && IntRect(0, 0, width(), height()).contains(point); 9315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 9325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 9335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)int PopupListBox::popupContentHeight() const 9345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 9355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return height(); 9365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 9375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 9385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} // namespace WebCore 939