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 "public/web/WebPopupMenuInfo.h" 51 #include "public/web/WebPopupType.h" 52 #include "public/web/WebViewClient.h" 53 #include "web/PopupContainerClient.h" 54 #include "web/WebPopupMenuImpl.h" 55 #include "web/WebViewImpl.h" 56 #include <limits> 57 58 namespace blink { 59 60 static const int borderSize = 1; 61 62 static PlatformMouseEvent constructRelativeMouseEvent(const PlatformMouseEvent& e, PopupContainer* parent, PopupListBox* child) 63 { 64 IntPoint pos = parent->convertSelfToChild(child, e.position()); 65 66 // FIXME: This is a horrible hack since PlatformMouseEvent has no setters for x/y. 67 PlatformMouseEvent relativeEvent = e; 68 IntPoint& relativePos = const_cast<IntPoint&>(relativeEvent.position()); 69 relativePos.setX(pos.x()); 70 relativePos.setY(pos.y()); 71 return relativeEvent; 72 } 73 74 static PlatformWheelEvent constructRelativeWheelEvent(const PlatformWheelEvent& e, PopupContainer* parent, PopupListBox* child) 75 { 76 IntPoint pos = parent->convertSelfToChild(child, e.position()); 77 78 // FIXME: This is a horrible hack since PlatformWheelEvent has no setters for x/y. 79 PlatformWheelEvent relativeEvent = e; 80 IntPoint& relativePos = const_cast<IntPoint&>(relativeEvent.position()); 81 relativePos.setX(pos.x()); 82 relativePos.setY(pos.y()); 83 return relativeEvent; 84 } 85 86 // static 87 PassRefPtr<PopupContainer> PopupContainer::create(PopupMenuClient* client, bool deviceSupportsTouch) 88 { 89 return adoptRef(new PopupContainer(client, deviceSupportsTouch)); 90 } 91 92 PopupContainer::PopupContainer(PopupMenuClient* client, bool deviceSupportsTouch) 93 : m_listBox(PopupListBox::create(client, deviceSupportsTouch, this)) 94 , m_popupOpen(false) 95 , m_client(0) 96 { 97 } 98 99 PopupContainer::~PopupContainer() 100 { 101 if (m_listBox->parent()) 102 m_listBox->setParent(0); 103 } 104 105 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) 106 { 107 ASSERT(listBox); 108 if (windowRect.x() >= screen.x() && windowRect.maxX() <= screen.maxX() && (widgetRectInScreen.x() < screen.x() || widgetRectInScreen.maxX() > screen.maxX())) { 109 // First, inverse the popup alignment if it does not fit the screen - 110 // this might fix things (or make them better). 111 IntRect inverseWidgetRectInScreen = widgetRectInScreen; 112 inverseWidgetRectInScreen.setX(inverseWidgetRectInScreen.x() + (isRTL ? -rtlOffset : rtlOffset)); 113 inverseWidgetRectInScreen.setY(inverseWidgetRectInScreen.y() + (isRTL ? -verticalOffset : verticalOffset)); 114 IntRect enclosingScreen = enclosingIntRect(screen); 115 unsigned originalCutoff = std::max(enclosingScreen.x() - widgetRectInScreen.x(), 0) + std::max(widgetRectInScreen.maxX() - enclosingScreen.maxX(), 0); 116 unsigned inverseCutoff = std::max(enclosingScreen.x() - inverseWidgetRectInScreen.x(), 0) + std::max(inverseWidgetRectInScreen.maxX() - enclosingScreen.maxX(), 0); 117 118 // Accept the inverse popup alignment if the trimmed content gets 119 // shorter than that in the original alignment case. 120 if (inverseCutoff < originalCutoff) 121 widgetRectInScreen = inverseWidgetRectInScreen; 122 123 if (widgetRectInScreen.x() < screen.x()) { 124 widgetRectInScreen.setWidth(widgetRectInScreen.maxX() - screen.x()); 125 widgetRectInScreen.setX(screen.x()); 126 listBox->setMaxWidthAndLayout(std::max(widgetRectInScreen.width() - borderSize * 2, 0)); 127 } else if (widgetRectInScreen.maxX() > screen.maxX()) { 128 widgetRectInScreen.setWidth(screen.maxX() - widgetRectInScreen.x()); 129 listBox->setMaxWidthAndLayout(std::max(widgetRectInScreen.width() - borderSize * 2, 0)); 130 } 131 } 132 133 // Calculate Y axis size. 134 if (widgetRectInScreen.maxY() > static_cast<int>(screen.maxY())) { 135 if (widgetRectInScreen.y() - widgetRectInScreen.height() - targetControlHeight - transformOffset.height() > 0) { 136 // There is enough room to open upwards. 137 widgetRectInScreen.move(-transformOffset.width(), -(widgetRectInScreen.height() + targetControlHeight + transformOffset.height())); 138 } else { 139 // Figure whether upwards or downwards has more room and set the 140 // maximum number of items. 141 int spaceAbove = widgetRectInScreen.y() - targetControlHeight + transformOffset.height(); 142 int spaceBelow = screen.maxY() - widgetRectInScreen.y(); 143 if (spaceAbove > spaceBelow) 144 listBox->setMaxHeight(spaceAbove); 145 else 146 listBox->setMaxHeight(spaceBelow); 147 listBox->layout(); 148 needToResizeView = true; 149 widgetRectInScreen.setHeight(listBox->popupContentHeight() + borderSize * 2); 150 // Move WebWidget upwards if necessary. 151 if (spaceAbove > spaceBelow) 152 widgetRectInScreen.move(-transformOffset.width(), -(widgetRectInScreen.height() + targetControlHeight + transformOffset.height())); 153 } 154 } 155 return widgetRectInScreen; 156 } 157 158 IntRect PopupContainer::layoutAndCalculateWidgetRect(int targetControlHeight, const IntSize& transformOffset, const IntPoint& popupInitialCoordinate) 159 { 160 // Reset the max width and height to their default values, they will be 161 // recomputed below if necessary. 162 m_listBox->setMaxHeight(PopupListBox::defaultMaxHeight); 163 m_listBox->setMaxWidth(std::numeric_limits<int>::max()); 164 165 // Lay everything out to figure out our preferred size, then tell the view's 166 // WidgetClient about it. It should assign us a client. 167 m_listBox->layout(); 168 fitToListBox(); 169 bool isRTL = this->isRTL(); 170 171 // Compute the starting x-axis for a normal RTL or right-aligned LTR 172 // dropdown. For those, the right edge of dropdown box should be aligned 173 // with the right edge of <select>/<input> element box, and the dropdown box 174 // should be expanded to the left if more space is needed. 175 // m_originalFrameRect.width() is the width of the target <select>/<input> 176 // element. 177 int rtlOffset = m_controlPosition.p2().x() - m_controlPosition.p1().x() - (m_listBox->width() + borderSize * 2); 178 int rightOffset = isRTL ? rtlOffset : 0; 179 180 // Compute the y-axis offset between the bottom left and bottom right 181 // points. If the <select>/<input> is transformed, they are not the same. 182 int verticalOffset = - m_controlPosition.p4().y() + m_controlPosition.p3().y(); 183 int verticalForRTLOffset = isRTL ? verticalOffset : 0; 184 185 // Assume m_listBox size is already calculated. 186 IntSize targetSize(m_listBox->width() + borderSize * 2, m_listBox->height() + borderSize * 2); 187 188 IntRect widgetRectInScreen; 189 // If the popup would extend past the bottom of the screen, open upwards 190 // instead. 191 FloatRect screen = screenAvailableRect(m_frameView.get()); 192 // Use popupInitialCoordinate.x() + rightOffset because RTL position 193 // needs to be considered. 194 float pageScaleFactor = m_frameView->frame().page()->pageScaleFactor(); 195 int popupX = round((popupInitialCoordinate.x() + rightOffset) * pageScaleFactor); 196 int popupY = round((popupInitialCoordinate.y() + verticalForRTLOffset) * pageScaleFactor); 197 widgetRectInScreen = chromeClient().rootViewToScreen(IntRect(popupX, popupY, targetSize.width(), targetSize.height())); 198 199 // If we have multiple screens and the browser rect is in one screen, we 200 // have to clip the window width to the screen width. 201 // When clipping, we also need to set a maximum width for the list box. 202 FloatRect windowRect = chromeClient().windowRect(); 203 204 bool needToResizeView = false; 205 widgetRectInScreen = layoutAndCalculateWidgetRectInternal(widgetRectInScreen, targetControlHeight, windowRect, screen, isRTL, rtlOffset, verticalOffset, transformOffset, m_listBox.get(), needToResizeView); 206 if (needToResizeView) 207 fitToListBox(); 208 209 return widgetRectInScreen; 210 } 211 212 void PopupContainer::showPopup(FrameView* view) 213 { 214 m_frameView = view; 215 m_listBox->m_focusedElement = m_frameView->frame().document()->focusedElement(); 216 217 IntSize transformOffset(m_controlPosition.p4().x() - m_controlPosition.p1().x(), m_controlPosition.p4().y() - m_controlPosition.p1().y() - m_controlSize.height()); 218 popupOpened(layoutAndCalculateWidgetRect(m_controlSize.height(), transformOffset, roundedIntPoint(m_controlPosition.p4()))); 219 m_popupOpen = true; 220 221 if (!m_listBox->parent()) 222 m_listBox->setParent(this); 223 224 m_listBox->scrollToRevealSelection(); 225 226 invalidate(); 227 } 228 229 void PopupContainer::hidePopup() 230 { 231 m_listBox->abandon(); 232 } 233 234 void PopupContainer::notifyPopupHidden() 235 { 236 if (!m_popupOpen) 237 return; 238 m_popupOpen = false; 239 240 // With Oilpan, we cannot assume that the FrameView's LocalFrame's 241 // page is still available, as the LocalFrame itself may have been 242 // detached from its FrameHost by now. 243 // 244 // So, if a popup menu is left in an open/shown state when 245 // finalized, the PopupMenu implementation of this container's 246 // listbox will hide itself when destructed, delivering the 247 // notifyPopupHidden() notification in the process & ending up here. 248 // If the LocalFrame has been detached already -- done when its 249 // HTMLFrameOwnerElement frame owner is detached as part of being 250 // torn down -- the connection to the FrameHost has been snipped & 251 // there's no page. Hence the null check. 252 // 253 // In a non-Oilpan setting, the RenderMenuList that controls/owns 254 // the PopupMenuChromium object and this PopupContainer is torn 255 // down and destructed before the frame and frame owner, hence the 256 // page will always be available in that setting and this will 257 // not be an issue. 258 if (WebViewImpl* webView = WebViewImpl::fromPage(m_frameView->frame().page())) 259 webView->popupClosed(this); 260 } 261 262 void PopupContainer::fitToListBox() 263 { 264 // Place the listbox within our border. 265 m_listBox->move(borderSize, borderSize); 266 267 // Size ourselves to contain listbox + border. 268 resize(m_listBox->width() + borderSize * 2, m_listBox->height() + borderSize * 2); 269 invalidate(); 270 } 271 272 bool PopupContainer::handleMouseDownEvent(const PlatformMouseEvent& event) 273 { 274 UserGestureIndicator gestureIndicator(DefinitelyProcessingNewUserGesture); 275 return m_listBox->handleMouseDownEvent( 276 constructRelativeMouseEvent(event, this, m_listBox.get())); 277 } 278 279 bool PopupContainer::handleMouseMoveEvent(const PlatformMouseEvent& event) 280 { 281 UserGestureIndicator gestureIndicator(DefinitelyProcessingNewUserGesture); 282 return m_listBox->handleMouseMoveEvent( 283 constructRelativeMouseEvent(event, this, m_listBox.get())); 284 } 285 286 bool PopupContainer::handleMouseReleaseEvent(const PlatformMouseEvent& event) 287 { 288 RefPtr<PopupContainer> protect(this); 289 UserGestureIndicator gestureIndicator(DefinitelyProcessingNewUserGesture); 290 return m_listBox->handleMouseReleaseEvent( 291 constructRelativeMouseEvent(event, this, m_listBox.get())); 292 } 293 294 bool PopupContainer::handleWheelEvent(const PlatformWheelEvent& event) 295 { 296 UserGestureIndicator gestureIndicator(DefinitelyProcessingNewUserGesture); 297 return m_listBox->handleWheelEvent( 298 constructRelativeWheelEvent(event, this, m_listBox.get())); 299 } 300 301 bool PopupContainer::handleTouchEvent(const PlatformTouchEvent&) 302 { 303 return false; 304 } 305 306 // FIXME: Refactor this code to share functionality with 307 // EventHandler::handleGestureEvent. 308 bool PopupContainer::handleGestureEvent(const PlatformGestureEvent& gestureEvent) 309 { 310 switch (gestureEvent.type()) { 311 case PlatformEvent::GestureTap: { 312 PlatformMouseEvent fakeMouseMove(gestureEvent.position(), gestureEvent.globalPosition(), NoButton, PlatformEvent::MouseMoved, /* clickCount */ 1, gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey(), PlatformMouseEvent::FromTouch, gestureEvent.timestamp()); 313 PlatformMouseEvent fakeMouseDown(gestureEvent.position(), gestureEvent.globalPosition(), LeftButton, PlatformEvent::MousePressed, /* clickCount */ 1, gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey(), PlatformMouseEvent::FromTouch, gestureEvent.timestamp()); 314 PlatformMouseEvent fakeMouseUp(gestureEvent.position(), gestureEvent.globalPosition(), LeftButton, PlatformEvent::MouseReleased, /* clickCount */ 1, gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey(), PlatformMouseEvent::FromTouch, gestureEvent.timestamp()); 315 // handleMouseMoveEvent(fakeMouseMove); 316 handleMouseDownEvent(fakeMouseDown); 317 handleMouseReleaseEvent(fakeMouseUp); 318 return true; 319 } 320 case PlatformEvent::GestureScrollUpdate: 321 case PlatformEvent::GestureScrollUpdateWithoutPropagation: { 322 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()); 323 handleWheelEvent(syntheticWheelEvent); 324 return true; 325 } 326 case PlatformEvent::GestureScrollBegin: 327 case PlatformEvent::GestureScrollEnd: 328 case PlatformEvent::GestureTapDown: 329 case PlatformEvent::GestureShowPress: 330 break; 331 default: 332 ASSERT_NOT_REACHED(); 333 } 334 return false; 335 } 336 337 bool PopupContainer::handleKeyEvent(const PlatformKeyboardEvent& event) 338 { 339 UserGestureIndicator gestureIndicator(DefinitelyProcessingNewUserGesture); 340 return m_listBox->handleKeyEvent(event); 341 } 342 343 void PopupContainer::hide() 344 { 345 m_listBox->abandon(); 346 } 347 348 void PopupContainer::paint(GraphicsContext* gc, const IntRect& rect) 349 { 350 // Adjust coords for scrolled frame. 351 IntRect r = intersection(rect, frameRect()); 352 int tx = x(); 353 int ty = y(); 354 355 r.move(-tx, -ty); 356 357 gc->translate(static_cast<float>(tx), static_cast<float>(ty)); 358 m_listBox->paint(gc, r); 359 gc->translate(-static_cast<float>(tx), -static_cast<float>(ty)); 360 361 paintBorder(gc, rect); 362 } 363 364 void PopupContainer::paintBorder(GraphicsContext* gc, const IntRect& rect) 365 { 366 // FIXME: Where do we get the border color from? 367 Color borderColor(127, 157, 185); 368 369 gc->setStrokeStyle(NoStroke); 370 gc->setFillColor(borderColor); 371 372 int tx = x(); 373 int ty = y(); 374 375 // top, left, bottom, right 376 gc->drawRect(IntRect(tx, ty, width(), borderSize)); 377 gc->drawRect(IntRect(tx, ty, borderSize, height())); 378 gc->drawRect(IntRect(tx, ty + height() - borderSize, width(), borderSize)); 379 gc->drawRect(IntRect(tx + width() - borderSize, ty, borderSize, height())); 380 } 381 382 bool PopupContainer::isInterestedInEventForKey(int keyCode) 383 { 384 return m_listBox->isInterestedInEventForKey(keyCode); 385 } 386 387 ChromeClient& PopupContainer::chromeClient() 388 { 389 return m_frameView->frame().page()->chrome().client(); 390 } 391 392 void PopupContainer::showInRect(const FloatQuad& controlPosition, const IntSize& controlSize, FrameView* v, int index) 393 { 394 // The controlSize is the size of the select box. It's usually larger than 395 // we need. Subtract border size so that usually the container will be 396 // displayed exactly the same width as the select box. 397 m_listBox->setBaseWidth(max(controlSize.width() - borderSize * 2, 0)); 398 399 m_listBox->updateFromElement(); 400 401 // We set the selected item in updateFromElement(), and disregard the 402 // index passed into this function (same as Webkit's PopupMenuWin.cpp) 403 // FIXME: make sure this is correct, and add an assertion. 404 // ASSERT(popupWindow(popup)->listBox()->selectedIndex() == index); 405 406 // Save and convert the controlPosition to main window coords. Each point is converted separately 407 // to window coordinates because the control could be in a transformed webview and then each point 408 // would be transformed by a different delta. 409 m_controlPosition.setP1(v->contentsToWindow(IntPoint(controlPosition.p1().x(), controlPosition.p1().y()))); 410 m_controlPosition.setP2(v->contentsToWindow(IntPoint(controlPosition.p2().x(), controlPosition.p2().y()))); 411 m_controlPosition.setP3(v->contentsToWindow(IntPoint(controlPosition.p3().x(), controlPosition.p3().y()))); 412 m_controlPosition.setP4(v->contentsToWindow(IntPoint(controlPosition.p4().x(), controlPosition.p4().y()))); 413 414 m_controlSize = controlSize; 415 416 // Position at (0, 0) since the frameRect().location() is relative to the 417 // parent WebWidget. 418 setFrameRect(IntRect(IntPoint(), controlSize)); 419 showPopup(v); 420 } 421 422 IntRect PopupContainer::refresh(const IntRect& targetControlRect) 423 { 424 m_listBox->setBaseWidth(max(m_controlSize.width() - borderSize * 2, 0)); 425 m_listBox->updateFromElement(); 426 427 IntPoint locationInWindow = m_frameView->contentsToWindow(targetControlRect.location()); 428 429 // Move it below the select widget. 430 locationInWindow.move(0, targetControlRect.height()); 431 432 IntRect widgetRectInScreen = layoutAndCalculateWidgetRect(targetControlRect.height(), IntSize(), locationInWindow); 433 434 // Reset the size (which can be set to the PopupListBox size in 435 // layoutAndGetRTLOffset(), exceeding the available widget rectangle.) 436 if (size() != widgetRectInScreen.size()) 437 resize(widgetRectInScreen.size()); 438 439 invalidate(); 440 441 return widgetRectInScreen; 442 } 443 444 inline bool PopupContainer::isRTL() const 445 { 446 return m_listBox->m_popupClient->menuStyle().textDirection() == RTL; 447 } 448 449 int PopupContainer::selectedIndex() const 450 { 451 return m_listBox->selectedIndex(); 452 } 453 454 int PopupContainer::menuItemHeight() const 455 { 456 return m_listBox->getRowHeight(0); 457 } 458 459 int PopupContainer::menuItemFontSize() const 460 { 461 return m_listBox->getRowFont(0).fontDescription().computedSize(); 462 } 463 464 PopupMenuStyle PopupContainer::menuStyle() const 465 { 466 return m_listBox->m_popupClient->menuStyle(); 467 } 468 469 const WTF::Vector<PopupItem*>& PopupContainer:: popupData() const 470 { 471 return m_listBox->items(); 472 } 473 474 String PopupContainer::getSelectedItemToolTip() 475 { 476 // We cannot use m_popupClient->selectedIndex() to choose tooltip message, 477 // because the selectedIndex() might return final selected index, not 478 // hovering selection. 479 return m_listBox->m_popupClient->itemToolTip(m_listBox->m_selectedIndex); 480 } 481 482 void PopupContainer::popupOpened(const IntRect& bounds) 483 { 484 WebViewImpl* webView = WebViewImpl::fromPage(m_frameView->frame().page()); 485 if (!webView->client()) 486 return; 487 488 WebWidget* webwidget = webView->client()->createPopupMenu(WebPopupTypeSelect); 489 if (!webwidget) 490 return; 491 // We only notify when the WebView has to handle the popup, as when 492 // the popup is handled externally, the fact that a popup is showing is 493 // transparent to the WebView. 494 webView->popupOpened(this); 495 toWebPopupMenuImpl(webwidget)->initialize(this, bounds); 496 } 497 498 void PopupContainer::getPopupMenuInfo(WebPopupMenuInfo* info) 499 { 500 const Vector<PopupItem*>& inputItems = popupData(); 501 502 WebVector<WebMenuItemInfo> outputItems(inputItems.size()); 503 504 for (size_t i = 0; i < inputItems.size(); ++i) { 505 const PopupItem& inputItem = *inputItems[i]; 506 WebMenuItemInfo& outputItem = outputItems[i]; 507 508 outputItem.label = inputItem.label; 509 outputItem.enabled = inputItem.enabled; 510 outputItem.textDirection = toWebTextDirection(inputItem.textDirection); 511 outputItem.hasTextDirectionOverride = inputItem.hasTextDirectionOverride; 512 513 switch (inputItem.type) { 514 case PopupItem::TypeOption: 515 outputItem.type = WebMenuItemInfo::Option; 516 break; 517 case PopupItem::TypeGroup: 518 outputItem.type = WebMenuItemInfo::Group; 519 break; 520 case PopupItem::TypeSeparator: 521 outputItem.type = WebMenuItemInfo::Separator; 522 break; 523 } 524 } 525 526 info->itemHeight = menuItemHeight(); 527 info->itemFontSize = menuItemFontSize(); 528 info->selectedIndex = selectedIndex(); 529 info->items.swap(outputItems); 530 info->rightAligned = menuStyle().textDirection() == RTL; 531 } 532 533 void PopupContainer::invalidateRect(const IntRect& rect) 534 { 535 if (HostWindow* h = hostWindow()) 536 h->invalidateContentsAndRootView(rect); 537 } 538 539 HostWindow* PopupContainer::hostWindow() const 540 { 541 return const_cast<PopupContainerClient*>(m_client); 542 } 543 544 IntPoint PopupContainer::convertChildToSelf(const Widget* child, const IntPoint& point) const 545 { 546 IntPoint newPoint = point; 547 newPoint.moveBy(child->location()); 548 return newPoint; 549 } 550 551 IntPoint PopupContainer::convertSelfToChild(const Widget* child, const IntPoint& point) const 552 { 553 IntPoint newPoint = point; 554 newPoint.moveBy(-child->location()); 555 return newPoint; 556 } 557 558 } // namespace blink 559