Refactoring of PopupMenuChromium For Readability and Maintainability
authorfsamuel@chromium.org <fsamuel@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 12 Aug 2011 23:18:48 +0000 (23:18 +0000)
committerfsamuel@chromium.org <fsamuel@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 12 Aug 2011 23:18:48 +0000 (23:18 +0000)
https://bugs.webkit.org/show_bug.cgi?id=66009

Reviewed by Darin Fisher.

Source/WebCore:

Split PopupMenuChromium into three sets of files: PopupMenuChromium.{h|cpp}, PopupContainer.{h|cpp},
and PopupLisBox.{h|cpp}  for readability and maintainability.

No new tests as there's no change in functionality.

* WebCore.gypi:
* platform/chromium/PopupContainer.cpp: Added.
(WebCore::constructRelativeMouseEvent):
(WebCore::constructRelativeWheelEvent):
(WebCore::PopupContainer::create):
(WebCore::PopupContainer::PopupContainer):
(WebCore::PopupContainer::~PopupContainer):
(WebCore::PopupContainer::layoutAndCalculateWidgetRect):
(WebCore::PopupContainer::showPopup):
(WebCore::PopupContainer::hidePopup):
(WebCore::PopupContainer::notifyPopupHidden):
(WebCore::PopupContainer::layoutAndGetRTLOffset):
(WebCore::PopupContainer::handleMouseDownEvent):
(WebCore::PopupContainer::handleMouseMoveEvent):
(WebCore::PopupContainer::handleMouseReleaseEvent):
(WebCore::PopupContainer::handleWheelEvent):
(WebCore::PopupContainer::handleTouchEvent):
(WebCore::PopupContainer::handleGestureEvent):
(WebCore::PopupContainer::handleKeyEvent):
(WebCore::PopupContainer::hide):
(WebCore::PopupContainer::paint):
(WebCore::PopupContainer::paintBorder):
(WebCore::PopupContainer::isInterestedInEventForKey):
(WebCore::PopupContainer::chromeClientChromium):
(WebCore::PopupContainer::showInRect):
(WebCore::PopupContainer::refresh):
(WebCore::PopupContainer::isRTL):
(WebCore::PopupContainer::selectedIndex):
(WebCore::PopupContainer::menuItemHeight):
(WebCore::PopupContainer::menuItemFontSize):
(WebCore::PopupContainer::menuStyle):
(WebCore::popupData):
(WebCore::PopupContainer::getSelectedItemToolTip):
* platform/chromium/PopupContainer.h: Added.
(WebCore::PopupContainer::listBox):
(WebCore::PopupContainer::popupType):
* platform/chromium/PopupListBox.cpp: Added.
(WebCore::PopupListBox::PopupListBox):
(WebCore::PopupListBox::handleMouseDownEvent):
(WebCore::PopupListBox::handleMouseMoveEvent):
(WebCore::PopupListBox::handleMouseReleaseEvent):
(WebCore::PopupListBox::handleWheelEvent):
(WebCore::PopupListBox::isInterestedInEventForKey):
(WebCore::PopupListBox::handleTouchEvent):
(WebCore::PopupListBox::handleGestureEvent):
(WebCore::isCharacterTypeEvent):
(WebCore::PopupListBox::handleKeyEvent):
(WebCore::PopupListBox::hostWindow):
(WebCore::stripLeadingWhiteSpace):
(WebCore::PopupListBox::typeAheadFind):
(WebCore::PopupListBox::paint):
(WebCore::PopupListBox::paintRow):
(WebCore::PopupListBox::getRowFont):
(WebCore::PopupListBox::abandon):
(WebCore::PopupListBox::pointToRowIndex):
(WebCore::PopupListBox::acceptIndex):
(WebCore::PopupListBox::selectIndex):
(WebCore::PopupListBox::setOriginalIndex):
(WebCore::PopupListBox::getRowHeight):
(WebCore::PopupListBox::getRowBounds):
(WebCore::PopupListBox::invalidateRow):
(WebCore::PopupListBox::scrollToRevealRow):
(WebCore::PopupListBox::isSelectableItem):
(WebCore::PopupListBox::clearSelection):
(WebCore::PopupListBox::selectNextRow):
(WebCore::PopupListBox::selectPreviousRow):
(WebCore::PopupListBox::adjustSelectedIndex):
(WebCore::PopupListBox::hidePopup):
(WebCore::PopupListBox::updateFromElement):
(WebCore::PopupListBox::setMaxWidthAndLayout):
(WebCore::PopupListBox::layout):
(WebCore::PopupListBox::clear):
(WebCore::PopupListBox::isPointInBounds):
* platform/chromium/PopupListBox.h: Added.
(WebCore::PopupItem::PopupItem):
(WebCore::PopupListBox::create):
(WebCore::PopupListBox::selectedIndex):
(WebCore::PopupListBox::numItems):
(WebCore::PopupListBox::setBaseWidth):
(WebCore::PopupListBox::setMaxHeight):
(WebCore::PopupListBox::setMaxWidth):
(WebCore::PopupListBox::disconnectClient):
(WebCore::PopupListBox::items):
(WebCore::PopupListBox::~PopupListBox):
(WebCore::PopupListBox::scrollToRevealSelection):
* platform/chromium/PopupMenuChromium.cpp:
* platform/chromium/PopupMenuChromium.h:

Source/WebKit/chromium:

* src/ChromeClientImpl.cpp:
* src/WebPopupMenuImpl.cpp:
* src/WebViewImpl.cpp:
* tests/PopupMenuTest.cpp:

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

13 files changed:
Source/WebCore/ChangeLog
Source/WebCore/WebCore.gypi
Source/WebCore/platform/chromium/PopupContainer.cpp [new file with mode: 0644]
Source/WebCore/platform/chromium/PopupContainer.h [new file with mode: 0644]
Source/WebCore/platform/chromium/PopupListBox.cpp [new file with mode: 0644]
Source/WebCore/platform/chromium/PopupListBox.h [new file with mode: 0644]
Source/WebCore/platform/chromium/PopupMenuChromium.cpp
Source/WebCore/platform/chromium/PopupMenuChromium.h
Source/WebKit/chromium/ChangeLog
Source/WebKit/chromium/src/ChromeClientImpl.cpp
Source/WebKit/chromium/src/WebPopupMenuImpl.cpp
Source/WebKit/chromium/src/WebViewImpl.cpp
Source/WebKit/chromium/tests/PopupMenuTest.cpp

index 5e73e43..1aab68e 100644 (file)
@@ -1,3 +1,103 @@
+2011-08-12  Fady Samuel  <fsamuel@chromium.org>
+
+        Refactoring of PopupMenuChromium For Readability and Maintainability
+        https://bugs.webkit.org/show_bug.cgi?id=66009
+
+        Reviewed by Darin Fisher.
+
+        Split PopupMenuChromium into three sets of files: PopupMenuChromium.{h|cpp}, PopupContainer.{h|cpp},
+        and PopupLisBox.{h|cpp}  for readability and maintainability.
+
+        No new tests as there's no change in functionality.
+
+        * WebCore.gypi:
+        * platform/chromium/PopupContainer.cpp: Added.
+        (WebCore::constructRelativeMouseEvent):
+        (WebCore::constructRelativeWheelEvent):
+        (WebCore::PopupContainer::create):
+        (WebCore::PopupContainer::PopupContainer):
+        (WebCore::PopupContainer::~PopupContainer):
+        (WebCore::PopupContainer::layoutAndCalculateWidgetRect):
+        (WebCore::PopupContainer::showPopup):
+        (WebCore::PopupContainer::hidePopup):
+        (WebCore::PopupContainer::notifyPopupHidden):
+        (WebCore::PopupContainer::layoutAndGetRTLOffset):
+        (WebCore::PopupContainer::handleMouseDownEvent):
+        (WebCore::PopupContainer::handleMouseMoveEvent):
+        (WebCore::PopupContainer::handleMouseReleaseEvent):
+        (WebCore::PopupContainer::handleWheelEvent):
+        (WebCore::PopupContainer::handleTouchEvent):
+        (WebCore::PopupContainer::handleGestureEvent):
+        (WebCore::PopupContainer::handleKeyEvent):
+        (WebCore::PopupContainer::hide):
+        (WebCore::PopupContainer::paint):
+        (WebCore::PopupContainer::paintBorder):
+        (WebCore::PopupContainer::isInterestedInEventForKey):
+        (WebCore::PopupContainer::chromeClientChromium):
+        (WebCore::PopupContainer::showInRect):
+        (WebCore::PopupContainer::refresh):
+        (WebCore::PopupContainer::isRTL):
+        (WebCore::PopupContainer::selectedIndex):
+        (WebCore::PopupContainer::menuItemHeight):
+        (WebCore::PopupContainer::menuItemFontSize):
+        (WebCore::PopupContainer::menuStyle):
+        (WebCore::popupData):
+        (WebCore::PopupContainer::getSelectedItemToolTip):
+        * platform/chromium/PopupContainer.h: Added.
+        (WebCore::PopupContainer::listBox):
+        (WebCore::PopupContainer::popupType):
+        * platform/chromium/PopupListBox.cpp: Added.
+        (WebCore::PopupListBox::PopupListBox):
+        (WebCore::PopupListBox::handleMouseDownEvent):
+        (WebCore::PopupListBox::handleMouseMoveEvent):
+        (WebCore::PopupListBox::handleMouseReleaseEvent):
+        (WebCore::PopupListBox::handleWheelEvent):
+        (WebCore::PopupListBox::isInterestedInEventForKey):
+        (WebCore::PopupListBox::handleTouchEvent):
+        (WebCore::PopupListBox::handleGestureEvent):
+        (WebCore::isCharacterTypeEvent):
+        (WebCore::PopupListBox::handleKeyEvent):
+        (WebCore::PopupListBox::hostWindow):
+        (WebCore::stripLeadingWhiteSpace):
+        (WebCore::PopupListBox::typeAheadFind):
+        (WebCore::PopupListBox::paint):
+        (WebCore::PopupListBox::paintRow):
+        (WebCore::PopupListBox::getRowFont):
+        (WebCore::PopupListBox::abandon):
+        (WebCore::PopupListBox::pointToRowIndex):
+        (WebCore::PopupListBox::acceptIndex):
+        (WebCore::PopupListBox::selectIndex):
+        (WebCore::PopupListBox::setOriginalIndex):
+        (WebCore::PopupListBox::getRowHeight):
+        (WebCore::PopupListBox::getRowBounds):
+        (WebCore::PopupListBox::invalidateRow):
+        (WebCore::PopupListBox::scrollToRevealRow):
+        (WebCore::PopupListBox::isSelectableItem):
+        (WebCore::PopupListBox::clearSelection):
+        (WebCore::PopupListBox::selectNextRow):
+        (WebCore::PopupListBox::selectPreviousRow):
+        (WebCore::PopupListBox::adjustSelectedIndex):
+        (WebCore::PopupListBox::hidePopup):
+        (WebCore::PopupListBox::updateFromElement):
+        (WebCore::PopupListBox::setMaxWidthAndLayout):
+        (WebCore::PopupListBox::layout):
+        (WebCore::PopupListBox::clear):
+        (WebCore::PopupListBox::isPointInBounds):
+        * platform/chromium/PopupListBox.h: Added.
+        (WebCore::PopupItem::PopupItem):
+        (WebCore::PopupListBox::create):
+        (WebCore::PopupListBox::selectedIndex):
+        (WebCore::PopupListBox::numItems):
+        (WebCore::PopupListBox::setBaseWidth):
+        (WebCore::PopupListBox::setMaxHeight):
+        (WebCore::PopupListBox::setMaxWidth):
+        (WebCore::PopupListBox::disconnectClient):
+        (WebCore::PopupListBox::items):
+        (WebCore::PopupListBox::~PopupListBox):
+        (WebCore::PopupListBox::scrollToRevealSelection):
+        * platform/chromium/PopupMenuChromium.cpp:
+        * platform/chromium/PopupMenuChromium.h:
+
 2011-08-12  Mark Rowe  <mrowe@apple.com>
 
         Be more forward-looking in the choice of compiler.
index 8c54550..ef054bd 100644 (file)
             'platform/chromium/PlatformThemeChromiumGtk.cpp',
             'platform/chromium/PlatformThemeChromiumGtk.h',
             'platform/chromium/PlatformWidget.h',
+            'platform/chromium/PopupContainer.cpp',
+            'platform/chromium/PopupContainer.h',
             'platform/chromium/PopupMenuChromium.cpp',
             'platform/chromium/PopupMenuChromium.h',
+            'platform/chromium/PopupListBox.cpp',
+            'platform/chromium/PopupListBox.h',
             'platform/chromium/PopupMenuPrivate.h',
             'platform/chromium/SSLKeyGeneratorChromium.cpp',
             'platform/chromium/ScrollAnimatorChromiumMac.h',
diff --git a/Source/WebCore/platform/chromium/PopupContainer.cpp b/Source/WebCore/platform/chromium/PopupContainer.cpp
new file mode 100644 (file)
index 0000000..21c46e6
--- /dev/null
@@ -0,0 +1,464 @@
+/*
+ * Copyright (c) 2011, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "PopupContainer.h"
+
+#include "Chrome.h"
+#include "ChromeClientChromium.h"
+#include "Document.h"
+#include "Frame.h"
+#include "FrameView.h"
+#include "FramelessScrollView.h"
+#include "FramelessScrollViewClient.h"
+#include "GraphicsContext.h"
+#include "IntRect.h"
+#include "Page.h"
+#include "PlatformKeyboardEvent.h"
+#include "PlatformMouseEvent.h"
+#include "PlatformScreen.h"
+#include "PlatformWheelEvent.h"
+#include "PopupListBox.h"
+#include "PopupMenuClient.h"
+#include "UserGestureIndicator.h"
+#include <limits>
+
+#if ENABLE(GESTURE_EVENTS)
+#include "PlatformGestureEvent.h"
+#endif
+
+#if ENABLE(TOUCH_EVENTS)
+#include "PlatformTouchEvent.h"
+#endif
+
+using namespace std;
+
+namespace WebCore {
+
+static const int kBorderSize = 1;
+
+static PlatformMouseEvent constructRelativeMouseEvent(const PlatformMouseEvent& e,
+                                                      FramelessScrollView* parent,
+                                                      FramelessScrollView* child)
+{
+    IntPoint pos = parent->convertSelfToChild(child, e.pos());
+
+    // FIXME: This is a horrible hack since PlatformMouseEvent has no setters for x/y.
+    PlatformMouseEvent relativeEvent = e;
+    IntPoint& relativePos = const_cast<IntPoint&>(relativeEvent.pos());
+    relativePos.setX(pos.x());
+    relativePos.setY(pos.y());
+    return relativeEvent;
+}
+
+static PlatformWheelEvent constructRelativeWheelEvent(const PlatformWheelEvent& e,
+                                                      FramelessScrollView* parent,
+                                                      FramelessScrollView* child)
+{
+    IntPoint pos = parent->convertSelfToChild(child, e.pos());
+
+    // FIXME: This is a horrible hack since PlatformWheelEvent has no setters for x/y.
+    PlatformWheelEvent relativeEvent = e;
+    IntPoint& relativePos = const_cast<IntPoint&>(relativeEvent.pos());
+    relativePos.setX(pos.x());
+    relativePos.setY(pos.y());
+    return relativeEvent;
+}
+
+// static
+PassRefPtr<PopupContainer> PopupContainer::create(PopupMenuClient* client,
+                                                  PopupType popupType,
+                                                  const PopupContainerSettings& settings)
+{
+    return adoptRef(new PopupContainer(client, popupType, settings));
+}
+
+PopupContainer::PopupContainer(PopupMenuClient* client,
+                               PopupType popupType,
+                               const PopupContainerSettings& settings)
+    : m_listBox(PopupListBox::create(client, settings))
+    , m_settings(settings)
+    , m_popupType(popupType)
+    , m_popupOpen(false)
+{
+    setScrollbarModes(ScrollbarAlwaysOff, ScrollbarAlwaysOff);
+}
+
+PopupContainer::~PopupContainer()
+{
+    if (m_listBox && m_listBox->parent())
+        removeChild(m_listBox.get());
+}
+
+IntRect PopupContainer::layoutAndCalculateWidgetRect(int targetControlHeight, const IntPoint& popupInitialCoordinate)
+{
+    // Reset the max width and height to their default values, they will be recomputed below
+    // if necessary.
+    m_listBox->setMaxHeight(kMaxHeight);
+    m_listBox->setMaxWidth(std::numeric_limits<int>::max());
+
+    // Lay everything out to figure out our preferred size, then tell the view's
+    // WidgetClient about it. It should assign us a client.
+    int rtlOffset = layoutAndGetRTLOffset();
+    bool isRTL = this->isRTL();
+    int rightOffset = isRTL ? rtlOffset : 0;
+
+    // Assume m_listBox size is already calculated.
+    IntSize targetSize(m_listBox->width() + kBorderSize * 2,
+                       m_listBox->height() + kBorderSize * 2);
+
+    IntRect widgetRect;
+    ChromeClientChromium* chromeClient = chromeClientChromium();
+    if (chromeClient) {
+        // If the popup would extend past the bottom of the screen, open upwards
+        // instead.
+        FloatRect screen = screenAvailableRect(m_frameView.get());
+        // Use popupInitialCoordinate.x() + rightOffset because RTL position
+        // needs to be considered.
+        widgetRect = chromeClient->windowToScreen(IntRect(popupInitialCoordinate.x() + rightOffset, popupInitialCoordinate.y(), targetSize.width(), targetSize.height()));
+
+        // If we have multiple screens and the browser rect is in one screen, we have
+        // to clip the window width to the screen width.
+        // When clipping, we also need to set a maximum width for the list box.
+        FloatRect windowRect = chromeClient->windowRect();
+        if (windowRect.x() >= screen.x() && windowRect.maxX() <= screen.maxX() && (widgetRect.x() < screen.x() || widgetRect.maxX() > screen.maxX())) {
+            // First, inverse the popup alignment if it does not fit the screen - this might fix things (or make them better).
+            IntRect inverseWidgetRect = chromeClient->windowToScreen(IntRect(popupInitialCoordinate.x() + (isRTL ? 0 : rtlOffset), popupInitialCoordinate.y(), targetSize.width(), targetSize.height()));
+            IntRect enclosingScreen = enclosingIntRect(screen);
+            unsigned originalCutoff = max(enclosingScreen.x() - widgetRect.x(), 0) + max(widgetRect.maxX() - enclosingScreen.maxX(), 0);
+            unsigned inverseCutoff = max(enclosingScreen.x() - inverseWidgetRect.x(), 0) + max(inverseWidgetRect.maxX() - enclosingScreen.maxX(), 0);
+
+            // Accept the inverse popup alignment if the trimmed content gets shorter than that in the original alignment case.
+            if (inverseCutoff < originalCutoff)
+                widgetRect = inverseWidgetRect;
+
+            if (widgetRect.x() < screen.x()) {
+                unsigned widgetRight = widgetRect.maxX();
+                widgetRect.setWidth(widgetRect.maxX() - screen.x());
+                widgetRect.setX(widgetRight - widgetRect.width());
+                listBox()->setMaxWidthAndLayout(max(widgetRect.width() - kBorderSize * 2, 0));
+            } else if (widgetRect.maxX() > screen.maxX()) {
+                widgetRect.setWidth(screen.maxX() - widgetRect.x());
+                listBox()->setMaxWidthAndLayout(max(widgetRect.width() - kBorderSize * 2, 0));
+            }
+        }
+
+        // Calculate Y axis size.
+        if (widgetRect.maxY() > static_cast<int>(screen.maxY())) {
+            if (widgetRect.y() - widgetRect.height() - targetControlHeight > 0) {
+                // There is enough room to open upwards.
+                widgetRect.move(0, -(widgetRect.height() + targetControlHeight));
+            } else {
+                // Figure whether upwards or downwards has more room and set the
+                // maximum number of items.
+                int spaceAbove = widgetRect.y() - targetControlHeight;
+                int spaceBelow = screen.maxY() - widgetRect.y();
+                if (spaceAbove > spaceBelow)
+                    m_listBox->setMaxHeight(spaceAbove);
+                else
+                    m_listBox->setMaxHeight(spaceBelow);
+                layoutAndGetRTLOffset();
+                // Our height has changed, so recompute only Y axis of widgetRect.
+                // We don't have to recompute X axis, so we only replace Y axis
+                // in widgetRect.
+                IntRect frameInScreen = chromeClient->windowToScreen(frameRect());
+                widgetRect.setY(frameInScreen.y());
+                widgetRect.setHeight(frameInScreen.height());
+                // And move upwards if necessary.
+                if (spaceAbove > spaceBelow)
+                    widgetRect.move(0, -(widgetRect.height() + targetControlHeight));
+            }
+        }
+    }
+    return widgetRect;
+}
+
+void PopupContainer::showPopup(FrameView* view)
+{
+    m_frameView = view;
+    listBox()->m_focusedNode = m_frameView->frame()->document()->focusedNode();
+
+    ChromeClientChromium* chromeClient = chromeClientChromium();
+    if (chromeClient) {
+        IntRect popupRect = frameRect();
+        chromeClient->popupOpened(this, layoutAndCalculateWidgetRect(popupRect.height(), popupRect.location()), false);
+        m_popupOpen = true;
+    }
+
+    if (!m_listBox->parent())
+        addChild(m_listBox.get());
+
+    // Enable scrollbars after the listbox is inserted into the hierarchy,
+    // so it has a proper WidgetClient.
+    m_listBox->setVerticalScrollbarMode(ScrollbarAuto);
+
+    m_listBox->scrollToRevealSelection();
+
+    invalidate();
+}
+
+void PopupContainer::hidePopup()
+{
+    listBox()->hidePopup();
+}
+
+void PopupContainer::notifyPopupHidden()
+{
+    if (!m_popupOpen)
+        return;
+    m_popupOpen = false;
+    chromeClientChromium()->popupClosed(this);
+}
+
+int PopupContainer::layoutAndGetRTLOffset()
+{
+    m_listBox->layout();
+
+    // Place the listbox within our border.
+    m_listBox->move(kBorderSize, kBorderSize);
+
+    // Size ourselves to contain listbox + border.
+    int listBoxWidth = m_listBox->width() + kBorderSize * 2;
+    resize(listBoxWidth, m_listBox->height() + kBorderSize * 2);
+    invalidate();
+
+    // Compute the starting x-axis for a normal RTL or right-aligned LTR dropdown. For those,
+    // the right edge of dropdown box should be aligned with the right edge of <select>/<input> element box,
+    // and the dropdown box should be expanded to the left if more space is needed.
+    // m_originalFrameRect.width() is the width of the target <select>/<input> element.
+    return m_originalFrameRect.width() - listBoxWidth;
+}
+
+bool PopupContainer::handleMouseDownEvent(const PlatformMouseEvent& event)
+{
+    UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
+    return m_listBox->handleMouseDownEvent(
+        constructRelativeMouseEvent(event, this, m_listBox.get()));
+}
+
+bool PopupContainer::handleMouseMoveEvent(const PlatformMouseEvent& event)
+{
+    UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
+    return m_listBox->handleMouseMoveEvent(
+        constructRelativeMouseEvent(event, this, m_listBox.get()));
+}
+
+bool PopupContainer::handleMouseReleaseEvent(const PlatformMouseEvent& event)
+{
+    RefPtr<PopupContainer> protect(this);
+    UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
+    return m_listBox->handleMouseReleaseEvent(
+        constructRelativeMouseEvent(event, this, m_listBox.get()));
+}
+
+bool PopupContainer::handleWheelEvent(const PlatformWheelEvent& event)
+{
+    UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
+    return m_listBox->handleWheelEvent(
+        constructRelativeWheelEvent(event, this, m_listBox.get()));
+}
+
+#if ENABLE(TOUCH_EVENTS)
+bool PopupContainer::handleTouchEvent(const PlatformTouchEvent&)
+{
+    return false;
+}
+#endif
+
+#if ENABLE(GESTURE_RECOGNIZER)
+// FIXME: Refactor this code to share functionality with EventHandler::handleGestureEvent.
+bool PopupContainer::handleGestureEvent(const PlatformGestureEvent& gestureEvent)
+{
+    switch (gestureEvent.type()) {
+    case PlatformGestureEvent::TapType: {
+        PlatformMouseEvent fakeMouseMove(gestureEvent.position(), gestureEvent.globalPosition(), NoButton, MouseEventMoved, /* clickCount */ 1, gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey(), gestureEvent.timestamp());
+        PlatformMouseEvent fakeMouseDown(gestureEvent.position(), gestureEvent.globalPosition(), LeftButton, MouseEventPressed, /* clickCount */ 1, gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey(), gestureEvent.timestamp());
+        PlatformMouseEvent fakeMouseUp(gestureEvent.position(), gestureEvent.globalPosition(), LeftButton, MouseEventReleased, /* clickCount */ 1, gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey(), gestureEvent.timestamp());
+        // handleMouseMoveEvent(fakeMouseMove);
+        handleMouseDownEvent(fakeMouseDown);
+        handleMouseReleaseEvent(fakeMouseUp);
+        return true;
+    }
+    case PlatformGestureEvent::ScrollUpdateType: {
+        PlatformWheelEvent syntheticWheelEvent(gestureEvent.position(), gestureEvent.globalPosition(), gestureEvent.deltaX(), gestureEvent.deltaY(), gestureEvent.deltaX() / 120.0f, gestureEvent.deltaY() / 120.0f, ScrollByPixelWheelEvent, /* isAccepted */ false, gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey());
+        handleWheelEvent(syntheticWheelEvent);
+        return true;
+    }
+    case PlatformGestureEvent::ScrollBeginType:
+    case PlatformGestureEvent::ScrollEndType:
+        break;
+    }
+    return false;
+}
+#endif
+
+bool PopupContainer::handleKeyEvent(const PlatformKeyboardEvent& event)
+{
+    UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
+    return m_listBox->handleKeyEvent(event);
+}
+
+void PopupContainer::hide()
+{
+    m_listBox->abandon();
+}
+
+void PopupContainer::paint(GraphicsContext* gc, const IntRect& rect)
+{
+    // adjust coords for scrolled frame
+    IntRect r = intersection(rect, frameRect());
+    int tx = x();
+    int ty = y();
+
+    r.move(-tx, -ty);
+
+    gc->translate(static_cast<float>(tx), static_cast<float>(ty));
+    m_listBox->paint(gc, r);
+    gc->translate(-static_cast<float>(tx), -static_cast<float>(ty));
+
+    paintBorder(gc, rect);
+}
+
+void PopupContainer::paintBorder(GraphicsContext* gc, const IntRect& rect)
+{
+    // FIXME: Where do we get the border color from?
+    Color borderColor(127, 157, 185);
+
+    gc->setStrokeStyle(NoStroke);
+    gc->setFillColor(borderColor, ColorSpaceDeviceRGB);
+
+    int tx = x();
+    int ty = y();
+
+    // top, left, bottom, right
+    gc->drawRect(IntRect(tx, ty, width(), kBorderSize));
+    gc->drawRect(IntRect(tx, ty, kBorderSize, height()));
+    gc->drawRect(IntRect(tx, ty + height() - kBorderSize, width(), kBorderSize));
+    gc->drawRect(IntRect(tx + width() - kBorderSize, ty, kBorderSize, height()));
+}
+
+bool PopupContainer::isInterestedInEventForKey(int keyCode)
+{
+    return m_listBox->isInterestedInEventForKey(keyCode);
+}
+
+ChromeClientChromium* PopupContainer::chromeClientChromium()
+{
+    return static_cast<ChromeClientChromium*>(m_frameView->frame()->page()->chrome()->client());
+}
+
+void PopupContainer::showInRect(const IntRect& r, FrameView* v, int index)
+{
+    // The rect is the size of the select box. It's usually larger than we need.
+    // subtract border size so that usually the container will be displayed
+    // exactly the same width as the select box.
+    listBox()->setBaseWidth(max(r.width() - kBorderSize * 2, 0));
+
+    listBox()->updateFromElement();
+
+    // We set the selected item in updateFromElement(), and disregard the
+    // index passed into this function (same as Webkit's PopupMenuWin.cpp)
+    // FIXME: make sure this is correct, and add an assertion.
+    // ASSERT(popupWindow(popup)->listBox()->selectedIndex() == index);
+
+    // Convert point to main window coords.
+    IntPoint location = v->contentsToWindow(r.location());
+
+    // Move it below the select widget.
+    location.move(0, r.height());
+
+    m_originalFrameRect = IntRect(location, r.size());
+    setFrameRect(m_originalFrameRect);
+    showPopup(v);
+}
+
+void PopupContainer::refresh(const IntRect& targetControlRect)
+{
+    IntPoint location = m_frameView->contentsToWindow(targetControlRect.location());
+    // Move it below the select widget.
+    location.move(0, targetControlRect.height());
+
+    listBox()->setBaseWidth(max(m_originalFrameRect.width() - kBorderSize * 2, 0));
+    setBoundsSize(m_originalFrameRect.size());
+
+    listBox()->updateFromElement();
+    // Store the original size to check if we need to request the location.
+    IntSize originalSize = size();
+    IntRect widgetRect = layoutAndCalculateWidgetRect(targetControlRect.height(), location);
+    if (originalSize != widgetRect.size()) {
+        ChromeClientChromium* chromeClient = chromeClientChromium();
+        if (chromeClient) {
+            IntPoint widgetLocation = chromeClient->screenToWindow(widgetRect.location());
+            widgetRect.setLocation(widgetLocation);
+            setFrameRect(widgetRect);
+        }
+    }
+
+    invalidate();
+}
+
+inline bool PopupContainer::isRTL() const
+{
+    return m_listBox->m_popupClient->menuStyle().textDirection() == RTL;
+}
+
+int PopupContainer::selectedIndex() const
+{
+    return m_listBox->selectedIndex();
+}
+
+int PopupContainer::menuItemHeight() const
+{
+    return m_listBox->getRowHeight(0);
+}
+
+int PopupContainer::menuItemFontSize() const
+{
+    return m_listBox->getRowFont(0).size();
+}
+
+PopupMenuStyle PopupContainer::menuStyle() const
+{
+    return m_listBox->m_popupClient->menuStyle();
+}
+
+const WTF::Vector<PopupItem*>& PopupContainer:: popupData() const
+{
+    return m_listBox->items();
+}
+
+String PopupContainer::getSelectedItemToolTip()
+{
+    // We cannot use m_popupClient->selectedIndex() to choose tooltip message,
+    // because the selectedIndex() might return final selected index, not hovering selection.
+    return listBox()->m_popupClient->itemToolTip(listBox()->m_selectedIndex);
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/chromium/PopupContainer.h b/Source/WebCore/platform/chromium/PopupContainer.h
new file mode 100644 (file)
index 0000000..452e1b4
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2011, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef PopupContainer_h
+#define PopupContainer_h
+
+#include "FramelessScrollView.h"
+#include "PopupListBox.h"
+#include "PopupMenuStyle.h"
+
+namespace WebCore {
+
+class ChromeClientChromium;
+class FrameView;
+class PopupMenuClient;
+
+class PopupContainer : public FramelessScrollView {
+public:
+    enum PopupType {
+        Select, // HTML select popup.
+        Suggestion, // Autocomplete/autofill popup.
+    };
+
+    static PassRefPtr<PopupContainer> create(PopupMenuClient*, PopupType,
+                                             const PopupContainerSettings&);
+
+    // Whether a key event should be sent to this popup.
+    virtual bool isInterestedInEventForKey(int keyCode);
+
+    // FramelessScrollView
+    virtual void paint(GraphicsContext*, const IntRect&);
+    virtual void hide();
+    virtual bool handleMouseDownEvent(const PlatformMouseEvent&);
+    virtual bool handleMouseMoveEvent(const PlatformMouseEvent&);
+    virtual bool handleMouseReleaseEvent(const PlatformMouseEvent&);
+    virtual bool handleWheelEvent(const PlatformWheelEvent&);
+    virtual bool handleKeyEvent(const PlatformKeyboardEvent&);
+#if ENABLE(TOUCH_EVENTS)
+    virtual bool handleTouchEvent(const PlatformTouchEvent&);
+#endif
+#if ENABLE(GESTURE_RECOGNIZER)
+    virtual bool handleGestureEvent(const PlatformGestureEvent&);
+#endif
+
+    // PopupContainer methods
+
+    // Show the popup
+    void showPopup(FrameView*);
+
+    // Show the popup in the specified rect for the specified frame.
+    // Note: this code was somehow arbitrarily factored-out of the Popup class
+    // so WebViewImpl can create a PopupContainer. This method is used for
+    // displaying auto complete popup menus on Mac Chromium, and for all
+    // popups on other platforms.
+    void showInRect(const IntRect&, FrameView*, int index);
+
+    // Hides the popup.
+    void hidePopup();
+
+    // The popup was hidden.
+    void notifyPopupHidden();
+
+    // Compute size of widget and children. Return right offset for the popup right alignment.
+    int layoutAndGetRTLOffset();
+
+    PopupListBox* listBox() const { return m_listBox.get(); }
+
+    bool isRTL() const;
+
+    // Gets the index of the item that the user is currently moused-over or
+    // has selected with the keyboard up/down arrows.
+    int selectedIndex() const;
+
+    // Refresh the popup values from the PopupMenuClient.
+    void refresh(const IntRect& targetControlRect);
+
+    // The menu per-item data.
+    const WTF::Vector<PopupItem*>& popupData() const;
+
+    // The height of a row in the menu.
+    int menuItemHeight() const;
+
+    // The size of the font being used.
+    int menuItemFontSize() const;
+
+    // The style of the menu being used.
+    PopupMenuStyle menuStyle() const;
+
+    PopupType popupType() const { return m_popupType; }
+
+    // While hovering popup menu window, we want to show tool tip message.
+    String getSelectedItemToolTip();
+
+private:
+    friend class WTF::RefCounted<PopupContainer>;
+
+    PopupContainer(PopupMenuClient*, PopupType, const PopupContainerSettings&);
+    ~PopupContainer();
+
+    // Paint the border.
+    void paintBorder(GraphicsContext*, const IntRect&);
+
+    // Layout and calculate popup widget size and location and returns it as IntRect.
+    IntRect layoutAndCalculateWidgetRect(int targetControlHeight, const IntPoint& popupInitialCoordinate);
+
+    // Returns the ChromeClient of the page this popup is associated with.
+    ChromeClientChromium* chromeClientChromium();
+
+    RefPtr<PopupListBox> m_listBox;
+    RefPtr<FrameView> m_frameView;
+
+    PopupContainerSettings m_settings;
+    PopupType m_popupType;
+    IntRect m_originalFrameRect;
+    // Whether the popup is currently open.
+    bool m_popupOpen;
+};
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/WebCore/platform/chromium/PopupListBox.cpp b/Source/WebCore/platform/chromium/PopupListBox.cpp
new file mode 100644 (file)
index 0000000..2015064
--- /dev/null
@@ -0,0 +1,911 @@
+/*
+ * Copyright (c) 2011, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "config.h"
+#include "PopupListBox.h"
+
+#include "Font.h"
+#include "FontSelector.h"
+#include "FramelessScrollViewClient.h"
+#include "GraphicsContext.h"
+#include "IntRect.h"
+#include "KeyboardCodes.h"
+#include "PlatformKeyboardEvent.h"
+#include "PlatformMouseEvent.h"
+#include "PlatformScreen.h"
+#include "PlatformWheelEvent.h"
+#include "PopupContainer.h"
+#include "PopupMenuChromium.h"
+#include "PopupMenuClient.h"
+#include "RenderTheme.h"
+#include "ScrollbarTheme.h"
+#include "StringTruncator.h"
+#include "TextRun.h"
+#include <limits>
+#include <wtf/CurrentTime.h>
+
+#if ENABLE(GESTURE_EVENTS)
+#include "PlatformGestureEvent.h"
+#endif
+
+#if ENABLE(TOUCH_EVENTS)
+#include "PlatformTouchEvent.h"
+#endif
+
+namespace WebCore {
+
+using namespace std;
+using namespace WTF;
+using namespace Unicode;
+
+PopupListBox::PopupListBox(PopupMenuClient* client, const PopupContainerSettings& settings)
+    : m_settings(settings)
+    , m_originalIndex(0)
+    , m_selectedIndex(0)
+    , m_acceptedIndexOnAbandon(-1)
+    , m_visibleRows(0)
+    , m_baseWidth(0)
+    , m_maxHeight(kMaxHeight)
+    , m_popupClient(client)
+    , m_repeatingChar(0)
+    , m_lastCharTime(0)
+    , m_maxWindowWidth(std::numeric_limits<int>::max())
+{
+    setScrollbarModes(ScrollbarAlwaysOff, ScrollbarAlwaysOff);
+}
+
+bool PopupListBox::handleMouseDownEvent(const PlatformMouseEvent& event)
+{
+    Scrollbar* scrollbar = scrollbarAtPoint(event.pos());
+    if (scrollbar) {
+        m_capturingScrollbar = scrollbar;
+        m_capturingScrollbar->mouseDown(event);
+        return true;
+    }
+
+    if (!isPointInBounds(event.pos()))
+        abandon();
+
+    return true;
+}
+
+bool PopupListBox::handleMouseMoveEvent(const PlatformMouseEvent& event)
+{
+    if (m_capturingScrollbar) {
+        m_capturingScrollbar->mouseMoved(event);
+        return true;
+    }
+
+    Scrollbar* scrollbar = scrollbarAtPoint(event.pos());
+    if (m_lastScrollbarUnderMouse != scrollbar) {
+        // Send mouse exited to the old scrollbar.
+        if (m_lastScrollbarUnderMouse)
+            m_lastScrollbarUnderMouse->mouseExited();
+        m_lastScrollbarUnderMouse = scrollbar;
+    }
+
+    if (scrollbar) {
+        scrollbar->mouseMoved(event);
+        return true;
+    }
+
+    if (!isPointInBounds(event.pos()))
+        return false;
+
+    selectIndex(pointToRowIndex(event.pos()));
+    return true;
+}
+
+bool PopupListBox::handleMouseReleaseEvent(const PlatformMouseEvent& event)
+{
+    if (m_capturingScrollbar) {
+        m_capturingScrollbar->mouseUp();
+        m_capturingScrollbar = 0;
+        return true;
+    }
+
+    if (!isPointInBounds(event.pos()))
+        return true;
+
+    // Need to check before calling acceptIndex(), because m_popupClient might be removed in acceptIndex() calling because of event handler.
+    bool isSelectPopup = m_popupClient->menuStyle().menuType() == PopupMenuStyle::SelectPopup;
+    if (acceptIndex(pointToRowIndex(event.pos())) && m_focusedNode && isSelectPopup) {
+        m_focusedNode->dispatchMouseEvent(event, eventNames().mouseupEvent);
+        m_focusedNode->dispatchMouseEvent(event, eventNames().clickEvent);
+
+        // Clear m_focusedNode here, because we cannot clear in hidePopup() which is called before dispatchMouseEvent() is called.
+        m_focusedNode = 0;
+    }
+
+    return true;
+}
+
+bool PopupListBox::handleWheelEvent(const PlatformWheelEvent& event)
+{
+    if (!isPointInBounds(event.pos())) {
+        abandon();
+        return true;
+    }
+
+    // Pass it off to the scroll view.
+    // Sadly, WebCore devs don't understand the whole "const" thing.
+    wheelEvent(const_cast<PlatformWheelEvent&>(event));
+    return true;
+}
+
+// Should be kept in sync with handleKeyEvent().
+bool PopupListBox::isInterestedInEventForKey(int keyCode)
+{
+    switch (keyCode) {
+    case VKEY_ESCAPE:
+    case VKEY_RETURN:
+    case VKEY_UP:
+    case VKEY_DOWN:
+    case VKEY_PRIOR:
+    case VKEY_NEXT:
+    case VKEY_HOME:
+    case VKEY_END:
+    case VKEY_TAB:
+        return true;
+    default:
+        return false;
+    }
+}
+
+#if ENABLE(TOUCH_EVENTS)
+bool PopupListBox::handleTouchEvent(const PlatformTouchEvent&)
+{
+    return false;
+}
+#endif
+
+#if ENABLE(GESTURE_RECOGNIZER)
+bool PopupListBox::handleGestureEvent(const PlatformGestureEvent&)
+{
+    return false;
+}
+#endif
+
+static bool isCharacterTypeEvent(const PlatformKeyboardEvent& event)
+{
+    // Check whether the event is a character-typed event or not.
+    // We use RawKeyDown/Char/KeyUp event scheme on all platforms,
+    // so PlatformKeyboardEvent::Char (not RawKeyDown) type event
+    // is considered as character type event.
+    return event.type() == PlatformKeyboardEvent::Char;
+}
+
+bool PopupListBox::handleKeyEvent(const PlatformKeyboardEvent& event)
+{
+    if (event.type() == PlatformKeyboardEvent::KeyUp)
+        return true;
+
+    if (!numItems() && event.windowsVirtualKeyCode() != VKEY_ESCAPE)
+        return true;
+
+    switch (event.windowsVirtualKeyCode()) {
+    case VKEY_ESCAPE:
+        abandon(); // may delete this
+        return true;
+    case VKEY_RETURN:
+        if (m_selectedIndex == -1)  {
+            hidePopup();
+            // Don't eat the enter if nothing is selected.
+            return false;
+        }
+        acceptIndex(m_selectedIndex); // may delete this
+        return true;
+    case VKEY_UP:
+    case VKEY_DOWN:
+        // We have to forward only shift + up combination to focused node when autofill popup.
+        // Because all characters from the cursor to the start of the text area should selected when you press shift + up arrow.
+        // shift + down should be the similar way to shift + up.
+        if (event.modifiers() && m_popupClient->menuStyle().menuType() == PopupMenuStyle::AutofillPopup)
+            m_focusedNode->dispatchKeyEvent(event);
+        else if (event.windowsVirtualKeyCode() == VKEY_UP)
+            selectPreviousRow();
+        else
+            selectNextRow();
+        break;
+    case VKEY_PRIOR:
+        adjustSelectedIndex(-m_visibleRows);
+        break;
+    case VKEY_NEXT:
+        adjustSelectedIndex(m_visibleRows);
+        break;
+    case VKEY_HOME:
+        adjustSelectedIndex(-m_selectedIndex);
+        break;
+    case VKEY_END:
+        adjustSelectedIndex(m_items.size());
+        break;
+    default:
+        if (!event.ctrlKey() && !event.altKey() && !event.metaKey()
+            && isPrintableChar(event.windowsVirtualKeyCode())
+            && isCharacterTypeEvent(event))
+            typeAheadFind(event);
+        break;
+    }
+
+    if (m_originalIndex != m_selectedIndex) {
+        // Keyboard events should update the selection immediately (but we don't
+        // want to fire the onchange event until the popup is closed, to match
+        // IE). We change the original index so we revert to that when the
+        // popup is closed.
+        if (m_settings.acceptOnAbandon)
+            m_acceptedIndexOnAbandon = m_selectedIndex;
+
+        setOriginalIndex(m_selectedIndex);
+        if (m_settings.setTextOnIndexChange)
+            m_popupClient->setTextFromItem(m_selectedIndex);
+    }
+    if (event.windowsVirtualKeyCode() == VKEY_TAB) {
+        // TAB is a special case as it should select the current item if any and
+        // advance focus.
+        if (m_selectedIndex >= 0) {
+            acceptIndex(m_selectedIndex); // May delete us.
+            // Return false so the TAB key event is propagated to the page.
+            return false;
+        }
+        // Call abandon() so we honor m_acceptedIndexOnAbandon if set.
+        abandon();
+        // Return false so the TAB key event is propagated to the page.
+        return false;
+    }
+
+    return true;
+}
+
+HostWindow* PopupListBox::hostWindow() const
+{
+    // Our parent is the root ScrollView, so it is the one that has a
+    // HostWindow. FrameView::hostWindow() works similarly.
+    return parent() ? parent()->hostWindow() : 0;
+}
+
+// From HTMLSelectElement.cpp
+static String stripLeadingWhiteSpace(const String& string)
+{
+    int length = string.length();
+    int i;
+    for (i = 0; i < length; ++i)
+        if (string[i] != noBreakSpace
+            && (string[i] <= 0x7F ? !isspace(string[i]) : (direction(string[i]) != WhiteSpaceNeutral)))
+            break;
+
+    return string.substring(i, length - i);
+}
+
+// From HTMLSelectElement.cpp, with modifications
+void PopupListBox::typeAheadFind(const PlatformKeyboardEvent& event)
+{
+    TimeStamp now = static_cast<TimeStamp>(currentTime() * 1000.0f);
+    TimeStamp delta = now - m_lastCharTime;
+
+    // Reset the time when user types in a character. The time gap between
+    // last character and the current character is used to indicate whether
+    // user typed in a string or just a character as the search prefix.
+    m_lastCharTime = now;
+
+    UChar c = event.windowsVirtualKeyCode();
+
+    String prefix;
+    int searchStartOffset = 1;
+    if (delta > kTypeAheadTimeoutMs) {
+        m_typedString = prefix = String(&c, 1);
+        m_repeatingChar = c;
+    } else {
+        m_typedString.append(c);
+
+        if (c == m_repeatingChar)
+            // The user is likely trying to cycle through all the items starting with this character, so just search on the character
+            prefix = String(&c, 1);
+        else {
+            m_repeatingChar = 0;
+            prefix = m_typedString;
+            searchStartOffset = 0;
+        }
+    }
+
+    // Compute a case-folded copy of the prefix string before beginning the search for
+    // a matching element. This code uses foldCase to work around the fact that
+    // String::startWith does not fold non-ASCII characters. This code can be changed
+    // to use startWith once that is fixed.
+    String prefixWithCaseFolded(prefix.foldCase());
+    int itemCount = numItems();
+    int index = (max(0, m_selectedIndex) + searchStartOffset) % itemCount;
+    for (int i = 0; i < itemCount; i++, index = (index + 1) % itemCount) {
+        if (!isSelectableItem(index))
+            continue;
+
+        if (stripLeadingWhiteSpace(m_items[index]->label).foldCase().startsWith(prefixWithCaseFolded)) {
+            selectIndex(index);
+            return;
+        }
+    }
+}
+
+void PopupListBox::paint(GraphicsContext* gc, const IntRect& rect)
+{
+    // adjust coords for scrolled frame
+    IntRect r = intersection(rect, frameRect());
+    int tx = x() - scrollX();
+    int ty = y() - scrollY();
+
+    r.move(-tx, -ty);
+
+    // set clip rect to match revised damage rect
+    gc->save();
+    gc->translate(static_cast<float>(tx), static_cast<float>(ty));
+    gc->clip(r);
+
+    // FIXME: Can we optimize scrolling to not require repainting the entire
+    // window? Should we?
+    for (int i = 0; i < numItems(); ++i)
+        paintRow(gc, r, i);
+
+    // Special case for an empty popup.
+    if (!numItems())
+        gc->fillRect(r, Color::white, ColorSpaceDeviceRGB);
+
+    gc->restore();
+
+    ScrollView::paint(gc, rect);
+}
+
+static const int separatorPadding = 4;
+static const int separatorHeight = 1;
+
+void PopupListBox::paintRow(GraphicsContext* gc, const IntRect& rect, int rowIndex)
+{
+    // This code is based largely on RenderListBox::paint* methods.
+
+    IntRect rowRect = getRowBounds(rowIndex);
+    if (!rowRect.intersects(rect))
+        return;
+
+    PopupMenuStyle style = m_popupClient->itemStyle(rowIndex);
+
+    // Paint background
+    Color backColor, textColor, labelColor;
+    if (rowIndex == m_selectedIndex) {
+        backColor = RenderTheme::defaultTheme()->activeListBoxSelectionBackgroundColor();
+        textColor = RenderTheme::defaultTheme()->activeListBoxSelectionForegroundColor();
+        labelColor = textColor;
+    } else {
+        backColor = style.backgroundColor();
+        textColor = style.foregroundColor();
+        // FIXME: for now the label color is hard-coded. It should be added to
+        // the PopupMenuStyle.
+        labelColor = Color(115, 115, 115);
+    }
+
+    // If we have a transparent background, make sure it has a color to blend
+    // against.
+    if (backColor.hasAlpha())
+        gc->fillRect(rowRect, Color::white, ColorSpaceDeviceRGB);
+
+    gc->fillRect(rowRect, backColor, ColorSpaceDeviceRGB);
+
+    // It doesn't look good but Autofill requires special style for separator.
+    // Autofill doesn't have padding and #dcdcdc color.
+    if (m_popupClient->itemIsSeparator(rowIndex)) {
+        int padding = style.menuType() == PopupMenuStyle::AutofillPopup ? 0 : separatorPadding;
+        IntRect separatorRect(
+            rowRect.x() + padding,
+            rowRect.y() + (rowRect.height() - separatorHeight) / 2,
+            rowRect.width() - 2 * padding, separatorHeight);
+        gc->fillRect(separatorRect, style.menuType() == PopupMenuStyle::AutofillPopup ? Color(0xdc, 0xdc, 0xdc) : textColor, ColorSpaceDeviceRGB);
+        return;
+    }
+
+    if (!style.isVisible())
+        return;
+
+    gc->setFillColor(textColor, ColorSpaceDeviceRGB);
+
+    Font itemFont = getRowFont(rowIndex);
+    // FIXME: http://crbug.com/19872 We should get the padding of individual option
+    // elements. This probably implies changes to PopupMenuClient.
+    bool rightAligned = m_popupClient->menuStyle().textDirection() == RTL;
+    int textX = 0;
+    int maxWidth = 0;
+    if (rightAligned)
+        maxWidth = rowRect.width() - max(0, m_popupClient->clientPaddingRight() - m_popupClient->clientInsetRight());
+    else {
+        textX = max(0, m_popupClient->clientPaddingLeft() - m_popupClient->clientInsetLeft());
+        maxWidth = rowRect.width() - textX;
+    }
+    // Prepare text to be drawn.
+    String itemText = m_popupClient->itemText(rowIndex);
+    String itemLabel = m_popupClient->itemLabel(rowIndex);
+    String itemIcon = m_popupClient->itemIcon(rowIndex);
+    if (m_settings.restrictWidthOfListBox) { // Truncate strings to fit in.
+        // FIXME: We should leftTruncate for the rtl case.
+        // StringTruncator::leftTruncate would have to be implemented.
+        String str = StringTruncator::rightTruncate(itemText, maxWidth, itemFont);
+        if (str != itemText) {
+            itemText = str;
+            // Don't display the label or icon, we already don't have enough room for the item text.
+            itemLabel = "";
+            itemIcon = "";
+        } else if (!itemLabel.isEmpty()) {
+            int availableWidth = maxWidth - kTextToLabelPadding -
+                StringTruncator::width(itemText, itemFont);
+            itemLabel = StringTruncator::rightTruncate(itemLabel, availableWidth, itemFont);
+        }
+    }
+
+    // Prepare the directionality to draw text.
+    TextRun textRun(itemText.characters(), itemText.length(), false, 0, 0, TextRun::AllowTrailingExpansion, style.textDirection(), style.hasTextDirectionOverride());
+    // If the text is right-to-left, make it right-aligned by adjusting its
+    // beginning position.
+    if (rightAligned)
+        textX += maxWidth - itemFont.width(textRun);
+
+    // Draw the item text.
+    int textY = rowRect.y() + itemFont.fontMetrics().ascent() + (rowRect.height() - itemFont.fontMetrics().height()) / 2;
+    gc->drawBidiText(itemFont, textRun, IntPoint(textX, textY));
+
+    // We are using the left padding as the right padding includes room for the scroll-bar which
+    // does not show in this case.
+    int rightPadding = max(0, m_popupClient->clientPaddingLeft() - m_popupClient->clientInsetLeft());
+    int remainingWidth = rowRect.width() - rightPadding;
+
+    // Draw the icon if applicable.
+    RefPtr<Image> image(Image::loadPlatformResource(itemIcon.utf8().data()));
+    if (image && !image->isNull()) {
+        IntRect imageRect = image->rect();
+        remainingWidth -= (imageRect.width() + kLabelToIconPadding);
+        imageRect.setX(rowRect.width() - rightPadding - imageRect.width());
+        imageRect.setY(rowRect.y() + (rowRect.height() - imageRect.height()) / 2);
+        gc->drawImage(image.get(), ColorSpaceDeviceRGB, imageRect);
+    }
+
+    // Draw the the label if applicable.
+    if (itemLabel.isEmpty())
+        return;
+
+    // Autofill label is 0.9 smaller than regular font size.
+    if (style.menuType() == PopupMenuStyle::AutofillPopup) {
+        itemFont = m_popupClient->itemStyle(rowIndex).font();
+        FontDescription d = itemFont.fontDescription();
+        d.setComputedSize(d.computedSize() * 0.9);
+        itemFont = Font(d, itemFont.letterSpacing(), itemFont.wordSpacing());
+        itemFont.update(0);
+    }
+
+    TextRun labelTextRun(itemLabel.characters(), itemLabel.length(), false, 0, 0, TextRun::AllowTrailingExpansion, style.textDirection(), style.hasTextDirectionOverride());
+    if (rightAligned)
+        textX = max(0, m_popupClient->clientPaddingLeft() - m_popupClient->clientInsetLeft());
+    else
+        textX = remainingWidth - itemFont.width(labelTextRun);
+
+    gc->setFillColor(labelColor, ColorSpaceDeviceRGB);
+    gc->drawBidiText(itemFont, labelTextRun, IntPoint(textX, textY));
+}
+
+Font PopupListBox::getRowFont(int rowIndex)
+{
+    Font itemFont = m_popupClient->itemStyle(rowIndex).font();
+    if (m_popupClient->itemIsLabel(rowIndex)) {
+        // Bold-ify labels (ie, an <optgroup> heading).
+        FontDescription d = itemFont.fontDescription();
+        d.setWeight(FontWeightBold);
+        Font font(d, itemFont.letterSpacing(), itemFont.wordSpacing());
+        font.update(0);
+        return font;
+    }
+
+    return itemFont;
+}
+
+void PopupListBox::abandon()
+{
+    RefPtr<PopupListBox> keepAlive(this);
+
+    m_selectedIndex = m_originalIndex;
+
+    hidePopup();
+
+    if (m_acceptedIndexOnAbandon >= 0) {
+        if (m_popupClient)
+            m_popupClient->valueChanged(m_acceptedIndexOnAbandon);
+        m_acceptedIndexOnAbandon = -1;
+    }
+}
+
+int PopupListBox::pointToRowIndex(const IntPoint& point)
+{
+    int y = scrollY() + point.y();
+
+    // FIXME: binary search if perf matters.
+    for (int i = 0; i < numItems(); ++i) {
+        if (y < m_items[i]->yOffset)
+            return i-1;
+    }
+
+    // Last item?
+    if (y < contentsHeight())
+        return m_items.size()-1;
+
+    return -1;
+}
+
+bool PopupListBox::acceptIndex(int index)
+{
+    // Clear m_acceptedIndexOnAbandon once user accepts the selected index.
+    if (m_acceptedIndexOnAbandon >= 0)
+        m_acceptedIndexOnAbandon = -1;
+
+    if (index >= numItems())
+        return false;
+
+    if (index < 0) {
+        if (m_popupClient) {
+            // Enter pressed with no selection, just close the popup.
+            hidePopup();
+        }
+        return false;
+    }
+
+    if (isSelectableItem(index)) {
+        RefPtr<PopupListBox> keepAlive(this);
+
+        // Hide ourselves first since valueChanged may have numerous side-effects.
+        hidePopup();
+
+        // Tell the <select> PopupMenuClient what index was selected.
+        m_popupClient->valueChanged(index);
+
+        return true;
+    }
+
+    return false;
+}
+
+void PopupListBox::selectIndex(int index)
+{
+    if (index < 0 || index >= numItems())
+        return;
+
+    bool isSelectable = isSelectableItem(index);
+    if (index != m_selectedIndex && isSelectable) {
+        invalidateRow(m_selectedIndex);
+        m_selectedIndex = index;
+        invalidateRow(m_selectedIndex);
+
+        scrollToRevealSelection();
+        m_popupClient->selectionChanged(m_selectedIndex);
+    } else if (!isSelectable)
+        clearSelection();
+}
+
+void PopupListBox::setOriginalIndex(int index)
+{
+    m_originalIndex = m_selectedIndex = index;
+}
+
+int PopupListBox::getRowHeight(int index)
+{
+    if (index < 0)
+        return PopupMenuChromium::minimumRowHeight();
+
+    if (m_popupClient->itemStyle(index).isDisplayNone())
+        return PopupMenuChromium::minimumRowHeight();
+
+    // Separator row height is the same size as itself.
+    if (m_popupClient->itemIsSeparator(index))
+        return max(separatorHeight, PopupMenuChromium::minimumRowHeight());
+
+    String icon = m_popupClient->itemIcon(index);
+    RefPtr<Image> image(Image::loadPlatformResource(icon.utf8().data()));
+
+    int fontHeight = getRowFont(index).fontMetrics().height();
+    int iconHeight = (image && !image->isNull()) ? image->rect().height() : 0;
+
+    int linePaddingHeight = m_popupClient->menuStyle().menuType() == PopupMenuStyle::AutofillPopup ? kLinePaddingHeight : 0;
+    int calculatedRowHeight = max(fontHeight, iconHeight) + linePaddingHeight * 2;
+    return max(calculatedRowHeight, PopupMenuChromium::minimumRowHeight());
+}
+
+IntRect PopupListBox::getRowBounds(int index)
+{
+    if (index < 0)
+        return IntRect(0, 0, visibleWidth(), getRowHeight(index));
+
+    return IntRect(0, m_items[index]->yOffset, visibleWidth(), getRowHeight(index));
+}
+
+void PopupListBox::invalidateRow(int index)
+{
+    if (index < 0)
+        return;
+
+    // Invalidate in the window contents, as FramelessScrollView::invalidateRect
+    // paints in the window coordinates.
+    invalidateRect(contentsToWindow(getRowBounds(index)));
+}
+
+void PopupListBox::scrollToRevealRow(int index)
+{
+    if (index < 0)
+        return;
+
+    IntRect rowRect = getRowBounds(index);
+
+    if (rowRect.y() < scrollY()) {
+        // Row is above current scroll position, scroll up.
+        ScrollView::setScrollPosition(IntPoint(0, rowRect.y()));
+    } else if (rowRect.maxY() > scrollY() + visibleHeight()) {
+        // Row is below current scroll position, scroll down.
+        ScrollView::setScrollPosition(IntPoint(0, rowRect.maxY() - visibleHeight()));
+    }
+}
+
+bool PopupListBox::isSelectableItem(int index)
+{
+    ASSERT(index >= 0 && index < numItems());
+    return m_items[index]->type == PopupItem::TypeOption && m_popupClient->itemIsEnabled(index);
+}
+
+void PopupListBox::clearSelection()
+{
+    if (m_selectedIndex != -1) {
+        invalidateRow(m_selectedIndex);
+        m_selectedIndex = -1;
+        m_popupClient->selectionCleared();
+    }
+}
+
+void PopupListBox::selectNextRow()
+{
+    if (!m_settings.loopSelectionNavigation || m_selectedIndex != numItems() - 1) {
+        adjustSelectedIndex(1);
+        return;
+    }
+
+    // We are moving past the last item, no row should be selected.
+    clearSelection();
+}
+
+void PopupListBox::selectPreviousRow()
+{
+    if (!m_settings.loopSelectionNavigation || m_selectedIndex > 0) {
+        adjustSelectedIndex(-1);
+        return;
+    }
+
+    if (!m_selectedIndex) {
+        // We are moving past the first item, clear the selection.
+        clearSelection();
+        return;
+    }
+
+    // No row is selected, jump to the last item.
+    selectIndex(numItems() - 1);
+    scrollToRevealSelection();
+}
+
+void PopupListBox::adjustSelectedIndex(int delta)
+{
+    int targetIndex = m_selectedIndex + delta;
+    targetIndex = min(max(targetIndex, 0), numItems() - 1);
+    if (!isSelectableItem(targetIndex)) {
+        // We didn't land on an option. Try to find one.
+        // We try to select the closest index to target, prioritizing any in
+        // the range [current, target].
+
+        int dir = delta > 0 ? 1 : -1;
+        int testIndex = m_selectedIndex;
+        int bestIndex = m_selectedIndex;
+        bool passedTarget = false;
+        while (testIndex >= 0 && testIndex < numItems()) {
+            if (isSelectableItem(testIndex))
+                bestIndex = testIndex;
+            if (testIndex == targetIndex)
+                passedTarget = true;
+            if (passedTarget && bestIndex != m_selectedIndex)
+                break;
+
+            testIndex += dir;
+        }
+
+        // Pick the best index, which may mean we don't change.
+        targetIndex = bestIndex;
+    }
+
+    // Select the new index, and ensure its visible. We do this regardless of
+    // whether the selection changed to ensure keyboard events always bring the
+    // selection into view.
+    selectIndex(targetIndex);
+    scrollToRevealSelection();
+}
+
+void PopupListBox::hidePopup()
+{
+    if (parent()) {
+        PopupContainer* container = static_cast<PopupContainer*>(parent());
+        if (container->client())
+            container->client()->popupClosed(container);
+        container->notifyPopupHidden();
+    }
+
+    if (m_popupClient)
+        m_popupClient->popupDidHide();
+}
+
+void PopupListBox::updateFromElement()
+{
+    clear();
+
+    int size = m_popupClient->listSize();
+    for (int i = 0; i < size; ++i) {
+        PopupItem::Type type;
+        if (m_popupClient->itemIsSeparator(i))
+            type = PopupItem::TypeSeparator;
+        else if (m_popupClient->itemIsLabel(i))
+            type = PopupItem::TypeGroup;
+        else
+            type = PopupItem::TypeOption;
+        m_items.append(new PopupItem(m_popupClient->itemText(i), type));
+        m_items[i]->enabled = isSelectableItem(i);
+        PopupMenuStyle style = m_popupClient->itemStyle(i);
+        m_items[i]->textDirection = style.textDirection();
+        m_items[i]->hasTextDirectionOverride = style.hasTextDirectionOverride();
+    }
+
+    m_selectedIndex = m_popupClient->selectedIndex();
+    setOriginalIndex(m_selectedIndex);
+
+    layout();
+}
+
+void PopupListBox::setMaxWidthAndLayout(int maxWidth)
+{
+    m_maxWindowWidth = maxWidth;
+    layout();
+}
+
+void PopupListBox::layout()
+{
+    bool isRightAligned = m_popupClient->menuStyle().textDirection() == RTL;
+
+    // Size our child items.
+    int baseWidth = 0;
+    int paddingWidth = 0;
+    int lineEndPaddingWidth = 0;
+    int y = 0;
+    for (int i = 0; i < numItems(); ++i) {
+        // Place the item vertically.
+        m_items[i]->yOffset = y;
+        if (m_popupClient->itemStyle(i).isDisplayNone())
+            continue;
+        y += getRowHeight(i);
+
+        // Ensure the popup is wide enough to fit this item.
+        Font itemFont = getRowFont(i);
+        String text = m_popupClient->itemText(i);
+        String label = m_popupClient->itemLabel(i);
+        String icon = m_popupClient->itemIcon(i);
+        RefPtr<Image> iconImage(Image::loadPlatformResource(icon.utf8().data()));
+        int width = 0;
+        if (!text.isEmpty())
+            width = itemFont.width(TextRun(text));
+        if (!label.isEmpty()) {
+            if (width > 0)
+                width += kTextToLabelPadding;
+            width += itemFont.width(TextRun(label));
+        }
+        if (iconImage && !iconImage->isNull()) {
+            if (width > 0)
+                width += kLabelToIconPadding;
+            width += iconImage->rect().width();
+        }
+
+        baseWidth = max(baseWidth, width);
+        // FIXME: http://b/1210481 We should get the padding of individual option elements.
+        paddingWidth = max(paddingWidth,
+            m_popupClient->clientPaddingLeft() + m_popupClient->clientPaddingRight());
+        lineEndPaddingWidth = max(lineEndPaddingWidth,
+            isRightAligned ? m_popupClient->clientPaddingLeft() : m_popupClient->clientPaddingRight());
+    }
+
+    // Calculate scroll bar width.
+    int windowHeight = 0;
+    m_visibleRows = min(numItems(), kMaxVisibleRows);
+
+    for (int i = 0; i < m_visibleRows; ++i) {
+        int rowHeight = getRowHeight(i);
+
+        // Only clip the window height for non-Mac platforms.
+        if (windowHeight + rowHeight > m_maxHeight) {
+            m_visibleRows = i;
+            break;
+        }
+
+        windowHeight += rowHeight;
+    }
+
+    // Set our widget and scrollable contents sizes.
+    int scrollbarWidth = 0;
+    if (m_visibleRows < numItems()) {
+        scrollbarWidth = ScrollbarTheme::nativeTheme()->scrollbarThickness();
+
+        // Use kMinEndOfLinePadding when there is a scrollbar so that we use
+        // as much as (lineEndPaddingWidth - kMinEndOfLinePadding) padding
+        // space for scrollbar and allow user to use CSS padding to make the
+        // popup listbox align with the select element.
+        paddingWidth = paddingWidth - lineEndPaddingWidth + kMinEndOfLinePadding;
+    }
+
+    int windowWidth;
+    int contentWidth;
+    if (m_settings.restrictWidthOfListBox) {
+        windowWidth = m_baseWidth;
+        contentWidth = m_baseWidth - scrollbarWidth;
+    } else {
+        windowWidth = baseWidth + scrollbarWidth + paddingWidth;
+        if (windowWidth > m_maxWindowWidth) {
+            // windowWidth exceeds m_maxWindowWidth, so we have to clip.
+            windowWidth = m_maxWindowWidth;
+            baseWidth = windowWidth - scrollbarWidth - paddingWidth;
+            m_baseWidth = baseWidth;
+        }
+        contentWidth = windowWidth - scrollbarWidth;
+
+        if (windowWidth < m_baseWidth) {
+            windowWidth = m_baseWidth;
+            contentWidth = m_baseWidth - scrollbarWidth;
+        } else
+            m_baseWidth = baseWidth;
+    }
+
+    resize(windowWidth, windowHeight);
+    setContentsSize(IntSize(contentWidth, getRowBounds(numItems() - 1).maxY()));
+
+    if (hostWindow())
+        scrollToRevealSelection();
+
+    invalidate();
+}
+
+void PopupListBox::clear()
+{
+    for (Vector<PopupItem*>::iterator it = m_items.begin(); it != m_items.end(); ++it)
+        delete *it;
+    m_items.clear();
+}
+
+bool PopupListBox::isPointInBounds(const IntPoint& point)
+{
+    return numItems() && IntRect(0, 0, width(), height()).contains(point);
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/chromium/PopupListBox.h b/Source/WebCore/platform/chromium/PopupListBox.h
new file mode 100644 (file)
index 0000000..4cec3a4
--- /dev/null
@@ -0,0 +1,300 @@
+/*
+ * Copyright (c) 2011, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef PopupListBox_h
+#define PopupListBox_h
+
+#include "Font.h"
+#include "FontSelector.h"
+#include "FramelessScrollView.h"
+#include "IntRect.h"
+#include "Node.h"
+
+namespace WebCore {
+
+typedef unsigned long long TimeStamp;
+
+static const int kLabelToIconPadding = 5;
+static const int kLinePaddingHeight = 3; // Padding height put at the top and bottom of each line.
+static const int kMaxHeight = 500;
+static const int kMaxVisibleRows = 20;
+static const int kMinEndOfLinePadding = 2;
+static const int kTextToLabelPadding = 10;
+static const TimeStamp kTypeAheadTimeoutMs = 1000;
+
+class GraphicsContext;
+class PlatformKeyboardEvent;
+class PlatformMouseEvent;
+#if ENABLE(GESTURE_EVENTS)
+class PlatformGestureEvent;
+#endif
+#if ENABLE(TOUCH_EVENTS)
+class PlatformTouchEvent;
+#endif
+class PlatformWheelEvent;
+class PopupMenuClient;
+
+struct PopupContainerSettings {
+    // Whether the PopupMenuClient should be told to change its text when a
+    // new item is selected by using the arrow keys.
+    bool setTextOnIndexChange;
+
+    // Whether the selection should be accepted when the popup menu is
+    // closed (through ESC being pressed or the focus going away).
+    // Note that when TAB is pressed, the selection is always accepted
+    // regardless of this setting.
+    bool acceptOnAbandon;
+
+    // Whether we should move the selection to the first/last item when
+    // the user presses down/up arrow keys and the last/first item is
+    // selected.
+    bool loopSelectionNavigation;
+
+    // Whether we should restrict the width of the PopupListBox or not.
+    // Autocomplete popups are restricted, combo-boxes (select tags) aren't.
+    bool restrictWidthOfListBox;
+};
+
+// A container for the data for each menu item (e.g. represented by <option>
+// or <optgroup> in a <select> widget) and is used by PopupListBox.
+struct PopupItem {
+    enum Type {
+        TypeOption,
+        TypeGroup,
+        TypeSeparator
+    };
+
+    PopupItem(const String& label, Type type)
+        : label(label)
+        , type(type)
+        , yOffset(0)
+    {
+    }
+    String label;
+    Type type;
+    int yOffset; // y offset of this item, relative to the top of the popup.
+    TextDirection textDirection;
+    bool hasTextDirectionOverride;
+    bool enabled;
+};
+
+// This class uses WebCore code to paint and handle events for a drop-down list
+// box ("combobox" on Windows).
+class PopupListBox : public FramelessScrollView {
+public:
+    static PassRefPtr<PopupListBox> create(PopupMenuClient* client, const PopupContainerSettings& settings)
+    {
+        return adoptRef(new PopupListBox(client, settings));
+    }
+
+    // FramelessScrollView
+    virtual void paint(GraphicsContext*, const IntRect&);
+    virtual bool handleMouseDownEvent(const PlatformMouseEvent&);
+    virtual bool handleMouseMoveEvent(const PlatformMouseEvent&);
+    virtual bool handleMouseReleaseEvent(const PlatformMouseEvent&);
+    virtual bool handleWheelEvent(const PlatformWheelEvent&);
+    virtual bool handleKeyEvent(const PlatformKeyboardEvent&);
+#if ENABLE(TOUCH_EVENTS)
+    virtual bool handleTouchEvent(const PlatformTouchEvent&);
+#endif
+#if ENABLE(GESTURE_RECOGNIZER)
+    virtual bool handleGestureEvent(const PlatformGestureEvent&);
+#endif
+
+    // ScrollView
+    virtual HostWindow* hostWindow() const;
+
+    // PopupListBox methods
+
+    // Hides the popup.
+    void hidePopup();
+
+    // Updates our internal list to match the client.
+    void updateFromElement();
+
+    // Frees any allocated resources used in a particular popup session.
+    void clear();
+
+    // Sets the index of the option that is displayed in the <select> widget in the page
+    void setOriginalIndex(int);
+
+    // Gets the index of the item that the user is currently moused over or has selected with
+    // the keyboard. This is not the same as the original index, since the user has not yet
+    // accepted this input.
+    int selectedIndex() const { return m_selectedIndex; }
+
+    // Moves selection down/up the given number of items, scrolling if necessary.
+    // Positive is down. The resulting index will be clamped to the range
+    // [0, numItems), and non-option items will be skipped.
+    void adjustSelectedIndex(int delta);
+
+    // Returns the number of items in the list.
+    int numItems() const { return static_cast<int>(m_items.size()); }
+
+    void setBaseWidth(int width) { m_baseWidth = std::min(m_maxWindowWidth, width); }
+
+    // Computes the size of widget and children.
+    void layout();
+
+    // Returns whether the popup wants to process events for the passed key.
+    bool isInterestedInEventForKey(int keyCode);
+
+    // Gets the height of a row.
+    int getRowHeight(int index);
+
+    void setMaxHeight(int maxHeight) { m_maxHeight = maxHeight; }
+
+    void setMaxWidth(int maxWidth) { m_maxWindowWidth = maxWidth; }
+
+    void setMaxWidthAndLayout(int);
+
+    void disconnectClient() { m_popupClient = 0; }
+
+    const Vector<PopupItem*>& items() const { return m_items; }
+
+private:
+    friend class PopupContainer;
+    friend class RefCounted<PopupListBox>;
+
+    PopupListBox(PopupMenuClient*, const PopupContainerSettings&);
+
+    ~PopupListBox()
+    {
+        clear();
+    }
+
+    // Closes the popup
+    void abandon();
+
+    // Returns true if the selection can be changed to index.
+    // Disabled items, or labels cannot be selected.
+    bool isSelectableItem(int index);
+
+    // Select an index in the list, scrolling if necessary.
+    void selectIndex(int index);
+
+    // Accepts the selected index as the value to be displayed in the <select> widget on
+    // the web page, and closes the popup. Returns true if index is accepted.
+    bool acceptIndex(int index);
+
+    // Clears the selection (so no row appears selected).
+    void clearSelection();
+
+    // Scrolls to reveal the given index.
+    void scrollToRevealRow(int index);
+    void scrollToRevealSelection() { scrollToRevealRow(m_selectedIndex); }
+
+    // Invalidates the row at the given index.
+    void invalidateRow(int index);
+
+    // Get the bounds of a row.
+    IntRect getRowBounds(int index);
+
+    // Converts a point to an index of the row the point is over
+    int pointToRowIndex(const IntPoint&);
+
+    // Paint an individual row
+    void paintRow(GraphicsContext*, const IntRect&, int rowIndex);
+
+    // Test if the given point is within the bounds of the popup window.
+    bool isPointInBounds(const IntPoint&);
+
+    // Called when the user presses a text key. Does a prefix-search of the items.
+    void typeAheadFind(const PlatformKeyboardEvent&);
+
+    // Returns the font to use for the given row
+    Font getRowFont(int index);
+
+    // Moves the selection down/up one item, taking care of looping back to the
+    // first/last element if m_loopSelectionNavigation is true.
+    void selectPreviousRow();
+    void selectNextRow();
+
+    // The settings that specify the behavior for this Popup window.
+    PopupContainerSettings m_settings;
+
+    // This is the index of the item marked as "selected" - i.e. displayed in the widget on the
+    // page.
+    int m_originalIndex;
+
+    // This is the index of the item that the user is hovered over or has selected using the
+    // keyboard in the list. They have not confirmed this selection by clicking or pressing
+    // enter yet however.
+    int m_selectedIndex;
+
+    // If >= 0, this is the index we should accept if the popup is "abandoned".
+    // This is used for keyboard navigation, where we want the
+    // selection to change immediately, and is only used if the settings
+    // acceptOnAbandon field is true.
+    int m_acceptedIndexOnAbandon;
+
+    // This is the number of rows visible in the popup. The maximum number visible at a time is
+    // defined as being kMaxVisibleRows. For a scrolled popup, this can be thought of as the
+    // page size in data units.
+    int m_visibleRows;
+
+    // Our suggested width, not including scrollbar.
+    int m_baseWidth;
+
+    // The maximum height we can be without being off-screen.
+    int m_maxHeight;
+
+    // A list of the options contained within the <select>
+    Vector<PopupItem*> m_items;
+
+    // The <select> PopupMenuClient that opened us.
+    PopupMenuClient* m_popupClient;
+
+    // The scrollbar which has mouse capture. Mouse events go straight to this
+    // if not null.
+    RefPtr<Scrollbar> m_capturingScrollbar;
+
+    // The last scrollbar that the mouse was over. Used for mouseover highlights.
+    RefPtr<Scrollbar> m_lastScrollbarUnderMouse;
+
+    // The string the user has typed so far into the popup. Used for typeAheadFind.
+    String m_typedString;
+
+    // The char the user has hit repeatedly. Used for typeAheadFind.
+    UChar m_repeatingChar;
+
+    // The last time the user hit a key. Used for typeAheadFind.
+    TimeStamp m_lastCharTime;
+
+    // If width exeeds screen width, we have to clip it.
+    int m_maxWindowWidth;
+
+    // To forward last mouse release event.
+    RefPtr<Node> m_focusedNode;
+
+};
+
+} // namespace WebCore
+
+#endif
index 438a29a..3b2f2ae 100644 (file)
 
 #include "config.h"
 #include "PopupMenuChromium.h"
-
-#include "Chrome.h"
-#include "ChromeClientChromium.h"
-#include "Font.h"
-#include "FontSelector.h"
-#include "FrameView.h"
-#include "Frame.h"
-#include "FramelessScrollView.h"
-#include "FramelessScrollViewClient.h"
-#include "GraphicsContext.h"
-#include "IntRect.h"
-#include "KeyboardCodes.h"
-#include "Page.h"
-#include "PlatformKeyboardEvent.h"
-#include "PlatformMouseEvent.h"
-#include "PlatformScreen.h"
-#include "PlatformWheelEvent.h"
-#include "PopupMenuClient.h"
-#include "RenderTheme.h"
-#include "ScrollbarTheme.h"
-#include "StringTruncator.h"
-#include "SystemTime.h"
-#include "TextRun.h"
-#include "UserGestureIndicator.h"
-#include <wtf/CurrentTime.h>
-#include <wtf/unicode/CharacterNames.h>
-
-#if ENABLE(GESTURE_EVENTS)
-#include "PlatformGestureEvent.h"
-#endif
-
-#if ENABLE(TOUCH_EVENTS)
-#include "PlatformTouchEvent.h"
-#endif
-
-using namespace std;
-using namespace WTF;
-using namespace Unicode;
-
-using std::min;
-using std::max;
+#include "PopupContainer.h"
 
 namespace WebCore {
 
 int PopupMenuChromium::s_minimumRowHeight = 0;
 
-typedef unsigned long long TimeStamp;
-
-static const int kMaxVisibleRows = 20;
-static const int kMaxHeight = 500;
-static const int kBorderSize = 1;
-static const int kTextToLabelPadding = 10;
-static const int kLabelToIconPadding = 5;
-static const int kMinEndOfLinePadding = 2;
-static const TimeStamp kTypeAheadTimeoutMs = 1000;
-static const int kLinePaddingHeight = 3; // Padding height put at the top and bottom of each line.
-
 // The settings used for the drop down menu.
 // This is the delegate used if none is provided.
 static const PopupContainerSettings dropDownSettings = {
@@ -97,1449 +46,6 @@ static const PopupContainerSettings dropDownSettings = {
     false // restrictWidthOfListBox
 };
 
-// This class uses WebCore code to paint and handle events for a drop-down list
-// box ("combobox" on Windows).
-class PopupListBox : public FramelessScrollView {
-public:
-    static PassRefPtr<PopupListBox> create(PopupMenuClient* client, const PopupContainerSettings& settings)
-    {
-        return adoptRef(new PopupListBox(client, settings));
-    }
-
-    // FramelessScrollView
-    virtual void paint(GraphicsContext*, const IntRect&);
-    virtual bool handleMouseDownEvent(const PlatformMouseEvent&);
-    virtual bool handleMouseMoveEvent(const PlatformMouseEvent&);
-    virtual bool handleMouseReleaseEvent(const PlatformMouseEvent&);
-    virtual bool handleWheelEvent(const PlatformWheelEvent&);
-    virtual bool handleKeyEvent(const PlatformKeyboardEvent&);
-#if ENABLE(TOUCH_EVENTS)
-    virtual bool handleTouchEvent(const PlatformTouchEvent&);
-#endif
-#if ENABLE(GESTURE_RECOGNIZER)
-    virtual bool handleGestureEvent(const PlatformGestureEvent&);
-#endif
-
-    // ScrollView
-    virtual HostWindow* hostWindow() const;
-
-    // PopupListBox methods
-
-    // Hides the popup.
-    void hidePopup();
-
-    // Updates our internal list to match the client.
-    void updateFromElement();
-
-    // Frees any allocated resources used in a particular popup session.
-    void clear();
-
-    // Sets the index of the option that is displayed in the <select> widget in the page
-    void setOriginalIndex(int index);
-
-    // Gets the index of the item that the user is currently moused over or has selected with
-    // the keyboard. This is not the same as the original index, since the user has not yet
-    // accepted this input.
-    int selectedIndex() const { return m_selectedIndex; }
-
-    // Moves selection down/up the given number of items, scrolling if necessary.
-    // Positive is down.  The resulting index will be clamped to the range
-    // [0, numItems), and non-option items will be skipped.
-    void adjustSelectedIndex(int delta);
-
-    // Returns the number of items in the list.
-    int numItems() const { return static_cast<int>(m_items.size()); }
-
-    void setBaseWidth(int width) { m_baseWidth = min(m_maxWindowWidth, width); }
-
-    // Computes the size of widget and children.
-    void layout();
-
-    // Returns whether the popup wants to process events for the passed key.
-    bool isInterestedInEventForKey(int keyCode);
-
-    // Gets the height of a row.
-    int getRowHeight(int index);
-
-    void setMaxHeight(int maxHeight) { m_maxHeight = maxHeight; }
-
-    void setMaxWidth(int maxWidth) { m_maxWindowWidth = maxWidth; }
-
-    void setMaxWidthAndLayout(int);
-
-    void disconnectClient() { m_popupClient = 0; }
-
-    const Vector<PopupItem*>& items() const { return m_items; }
-
-private:
-    friend class PopupContainer;
-    friend class RefCounted<PopupListBox>;
-
-    PopupListBox(PopupMenuClient* client, const PopupContainerSettings& settings)
-        : m_settings(settings)
-        , m_originalIndex(0)
-        , m_selectedIndex(0)
-        , m_acceptedIndexOnAbandon(-1)
-        , m_visibleRows(0)
-        , m_baseWidth(0)
-        , m_maxHeight(kMaxHeight)
-        , m_popupClient(client)
-        , m_repeatingChar(0)
-        , m_lastCharTime(0)
-        , m_maxWindowWidth(numeric_limits<int>::max())
-    {
-        setScrollbarModes(ScrollbarAlwaysOff, ScrollbarAlwaysOff);
-    }
-
-    ~PopupListBox()
-    {
-        clear();
-    }
-
-    // Closes the popup
-    void abandon();
-
-    // Returns true if the selection can be changed to index.
-    // Disabled items, or labels cannot be selected.
-    bool isSelectableItem(int index);
-
-    // Select an index in the list, scrolling if necessary.
-    void selectIndex(int index);
-
-    // Accepts the selected index as the value to be displayed in the <select> widget on
-    // the web page, and closes the popup. Returns true if index is accepted.
-    bool acceptIndex(int index);
-
-    // Clears the selection (so no row appears selected).
-    void clearSelection();
-
-    // Scrolls to reveal the given index.
-    void scrollToRevealRow(int index);
-    void scrollToRevealSelection() { scrollToRevealRow(m_selectedIndex); }
-
-    // Invalidates the row at the given index.
-    void invalidateRow(int index);
-
-    // Get the bounds of a row.
-    IntRect getRowBounds(int index);
-
-    // Converts a point to an index of the row the point is over
-    int pointToRowIndex(const IntPoint&);
-
-    // Paint an individual row
-    void paintRow(GraphicsContext*, const IntRect&, int rowIndex);
-
-    // Test if the given point is within the bounds of the popup window.
-    bool isPointInBounds(const IntPoint&);
-
-    // Called when the user presses a text key.  Does a prefix-search of the items.
-    void typeAheadFind(const PlatformKeyboardEvent&);
-
-    // Returns the font to use for the given row
-    Font getRowFont(int index);
-
-    // Moves the selection down/up one item, taking care of looping back to the
-    // first/last element if m_loopSelectionNavigation is true.
-    void selectPreviousRow();
-    void selectNextRow();
-
-    // The settings that specify the behavior for this Popup window.
-    PopupContainerSettings m_settings;
-
-    // This is the index of the item marked as "selected" - i.e. displayed in the widget on the
-    // page.
-    int m_originalIndex;
-
-    // This is the index of the item that the user is hovered over or has selected using the
-    // keyboard in the list. They have not confirmed this selection by clicking or pressing
-    // enter yet however.
-    int m_selectedIndex;
-
-    // If >= 0, this is the index we should accept if the popup is "abandoned".
-    // This is used for keyboard navigation, where we want the
-    // selection to change immediately, and is only used if the settings
-    // acceptOnAbandon field is true.
-    int m_acceptedIndexOnAbandon;
-
-    // This is the number of rows visible in the popup. The maximum number visible at a time is
-    // defined as being kMaxVisibleRows. For a scrolled popup, this can be thought of as the
-    // page size in data units.
-    int m_visibleRows;
-
-    // Our suggested width, not including scrollbar.
-    int m_baseWidth;
-
-    // The maximum height we can be without being off-screen.
-    int m_maxHeight;
-
-    // A list of the options contained within the <select>
-    Vector<PopupItem*> m_items;
-
-    // The <select> PopupMenuClient that opened us.
-    PopupMenuClient* m_popupClient;
-
-    // The scrollbar which has mouse capture.  Mouse events go straight to this
-    // if non-NULL.
-    RefPtr<Scrollbar> m_capturingScrollbar;
-
-    // The last scrollbar that the mouse was over.  Used for mouseover highlights.
-    RefPtr<Scrollbar> m_lastScrollbarUnderMouse;
-
-    // The string the user has typed so far into the popup. Used for typeAheadFind.
-    String m_typedString;
-
-    // The char the user has hit repeatedly.  Used for typeAheadFind.
-    UChar m_repeatingChar;
-
-    // The last time the user hit a key.  Used for typeAheadFind.
-    TimeStamp m_lastCharTime;
-
-    // If width exeeds screen width, we have to clip it.
-    int m_maxWindowWidth;
-
-    // To forward last mouse release event.
-    RefPtr<Node> m_focusedNode;
-};
-
-static PlatformMouseEvent constructRelativeMouseEvent(const PlatformMouseEvent& e,
-                                                      FramelessScrollView* parent,
-                                                      FramelessScrollView* child)
-{
-    IntPoint pos = parent->convertSelfToChild(child, e.pos());
-
-    // FIXME: This is a horrible hack since PlatformMouseEvent has no setters for x/y.
-    PlatformMouseEvent relativeEvent = e;
-    IntPoint& relativePos = const_cast<IntPoint&>(relativeEvent.pos());
-    relativePos.setX(pos.x());
-    relativePos.setY(pos.y());
-    return relativeEvent;
-}
-
-static PlatformWheelEvent constructRelativeWheelEvent(const PlatformWheelEvent& e,
-                                                      FramelessScrollView* parent,
-                                                      FramelessScrollView* child)
-{
-    IntPoint pos = parent->convertSelfToChild(child, e.pos());
-
-    // FIXME: This is a horrible hack since PlatformWheelEvent has no setters for x/y.
-    PlatformWheelEvent relativeEvent = e;
-    IntPoint& relativePos = const_cast<IntPoint&>(relativeEvent.pos());
-    relativePos.setX(pos.x());
-    relativePos.setY(pos.y());
-    return relativeEvent;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// PopupContainer implementation
-
-// static
-PassRefPtr<PopupContainer> PopupContainer::create(PopupMenuClient* client,
-                                                  PopupType popupType,
-                                                  const PopupContainerSettings& settings)
-{
-    return adoptRef(new PopupContainer(client, popupType, settings));
-}
-
-PopupContainer::PopupContainer(PopupMenuClient* client,
-                               PopupType popupType,
-                               const PopupContainerSettings& settings)
-    : m_listBox(PopupListBox::create(client, settings))
-    , m_settings(settings)
-    , m_popupType(popupType)
-    , m_popupOpen(false)
-{
-    setScrollbarModes(ScrollbarAlwaysOff, ScrollbarAlwaysOff);
-}
-
-PopupContainer::~PopupContainer()
-{
-    if (m_listBox && m_listBox->parent())
-        removeChild(m_listBox.get());
-}
-
-IntRect PopupContainer::layoutAndCalculateWidgetRect(int targetControlHeight, const IntPoint& popupInitialCoordinate)
-{
-    // Reset the max width and height to their default values, they will be recomputed below
-    // if necessary.
-    m_listBox->setMaxHeight(kMaxHeight);
-    m_listBox->setMaxWidth(numeric_limits<int>::max());
-
-    // Lay everything out to figure out our preferred size, then tell the view's
-    // WidgetClient about it.  It should assign us a client.
-    int rtlOffset = layoutAndGetRTLOffset();
-    bool isRTL = this->isRTL();
-    int rightOffset = isRTL ? rtlOffset : 0;
-
-    // Assume m_listBox size is already calculated.
-    IntSize targetSize(m_listBox->width() + kBorderSize * 2,
-                       m_listBox->height() + kBorderSize * 2);
-
-    IntRect widgetRect;
-    ChromeClientChromium* chromeClient = chromeClientChromium();
-    if (chromeClient) {
-        // If the popup would extend past the bottom of the screen, open upwards
-        // instead.
-        FloatRect screen = screenAvailableRect(m_frameView.get());
-        // Use popupInitialCoordinate.x() + rightOffset because RTL position
-        // needs to be considered.
-        widgetRect = chromeClient->windowToScreen(IntRect(popupInitialCoordinate.x() + rightOffset, popupInitialCoordinate.y(), targetSize.width(), targetSize.height()));
-
-        // If we have multiple screens and the browser rect is in one screen, we have
-        // to clip the window width to the screen width.
-        // When clipping, we also need to set a maximum width for the list box.
-        FloatRect windowRect = chromeClient->windowRect();
-        if (windowRect.x() >= screen.x() && windowRect.maxX() <= screen.maxX() && (widgetRect.x() < screen.x() || widgetRect.maxX() > screen.maxX())) {
-            // First, inverse the popup alignment if it does not fit the screen - this might fix things (or make them better).
-            IntRect inverseWidgetRect = chromeClient->windowToScreen(IntRect(popupInitialCoordinate.x() + (isRTL ? 0 : rtlOffset), popupInitialCoordinate.y(), targetSize.width(), targetSize.height()));
-            IntRect enclosingScreen = enclosingIntRect(screen);
-            unsigned originalCutoff = max(enclosingScreen.x() - widgetRect.x(), 0) + max(widgetRect.maxX() - enclosingScreen.maxX(), 0);
-            unsigned inverseCutoff = max(enclosingScreen.x() - inverseWidgetRect.x(), 0) + max(inverseWidgetRect.maxX() - enclosingScreen.maxX(), 0);
-
-            // Accept the inverse popup alignment if the trimmed content gets shorter than that in the original alignment case.
-            if (inverseCutoff < originalCutoff)
-                widgetRect = inverseWidgetRect;
-
-            if (widgetRect.x() < screen.x()) {
-                unsigned widgetRight = widgetRect.maxX();
-                widgetRect.setWidth(widgetRect.maxX() - screen.x());
-                widgetRect.setX(widgetRight - widgetRect.width());
-                listBox()->setMaxWidthAndLayout(max(widgetRect.width() - kBorderSize * 2, 0));
-            } else if (widgetRect.maxX() > screen.maxX()) {
-                widgetRect.setWidth(screen.maxX() - widgetRect.x());
-                listBox()->setMaxWidthAndLayout(max(widgetRect.width() - kBorderSize * 2, 0));
-            }
-        }
-
-        // Calculate Y axis size.
-        if (widgetRect.maxY() > static_cast<int>(screen.maxY())) {
-            if (widgetRect.y() - widgetRect.height() - targetControlHeight > 0) {
-                // There is enough room to open upwards.
-                widgetRect.move(0, -(widgetRect.height() + targetControlHeight));
-            } else {
-                // Figure whether upwards or downwards has more room and set the
-                // maximum number of items.
-                int spaceAbove = widgetRect.y() - targetControlHeight;
-                int spaceBelow = screen.maxY() - widgetRect.y();
-                if (spaceAbove > spaceBelow)
-                    m_listBox->setMaxHeight(spaceAbove);
-                else
-                    m_listBox->setMaxHeight(spaceBelow);
-                layoutAndGetRTLOffset();
-                // Our height has changed, so recompute only Y axis of widgetRect.
-                // We don't have to recompute X axis, so we only replace Y axis
-                // in widgetRect.
-                IntRect frameInScreen = chromeClient->windowToScreen(frameRect());
-                widgetRect.setY(frameInScreen.y());
-                widgetRect.setHeight(frameInScreen.height());
-                // And move upwards if necessary.
-                if (spaceAbove > spaceBelow)
-                    widgetRect.move(0, -(widgetRect.height() + targetControlHeight));
-            }
-        }
-    }
-    return widgetRect;
-}
-
-void PopupContainer::showPopup(FrameView* view)
-{
-    m_frameView = view;
-    listBox()->m_focusedNode = m_frameView->frame()->document()->focusedNode();
-
-    ChromeClientChromium* chromeClient = chromeClientChromium();
-    if (chromeClient) {
-        IntRect popupRect = frameRect();
-        chromeClient->popupOpened(this, layoutAndCalculateWidgetRect(popupRect.height(), popupRect.location()), false);
-        m_popupOpen = true;
-    }
-
-    if (!m_listBox->parent())
-        addChild(m_listBox.get());
-
-    // Enable scrollbars after the listbox is inserted into the hierarchy,
-    // so it has a proper WidgetClient.
-    m_listBox->setVerticalScrollbarMode(ScrollbarAuto);
-
-    m_listBox->scrollToRevealSelection();
-
-    invalidate();
-}
-
-void PopupContainer::hidePopup()
-{
-    listBox()->hidePopup();
-}
-
-void PopupContainer::notifyPopupHidden()
-{
-    if (!m_popupOpen)
-        return;
-    m_popupOpen = false;
-    chromeClientChromium()->popupClosed(this);
-}
-
-int PopupContainer::layoutAndGetRTLOffset()
-{
-    m_listBox->layout();
-
-    // Place the listbox within our border.
-    m_listBox->move(kBorderSize, kBorderSize);
-
-    // Size ourselves to contain listbox + border.
-    int listBoxWidth = m_listBox->width() + kBorderSize * 2;
-    resize(listBoxWidth, m_listBox->height() + kBorderSize * 2);
-    invalidate();
-
-    // Compute the starting x-axis for a normal RTL or right-aligned LTR dropdown. For those,
-    // the right edge of dropdown box should be aligned with the right edge of <select>/<input> element box,
-    // and the dropdown box should be expanded to the left if more space is needed.
-    // m_originalFrameRect.width() is the width of the target <select>/<input> element.
-    return m_originalFrameRect.width() - listBoxWidth;
-}
-
-bool PopupContainer::handleMouseDownEvent(const PlatformMouseEvent& event)
-{
-    UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
-    return m_listBox->handleMouseDownEvent(
-        constructRelativeMouseEvent(event, this, m_listBox.get()));
-}
-
-bool PopupContainer::handleMouseMoveEvent(const PlatformMouseEvent& event)
-{
-    UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
-    return m_listBox->handleMouseMoveEvent(
-        constructRelativeMouseEvent(event, this, m_listBox.get()));
-}
-
-bool PopupContainer::handleMouseReleaseEvent(const PlatformMouseEvent& event)
-{
-    RefPtr<PopupContainer> protect(this);
-    UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
-    return m_listBox->handleMouseReleaseEvent(
-        constructRelativeMouseEvent(event, this, m_listBox.get()));
-}
-
-bool PopupContainer::handleWheelEvent(const PlatformWheelEvent& event)
-{
-    UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
-    return m_listBox->handleWheelEvent(
-        constructRelativeWheelEvent(event, this, m_listBox.get()));
-}
-
-#if ENABLE(TOUCH_EVENTS)
-bool PopupContainer::handleTouchEvent(const PlatformTouchEvent&)
-{
-    return false;
-}
-#endif
-
-#if ENABLE(GESTURE_RECOGNIZER)
-// FIXME: Refactor this code to share functionality with EventHandler::handleGestureEvent.
-bool PopupContainer::handleGestureEvent(const PlatformGestureEvent& gestureEvent)
-{
-    switch (gestureEvent.type()) {
-    case PlatformGestureEvent::TapType: {
-        PlatformMouseEvent fakeMouseMove(gestureEvent.position(), gestureEvent.globalPosition(), NoButton, MouseEventMoved, /* clickCount */ 1, gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey(), gestureEvent.timestamp());
-        PlatformMouseEvent fakeMouseDown(gestureEvent.position(), gestureEvent.globalPosition(), LeftButton, MouseEventPressed, /* clickCount */ 1, gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey(), gestureEvent.timestamp());
-        PlatformMouseEvent fakeMouseUp(gestureEvent.position(), gestureEvent.globalPosition(), LeftButton, MouseEventReleased, /* clickCount */ 1, gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey(), gestureEvent.timestamp());
-        // handleMouseMoveEvent(fakeMouseMove);
-        handleMouseDownEvent(fakeMouseDown);
-        handleMouseReleaseEvent(fakeMouseUp);
-        return true;
-    }
-    case PlatformGestureEvent::ScrollUpdateType: {
-        PlatformWheelEvent syntheticWheelEvent(gestureEvent.position(), gestureEvent.globalPosition(), gestureEvent.deltaX(), gestureEvent.deltaY(), gestureEvent.deltaX() / 120.0f, gestureEvent.deltaY() / 120.0f, ScrollByPixelWheelEvent, /* isAccepted */ false, gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey());
-        handleWheelEvent(syntheticWheelEvent);
-        return true;
-    }
-    case PlatformGestureEvent::ScrollBeginType:
-    case PlatformGestureEvent::ScrollEndType:
-        break;
-    }
-    return false;
-}
-#endif
-
-bool PopupContainer::handleKeyEvent(const PlatformKeyboardEvent& event)
-{
-    UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
-    return m_listBox->handleKeyEvent(event);
-}
-
-void PopupContainer::hide()
-{
-    m_listBox->abandon();
-}
-
-void PopupContainer::paint(GraphicsContext* gc, const IntRect& rect)
-{
-    // adjust coords for scrolled frame
-    IntRect r = intersection(rect, frameRect());
-    int tx = x();
-    int ty = y();
-
-    r.move(-tx, -ty);
-
-    gc->translate(static_cast<float>(tx), static_cast<float>(ty));
-    m_listBox->paint(gc, r);
-    gc->translate(-static_cast<float>(tx), -static_cast<float>(ty));
-
-    paintBorder(gc, rect);
-}
-
-void PopupContainer::paintBorder(GraphicsContext* gc, const IntRect& rect)
-{
-    // FIXME: Where do we get the border color from?
-    Color borderColor(127, 157, 185);
-
-    gc->setStrokeStyle(NoStroke);
-    gc->setFillColor(borderColor, ColorSpaceDeviceRGB);
-
-    int tx = x();
-    int ty = y();
-
-    // top, left, bottom, right
-    gc->drawRect(IntRect(tx, ty, width(), kBorderSize));
-    gc->drawRect(IntRect(tx, ty, kBorderSize, height()));
-    gc->drawRect(IntRect(tx, ty + height() - kBorderSize, width(), kBorderSize));
-    gc->drawRect(IntRect(tx + width() - kBorderSize, ty, kBorderSize, height()));
-}
-
-bool PopupContainer::isInterestedInEventForKey(int keyCode)
-{
-    return m_listBox->isInterestedInEventForKey(keyCode);
-}
-
-ChromeClientChromium* PopupContainer::chromeClientChromium()
-{
-    return static_cast<ChromeClientChromium*>(m_frameView->frame()->page()->chrome()->client());
-}
-
-void PopupContainer::showInRect(const IntRect& r, FrameView* v, int index)
-{
-    // The rect is the size of the select box. It's usually larger than we need.
-    // subtract border size so that usually the container will be displayed
-    // exactly the same width as the select box.
-    listBox()->setBaseWidth(max(r.width() - kBorderSize * 2, 0));
-
-    listBox()->updateFromElement();
-
-    // We set the selected item in updateFromElement(), and disregard the
-    // index passed into this function (same as Webkit's PopupMenuWin.cpp)
-    // FIXME: make sure this is correct, and add an assertion.
-    // ASSERT(popupWindow(popup)->listBox()->selectedIndex() == index);
-
-    // Convert point to main window coords.
-    IntPoint location = v->contentsToWindow(r.location());
-
-    // Move it below the select widget.
-    location.move(0, r.height());
-
-    m_originalFrameRect = IntRect(location, r.size());
-    setFrameRect(m_originalFrameRect);
-    showPopup(v);
-}
-
-void PopupContainer::refresh(const IntRect& targetControlRect)
-{
-    IntPoint location = m_frameView->contentsToWindow(targetControlRect.location());
-    // Move it below the select widget.
-    location.move(0, targetControlRect.height());
-
-    listBox()->setBaseWidth(max(m_originalFrameRect.width() - kBorderSize * 2, 0));
-    setBoundsSize(m_originalFrameRect.size());
-
-    listBox()->updateFromElement();
-    // Store the original size to check if we need to request the location.
-    IntSize originalSize = size();
-    IntRect widgetRect = layoutAndCalculateWidgetRect(targetControlRect.height(), location);
-    if (originalSize != widgetRect.size()) {
-        ChromeClientChromium* chromeClient = chromeClientChromium();
-        if (chromeClient) {
-            IntPoint widgetLocation = chromeClient->screenToWindow(widgetRect.location());
-            widgetRect.setLocation(widgetLocation);
-            setFrameRect(widgetRect);
-        }
-    }
-
-    invalidate();
-}
-
-inline bool PopupContainer::isRTL() const
-{
-    return m_listBox->m_popupClient->menuStyle().textDirection() == RTL;
-}
-
-int PopupContainer::selectedIndex() const
-{
-    return m_listBox->selectedIndex();
-}
-
-int PopupContainer::menuItemHeight() const
-{
-    return m_listBox->getRowHeight(0);
-}
-
-int PopupContainer::menuItemFontSize() const
-{
-    return m_listBox->getRowFont(0).size();
-}
-
-PopupMenuStyle PopupContainer::menuStyle() const
-{
-    return m_listBox->m_popupClient->menuStyle();
-}
-
-const WTF::Vector<PopupItem*>& PopupContainer:: popupData() const
-{
-    return m_listBox->items();
-}
-
-String PopupContainer::getSelectedItemToolTip()
-{
-    // We cannot use m_popupClient->selectedIndex() to choose tooltip message,
-    // because the selectedIndex() might return final selected index, not hovering selection.
-    return listBox()->m_popupClient->itemToolTip(listBox()->m_selectedIndex);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// PopupListBox implementation
-
-bool PopupListBox::handleMouseDownEvent(const PlatformMouseEvent& event)
-{
-    Scrollbar* scrollbar = scrollbarAtPoint(event.pos());
-    if (scrollbar) {
-        m_capturingScrollbar = scrollbar;
-        m_capturingScrollbar->mouseDown(event);
-        return true;
-    }
-
-    if (!isPointInBounds(event.pos()))
-        abandon();
-
-    return true;
-}
-
-bool PopupListBox::handleMouseMoveEvent(const PlatformMouseEvent& event)
-{
-    if (m_capturingScrollbar) {
-        m_capturingScrollbar->mouseMoved(event);
-        return true;
-    }
-
-    Scrollbar* scrollbar = scrollbarAtPoint(event.pos());
-    if (m_lastScrollbarUnderMouse != scrollbar) {
-        // Send mouse exited to the old scrollbar.
-        if (m_lastScrollbarUnderMouse)
-            m_lastScrollbarUnderMouse->mouseExited();
-        m_lastScrollbarUnderMouse = scrollbar;
-    }
-
-    if (scrollbar) {
-        scrollbar->mouseMoved(event);
-        return true;
-    }
-
-    if (!isPointInBounds(event.pos()))
-        return false;
-
-    selectIndex(pointToRowIndex(event.pos()));
-    return true;
-}
-
-bool PopupListBox::handleMouseReleaseEvent(const PlatformMouseEvent& event)
-{
-    if (m_capturingScrollbar) {
-        m_capturingScrollbar->mouseUp();
-        m_capturingScrollbar = 0;
-        return true;
-    }
-
-    if (!isPointInBounds(event.pos()))
-        return true;
-
-    // Need to check before calling acceptIndex(), because m_popupClient might be removed in acceptIndex() calling because of event handler.
-    bool isSelectPopup = m_popupClient->menuStyle().menuType() == PopupMenuStyle::SelectPopup;
-    if (acceptIndex(pointToRowIndex(event.pos())) && m_focusedNode && isSelectPopup) {
-        m_focusedNode->dispatchMouseEvent(event, eventNames().mouseupEvent);
-        m_focusedNode->dispatchMouseEvent(event, eventNames().clickEvent);
-
-        // Clear m_focusedNode here, because we cannot clear in hidePopup() which is called before dispatchMouseEvent() is called.
-        m_focusedNode = 0;
-    }
-
-    return true;
-}
-
-bool PopupListBox::handleWheelEvent(const PlatformWheelEvent& event)
-{
-    if (!isPointInBounds(event.pos())) {
-        abandon();
-        return true;
-    }
-
-    // Pass it off to the scroll view.
-    // Sadly, WebCore devs don't understand the whole "const" thing.
-    wheelEvent(const_cast<PlatformWheelEvent&>(event));
-    return true;
-}
-
-// Should be kept in sync with handleKeyEvent().
-bool PopupListBox::isInterestedInEventForKey(int keyCode)
-{
-    switch (keyCode) {
-    case VKEY_ESCAPE:
-    case VKEY_RETURN:
-    case VKEY_UP:
-    case VKEY_DOWN:
-    case VKEY_PRIOR:
-    case VKEY_NEXT:
-    case VKEY_HOME:
-    case VKEY_END:
-    case VKEY_TAB:
-        return true;
-    default:
-        return false;
-    }
-}
-
-#if ENABLE(TOUCH_EVENTS)
-bool PopupListBox::handleTouchEvent(const PlatformTouchEvent&)
-{
-    return false;
-}
-#endif
-
-#if ENABLE(GESTURE_RECOGNIZER)
-bool PopupListBox::handleGestureEvent(const PlatformGestureEvent&)
-{
-    return false;
-}
-#endif
-
-static bool isCharacterTypeEvent(const PlatformKeyboardEvent& event)
-{
-    // Check whether the event is a character-typed event or not.
-    // We use RawKeyDown/Char/KeyUp event scheme on all platforms,
-    // so PlatformKeyboardEvent::Char (not RawKeyDown) type event
-    // is considered as character type event.
-    return event.type() == PlatformKeyboardEvent::Char;
-}
-
-bool PopupListBox::handleKeyEvent(const PlatformKeyboardEvent& event)
-{
-    if (event.type() == PlatformKeyboardEvent::KeyUp)
-        return true;
-
-    if (numItems() == 0 && event.windowsVirtualKeyCode() != VKEY_ESCAPE)
-        return true;
-
-    switch (event.windowsVirtualKeyCode()) {
-    case VKEY_ESCAPE:
-        abandon();  // may delete this
-        return true;
-    case VKEY_RETURN:
-        if (m_selectedIndex == -1)  {
-            hidePopup();
-            // Don't eat the enter if nothing is selected.
-            return false;
-        }
-        acceptIndex(m_selectedIndex);  // may delete this
-        return true;
-    case VKEY_UP:
-    case VKEY_DOWN:
-        // We have to forward only shift + up combination to focused node when autofill popup.
-        // Because all characters from the cursor to the start of the text area should selected when you press shift + up arrow.
-        // shift + down should be the similar way to shift + up.
-        if (event.modifiers() && m_popupClient->menuStyle().menuType() == PopupMenuStyle::AutofillPopup)
-            m_focusedNode->dispatchKeyEvent(event);
-        else if (event.windowsVirtualKeyCode() == VKEY_UP)
-            selectPreviousRow();
-        else
-            selectNextRow();
-        break;
-    case VKEY_PRIOR:
-        adjustSelectedIndex(-m_visibleRows);
-        break;
-    case VKEY_NEXT:
-        adjustSelectedIndex(m_visibleRows);
-        break;
-    case VKEY_HOME:
-        adjustSelectedIndex(-m_selectedIndex);
-        break;
-    case VKEY_END:
-        adjustSelectedIndex(m_items.size());
-        break;
-    default:
-        if (!event.ctrlKey() && !event.altKey() && !event.metaKey()
-            && isPrintableChar(event.windowsVirtualKeyCode())
-            && isCharacterTypeEvent(event))
-            typeAheadFind(event);
-        break;
-    }
-
-    if (m_originalIndex != m_selectedIndex) {
-        // Keyboard events should update the selection immediately (but we don't
-        // want to fire the onchange event until the popup is closed, to match
-        // IE).  We change the original index so we revert to that when the
-        // popup is closed.
-        if (m_settings.acceptOnAbandon)
-            m_acceptedIndexOnAbandon = m_selectedIndex;
-
-        setOriginalIndex(m_selectedIndex);
-        if (m_settings.setTextOnIndexChange)
-            m_popupClient->setTextFromItem(m_selectedIndex);
-    }
-    if (event.windowsVirtualKeyCode() == VKEY_TAB) {
-        // TAB is a special case as it should select the current item if any and
-        // advance focus.
-        if (m_selectedIndex >= 0) {
-            acceptIndex(m_selectedIndex); // May delete us.
-            // Return false so the TAB key event is propagated to the page.
-            return false;
-        }
-        // Call abandon() so we honor m_acceptedIndexOnAbandon if set.
-        abandon();
-        // Return false so the TAB key event is propagated to the page.
-        return false;
-    }
-
-    return true;
-}
-
-HostWindow* PopupListBox::hostWindow() const
-{
-    // Our parent is the root ScrollView, so it is the one that has a
-    // HostWindow.  FrameView::hostWindow() works similarly.
-    return parent() ? parent()->hostWindow() : 0;
-}
-
-// From HTMLSelectElement.cpp
-static String stripLeadingWhiteSpace(const String& string)
-{
-    int length = string.length();
-    int i;
-    for (i = 0; i < length; ++i)
-        if (string[i] != noBreakSpace
-            && (string[i] <= 0x7F ? !isspace(string[i]) : (direction(string[i]) != WhiteSpaceNeutral)))
-            break;
-
-    return string.substring(i, length - i);
-}
-
-// From HTMLSelectElement.cpp, with modifications
-void PopupListBox::typeAheadFind(const PlatformKeyboardEvent& event)
-{
-    TimeStamp now = static_cast<TimeStamp>(currentTime() * 1000.0f);
-    TimeStamp delta = now - m_lastCharTime;
-
-    // Reset the time when user types in a character. The time gap between
-    // last character and the current character is used to indicate whether
-    // user typed in a string or just a character as the search prefix.
-    m_lastCharTime = now;
-
-    UChar c = event.windowsVirtualKeyCode();
-
-    String prefix;
-    int searchStartOffset = 1;
-    if (delta > kTypeAheadTimeoutMs) {
-        m_typedString = prefix = String(&c, 1);
-        m_repeatingChar = c;
-    } else {
-        m_typedString.append(c);
-
-        if (c == m_repeatingChar)
-            // The user is likely trying to cycle through all the items starting with this character, so just search on the character
-            prefix = String(&c, 1);
-        else {
-            m_repeatingChar = 0;
-            prefix = m_typedString;
-            searchStartOffset = 0;
-        }
-    }
-
-    // Compute a case-folded copy of the prefix string before beginning the search for
-    // a matching element. This code uses foldCase to work around the fact that
-    // String::startWith does not fold non-ASCII characters. This code can be changed
-    // to use startWith once that is fixed.
-    String prefixWithCaseFolded(prefix.foldCase());
-    int itemCount = numItems();
-    int index = (max(0, m_selectedIndex) + searchStartOffset) % itemCount;
-    for (int i = 0; i < itemCount; i++, index = (index + 1) % itemCount) {
-        if (!isSelectableItem(index))
-            continue;
-
-        if (stripLeadingWhiteSpace(m_items[index]->label).foldCase().startsWith(prefixWithCaseFolded)) {
-            selectIndex(index);
-            return;
-        }
-    }
-}
-
-void PopupListBox::paint(GraphicsContext* gc, const IntRect& rect)
-{
-    // adjust coords for scrolled frame
-    IntRect r = intersection(rect, frameRect());
-    int tx = x() - scrollX();
-    int ty = y() - scrollY();
-
-    r.move(-tx, -ty);
-
-    // set clip rect to match revised damage rect
-    gc->save();
-    gc->translate(static_cast<float>(tx), static_cast<float>(ty));
-    gc->clip(r);
-
-    // FIXME: Can we optimize scrolling to not require repainting the entire
-    // window?  Should we?
-    for (int i = 0; i < numItems(); ++i)
-        paintRow(gc, r, i);
-
-    // Special case for an empty popup.
-    if (numItems() == 0)
-        gc->fillRect(r, Color::white, ColorSpaceDeviceRGB);
-
-    gc->restore();
-
-    ScrollView::paint(gc, rect);
-}
-
-static const int separatorPadding = 4;
-static const int separatorHeight = 1;
-
-void PopupListBox::paintRow(GraphicsContext* gc, const IntRect& rect, int rowIndex)
-{
-    // This code is based largely on RenderListBox::paint* methods.
-
-    IntRect rowRect = getRowBounds(rowIndex);
-    if (!rowRect.intersects(rect))
-        return;
-
-    PopupMenuStyle style = m_popupClient->itemStyle(rowIndex);
-
-    // Paint background
-    Color backColor, textColor, labelColor;
-    if (rowIndex == m_selectedIndex) {
-        backColor = RenderTheme::defaultTheme()->activeListBoxSelectionBackgroundColor();
-        textColor = RenderTheme::defaultTheme()->activeListBoxSelectionForegroundColor();
-        labelColor = textColor;
-    } else {
-        backColor = style.backgroundColor();
-        textColor = style.foregroundColor();
-        // FIXME: for now the label color is hard-coded. It should be added to
-        // the PopupMenuStyle.
-        labelColor = Color(115, 115, 115);
-    }
-
-    // If we have a transparent background, make sure it has a color to blend
-    // against.
-    if (backColor.hasAlpha())
-        gc->fillRect(rowRect, Color::white, ColorSpaceDeviceRGB);
-
-    gc->fillRect(rowRect, backColor, ColorSpaceDeviceRGB);
-
-    // It doesn't look good but Autofill requires special style for separator.
-    // Autofill doesn't have padding and #dcdcdc color.
-    if (m_popupClient->itemIsSeparator(rowIndex)) {
-        int padding = style.menuType() == PopupMenuStyle::AutofillPopup ? 0 : separatorPadding;
-        IntRect separatorRect(
-            rowRect.x() + padding,
-            rowRect.y() + (rowRect.height() - separatorHeight) / 2,
-            rowRect.width() - 2 * padding, separatorHeight);
-        gc->fillRect(separatorRect, style.menuType() == PopupMenuStyle::AutofillPopup ? Color(0xdc, 0xdc, 0xdc) : textColor, ColorSpaceDeviceRGB);
-        return;
-    }
-
-    if (!style.isVisible())
-        return;
-
-    gc->setFillColor(textColor, ColorSpaceDeviceRGB);
-
-    Font itemFont = getRowFont(rowIndex);
-    // FIXME: http://crbug.com/19872 We should get the padding of individual option
-    // elements.  This probably implies changes to PopupMenuClient.
-    bool rightAligned = m_popupClient->menuStyle().textDirection() == RTL;
-    int textX = 0;
-    int maxWidth = 0;
-    if (rightAligned)
-        maxWidth = rowRect.width() - max(0, m_popupClient->clientPaddingRight() - m_popupClient->clientInsetRight());
-    else {
-        textX = max(0, m_popupClient->clientPaddingLeft() - m_popupClient->clientInsetLeft());
-        maxWidth = rowRect.width() - textX;
-    }
-    // Prepare text to be drawn.
-    String itemText = m_popupClient->itemText(rowIndex);
-    String itemLabel = m_popupClient->itemLabel(rowIndex);
-    String itemIcon = m_popupClient->itemIcon(rowIndex);
-    if (m_settings.restrictWidthOfListBox) { // Truncate strings to fit in.
-        // FIXME: We should leftTruncate for the rtl case.
-        // StringTruncator::leftTruncate would have to be implemented.
-        String str = StringTruncator::rightTruncate(itemText, maxWidth, itemFont);
-        if (str != itemText) {
-            itemText = str;
-            // Don't display the label or icon, we already don't have enough room for the item text.
-            itemLabel = "";
-            itemIcon = "";
-        } else if (!itemLabel.isEmpty()) {
-            int availableWidth = maxWidth - kTextToLabelPadding -
-                StringTruncator::width(itemText, itemFont);
-            itemLabel = StringTruncator::rightTruncate(itemLabel, availableWidth, itemFont);
-        }
-    }
-
-    // Prepare the directionality to draw text.
-    TextRun textRun(itemText.characters(), itemText.length(), false, 0, 0, TextRun::AllowTrailingExpansion, style.textDirection(), style.hasTextDirectionOverride());
-    // If the text is right-to-left, make it right-aligned by adjusting its
-    // beginning position.
-    if (rightAligned)
-        textX += maxWidth - itemFont.width(textRun);
-
-    // Draw the item text.
-    int textY = rowRect.y() + itemFont.fontMetrics().ascent() + (rowRect.height() - itemFont.fontMetrics().height()) / 2;
-    gc->drawBidiText(itemFont, textRun, IntPoint(textX, textY));
-
-    // We are using the left padding as the right padding includes room for the scroll-bar which
-    // does not show in this case.
-    int rightPadding = max(0, m_popupClient->clientPaddingLeft() - m_popupClient->clientInsetLeft());
-    int remainingWidth = rowRect.width() - rightPadding;
-
-    // Draw the icon if applicable.
-    RefPtr<Image> image(Image::loadPlatformResource(itemIcon.utf8().data()));
-    if (image && !image->isNull()) {
-        IntRect imageRect = image->rect();
-        remainingWidth -= (imageRect.width() + kLabelToIconPadding);
-        imageRect.setX(rowRect.width() - rightPadding - imageRect.width());
-        imageRect.setY(rowRect.y() + (rowRect.height() - imageRect.height()) / 2);
-        gc->drawImage(image.get(), ColorSpaceDeviceRGB, imageRect);
-    }
-
-    // Draw the the label if applicable.
-    if (itemLabel.isEmpty())
-        return;
-
-    // Autofill label is 0.9 smaller than regular font size.
-    if (style.menuType() == PopupMenuStyle::AutofillPopup) {
-        itemFont = m_popupClient->itemStyle(rowIndex).font();
-        FontDescription d = itemFont.fontDescription();
-        d.setComputedSize(d.computedSize() * 0.9);
-        itemFont = Font(d, itemFont.letterSpacing(), itemFont.wordSpacing());
-        itemFont.update(0);
-    }
-
-    TextRun labelTextRun(itemLabel.characters(), itemLabel.length(), false, 0, 0, TextRun::AllowTrailingExpansion, style.textDirection(), style.hasTextDirectionOverride());
-    if (rightAligned)
-        textX = max(0, m_popupClient->clientPaddingLeft() - m_popupClient->clientInsetLeft());
-    else
-        textX = remainingWidth - itemFont.width(labelTextRun);
-
-    gc->setFillColor(labelColor, ColorSpaceDeviceRGB);
-    gc->drawBidiText(itemFont, labelTextRun, IntPoint(textX, textY));
-}
-
-Font PopupListBox::getRowFont(int rowIndex)
-{
-    Font itemFont = m_popupClient->itemStyle(rowIndex).font();
-    if (m_popupClient->itemIsLabel(rowIndex)) {
-        // Bold-ify labels (ie, an <optgroup> heading).
-        FontDescription d = itemFont.fontDescription();
-        d.setWeight(FontWeightBold);
-        Font font(d, itemFont.letterSpacing(), itemFont.wordSpacing());
-        font.update(0);
-        return font;
-    }
-
-    return itemFont;
-}
-
-void PopupListBox::abandon()
-{
-    RefPtr<PopupListBox> keepAlive(this);
-
-    m_selectedIndex = m_originalIndex;
-
-    hidePopup();
-
-    if (m_acceptedIndexOnAbandon >= 0) {
-        if (m_popupClient)
-            m_popupClient->valueChanged(m_acceptedIndexOnAbandon);
-        m_acceptedIndexOnAbandon = -1;
-    }
-}
-
-int PopupListBox::pointToRowIndex(const IntPoint& point)
-{
-    int y = scrollY() + point.y();
-
-    // FIXME: binary search if perf matters.
-    for (int i = 0; i < numItems(); ++i) {
-        if (y < m_items[i]->yOffset)
-            return i-1;
-    }
-
-    // Last item?
-    if (y < contentsHeight())
-        return m_items.size()-1;
-
-    return -1;
-}
-
-bool PopupListBox::acceptIndex(int index)
-{
-    // Clear m_acceptedIndexOnAbandon once user accepts the selected index.
-    if (m_acceptedIndexOnAbandon >= 0)
-        m_acceptedIndexOnAbandon = -1;
-
-    if (index >= numItems())
-        return false;
-
-    if (index < 0) {
-        if (m_popupClient) {
-            // Enter pressed with no selection, just close the popup.
-            hidePopup();
-        }
-        return false;
-    }
-
-    if (isSelectableItem(index)) {
-        RefPtr<PopupListBox> keepAlive(this);
-
-        // Hide ourselves first since valueChanged may have numerous side-effects.
-        hidePopup();
-
-        // Tell the <select> PopupMenuClient what index was selected.
-        m_popupClient->valueChanged(index);
-
-        return true;
-    }
-
-    return false;
-}
-
-void PopupListBox::selectIndex(int index)
-{
-    if (index < 0 || index >= numItems())
-        return;
-
-    bool isSelectable = isSelectableItem(index);
-    if (index != m_selectedIndex && isSelectable) {
-        invalidateRow(m_selectedIndex);
-        m_selectedIndex = index;
-        invalidateRow(m_selectedIndex);
-
-        scrollToRevealSelection();
-        m_popupClient->selectionChanged(m_selectedIndex);
-    } else if (!isSelectable) {
-        clearSelection();
-    }
-}
-
-void PopupListBox::setOriginalIndex(int index)
-{
-    m_originalIndex = m_selectedIndex = index;
-}
-
-int PopupListBox::getRowHeight(int index)
-{
-    if (index < 0)
-        return PopupMenuChromium::minimumRowHeight();
-
-    if (m_popupClient->itemStyle(index).isDisplayNone())
-        return PopupMenuChromium::minimumRowHeight();
-
-    // Separator row height is the same size as itself.
-    if (m_popupClient->itemIsSeparator(index))
-        return max(separatorHeight, PopupMenuChromium::minimumRowHeight());
-
-    String icon = m_popupClient->itemIcon(index);
-    RefPtr<Image> image(Image::loadPlatformResource(icon.utf8().data()));
-
-    int fontHeight = getRowFont(index).fontMetrics().height();
-    int iconHeight = (image && !image->isNull()) ? image->rect().height() : 0;
-
-    int linePaddingHeight = m_popupClient->menuStyle().menuType() == PopupMenuStyle::AutofillPopup ? kLinePaddingHeight : 0;
-    int calculatedRowHeight = max(fontHeight, iconHeight) + linePaddingHeight * 2;
-    return max(calculatedRowHeight, PopupMenuChromium::minimumRowHeight());
-}
-
-IntRect PopupListBox::getRowBounds(int index)
-{
-    if (index < 0)
-        return IntRect(0, 0, visibleWidth(), getRowHeight(index));
-
-    return IntRect(0, m_items[index]->yOffset, visibleWidth(), getRowHeight(index));
-}
-
-void PopupListBox::invalidateRow(int index)
-{
-    if (index < 0)
-        return;
-
-    // Invalidate in the window contents, as FramelessScrollView::invalidateRect
-    // paints in the window coordinates.
-    invalidateRect(contentsToWindow(getRowBounds(index)));
-}
-
-void PopupListBox::scrollToRevealRow(int index)
-{
-    if (index < 0)
-        return;
-
-    IntRect rowRect = getRowBounds(index);
-
-    if (rowRect.y() < scrollY()) {
-        // Row is above current scroll position, scroll up.
-        ScrollView::setScrollPosition(IntPoint(0, rowRect.y()));
-    } else if (rowRect.maxY() > scrollY() + visibleHeight()) {
-        // Row is below current scroll position, scroll down.
-        ScrollView::setScrollPosition(IntPoint(0, rowRect.maxY() - visibleHeight()));
-    }
-}
-
-bool PopupListBox::isSelectableItem(int index)
-{
-    ASSERT(index >= 0 && index < numItems());
-    return m_items[index]->type == PopupItem::TypeOption && m_popupClient->itemIsEnabled(index);
-}
-
-void PopupListBox::clearSelection()
-{
-    if (m_selectedIndex != -1) {
-        invalidateRow(m_selectedIndex);
-        m_selectedIndex = -1;
-        m_popupClient->selectionCleared();
-    }
-}
-
-void PopupListBox::selectNextRow()
-{
-    if (!m_settings.loopSelectionNavigation || m_selectedIndex != numItems() - 1) {
-        adjustSelectedIndex(1);
-        return;
-    }
-
-    // We are moving past the last item, no row should be selected.
-    clearSelection();
-}
-
-void PopupListBox::selectPreviousRow()
-{
-    if (!m_settings.loopSelectionNavigation || m_selectedIndex > 0) {
-        adjustSelectedIndex(-1);
-        return;
-    }
-
-    if (m_selectedIndex == 0) {
-        // We are moving past the first item, clear the selection.
-        clearSelection();
-        return;
-    }
-
-    // No row is selected, jump to the last item.
-    selectIndex(numItems() - 1);
-    scrollToRevealSelection();
-}
-
-void PopupListBox::adjustSelectedIndex(int delta)
-{
-    int targetIndex = m_selectedIndex + delta;
-    targetIndex = min(max(targetIndex, 0), numItems() - 1);
-    if (!isSelectableItem(targetIndex)) {
-        // We didn't land on an option.  Try to find one.
-        // We try to select the closest index to target, prioritizing any in
-        // the range [current, target].
-
-        int dir = delta > 0 ? 1 : -1;
-        int testIndex = m_selectedIndex;
-        int bestIndex = m_selectedIndex;
-        bool passedTarget = false;
-        while (testIndex >= 0 && testIndex < numItems()) {
-            if (isSelectableItem(testIndex))
-                bestIndex = testIndex;
-            if (testIndex == targetIndex)
-                passedTarget = true;
-            if (passedTarget && bestIndex != m_selectedIndex)
-                break;
-
-            testIndex += dir;
-        }
-
-        // Pick the best index, which may mean we don't change.
-        targetIndex = bestIndex;
-    }
-
-    // Select the new index, and ensure its visible.  We do this regardless of
-    // whether the selection changed to ensure keyboard events always bring the
-    // selection into view.
-    selectIndex(targetIndex);
-    scrollToRevealSelection();
-}
-
-void PopupListBox::hidePopup()
-{
-    if (parent()) {
-        PopupContainer* container = static_cast<PopupContainer*>(parent());
-        if (container->client())
-            container->client()->popupClosed(container);
-        container->notifyPopupHidden();
-    }
-
-    if (m_popupClient)
-        m_popupClient->popupDidHide();
-}
-
-void PopupListBox::updateFromElement()
-{
-    clear();
-
-    int size = m_popupClient->listSize();
-    for (int i = 0; i < size; ++i) {
-        PopupItem::Type type;
-        if (m_popupClient->itemIsSeparator(i))
-            type = PopupItem::TypeSeparator;
-        else if (m_popupClient->itemIsLabel(i))
-            type = PopupItem::TypeGroup;
-        else
-            type = PopupItem::TypeOption;
-        m_items.append(new PopupItem(m_popupClient->itemText(i), type));
-        m_items[i]->enabled = isSelectableItem(i);
-        PopupMenuStyle style = m_popupClient->itemStyle(i);
-        m_items[i]->textDirection = style.textDirection();
-        m_items[i]->hasTextDirectionOverride = style.hasTextDirectionOverride();
-    }
-
-    m_selectedIndex = m_popupClient->selectedIndex();
-    setOriginalIndex(m_selectedIndex);
-
-    layout();
-}
-
-void PopupListBox::setMaxWidthAndLayout(int maxWidth)
-{
-    m_maxWindowWidth = maxWidth;
-    layout();
-}
-
-void PopupListBox::layout()
-{
-    bool isRightAligned = m_popupClient->menuStyle().textDirection() == RTL;
-    
-    // Size our child items.
-    int baseWidth = 0;
-    int paddingWidth = 0;
-    int lineEndPaddingWidth = 0;
-    int y = 0;
-    for (int i = 0; i < numItems(); ++i) {
-        // Place the item vertically.
-        m_items[i]->yOffset = y;
-        if (m_popupClient->itemStyle(i).isDisplayNone())
-            continue;
-        y += getRowHeight(i);
-
-        // Ensure the popup is wide enough to fit this item.
-        Font itemFont = getRowFont(i);
-        String text = m_popupClient->itemText(i);
-        String label = m_popupClient->itemLabel(i);
-        String icon = m_popupClient->itemIcon(i);
-        RefPtr<Image> iconImage(Image::loadPlatformResource(icon.utf8().data()));
-        int width = 0;
-        if (!text.isEmpty())
-            width = itemFont.width(TextRun(text));
-        if (!label.isEmpty()) {
-            if (width > 0)
-                width += kTextToLabelPadding;
-            width += itemFont.width(TextRun(label));
-        }
-        if (iconImage && !iconImage->isNull()) {
-            if (width > 0)
-                width += kLabelToIconPadding;
-            width += iconImage->rect().width();
-        }
-
-        baseWidth = max(baseWidth, width);
-        // FIXME: http://b/1210481 We should get the padding of individual option elements.
-        paddingWidth = max(paddingWidth,
-            m_popupClient->clientPaddingLeft() + m_popupClient->clientPaddingRight());
-        lineEndPaddingWidth = max(lineEndPaddingWidth,
-            isRightAligned ? m_popupClient->clientPaddingLeft() : m_popupClient->clientPaddingRight());
-    }
-
-    // Calculate scroll bar width.
-    int windowHeight = 0;
-    m_visibleRows = min(numItems(), kMaxVisibleRows);
-
-    for (int i = 0; i < m_visibleRows; ++i) {
-        int rowHeight = getRowHeight(i);
-
-        // Only clip the window height for non-Mac platforms.
-        if (windowHeight + rowHeight > m_maxHeight) {
-            m_visibleRows = i;
-            break;
-        }
-
-        windowHeight += rowHeight;
-    }
-
-    // Set our widget and scrollable contents sizes.
-    int scrollbarWidth = 0;
-    if (m_visibleRows < numItems()) {
-        scrollbarWidth = ScrollbarTheme::nativeTheme()->scrollbarThickness();
-
-        // Use kMinEndOfLinePadding when there is a scrollbar so that we use
-        // as much as (lineEndPaddingWidth - kMinEndOfLinePadding) padding
-        // space for scrollbar and allow user to use CSS padding to make the
-        // popup listbox align with the select element.
-        paddingWidth = paddingWidth - lineEndPaddingWidth + kMinEndOfLinePadding;
-    }
-
-    int windowWidth;
-    int contentWidth;
-    if (m_settings.restrictWidthOfListBox) {
-        windowWidth = m_baseWidth;
-        contentWidth = m_baseWidth - scrollbarWidth;
-    } else {
-        windowWidth = baseWidth + scrollbarWidth + paddingWidth;
-        if (windowWidth > m_maxWindowWidth) {
-            // windowWidth exceeds m_maxWindowWidth, so we have to clip.
-            windowWidth = m_maxWindowWidth;
-            baseWidth = windowWidth - scrollbarWidth - paddingWidth;
-            m_baseWidth = baseWidth;
-        }
-        contentWidth = windowWidth - scrollbarWidth;
-
-        if (windowWidth < m_baseWidth) {
-            windowWidth = m_baseWidth;
-            contentWidth = m_baseWidth - scrollbarWidth;
-        } else
-            m_baseWidth = baseWidth;
-    }
-
-    resize(windowWidth, windowHeight);
-    setContentsSize(IntSize(contentWidth, getRowBounds(numItems() - 1).maxY()));
-
-    if (hostWindow())
-        scrollToRevealSelection();
-
-    invalidate();
-}
-
-void PopupListBox::clear()
-{
-    for (Vector<PopupItem*>::iterator it = m_items.begin(); it != m_items.end(); ++it)
-        delete *it;
-    m_items.clear();
-}
-
-bool PopupListBox::isPointInBounds(const IntPoint& point)
-{
-    return numItems() != 0 && IntRect(0, 0, width(), height()).contains(point);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// PopupMenuChromium implementation
-//
-// Note: you cannot add methods to this class, since it is defined above the
-//       portability layer. To access methods and properties on the
-//       popup widgets, use |popupWindow| above.
-
 PopupMenuChromium::PopupMenuChromium(PopupMenuClient* client)
     : m_popupClient(client)
 {
index 82d879b..edd3552 100644 (file)
 
 #include "config.h"
 
-#include "FramelessScrollView.h"
-#include "IntRect.h"
-#include "PlatformString.h"
 #include "PopupMenu.h"
 #include "PopupMenuPrivate.h"
-#include "PopupMenuStyle.h"
 
 namespace WebCore {
 
 class ChromeClientChromium;
 class FrameView;
-class PopupListBox;
+class IntRect;
+class PopupItem;
 class PopupMenuClient;
 
-// A container for the data for each menu item (e.g. represented by <option>
-// or <optgroup> in a <select> widget) and is used by PopupListBox.
-struct PopupItem {
-    enum Type {
-        TypeOption,
-        TypeGroup,
-        TypeSeparator
-    };
-
-    PopupItem(const String& label, Type type)
-        : label(label)
-        , type(type)
-        , yOffset(0)
-    {
-    }
-    String label;
-    Type type;
-    int yOffset; // y offset of this item, relative to the top of the popup.
-    TextDirection textDirection;
-    bool hasTextDirectionOverride;
-    bool enabled;
-};
-
-// FIXME: Our FramelessScrollView classes should probably implement HostWindow!
-
-// The PopupContainer class holds a PopupListBox (see cpp file).  Its sole purpose is to be
-// able to draw a border around its child.  All its paint/event handling is
-// just forwarded to the child listBox (with the appropriate transforms).
-// NOTE: this class is exposed so it can be instantiated direcly for the
-// autofill popup.  We cannot use the Popup class directly in that case as the
-// autofill popup should not be focused when shown and we want to forward the
-// key events to it (through handleKeyEvent).
-
-struct PopupContainerSettings {
-    // Whether the PopupMenuClient should be told to change its text when a
-    // new item is selected by using the arrow keys.
-    bool setTextOnIndexChange;
-
-    // Whether the selection should be accepted when the popup menu is
-    // closed (through ESC being pressed or the focus going away).
-    // Note that when TAB is pressed, the selection is always accepted
-    // regardless of this setting.
-    bool acceptOnAbandon;
-
-    // Whether we should move the selection to the first/last item when
-    // the user presses down/up arrow keys and the last/first item is
-    // selected.
-    bool loopSelectionNavigation;
-
-    // Whether we should restrict the width of the PopupListBox or not.
-    // Autocomplete popups are restricted, combo-boxes (select tags) aren't.
-    bool restrictWidthOfListBox;
-};
-
-class PopupContainer : public FramelessScrollView {
-public:
-    enum PopupType {
-        Select, // HTML select popup.
-        Suggestion, // Autocomplete/autofill popup.
-    };
-
-    static PassRefPtr<PopupContainer> create(PopupMenuClient*, PopupType,
-                                             const PopupContainerSettings&);
-
-    // Whether a key event should be sent to this popup.
-    virtual bool isInterestedInEventForKey(int keyCode);
-
-    // FramelessScrollView
-    virtual void paint(GraphicsContext*, const IntRect&);
-    virtual void hide();
-    virtual bool handleMouseDownEvent(const PlatformMouseEvent&);
-    virtual bool handleMouseMoveEvent(const PlatformMouseEvent&);
-    virtual bool handleMouseReleaseEvent(const PlatformMouseEvent&);
-    virtual bool handleWheelEvent(const PlatformWheelEvent&);
-    virtual bool handleKeyEvent(const PlatformKeyboardEvent&);
-#if ENABLE(TOUCH_EVENTS)
-    virtual bool handleTouchEvent(const PlatformTouchEvent&);
-#endif
-#if ENABLE(GESTURE_RECOGNIZER)
-    virtual bool handleGestureEvent(const PlatformGestureEvent&);
-#endif
-
-    // PopupContainer methods
-
-    // Show the popup
-    void showPopup(FrameView*);
-
-    // Show the popup in the specified rect for the specified frame.
-    // Note: this code was somehow arbitrarily factored-out of the Popup class
-    // so WebViewImpl can create a PopupContainer. This method is used for
-    // displaying auto complete popup menus on Mac Chromium, and for all
-    // popups on other platforms.
-    void showInRect(const IntRect&, FrameView*, int index);
-
-    // Hides the popup.
-    void hidePopup();
-
-    // The popup was hidden.
-    void notifyPopupHidden();
-
-    // Compute size of widget and children. Return right offset for the popup right alignment.
-    int layoutAndGetRTLOffset();
-
-    PopupListBox* listBox() const { return m_listBox.get(); }
-
-    bool isRTL() const;
-
-    // Gets the index of the item that the user is currently moused-over or
-    // has selected with the keyboard up/down arrows.
-    int selectedIndex() const;
-
-    // Refresh the popup values from the PopupMenuClient.
-    void refresh(const IntRect& targetControlRect);
-
-    // The menu per-item data.
-    const WTF::Vector<PopupItem*>& popupData() const;
-
-    // The height of a row in the menu.
-    int menuItemHeight() const;
-
-    // The size of the font being used.
-    int menuItemFontSize() const;
-
-    // The style of the menu being used.
-    PopupMenuStyle menuStyle() const;
-
-    PopupType popupType() const { return m_popupType; }
-
-    // While hovering popup menu window, we want to show tool tip message.
-    String getSelectedItemToolTip();
-
-private:
-    friend class WTF::RefCounted<PopupContainer>;
-
-    PopupContainer(PopupMenuClient*, PopupType, const PopupContainerSettings&);
-    ~PopupContainer();
-
-    // Paint the border.
-    void paintBorder(GraphicsContext*, const IntRect&);
-
-    // Layout and calculate popup widget size and location and returns it as IntRect.
-    IntRect layoutAndCalculateWidgetRect(int targetControlHeight, const IntPoint& popupInitialCoordinate);
-
-    // Returns the ChromeClient of the page this popup is associated with.
-    ChromeClientChromium* chromeClientChromium();
-
-    RefPtr<PopupListBox> m_listBox;
-    RefPtr<FrameView> m_frameView;
-
-    PopupContainerSettings m_settings;
-    PopupType m_popupType;
-    IntRect m_originalFrameRect;
-    // Whether the popup is currently open.
-    bool m_popupOpen;
-};
-
 class PopupMenuChromium : public PopupMenu {
 public:
     PopupMenuChromium(PopupMenuClient*);
index 7c4dd58..f05420c 100644 (file)
@@ -1,5 +1,17 @@
 2011-08-12  Fady Samuel  <fsamuel@chromium.org>
 
+        Refactoring of PopupMenuChromium For Readability and Maintainability
+        https://bugs.webkit.org/show_bug.cgi?id=66009
+
+        Reviewed by Darin Fisher.
+
+        * src/ChromeClientImpl.cpp:
+        * src/WebPopupMenuImpl.cpp:
+        * src/WebViewImpl.cpp:
+        * tests/PopupMenuTest.cpp:
+
+2011-08-12  Fady Samuel  <fsamuel@chromium.org>
+
         Expose pageScaleFactor() to Chromium's WebViewImpl
         https://bugs.webkit.org/show_bug.cgi?id=66067
 
index 20bb5a4..0b21c9b 100644 (file)
@@ -57,6 +57,7 @@
 #include "NotificationPresenterImpl.h"
 #include "Page.h"
 #include "PlatformBridge.h"
+#include "PopupContainer.h"
 #include "PopupMenuChromium.h"
 #include "RenderWidget.h"
 #include "ScriptController.h"
index 838238d..675c43a 100644 (file)
@@ -40,6 +40,7 @@
 #include "PlatformKeyboardEvent.h"
 #include "PlatformMouseEvent.h"
 #include "PlatformWheelEvent.h"
+#include "PopupContainer.h"
 #include "PopupMenuChromium.h"
 #include "SkiaUtils.h"
 
index 1f6ce63..2bfbf47 100644 (file)
@@ -85,7 +85,7 @@
 #include "PlatformMouseEvent.h"
 #include "PlatformThemeChromiumGtk.h"
 #include "PlatformWheelEvent.h"
-#include "PopupMenuChromium.h"
+#include "PopupContainer.h"
 #include "PopupMenuClient.h"
 #include "ProgressTracker.h"
 #include "RenderView.h"
index ed98605..309272a 100644 (file)
@@ -37,6 +37,7 @@
 #include "Element.h"
 #include "FrameView.h"
 #include "KeyboardCodes.h"
+#include "PopupContainer.h"
 #include "PopupMenu.h"
 #include "PopupMenuClient.h"
 #include "PopupMenuChromium.h"