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 |