Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(118)

Side by Side Diff: Source/web/PopupContainer.cpp

Issue 736883002: Implement <select> Popup Menu using PagePopup (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(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/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 <algorithm>
57 #include <limits>
58
59 namespace blink {
60
61 static const int borderSize = 1;
62
63 static PlatformMouseEvent constructRelativeMouseEvent(const PlatformMouseEvent& e, PopupContainer* parent, PopupListBox* child)
64 {
65 IntPoint pos = parent->convertSelfToChild(child, e.position());
66
67 // FIXME: This is a horrible hack since PlatformMouseEvent has no setters fo r x/y.
68 PlatformMouseEvent relativeEvent = e;
69 IntPoint& relativePos = const_cast<IntPoint&>(relativeEvent.position());
70 relativePos.setX(pos.x());
71 relativePos.setY(pos.y());
72 return relativeEvent;
73 }
74
75 static PlatformWheelEvent constructRelativeWheelEvent(const PlatformWheelEvent& e, PopupContainer* parent, PopupListBox* child)
76 {
77 IntPoint pos = parent->convertSelfToChild(child, e.position());
78
79 // FIXME: This is a horrible hack since PlatformWheelEvent has no setters fo r x/y.
80 PlatformWheelEvent relativeEvent = e;
81 IntPoint& relativePos = const_cast<IntPoint&>(relativeEvent.position());
82 relativePos.setX(pos.x());
83 relativePos.setY(pos.y());
84 return relativeEvent;
85 }
86
87 // static
88 PassRefPtrWillBeRawPtr<PopupContainer> PopupContainer::create(PopupMenuClient* c lient, bool deviceSupportsTouch)
89 {
90 return adoptRefWillBeNoop(new PopupContainer(client, deviceSupportsTouch));
91 }
92
93 PopupContainer::PopupContainer(PopupMenuClient* client, bool deviceSupportsTouch )
94 : m_listBox(PopupListBox::create(client, deviceSupportsTouch, this))
95 , m_popupOpen(false)
96 , m_client(0)
97 {
98 }
99
100 PopupContainer::~PopupContainer()
101 {
102 #if !ENABLE(OILPAN)
103 if (m_listBox->parent())
104 m_listBox->setParent(0);
105 #endif
106 }
107
108 void PopupContainer::trace(Visitor* visitor)
109 {
110 visitor->trace(m_frameView);
111 visitor->trace(m_listBox);
112 Widget::trace(visitor);
113 }
114
115 IntRect PopupContainer::layoutAndCalculateWidgetRectInternal(IntRect widgetRectI nScreen, int targetControlHeight, const FloatRect& windowRect, const FloatRect& screen, bool isRTL, const int rtlOffset, const int verticalOffset, const IntSize & transformOffset, PopupContent* listBox, bool& needToResizeView)
116 {
117 ASSERT(listBox);
118 if (windowRect.x() >= screen.x() && windowRect.maxX() <= screen.maxX() && (w idgetRectInScreen.x() < screen.x() || widgetRectInScreen.maxX() > screen.maxX()) ) {
119 // First, inverse the popup alignment if it does not fit the screen -
120 // this might fix things (or make them better).
121 IntRect inverseWidgetRectInScreen = widgetRectInScreen;
122 inverseWidgetRectInScreen.setX(inverseWidgetRectInScreen.x() + (isRTL ? -rtlOffset : rtlOffset));
123 inverseWidgetRectInScreen.setY(inverseWidgetRectInScreen.y() + (isRTL ? -verticalOffset : verticalOffset));
124 IntRect enclosingScreen = enclosingIntRect(screen);
125 unsigned originalCutoff = std::max(enclosingScreen.x() - widgetRectInScr een.x(), 0) + std::max(widgetRectInScreen.maxX() - enclosingScreen.maxX(), 0);
126 unsigned inverseCutoff = std::max(enclosingScreen.x() - inverseWidgetRec tInScreen.x(), 0) + std::max(inverseWidgetRectInScreen.maxX() - enclosingScreen. 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 FloatRect screen = screenAvailableRect(m_frameView.get());
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().rootViewToScreen(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 FloatRect 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->abandon();
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 RenderMenuList 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->abandon();
355 }
356
357 void PopupContainer::paint(GraphicsContext* gc, const IntRect& rect)
358 {
359 // Adjust coords for scrolled frame.
360 IntRect r = intersection(rect, frameRect());
361 int tx = x();
362 int ty = y();
363
364 r.move(-tx, -ty);
365
366 gc->translate(static_cast<float>(tx), static_cast<float>(ty));
367 m_listBox->paint(gc, r);
368 gc->translate(-static_cast<float>(tx), -static_cast<float>(ty));
369
370 paintBorder(gc, rect);
371 }
372
373 void PopupContainer::paintBorder(GraphicsContext* gc, const IntRect& rect)
374 {
375 // FIXME: Where do we get the border color from?
376 Color borderColor(127, 157, 185);
377
378 gc->setStrokeStyle(NoStroke);
379 gc->setFillColor(borderColor);
380
381 int tx = x();
382 int ty = y();
383
384 // top, left, bottom, right
385 gc->drawRect(IntRect(tx, ty, width(), borderSize));
386 gc->drawRect(IntRect(tx, ty, borderSize, height()));
387 gc->drawRect(IntRect(tx, ty + height() - borderSize, width(), borderSize));
388 gc->drawRect(IntRect(tx + width() - borderSize, ty, borderSize, height()));
389 }
390
391 bool PopupContainer::isInterestedInEventForKey(int keyCode)
392 {
393 return m_listBox->isInterestedInEventForKey(keyCode);
394 }
395
396 ChromeClient& PopupContainer::chromeClient()
397 {
398 return m_frameView->frame().page()->chrome().client();
399 }
400
401 void PopupContainer::showInRect(const FloatQuad& controlPosition, const IntSize& controlSize, FrameView* v, int index)
402 {
403 // The controlSize is the size of the select box. It's usually larger than
404 // we need. Subtract border size so that usually the container will be
405 // displayed exactly the same width as the select box.
406 m_listBox->setBaseWidth(std::max(controlSize.width() - borderSize * 2, 0));
407
408 m_listBox->updateFromElement();
409
410 // We set the selected item in updateFromElement(), and disregard the
411 // index passed into this function (same as Webkit's PopupMenuWin.cpp)
412 // FIXME: make sure this is correct, and add an assertion.
413 // ASSERT(popupWindow(popup)->listBox()->selectedIndex() == index);
414
415 // Save and convert the controlPosition to main window coords. Each point is converted separately
416 // to window coordinates because the control could be in a transformed webvi ew and then each point
417 // would be transformed by a different delta.
418 m_controlPosition.setP1(v->contentsToWindow(IntPoint(controlPosition.p1().x( ), controlPosition.p1().y())));
419 m_controlPosition.setP2(v->contentsToWindow(IntPoint(controlPosition.p2().x( ), controlPosition.p2().y())));
420 m_controlPosition.setP3(v->contentsToWindow(IntPoint(controlPosition.p3().x( ), controlPosition.p3().y())));
421 m_controlPosition.setP4(v->contentsToWindow(IntPoint(controlPosition.p4().x( ), controlPosition.p4().y())));
422
423 m_controlSize = controlSize;
424
425 // Position at (0, 0) since the frameRect().location() is relative to the
426 // parent WebWidget.
427 setFrameRect(IntRect(IntPoint(), controlSize));
428 showPopup(v);
429 }
430
431 IntRect PopupContainer::refresh(const IntRect& targetControlRect)
432 {
433 m_listBox->setBaseWidth(std::max(m_controlSize.width() - borderSize * 2, 0)) ;
434 m_listBox->updateFromElement();
435
436 IntPoint locationInWindow = m_frameView->contentsToWindow(targetControlRect. location());
437
438 // Move it below the select widget.
439 locationInWindow.move(0, targetControlRect.height());
440
441 IntRect widgetRectInScreen = layoutAndCalculateWidgetRect(targetControlRect. height(), IntSize(), locationInWindow);
442
443 // Reset the size (which can be set to the PopupListBox size in
444 // layoutAndGetRTLOffset(), exceeding the available widget rectangle.)
445 if (size() != widgetRectInScreen.size())
446 resize(widgetRectInScreen.size());
447
448 invalidate();
449
450 return widgetRectInScreen;
451 }
452
453 inline bool PopupContainer::isRTL() const
454 {
455 return m_listBox->m_popupClient->menuStyle().textDirection() == RTL;
456 }
457
458 int PopupContainer::selectedIndex() const
459 {
460 return m_listBox->selectedIndex();
461 }
462
463 int PopupContainer::menuItemHeight() const
464 {
465 return m_listBox->getRowHeight(0);
466 }
467
468 int PopupContainer::menuItemFontSize() const
469 {
470 return m_listBox->getRowFont(0).fontDescription().computedSize();
471 }
472
473 PopupMenuStyle PopupContainer::menuStyle() const
474 {
475 return m_listBox->m_popupClient->menuStyle();
476 }
477
478 const WTF::Vector<PopupItem*>& PopupContainer:: popupData() const
479 {
480 return m_listBox->items();
481 }
482
483 String PopupContainer::getSelectedItemToolTip()
484 {
485 // We cannot use m_popupClient->selectedIndex() to choose tooltip message,
486 // because the selectedIndex() might return final selected index, not
487 // hovering selection.
488 return m_listBox->m_popupClient->itemToolTip(m_listBox->m_selectedIndex);
489 }
490
491 void PopupContainer::popupOpened(const IntRect& bounds)
492 {
493 WebViewImpl* webView = WebViewImpl::fromPage(m_frameView->frame().page());
494 if (!webView->client())
495 return;
496
497 WebWidget* webwidget = webView->client()->createPopupMenu(WebPopupTypeSelect );
498 if (!webwidget)
499 return;
500 // We only notify when the WebView has to handle the popup, as when
501 // the popup is handled externally, the fact that a popup is showing is
502 // transparent to the WebView.
503 webView->popupOpened(this);
504 toWebPopupMenuImpl(webwidget)->initialize(this, bounds);
505 }
506
507 void PopupContainer::getPopupMenuInfo(WebPopupMenuInfo* info)
508 {
509 const Vector<PopupItem*>& inputItems = popupData();
510
511 WebVector<WebMenuItemInfo> outputItems(inputItems.size());
512
513 for (size_t i = 0; i < inputItems.size(); ++i) {
514 const PopupItem& inputItem = *inputItems[i];
515 WebMenuItemInfo& outputItem = outputItems[i];
516
517 outputItem.label = inputItem.label;
518 outputItem.enabled = inputItem.enabled;
519 outputItem.textDirection = toWebTextDirection(inputItem.textDirection);
520 outputItem.hasTextDirectionOverride = inputItem.hasTextDirectionOverride ;
521
522 switch (inputItem.type) {
523 case PopupItem::TypeOption:
524 outputItem.type = WebMenuItemInfo::Option;
525 break;
526 case PopupItem::TypeGroup:
527 outputItem.type = WebMenuItemInfo::Group;
528 break;
529 case PopupItem::TypeSeparator:
530 outputItem.type = WebMenuItemInfo::Separator;
531 break;
532 }
533 }
534
535 info->itemHeight = menuItemHeight();
536 info->itemFontSize = menuItemFontSize();
537 info->selectedIndex = selectedIndex();
538 info->items.swap(outputItems);
539 info->rightAligned = menuStyle().textDirection() == RTL;
540 }
541
542 void PopupContainer::invalidateRect(const IntRect& rect)
543 {
544 if (HostWindow* h = hostWindow())
545 h->invalidateContentsAndRootView(rect);
546 }
547
548 HostWindow* PopupContainer::hostWindow() const
549 {
550 return const_cast<PopupContainerClient*>(m_client);
551 }
552
553 IntPoint PopupContainer::convertChildToSelf(const Widget* child, const IntPoint& point) const
554 {
555 IntPoint newPoint = point;
556 newPoint.moveBy(child->location());
557 return newPoint;
558 }
559
560 IntPoint PopupContainer::convertSelfToChild(const Widget* child, const IntPoint& point) const
561 {
562 IntPoint newPoint = point;
563 newPoint.moveBy(-child->location());
564 return newPoint;
565 }
566
567 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698