Home | History | Annotate | Download | only in web
      1 /*
      2  * Copyright (c) 2011, Google Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions are
      6  * met:
      7  *
      8  *     * Redistributions of source code must retain the above copyright
      9  * notice, this list of conditions and the following disclaimer.
     10  *     * Redistributions in binary form must reproduce the above
     11  * copyright notice, this list of conditions and the following disclaimer
     12  * in the documentation and/or other materials provided with the
     13  * distribution.
     14  *     * Neither the name of Google Inc. nor the names of its
     15  * contributors may be used to endorse or promote products derived from
     16  * this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 #include "config.h"
     32 #include "web/PopupContainer.h"
     33 
     34 #include "core/dom/Document.h"
     35 #include "core/frame/FrameView.h"
     36 #include "core/frame/LocalFrame.h"
     37 #include "core/page/Chrome.h"
     38 #include "core/page/ChromeClient.h"
     39 #include "core/page/Page.h"
     40 #include "platform/PlatformGestureEvent.h"
     41 #include "platform/PlatformKeyboardEvent.h"
     42 #include "platform/PlatformMouseEvent.h"
     43 #include "platform/PlatformScreen.h"
     44 #include "platform/PlatformTouchEvent.h"
     45 #include "platform/PlatformWheelEvent.h"
     46 #include "platform/PopupMenuClient.h"
     47 #include "platform/UserGestureIndicator.h"
     48 #include "platform/geometry/IntRect.h"
     49 #include "platform/graphics/GraphicsContext.h"
     50 #include "platform/scroll/FramelessScrollViewClient.h"
     51 #include "public/web/WebPopupMenuInfo.h"
     52 #include "public/web/WebPopupType.h"
     53 #include "public/web/WebViewClient.h"
     54 #include "web/WebPopupMenuImpl.h"
     55 #include "web/WebViewImpl.h"
     56 #include <limits>
     57 
     58 namespace blink {
     59 
     60 using namespace WebCore;
     61 
     62 static const int borderSize = 1;
     63 
     64 static PlatformMouseEvent constructRelativeMouseEvent(const PlatformMouseEvent& e, FramelessScrollView* parent, FramelessScrollView* child)
     65 {
     66     IntPoint pos = parent->convertSelfToChild(child, e.position());
     67 
     68     // FIXME: This is a horrible hack since PlatformMouseEvent has no setters for x/y.
     69     PlatformMouseEvent relativeEvent = e;
     70     IntPoint& relativePos = const_cast<IntPoint&>(relativeEvent.position());
     71     relativePos.setX(pos.x());
     72     relativePos.setY(pos.y());
     73     return relativeEvent;
     74 }
     75 
     76 static PlatformWheelEvent constructRelativeWheelEvent(const PlatformWheelEvent& e, FramelessScrollView* parent, FramelessScrollView* child)
     77 {
     78     IntPoint pos = parent->convertSelfToChild(child, e.position());
     79 
     80     // FIXME: This is a horrible hack since PlatformWheelEvent has no setters for x/y.
     81     PlatformWheelEvent relativeEvent = e;
     82     IntPoint& relativePos = const_cast<IntPoint&>(relativeEvent.position());
     83     relativePos.setX(pos.x());
     84     relativePos.setY(pos.y());
     85     return relativeEvent;
     86 }
     87 
     88 // static
     89 PassRefPtr<PopupContainer> PopupContainer::create(PopupMenuClient* client, bool deviceSupportsTouch)
     90 {
     91     return adoptRef(new PopupContainer(client, deviceSupportsTouch));
     92 }
     93 
     94 PopupContainer::PopupContainer(PopupMenuClient* client, bool deviceSupportsTouch)
     95     : m_listBox(PopupListBox::create(client, deviceSupportsTouch))
     96     , m_popupOpen(false)
     97 {
     98     setScrollbarModes(ScrollbarAlwaysOff, ScrollbarAlwaysOff);
     99 }
    100 
    101 PopupContainer::~PopupContainer()
    102 {
    103     if (m_listBox && m_listBox->parent())
    104         removeChild(m_listBox.get());
    105 }
    106 
    107 IntRect PopupContainer::layoutAndCalculateWidgetRectInternal(IntRect widgetRectInScreen, int targetControlHeight, const FloatRect& windowRect, const FloatRect& screen, bool isRTL, const int rtlOffset, const int verticalOffset, const IntSize& transformOffset, PopupContent* listBox, bool& needToResizeView)
    108 {
    109     ASSERT(listBox);
    110     if (windowRect.x() >= screen.x() && windowRect.maxX() <= screen.maxX() && (widgetRectInScreen.x() < screen.x() || widgetRectInScreen.maxX() > screen.maxX())) {
    111         // First, inverse the popup alignment if it does not fit the screen -
    112         // this might fix things (or make them better).
    113         IntRect inverseWidgetRectInScreen = widgetRectInScreen;
    114         inverseWidgetRectInScreen.setX(inverseWidgetRectInScreen.x() + (isRTL ? -rtlOffset : rtlOffset));
    115         inverseWidgetRectInScreen.setY(inverseWidgetRectInScreen.y() + (isRTL ? -verticalOffset : verticalOffset));
    116         IntRect enclosingScreen = enclosingIntRect(screen);
    117         unsigned originalCutoff = std::max(enclosingScreen.x() - widgetRectInScreen.x(), 0) + std::max(widgetRectInScreen.maxX() - enclosingScreen.maxX(), 0);
    118         unsigned inverseCutoff = std::max(enclosingScreen.x() - inverseWidgetRectInScreen.x(), 0) + std::max(inverseWidgetRectInScreen.maxX() - enclosingScreen.maxX(), 0);
    119 
    120         // Accept the inverse popup alignment if the trimmed content gets
    121         // shorter than that in the original alignment case.
    122         if (inverseCutoff < originalCutoff)
    123             widgetRectInScreen = inverseWidgetRectInScreen;
    124 
    125         if (widgetRectInScreen.x() < screen.x()) {
    126             widgetRectInScreen.setWidth(widgetRectInScreen.maxX() - screen.x());
    127             widgetRectInScreen.setX(screen.x());
    128             listBox->setMaxWidthAndLayout(std::max(widgetRectInScreen.width() - borderSize * 2, 0));
    129         } else if (widgetRectInScreen.maxX() > screen.maxX()) {
    130             widgetRectInScreen.setWidth(screen.maxX() - widgetRectInScreen.x());
    131             listBox->setMaxWidthAndLayout(std::max(widgetRectInScreen.width() - borderSize * 2, 0));
    132         }
    133     }
    134 
    135     // Calculate Y axis size.
    136     if (widgetRectInScreen.maxY() > static_cast<int>(screen.maxY())) {
    137         if (widgetRectInScreen.y() - widgetRectInScreen.height() - targetControlHeight - transformOffset.height() > 0) {
    138             // There is enough room to open upwards.
    139             widgetRectInScreen.move(-transformOffset.width(), -(widgetRectInScreen.height() + targetControlHeight + transformOffset.height()));
    140         } else {
    141             // Figure whether upwards or downwards has more room and set the
    142             // maximum number of items.
    143             int spaceAbove = widgetRectInScreen.y() - targetControlHeight + transformOffset.height();
    144             int spaceBelow = screen.maxY() - widgetRectInScreen.y();
    145             if (spaceAbove > spaceBelow)
    146                 listBox->setMaxHeight(spaceAbove);
    147             else
    148                 listBox->setMaxHeight(spaceBelow);
    149             listBox->layout();
    150             needToResizeView = true;
    151             widgetRectInScreen.setHeight(listBox->popupContentHeight() + borderSize * 2);
    152             // Move WebWidget upwards if necessary.
    153             if (spaceAbove > spaceBelow)
    154                 widgetRectInScreen.move(-transformOffset.width(), -(widgetRectInScreen.height() + targetControlHeight + transformOffset.height()));
    155         }
    156     }
    157     return widgetRectInScreen;
    158 }
    159 
    160 IntRect PopupContainer::layoutAndCalculateWidgetRect(int targetControlHeight, const IntSize& transformOffset, const IntPoint& popupInitialCoordinate)
    161 {
    162     // Reset the max width and height to their default values, they will be
    163     // recomputed below if necessary.
    164     m_listBox->setMaxHeight(PopupListBox::defaultMaxHeight);
    165     m_listBox->setMaxWidth(std::numeric_limits<int>::max());
    166 
    167     // Lay everything out to figure out our preferred size, then tell the view's
    168     // WidgetClient about it. It should assign us a client.
    169     m_listBox->layout();
    170     fitToListBox();
    171     bool isRTL = this->isRTL();
    172 
    173     // Compute the starting x-axis for a normal RTL or right-aligned LTR
    174     // dropdown. For those, the right edge of dropdown box should be aligned
    175     // with the right edge of <select>/<input> element box, and the dropdown box
    176     // should be expanded to the left if more space is needed.
    177     // m_originalFrameRect.width() is the width of the target <select>/<input>
    178     // element.
    179     int rtlOffset = m_controlPosition.p2().x() - m_controlPosition.p1().x() - (m_listBox->width() + borderSize * 2);
    180     int rightOffset = isRTL ? rtlOffset : 0;
    181 
    182     // Compute the y-axis offset between the bottom left and bottom right
    183     // points. If the <select>/<input> is transformed, they are not the same.
    184     int verticalOffset = - m_controlPosition.p4().y() + m_controlPosition.p3().y();
    185     int verticalForRTLOffset = isRTL ? verticalOffset : 0;
    186 
    187     // Assume m_listBox size is already calculated.
    188     IntSize targetSize(m_listBox->width() + borderSize * 2, m_listBox->height() + borderSize * 2);
    189 
    190     IntRect widgetRectInScreen;
    191     // If the popup would extend past the bottom of the screen, open upwards
    192     // instead.
    193     FloatRect screen = screenAvailableRect(m_frameView.get());
    194     // Use popupInitialCoordinate.x() + rightOffset because RTL position
    195     // needs to be considered.
    196     float pageScaleFactor = m_frameView->frame().page()->pageScaleFactor();
    197     int popupX = round((popupInitialCoordinate.x() + rightOffset) * pageScaleFactor);
    198     int popupY = round((popupInitialCoordinate.y() + verticalForRTLOffset) * pageScaleFactor);
    199     widgetRectInScreen = chromeClient().rootViewToScreen(IntRect(popupX, popupY, targetSize.width(), targetSize.height()));
    200 
    201     // If we have multiple screens and the browser rect is in one screen, we
    202     // have to clip the window width to the screen width.
    203     // When clipping, we also need to set a maximum width for the list box.
    204     FloatRect windowRect = chromeClient().windowRect();
    205 
    206     bool needToResizeView = false;
    207     widgetRectInScreen = layoutAndCalculateWidgetRectInternal(widgetRectInScreen, targetControlHeight, windowRect, screen, isRTL, rtlOffset, verticalOffset, transformOffset, m_listBox.get(), needToResizeView);
    208     if (needToResizeView)
    209         fitToListBox();
    210 
    211     return widgetRectInScreen;
    212 }
    213 
    214 void PopupContainer::showPopup(FrameView* view)
    215 {
    216     m_frameView = view;
    217     listBox()->m_focusedElement = m_frameView->frame().document()->focusedElement();
    218 
    219     IntSize transformOffset(m_controlPosition.p4().x() - m_controlPosition.p1().x(), m_controlPosition.p4().y() - m_controlPosition.p1().y() - m_controlSize.height());
    220     popupOpened(layoutAndCalculateWidgetRect(m_controlSize.height(), transformOffset, roundedIntPoint(m_controlPosition.p4())));
    221     m_popupOpen = true;
    222 
    223     if (!m_listBox->parent())
    224         addChild(m_listBox.get());
    225 
    226     // Enable scrollbars after the listbox is inserted into the hierarchy,
    227     // so it has a proper WidgetClient.
    228     m_listBox->setVerticalScrollbarMode(ScrollbarAuto);
    229 
    230     m_listBox->scrollToRevealSelection();
    231 
    232     invalidate();
    233 }
    234 
    235 void PopupContainer::hidePopup()
    236 {
    237     listBox()->abandon();
    238 }
    239 
    240 void PopupContainer::notifyPopupHidden()
    241 {
    242     if (!m_popupOpen)
    243         return;
    244     m_popupOpen = false;
    245     WebViewImpl::fromPage(m_frameView->frame().page())->popupClosed(this);
    246 }
    247 
    248 void PopupContainer::fitToListBox()
    249 {
    250     // Place the listbox within our border.
    251     m_listBox->move(borderSize, borderSize);
    252 
    253     // Size ourselves to contain listbox + border.
    254     resize(m_listBox->width() + borderSize * 2, m_listBox->height() + borderSize * 2);
    255     invalidate();
    256 }
    257 
    258 bool PopupContainer::handleMouseDownEvent(const PlatformMouseEvent& event)
    259 {
    260     UserGestureIndicator gestureIndicator(DefinitelyProcessingNewUserGesture);
    261     return m_listBox->handleMouseDownEvent(
    262         constructRelativeMouseEvent(event, this, m_listBox.get()));
    263 }
    264 
    265 bool PopupContainer::handleMouseMoveEvent(const PlatformMouseEvent& event)
    266 {
    267     UserGestureIndicator gestureIndicator(DefinitelyProcessingNewUserGesture);
    268     return m_listBox->handleMouseMoveEvent(
    269         constructRelativeMouseEvent(event, this, m_listBox.get()));
    270 }
    271 
    272 bool PopupContainer::handleMouseReleaseEvent(const PlatformMouseEvent& event)
    273 {
    274     RefPtr<PopupContainer> protect(this);
    275     UserGestureIndicator gestureIndicator(DefinitelyProcessingNewUserGesture);
    276     return m_listBox->handleMouseReleaseEvent(
    277         constructRelativeMouseEvent(event, this, m_listBox.get()));
    278 }
    279 
    280 bool PopupContainer::handleWheelEvent(const PlatformWheelEvent& event)
    281 {
    282     UserGestureIndicator gestureIndicator(DefinitelyProcessingNewUserGesture);
    283     return m_listBox->handleWheelEvent(
    284         constructRelativeWheelEvent(event, this, m_listBox.get()));
    285 }
    286 
    287 bool PopupContainer::handleTouchEvent(const PlatformTouchEvent&)
    288 {
    289     return false;
    290 }
    291 
    292 // FIXME: Refactor this code to share functionality with
    293 // EventHandler::handleGestureEvent.
    294 bool PopupContainer::handleGestureEvent(const PlatformGestureEvent& gestureEvent)
    295 {
    296     switch (gestureEvent.type()) {
    297     case PlatformEvent::GestureTap: {
    298         PlatformMouseEvent fakeMouseMove(gestureEvent.position(), gestureEvent.globalPosition(), NoButton, PlatformEvent::MouseMoved, /* clickCount */ 1, gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey(), gestureEvent.timestamp());
    299         PlatformMouseEvent fakeMouseDown(gestureEvent.position(), gestureEvent.globalPosition(), LeftButton, PlatformEvent::MousePressed, /* clickCount */ 1, gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey(), gestureEvent.timestamp());
    300         PlatformMouseEvent fakeMouseUp(gestureEvent.position(), gestureEvent.globalPosition(), LeftButton, PlatformEvent::MouseReleased, /* clickCount */ 1, gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey(), gestureEvent.timestamp());
    301         // handleMouseMoveEvent(fakeMouseMove);
    302         handleMouseDownEvent(fakeMouseDown);
    303         handleMouseReleaseEvent(fakeMouseUp);
    304         return true;
    305     }
    306     case PlatformEvent::GestureScrollUpdate:
    307     case PlatformEvent::GestureScrollUpdateWithoutPropagation: {
    308         PlatformWheelEvent syntheticWheelEvent(gestureEvent.position(), gestureEvent.globalPosition(), gestureEvent.deltaX(), gestureEvent.deltaY(), gestureEvent.deltaX() / 120.0f, gestureEvent.deltaY() / 120.0f, ScrollByPixelWheelEvent, gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey());
    309         handleWheelEvent(syntheticWheelEvent);
    310         return true;
    311     }
    312     case PlatformEvent::GestureScrollBegin:
    313     case PlatformEvent::GestureScrollEnd:
    314     case PlatformEvent::GestureTapDown:
    315     case PlatformEvent::GestureShowPress:
    316         break;
    317     default:
    318         ASSERT_NOT_REACHED();
    319     }
    320     return false;
    321 }
    322 
    323 bool PopupContainer::handleKeyEvent(const PlatformKeyboardEvent& event)
    324 {
    325     UserGestureIndicator gestureIndicator(DefinitelyProcessingNewUserGesture);
    326     return m_listBox->handleKeyEvent(event);
    327 }
    328 
    329 void PopupContainer::hide()
    330 {
    331     m_listBox->abandon();
    332 }
    333 
    334 void PopupContainer::paint(GraphicsContext* gc, const IntRect& rect)
    335 {
    336     // Adjust coords for scrolled frame.
    337     IntRect r = intersection(rect, frameRect());
    338     int tx = x();
    339     int ty = y();
    340 
    341     r.move(-tx, -ty);
    342 
    343     gc->translate(static_cast<float>(tx), static_cast<float>(ty));
    344     m_listBox->paint(gc, r);
    345     gc->translate(-static_cast<float>(tx), -static_cast<float>(ty));
    346 
    347     paintBorder(gc, rect);
    348 }
    349 
    350 void PopupContainer::paintBorder(GraphicsContext* gc, const IntRect& rect)
    351 {
    352     // FIXME: Where do we get the border color from?
    353     Color borderColor(127, 157, 185);
    354 
    355     gc->setStrokeStyle(NoStroke);
    356     gc->setFillColor(borderColor);
    357 
    358     int tx = x();
    359     int ty = y();
    360 
    361     // top, left, bottom, right
    362     gc->drawRect(IntRect(tx, ty, width(), borderSize));
    363     gc->drawRect(IntRect(tx, ty, borderSize, height()));
    364     gc->drawRect(IntRect(tx, ty + height() - borderSize, width(), borderSize));
    365     gc->drawRect(IntRect(tx + width() - borderSize, ty, borderSize, height()));
    366 }
    367 
    368 bool PopupContainer::isInterestedInEventForKey(int keyCode)
    369 {
    370     return m_listBox->isInterestedInEventForKey(keyCode);
    371 }
    372 
    373 ChromeClient& PopupContainer::chromeClient()
    374 {
    375     return m_frameView->frame().page()->chrome().client();
    376 }
    377 
    378 void PopupContainer::showInRect(const FloatQuad& controlPosition, const IntSize& controlSize, FrameView* v, int index)
    379 {
    380     // The controlSize is the size of the select box. It's usually larger than
    381     // we need. Subtract border size so that usually the container will be
    382     // displayed exactly the same width as the select box.
    383     listBox()->setBaseWidth(max(controlSize.width() - borderSize * 2, 0));
    384 
    385     listBox()->updateFromElement();
    386 
    387     // We set the selected item in updateFromElement(), and disregard the
    388     // index passed into this function (same as Webkit's PopupMenuWin.cpp)
    389     // FIXME: make sure this is correct, and add an assertion.
    390     // ASSERT(popupWindow(popup)->listBox()->selectedIndex() == index);
    391 
    392     // Save and convert the controlPosition to main window coords. Each point is converted separately
    393     // to window coordinates because the control could be in a transformed webview and then each point
    394     // would be transformed by a different delta.
    395     m_controlPosition.setP1(v->contentsToWindow(IntPoint(controlPosition.p1().x(), controlPosition.p1().y())));
    396     m_controlPosition.setP2(v->contentsToWindow(IntPoint(controlPosition.p2().x(), controlPosition.p2().y())));
    397     m_controlPosition.setP3(v->contentsToWindow(IntPoint(controlPosition.p3().x(), controlPosition.p3().y())));
    398     m_controlPosition.setP4(v->contentsToWindow(IntPoint(controlPosition.p4().x(), controlPosition.p4().y())));
    399 
    400     m_controlSize = controlSize;
    401 
    402     // Position at (0, 0) since the frameRect().location() is relative to the
    403     // parent WebWidget.
    404     setFrameRect(IntRect(IntPoint(), controlSize));
    405     showPopup(v);
    406 }
    407 
    408 IntRect PopupContainer::refresh(const IntRect& targetControlRect)
    409 {
    410     listBox()->setBaseWidth(max(m_controlSize.width() - borderSize * 2, 0));
    411     listBox()->updateFromElement();
    412 
    413     IntPoint locationInWindow = m_frameView->contentsToWindow(targetControlRect.location());
    414 
    415     // Move it below the select widget.
    416     locationInWindow.move(0, targetControlRect.height());
    417 
    418     IntRect widgetRectInScreen = layoutAndCalculateWidgetRect(targetControlRect.height(), IntSize(), locationInWindow);
    419 
    420     // Reset the size (which can be set to the PopupListBox size in
    421     // layoutAndGetRTLOffset(), exceeding the available widget rectangle.)
    422     if (size() != widgetRectInScreen.size())
    423         resize(widgetRectInScreen.size());
    424 
    425     invalidate();
    426 
    427     return widgetRectInScreen;
    428 }
    429 
    430 inline bool PopupContainer::isRTL() const
    431 {
    432     return m_listBox->m_popupClient->menuStyle().textDirection() == RTL;
    433 }
    434 
    435 int PopupContainer::selectedIndex() const
    436 {
    437     return m_listBox->selectedIndex();
    438 }
    439 
    440 int PopupContainer::menuItemHeight() const
    441 {
    442     return m_listBox->getRowHeight(0);
    443 }
    444 
    445 int PopupContainer::menuItemFontSize() const
    446 {
    447     return m_listBox->getRowFont(0).fontDescription().computedSize();
    448 }
    449 
    450 PopupMenuStyle PopupContainer::menuStyle() const
    451 {
    452     return m_listBox->m_popupClient->menuStyle();
    453 }
    454 
    455 const WTF::Vector<PopupItem*>& PopupContainer:: popupData() const
    456 {
    457     return m_listBox->items();
    458 }
    459 
    460 String PopupContainer::getSelectedItemToolTip()
    461 {
    462     // We cannot use m_popupClient->selectedIndex() to choose tooltip message,
    463     // because the selectedIndex() might return final selected index, not
    464     // hovering selection.
    465     return listBox()->m_popupClient->itemToolTip(listBox()->m_selectedIndex);
    466 }
    467 
    468 void PopupContainer::popupOpened(const IntRect& bounds)
    469 {
    470     WebViewImpl* webView = WebViewImpl::fromPage(m_frameView->frame().page());
    471     if (!webView->client())
    472         return;
    473 
    474     WebWidget* webwidget = webView->client()->createPopupMenu(WebPopupTypeSelect);
    475     if (!webwidget)
    476         return;
    477     // We only notify when the WebView has to handle the popup, as when
    478     // the popup is handled externally, the fact that a popup is showing is
    479     // transparent to the WebView.
    480     webView->popupOpened(this);
    481     toWebPopupMenuImpl(webwidget)->initialize(this, bounds);
    482 }
    483 
    484 void PopupContainer::getPopupMenuInfo(WebPopupMenuInfo* info)
    485 {
    486     const Vector<PopupItem*>& inputItems = popupData();
    487 
    488     WebVector<WebMenuItemInfo> outputItems(inputItems.size());
    489 
    490     for (size_t i = 0; i < inputItems.size(); ++i) {
    491         const PopupItem& inputItem = *inputItems[i];
    492         WebMenuItemInfo& outputItem = outputItems[i];
    493 
    494         outputItem.label = inputItem.label;
    495         outputItem.enabled = inputItem.enabled;
    496         if (inputItem.textDirection == WebCore::RTL)
    497             outputItem.textDirection = WebTextDirectionRightToLeft;
    498         else
    499             outputItem.textDirection = WebTextDirectionLeftToRight;
    500         outputItem.hasTextDirectionOverride = inputItem.hasTextDirectionOverride;
    501 
    502         switch (inputItem.type) {
    503         case PopupItem::TypeOption:
    504             outputItem.type = WebMenuItemInfo::Option;
    505             break;
    506         case PopupItem::TypeGroup:
    507             outputItem.type = WebMenuItemInfo::Group;
    508             break;
    509         case PopupItem::TypeSeparator:
    510             outputItem.type = WebMenuItemInfo::Separator;
    511             break;
    512         }
    513     }
    514 
    515     info->itemHeight = menuItemHeight();
    516     info->itemFontSize = menuItemFontSize();
    517     info->selectedIndex = selectedIndex();
    518     info->items.swap(outputItems);
    519     info->rightAligned = menuStyle().textDirection() == RTL;
    520 }
    521 
    522 } // namespace blink
    523