| OLD | NEW |
| (Empty) |
| 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/FrameHost.h" | |
| 36 #include "core/frame/FrameView.h" | |
| 37 #include "core/frame/LocalFrame.h" | |
| 38 #include "core/html/forms/PopupMenuClient.h" | |
| 39 #include "core/page/ChromeClient.h" | |
| 40 #include "core/page/Page.h" | |
| 41 #include "core/paint/TransformRecorder.h" | |
| 42 #include "platform/PlatformGestureEvent.h" | |
| 43 #include "platform/PlatformKeyboardEvent.h" | |
| 44 #include "platform/PlatformMouseEvent.h" | |
| 45 #include "platform/PlatformTouchEvent.h" | |
| 46 #include "platform/PlatformWheelEvent.h" | |
| 47 #include "platform/UserGestureIndicator.h" | |
| 48 #include "platform/geometry/IntRect.h" | |
| 49 #include "platform/graphics/GraphicsContext.h" | |
| 50 #include "platform/graphics/paint/DrawingRecorder.h" | |
| 51 #include "public/web/WebPopupMenuInfo.h" | |
| 52 #include "public/web/WebPopupType.h" | |
| 53 #include "public/web/WebViewClient.h" | |
| 54 #include "web/PopupContainerClient.h" | |
| 55 #include "web/WebPopupMenuImpl.h" | |
| 56 #include "web/WebViewImpl.h" | |
| 57 #include <algorithm> | |
| 58 #include <limits> | |
| 59 | |
| 60 namespace blink { | |
| 61 | |
| 62 static const int borderSize = 1; | |
| 63 | |
| 64 static PlatformMouseEvent constructRelativeMouseEvent(const PlatformMouseEvent&
e, PopupContainer* parent, PopupListBox* child) | |
| 65 { | |
| 66 IntPoint pos = parent->convertSelfToChild(child, e.position()); | |
| 67 | |
| 68 // FIXME: This is a horrible hack since PlatformMouseEvent has no setters fo
r 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, PopupContainer* parent, PopupListBox* child) | |
| 77 { | |
| 78 IntPoint pos = parent->convertSelfToChild(child, e.position()); | |
| 79 | |
| 80 // FIXME: This is a horrible hack since PlatformWheelEvent has no setters fo
r 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 PassRefPtrWillBeRawPtr<PopupContainer> PopupContainer::create(PopupMenuClient* c
lient, bool deviceSupportsTouch) | |
| 90 { | |
| 91 return adoptRefWillBeNoop(new PopupContainer(client, deviceSupportsTouch)); | |
| 92 } | |
| 93 | |
| 94 PopupContainer::PopupContainer(PopupMenuClient* client, bool deviceSupportsTouch
) | |
| 95 : m_listBox(PopupListBox::create(client, deviceSupportsTouch, this)) | |
| 96 , m_popupOpen(false) | |
| 97 , m_client(0) | |
| 98 { | |
| 99 } | |
| 100 | |
| 101 PopupContainer::~PopupContainer() | |
| 102 { | |
| 103 #if !ENABLE(OILPAN) | |
| 104 if (m_listBox->parent()) | |
| 105 m_listBox->setParent(0); | |
| 106 #endif | |
| 107 } | |
| 108 | |
| 109 DEFINE_TRACE(PopupContainer) | |
| 110 { | |
| 111 visitor->trace(m_frameView); | |
| 112 visitor->trace(m_listBox); | |
| 113 Widget::trace(visitor); | |
| 114 } | |
| 115 | |
| 116 IntRect PopupContainer::layoutAndCalculateWidgetRectInternal(IntRect widgetRectI
nScreen, int targetControlHeight, const IntRect& windowRect, const IntRect& scre
en, bool isRTL, const int rtlOffset, const int verticalOffset, const IntSize& tr
ansformOffset, PopupContent* listBox, bool& needToResizeView) | |
| 117 { | |
| 118 ASSERT(listBox); | |
| 119 if (windowRect.x() >= screen.x() && windowRect.maxX() <= screen.maxX() && (w
idgetRectInScreen.x() < screen.x() || widgetRectInScreen.maxX() > screen.maxX())
) { | |
| 120 // First, inverse the popup alignment if it does not fit the screen - | |
| 121 // this might fix things (or make them better). | |
| 122 IntRect inverseWidgetRectInScreen = widgetRectInScreen; | |
| 123 inverseWidgetRectInScreen.setX(inverseWidgetRectInScreen.x() + (isRTL ?
-rtlOffset : rtlOffset)); | |
| 124 inverseWidgetRectInScreen.setY(inverseWidgetRectInScreen.y() + (isRTL ?
-verticalOffset : verticalOffset)); | |
| 125 unsigned originalCutoff = std::max(screen.x() - widgetRectInScreen.x(),
0) + std::max(widgetRectInScreen.maxX() - screen.maxX(), 0); | |
| 126 unsigned inverseCutoff = std::max(screen.x() - inverseWidgetRectInScreen
.x(), 0) + std::max(inverseWidgetRectInScreen.maxX() - screen.maxX(), 0); | |
| 127 | |
| 128 // Accept the inverse popup alignment if the trimmed content gets | |
| 129 // shorter than that in the original alignment case. | |
| 130 if (inverseCutoff < originalCutoff) | |
| 131 widgetRectInScreen = inverseWidgetRectInScreen; | |
| 132 | |
| 133 if (widgetRectInScreen.x() < screen.x()) { | |
| 134 widgetRectInScreen.setWidth(widgetRectInScreen.maxX() - screen.x()); | |
| 135 widgetRectInScreen.setX(screen.x()); | |
| 136 listBox->setMaxWidthAndLayout(std::max(widgetRectInScreen.width() -
borderSize * 2, 0)); | |
| 137 } else if (widgetRectInScreen.maxX() > screen.maxX()) { | |
| 138 widgetRectInScreen.setWidth(screen.maxX() - widgetRectInScreen.x()); | |
| 139 listBox->setMaxWidthAndLayout(std::max(widgetRectInScreen.width() -
borderSize * 2, 0)); | |
| 140 } | |
| 141 } | |
| 142 | |
| 143 // Calculate Y axis size. | |
| 144 if (widgetRectInScreen.maxY() > static_cast<int>(screen.maxY())) { | |
| 145 if (widgetRectInScreen.y() - widgetRectInScreen.height() - targetControl
Height - transformOffset.height() > 0) { | |
| 146 // There is enough room to open upwards. | |
| 147 widgetRectInScreen.move(-transformOffset.width(), -(widgetRectInScre
en.height() + targetControlHeight + transformOffset.height())); | |
| 148 } else { | |
| 149 // Figure whether upwards or downwards has more room and set the | |
| 150 // maximum number of items. | |
| 151 int spaceAbove = widgetRectInScreen.y() - targetControlHeight + tran
sformOffset.height(); | |
| 152 int spaceBelow = screen.maxY() - widgetRectInScreen.y(); | |
| 153 if (spaceAbove > spaceBelow) | |
| 154 listBox->setMaxHeight(spaceAbove); | |
| 155 else | |
| 156 listBox->setMaxHeight(spaceBelow); | |
| 157 listBox->layout(); | |
| 158 needToResizeView = true; | |
| 159 widgetRectInScreen.setHeight(listBox->popupContentHeight() + borderS
ize * 2); | |
| 160 // Move WebWidget upwards if necessary. | |
| 161 if (spaceAbove > spaceBelow) | |
| 162 widgetRectInScreen.move(-transformOffset.width(), -(widgetRectIn
Screen.height() + targetControlHeight + transformOffset.height())); | |
| 163 } | |
| 164 } | |
| 165 return widgetRectInScreen; | |
| 166 } | |
| 167 | |
| 168 IntRect PopupContainer::layoutAndCalculateWidgetRect(int targetControlHeight, co
nst IntSize& transformOffset, const IntPoint& popupInitialCoordinate) | |
| 169 { | |
| 170 // Reset the max width and height to their default values, they will be | |
| 171 // recomputed below if necessary. | |
| 172 m_listBox->setMaxHeight(PopupListBox::defaultMaxHeight); | |
| 173 m_listBox->setMaxWidth(std::numeric_limits<int>::max()); | |
| 174 | |
| 175 // Lay everything out to figure out our preferred size, then tell the view's | |
| 176 // WidgetClient about it. It should assign us a client. | |
| 177 m_listBox->layout(); | |
| 178 fitToListBox(); | |
| 179 bool isRTL = this->isRTL(); | |
| 180 | |
| 181 // Compute the starting x-axis for a normal RTL or right-aligned LTR | |
| 182 // dropdown. For those, the right edge of dropdown box should be aligned | |
| 183 // with the right edge of <select>/<input> element box, and the dropdown box | |
| 184 // should be expanded to the left if more space is needed. | |
| 185 // m_originalFrameRect.width() is the width of the target <select>/<input> | |
| 186 // element. | |
| 187 int rtlOffset = m_controlPosition.p2().x() - m_controlPosition.p1().x() - (m
_listBox->width() + borderSize * 2); | |
| 188 int rightOffset = isRTL ? rtlOffset : 0; | |
| 189 | |
| 190 // Compute the y-axis offset between the bottom left and bottom right | |
| 191 // points. If the <select>/<input> is transformed, they are not the same. | |
| 192 int verticalOffset = - m_controlPosition.p4().y() + m_controlPosition.p3().y
(); | |
| 193 int verticalForRTLOffset = isRTL ? verticalOffset : 0; | |
| 194 | |
| 195 // Assume m_listBox size is already calculated. | |
| 196 IntSize targetSize(m_listBox->width() + borderSize * 2, m_listBox->height()
+ borderSize * 2); | |
| 197 | |
| 198 IntRect widgetRectInScreen; | |
| 199 // If the popup would extend past the bottom of the screen, open upwards | |
| 200 // instead. | |
| 201 IntRect screen = chromeClient().screenInfo().availableRect; | |
| 202 // Use popupInitialCoordinate.x() + rightOffset because RTL position | |
| 203 // needs to be considered. | |
| 204 float pageScaleFactor = m_frameView->frame().page()->pageScaleFactor(); | |
| 205 int popupX = round((popupInitialCoordinate.x() + rightOffset) * pageScaleFac
tor); | |
| 206 int popupY = round((popupInitialCoordinate.y() + verticalForRTLOffset) * pag
eScaleFactor); | |
| 207 widgetRectInScreen = chromeClient().viewportToScreen(IntRect(popupX, popupY,
targetSize.width(), targetSize.height())); | |
| 208 | |
| 209 // If we have multiple screens and the browser rect is in one screen, we | |
| 210 // have to clip the window width to the screen width. | |
| 211 // When clipping, we also need to set a maximum width for the list box. | |
| 212 IntRect windowRect = chromeClient().windowRect(); | |
| 213 | |
| 214 bool needToResizeView = false; | |
| 215 widgetRectInScreen = layoutAndCalculateWidgetRectInternal(widgetRectInScreen
, targetControlHeight, windowRect, screen, isRTL, rtlOffset, verticalOffset, tra
nsformOffset, m_listBox.get(), needToResizeView); | |
| 216 if (needToResizeView) | |
| 217 fitToListBox(); | |
| 218 | |
| 219 return widgetRectInScreen; | |
| 220 } | |
| 221 | |
| 222 void PopupContainer::showPopup(FrameView* view) | |
| 223 { | |
| 224 m_frameView = view; | |
| 225 m_listBox->m_focusedElement = m_frameView->frame().document()->focusedElemen
t(); | |
| 226 | |
| 227 IntSize transformOffset(m_controlPosition.p4().x() - m_controlPosition.p1().
x(), m_controlPosition.p4().y() - m_controlPosition.p1().y() - m_controlSize.hei
ght()); | |
| 228 popupOpened(layoutAndCalculateWidgetRect(m_controlSize.height(), transformOf
fset, roundedIntPoint(m_controlPosition.p4()))); | |
| 229 m_popupOpen = true; | |
| 230 | |
| 231 if (!m_listBox->parent()) | |
| 232 m_listBox->setParent(this); | |
| 233 | |
| 234 m_listBox->scrollToRevealSelection(); | |
| 235 | |
| 236 invalidate(); | |
| 237 } | |
| 238 | |
| 239 void PopupContainer::hidePopup() | |
| 240 { | |
| 241 m_listBox->cancel(); | |
| 242 } | |
| 243 | |
| 244 void PopupContainer::notifyPopupHidden() | |
| 245 { | |
| 246 if (!m_popupOpen) | |
| 247 return; | |
| 248 m_popupOpen = false; | |
| 249 | |
| 250 // With Oilpan, we cannot assume that the FrameView's LocalFrame's | |
| 251 // page is still available, as the LocalFrame itself may have been | |
| 252 // detached from its FrameHost by now. | |
| 253 // | |
| 254 // So, if a popup menu is left in an open/shown state when | |
| 255 // finalized, the PopupMenu implementation of this container's | |
| 256 // listbox will hide itself when destructed, delivering the | |
| 257 // notifyPopupHidden() notification in the process & ending up here. | |
| 258 // If the LocalFrame has been detached already -- done when its | |
| 259 // HTMLFrameOwnerElement frame owner is detached as part of being | |
| 260 // torn down -- the connection to the FrameHost has been snipped & | |
| 261 // there's no page. Hence the null check. | |
| 262 // | |
| 263 // In a non-Oilpan setting, the LayoutMenuList that controls/owns | |
| 264 // the PopupMenuChromium object and this PopupContainer is torn | |
| 265 // down and destructed before the frame and frame owner, hence the | |
| 266 // page will always be available in that setting and this will | |
| 267 // not be an issue. | |
| 268 if (WebViewImpl* webView = WebViewImpl::fromPage(m_frameView->frame().page()
)) | |
| 269 webView->popupClosed(this); | |
| 270 } | |
| 271 | |
| 272 void PopupContainer::fitToListBox() | |
| 273 { | |
| 274 // Place the listbox within our border. | |
| 275 m_listBox->move(borderSize, borderSize); | |
| 276 | |
| 277 // Size ourselves to contain listbox + border. | |
| 278 resize(m_listBox->width() + borderSize * 2, m_listBox->height() + borderSize
* 2); | |
| 279 invalidate(); | |
| 280 } | |
| 281 | |
| 282 bool PopupContainer::handleMouseDownEvent(const PlatformMouseEvent& event) | |
| 283 { | |
| 284 UserGestureIndicator gestureIndicator(DefinitelyProcessingNewUserGesture); | |
| 285 return m_listBox->handleMouseDownEvent( | |
| 286 constructRelativeMouseEvent(event, this, m_listBox.get())); | |
| 287 } | |
| 288 | |
| 289 bool PopupContainer::handleMouseMoveEvent(const PlatformMouseEvent& event) | |
| 290 { | |
| 291 UserGestureIndicator gestureIndicator(DefinitelyProcessingNewUserGesture); | |
| 292 return m_listBox->handleMouseMoveEvent( | |
| 293 constructRelativeMouseEvent(event, this, m_listBox.get())); | |
| 294 } | |
| 295 | |
| 296 bool PopupContainer::handleMouseReleaseEvent(const PlatformMouseEvent& event) | |
| 297 { | |
| 298 RefPtrWillBeRawPtr<PopupContainer> protect(this); | |
| 299 UserGestureIndicator gestureIndicator(DefinitelyProcessingNewUserGesture); | |
| 300 return m_listBox->handleMouseReleaseEvent( | |
| 301 constructRelativeMouseEvent(event, this, m_listBox.get())); | |
| 302 } | |
| 303 | |
| 304 bool PopupContainer::handleWheelEvent(const PlatformWheelEvent& event) | |
| 305 { | |
| 306 UserGestureIndicator gestureIndicator(DefinitelyProcessingNewUserGesture); | |
| 307 return m_listBox->handleWheelEvent( | |
| 308 constructRelativeWheelEvent(event, this, m_listBox.get())); | |
| 309 } | |
| 310 | |
| 311 bool PopupContainer::handleTouchEvent(const PlatformTouchEvent&) | |
| 312 { | |
| 313 return false; | |
| 314 } | |
| 315 | |
| 316 // FIXME: Refactor this code to share functionality with | |
| 317 // EventHandler::handleGestureEvent. | |
| 318 bool PopupContainer::handleGestureEvent(const PlatformGestureEvent& gestureEvent
) | |
| 319 { | |
| 320 switch (gestureEvent.type()) { | |
| 321 case PlatformEvent::GestureTap: { | |
| 322 PlatformMouseEvent fakeMouseMove(gestureEvent.position(), gestureEvent.g
lobalPosition(), NoButton, PlatformEvent::MouseMoved, /* clickCount */ 1, gestur
eEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.m
etaKey(), PlatformMouseEvent::FromTouch, gestureEvent.timestamp()); | |
| 323 PlatformMouseEvent fakeMouseDown(gestureEvent.position(), gestureEvent.g
lobalPosition(), LeftButton, PlatformEvent::MousePressed, /* clickCount */ 1, ge
stureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEve
nt.metaKey(), PlatformMouseEvent::FromTouch, gestureEvent.timestamp()); | |
| 324 PlatformMouseEvent fakeMouseUp(gestureEvent.position(), gestureEvent.glo
balPosition(), LeftButton, PlatformEvent::MouseReleased, /* clickCount */ 1, ges
tureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEven
t.metaKey(), PlatformMouseEvent::FromTouch, gestureEvent.timestamp()); | |
| 325 // handleMouseMoveEvent(fakeMouseMove); | |
| 326 handleMouseDownEvent(fakeMouseDown); | |
| 327 handleMouseReleaseEvent(fakeMouseUp); | |
| 328 return true; | |
| 329 } | |
| 330 case PlatformEvent::GestureScrollUpdate: { | |
| 331 PlatformWheelEvent syntheticWheelEvent(gestureEvent.position(), gestureE
vent.globalPosition(), gestureEvent.deltaX(), gestureEvent.deltaY(), gestureEven
t.deltaX() / 120.0f, gestureEvent.deltaY() / 120.0f, ScrollByPixelWheelEvent, ge
stureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEve
nt.metaKey()); | |
| 332 handleWheelEvent(syntheticWheelEvent); | |
| 333 return true; | |
| 334 } | |
| 335 case PlatformEvent::GestureScrollBegin: | |
| 336 case PlatformEvent::GestureScrollEnd: | |
| 337 case PlatformEvent::GestureTapDown: | |
| 338 case PlatformEvent::GestureShowPress: | |
| 339 break; | |
| 340 default: | |
| 341 ASSERT_NOT_REACHED(); | |
| 342 } | |
| 343 return false; | |
| 344 } | |
| 345 | |
| 346 bool PopupContainer::handleKeyEvent(const PlatformKeyboardEvent& event) | |
| 347 { | |
| 348 UserGestureIndicator gestureIndicator(DefinitelyProcessingNewUserGesture); | |
| 349 return m_listBox->handleKeyEvent(event); | |
| 350 } | |
| 351 | |
| 352 void PopupContainer::hide() | |
| 353 { | |
| 354 m_listBox->cancel(); | |
| 355 } | |
| 356 | |
| 357 void PopupContainer::paint(GraphicsContext* gc, const IntRect& paintRect) | |
| 358 { | |
| 359 TransformRecorder transformRecorder(*gc, *this, AffineTransform::translation
(x(), y())); | |
| 360 IntRect adjustedPaintRect = intersection(paintRect, frameRect()); | |
| 361 adjustedPaintRect.moveBy(-location()); | |
| 362 | |
| 363 m_listBox->paint(gc, adjustedPaintRect); | |
| 364 paintBorder(gc, adjustedPaintRect); | |
| 365 } | |
| 366 | |
| 367 void PopupContainer::paintBorder(GraphicsContext* gc, const IntRect& rect) | |
| 368 { | |
| 369 DrawingRecorder drawingRecorder(*gc, *this, DisplayItem::PopupContainerBorde
r, boundsRect()); | |
| 370 if (drawingRecorder.canUseCachedDrawing()) | |
| 371 return; | |
| 372 | |
| 373 // FIXME: Where do we get the border color from? | |
| 374 Color borderColor(127, 157, 185); | |
| 375 | |
| 376 gc->setStrokeStyle(SolidStroke); | |
| 377 gc->setStrokeThickness(borderSize); | |
| 378 gc->setStrokeColor(borderColor); | |
| 379 | |
| 380 FloatRect borderRect(boundsRect()); | |
| 381 borderRect.inflate(-gc->strokeThickness() / 2); | |
| 382 gc->strokeRect(borderRect); | |
| 383 } | |
| 384 | |
| 385 ChromeClient& PopupContainer::chromeClient() | |
| 386 { | |
| 387 return m_frameView->frame().page()->chromeClient(); | |
| 388 } | |
| 389 | |
| 390 void PopupContainer::showInRect(const FloatQuad& controlPosition, const IntSize&
controlSize, FrameView* v, int index) | |
| 391 { | |
| 392 // The controlSize is the size of the select box. It's usually larger than | |
| 393 // we need. Subtract border size so that usually the container will be | |
| 394 // displayed exactly the same width as the select box. | |
| 395 m_listBox->setBaseWidth(std::max(controlSize.width() - borderSize * 2, 0)); | |
| 396 m_listBox->setSelectedIndex(m_listBox->m_popupClient->selectedIndex()); | |
| 397 m_listBox->updateFromElement(); | |
| 398 | |
| 399 // We set the selected item in updateFromElement(), and disregard the | |
| 400 // index passed into this function (same as Webkit's PopupMenuWin.cpp) | |
| 401 // FIXME: make sure this is correct, and add an assertion. | |
| 402 // ASSERT(popupWindow(popup)->listBox()->selectedIndex() == index); | |
| 403 | |
| 404 // Save and convert the controlPosition to main window coords. Each point is
converted separately | |
| 405 // to window coordinates because the control could be in a transformed webvi
ew and then each point | |
| 406 // would be transformed by a different delta. | |
| 407 m_controlPosition.setP1(v->contentsToRootFrame(IntPoint(controlPosition.p1()
.x(), controlPosition.p1().y()))); | |
| 408 m_controlPosition.setP2(v->contentsToRootFrame(IntPoint(controlPosition.p2()
.x(), controlPosition.p2().y()))); | |
| 409 m_controlPosition.setP3(v->contentsToRootFrame(IntPoint(controlPosition.p3()
.x(), controlPosition.p3().y()))); | |
| 410 m_controlPosition.setP4(v->contentsToRootFrame(IntPoint(controlPosition.p4()
.x(), controlPosition.p4().y()))); | |
| 411 | |
| 412 FloatRect controlBounds = m_controlPosition.boundingBox(); | |
| 413 controlBounds = v->page()->frameHost().pinchViewport().mainViewToViewportCSS
Pixels(controlBounds); | |
| 414 m_controlPosition = controlBounds; | |
| 415 | |
| 416 m_controlSize = controlSize; | |
| 417 | |
| 418 // Position at (0, 0) since the frameRect().location() is relative to the | |
| 419 // parent WebWidget. | |
| 420 setFrameRect(IntRect(IntPoint(), controlSize)); | |
| 421 showPopup(v); | |
| 422 } | |
| 423 | |
| 424 inline bool PopupContainer::isRTL() const | |
| 425 { | |
| 426 return m_listBox->m_popupClient->menuStyle().textDirection() == RTL; | |
| 427 } | |
| 428 | |
| 429 int PopupContainer::selectedIndex() const | |
| 430 { | |
| 431 return m_listBox->selectedIndex(); | |
| 432 } | |
| 433 | |
| 434 int PopupContainer::menuItemHeight() const | |
| 435 { | |
| 436 return m_listBox->getRowHeight(0); | |
| 437 } | |
| 438 | |
| 439 int PopupContainer::menuItemFontSize() const | |
| 440 { | |
| 441 return m_listBox->getRowFont(0).fontDescription().computedSize(); | |
| 442 } | |
| 443 | |
| 444 PopupMenuStyle PopupContainer::menuStyle() const | |
| 445 { | |
| 446 return m_listBox->m_popupClient->menuStyle(); | |
| 447 } | |
| 448 | |
| 449 String PopupContainer::getSelectedItemToolTip() | |
| 450 { | |
| 451 // We cannot use m_popupClient->selectedIndex() to choose tooltip message, | |
| 452 // because the selectedIndex() might return final selected index, not | |
| 453 // hovering selection. | |
| 454 return m_listBox->m_popupClient->itemToolTip(m_listBox->m_selectedIndex); | |
| 455 } | |
| 456 | |
| 457 void PopupContainer::popupOpened(const IntRect& bounds) | |
| 458 { | |
| 459 WebViewImpl* webView = WebViewImpl::fromPage(m_frameView->frame().page()); | |
| 460 if (!webView->client()) | |
| 461 return; | |
| 462 | |
| 463 WebWidget* webwidget = webView->client()->createPopupMenu(WebPopupTypeSelect
); | |
| 464 if (!webwidget) | |
| 465 return; | |
| 466 // We only notify when the WebView has to handle the popup, as when | |
| 467 // the popup is handled externally, the fact that a popup is showing is | |
| 468 // transparent to the WebView. | |
| 469 webView->popupOpened(this); | |
| 470 toWebPopupMenuImpl(webwidget)->initialize(this, bounds); | |
| 471 } | |
| 472 | |
| 473 void PopupContainer::invalidateRect(const IntRect& rect) | |
| 474 { | |
| 475 if (HostWindow* h = hostWindow()) | |
| 476 h->invalidateRect(rect); | |
| 477 if (m_client) | |
| 478 m_client->invalidateDisplayItemClient(displayItemClient()); | |
| 479 } | |
| 480 | |
| 481 HostWindow* PopupContainer::hostWindow() const | |
| 482 { | |
| 483 return m_client; | |
| 484 } | |
| 485 | |
| 486 IntPoint PopupContainer::convertChildToSelf(const Widget* child, const IntPoint&
point) const | |
| 487 { | |
| 488 IntPoint newPoint = point; | |
| 489 newPoint.moveBy(child->location()); | |
| 490 return newPoint; | |
| 491 } | |
| 492 | |
| 493 IntPoint PopupContainer::convertSelfToChild(const Widget* child, const IntPoint&
point) const | |
| 494 { | |
| 495 IntPoint newPoint = point; | |
| 496 newPoint.moveBy(-child->location()); | |
| 497 return newPoint; | |
| 498 } | |
| 499 | |
| 500 } // namespace blink | |
| OLD | NEW |