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

Side by Side Diff: Source/WebCore/platform/win/PopupMenuWin.cpp

Issue 13642009: WebCore: Remove PLATFORM(WIN) files we do not use. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 7 years, 8 months 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
« no previous file with comments | « Source/WebCore/platform/win/PopupMenuWin.h ('k') | Source/WebCore/platform/win/RunLoopWin.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * Copyright (C) 2006, 2007, 2008, 2011 Apple Inc. All rights reserved.
3 * Copyright (C) 2007-2009 Torch Mobile Inc.
4 * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public License
17 * along with this library; see the file COPYING.LIB. If not, write to
18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20 *
21 */
22
23 #include "config.h"
24 #include "PopupMenuWin.h"
25
26 #include "BitmapInfo.h"
27 #include "Document.h"
28 #include "FloatRect.h"
29 #include "FontSelector.h"
30 #include "Frame.h"
31 #include "FrameView.h"
32 #include "GraphicsContext.h"
33 #include "HTMLNames.h"
34 #include "HWndDC.h"
35 #include "HostWindow.h"
36 #include "LengthFunctions.h"
37 #include "Page.h"
38 #include "PlatformMouseEvent.h"
39 #include "PlatformScreen.h"
40 #include "RenderMenuList.h"
41 #include "RenderTheme.h"
42 #include "RenderView.h"
43 #include "Scrollbar.h"
44 #include "ScrollbarTheme.h"
45 #include "SimpleFontData.h"
46 #include "TextRun.h"
47 #include "WebCoreInstanceHandle.h"
48 #include "WindowsExtras.h"
49
50 #include <windows.h>
51 #include <windowsx.h>
52 #if OS(WINCE)
53 #include <ResDefCE.h>
54 #define MAKEPOINTS(l) (*((POINTS FAR *)&(l)))
55 #endif
56
57 #define HIGH_BIT_MASK_SHORT 0x8000
58
59 using std::min;
60
61 namespace WebCore {
62
63 using namespace HTMLNames;
64
65 // Default Window animation duration in milliseconds
66 static const int defaultAnimationDuration = 200;
67 // Maximum height of a popup window
68 static const int maxPopupHeight = 320;
69
70 const int optionSpacingMiddle = 1;
71 const int popupWindowBorderWidth = 1;
72
73 static LPCWSTR kPopupWindowClassName = L"PopupWindowClass";
74
75 // This is used from within our custom message pump when we want to send a
76 // message to the web view and not have our message stolen and sent to
77 // the popup window.
78 static const UINT WM_HOST_WINDOW_FIRST = WM_USER;
79 static const UINT WM_HOST_WINDOW_CHAR = WM_USER + WM_CHAR;
80 static const UINT WM_HOST_WINDOW_MOUSEMOVE = WM_USER + WM_MOUSEMOVE;
81
82 // FIXME: Remove this as soon as practical.
83 static inline bool isASCIIPrintable(unsigned c)
84 {
85 return c >= 0x20 && c <= 0x7E;
86 }
87
88 static void translatePoint(LPARAM& lParam, HWND from, HWND to)
89 {
90 POINT pt;
91 pt.x = (short)GET_X_LPARAM(lParam);
92 pt.y = (short)GET_Y_LPARAM(lParam);
93 ::MapWindowPoints(from, to, &pt, 1);
94 lParam = MAKELPARAM(pt.x, pt.y);
95 }
96
97 static FloatRect monitorFromHwnd(HWND hwnd)
98 {
99 HMONITOR monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY);
100 MONITORINFOEX monitorInfo;
101 monitorInfo.cbSize = sizeof(MONITORINFOEX);
102 GetMonitorInfo(monitor, &monitorInfo);
103 return monitorInfo.rcWork;
104 }
105
106 PopupMenuWin::PopupMenuWin(PopupMenuClient* client)
107 : m_popupClient(client)
108 , m_scrollbar(0)
109 , m_popup(0)
110 , m_DC(0)
111 , m_bmp(0)
112 , m_wasClicked(false)
113 , m_itemHeight(0)
114 , m_scrollOffset(0)
115 , m_wheelDelta(0)
116 , m_focusedIndex(0)
117 , m_scrollbarCapturingMouse(false)
118 , m_showPopup(false)
119 {
120 }
121
122 PopupMenuWin::~PopupMenuWin()
123 {
124 if (m_bmp)
125 ::DeleteObject(m_bmp);
126 if (m_DC)
127 ::DeleteDC(m_DC);
128 if (m_popup)
129 ::DestroyWindow(m_popup);
130 if (m_scrollbar)
131 m_scrollbar->setParent(0);
132 }
133
134 void PopupMenuWin::disconnectClient()
135 {
136 m_popupClient = 0;
137 }
138
139 LPCWSTR PopupMenuWin::popupClassName()
140 {
141 return kPopupWindowClassName;
142 }
143
144 void PopupMenuWin::show(const IntRect& r, FrameView* view, int index)
145 {
146 calculatePositionAndSize(r, view);
147 if (clientRect().isEmpty())
148 return;
149
150 HWND hostWindow = view->hostWindow()->platformPageClient();
151
152 if (!m_scrollbar && visibleItems() < client()->listSize()) {
153 // We need a scroll bar
154 m_scrollbar = client()->createScrollbar(this, VerticalScrollbar, SmallSc rollbar);
155 m_scrollbar->styleChanged();
156 }
157
158 // We need to reposition the popup window to its final coordinates.
159 // Before calling this, the popup hwnd is currently the size of and at the l ocation of the menu list client so it needs to be updated.
160 ::MoveWindow(m_popup, m_windowRect.x(), m_windowRect.y(), m_windowRect.width (), m_windowRect.height(), false);
161
162 // Determine whether we should animate our popups
163 // Note: Must use 'BOOL' and 'FALSE' instead of 'bool' and 'false' to avoid stack corruption with SystemParametersInfo
164 BOOL shouldAnimate = FALSE;
165 #if !OS(WINCE)
166 ::SystemParametersInfo(SPI_GETCOMBOBOXANIMATION, 0, &shouldAnimate, 0);
167
168 if (shouldAnimate) {
169 RECT viewRect = {0};
170 ::GetWindowRect(hostWindow, &viewRect);
171 if (!::IsRectEmpty(&viewRect))
172 ::AnimateWindow(m_popup, defaultAnimationDuration, AW_BLEND);
173 } else
174 #endif
175 ::ShowWindow(m_popup, SW_SHOWNOACTIVATE);
176
177 if (client()) {
178 int index = client()->selectedIndex();
179 if (index >= 0)
180 setFocusedIndex(index);
181 }
182
183 m_showPopup = true;
184
185 // Protect the popup menu in case its owner is destroyed while we're running the message pump.
186 RefPtr<PopupMenu> protect(this);
187
188 ::SetCapture(hostWindow);
189
190 MSG msg;
191 HWND activeWindow;
192
193 while (::GetMessage(&msg, 0, 0, 0)) {
194 switch (msg.message) {
195 case WM_HOST_WINDOW_MOUSEMOVE:
196 case WM_HOST_WINDOW_CHAR:
197 if (msg.hwnd == m_popup) {
198 // This message should be sent to the host window.
199 msg.hwnd = hostWindow;
200 msg.message -= WM_HOST_WINDOW_FIRST;
201 }
202 break;
203
204 // Steal mouse messages.
205 #if !OS(WINCE)
206 case WM_NCMOUSEMOVE:
207 case WM_NCLBUTTONDOWN:
208 case WM_NCLBUTTONUP:
209 case WM_NCLBUTTONDBLCLK:
210 case WM_NCRBUTTONDOWN:
211 case WM_NCRBUTTONUP:
212 case WM_NCRBUTTONDBLCLK:
213 case WM_NCMBUTTONDOWN:
214 case WM_NCMBUTTONUP:
215 case WM_NCMBUTTONDBLCLK:
216 #endif
217 case WM_MOUSEWHEEL:
218 msg.hwnd = m_popup;
219 break;
220
221 // These mouse messages use client coordinates so we need to convert them.
222 case WM_MOUSEMOVE:
223 case WM_LBUTTONDOWN:
224 case WM_LBUTTONUP:
225 case WM_LBUTTONDBLCLK:
226 case WM_RBUTTONDOWN:
227 case WM_RBUTTONUP:
228 case WM_RBUTTONDBLCLK:
229 case WM_MBUTTONDOWN:
230 case WM_MBUTTONUP:
231 case WM_MBUTTONDBLCLK: {
232 // Translate the coordinate.
233 translatePoint(msg.lParam, msg.hwnd, m_popup);
234
235 msg.hwnd = m_popup;
236 break;
237 }
238
239 // Steal all keyboard messages.
240 case WM_KEYDOWN:
241 case WM_KEYUP:
242 case WM_CHAR:
243 case WM_DEADCHAR:
244 case WM_SYSKEYDOWN:
245 case WM_SYSKEYUP:
246 case WM_SYSCHAR:
247 case WM_SYSDEADCHAR:
248 msg.hwnd = m_popup;
249 break;
250 }
251
252 ::TranslateMessage(&msg);
253 ::DispatchMessage(&msg);
254
255 if (!m_popupClient)
256 break;
257
258 if (!m_showPopup)
259 break;
260 activeWindow = ::GetActiveWindow();
261 if (activeWindow != hostWindow && !::IsChild(activeWindow, hostWindow))
262 break;
263 if (::GetCapture() != hostWindow)
264 break;
265 }
266
267 if (::GetCapture() == hostWindow)
268 ::ReleaseCapture();
269
270 // We're done, hide the popup if necessary.
271 hide();
272 }
273
274 void PopupMenuWin::hide()
275 {
276 if (!m_showPopup)
277 return;
278
279 m_showPopup = false;
280
281 ::ShowWindow(m_popup, SW_HIDE);
282
283 if (client())
284 client()->popupDidHide();
285
286 // Post a WM_NULL message to wake up the message pump if necessary.
287 ::PostMessage(m_popup, WM_NULL, 0, 0);
288 }
289
290 // The screen that the popup is placed on should be whichever one the popup menu button lies on.
291 // We fake an hwnd (here we use the popup's hwnd) on top of the button which we can then use to determine the screen.
292 // We can then proceed with our final position/size calculations.
293 void PopupMenuWin::calculatePositionAndSize(const IntRect& r, FrameView* v)
294 {
295 // First get the screen coordinates of the popup menu client.
296 HWND hostWindow = v->hostWindow()->platformPageClient();
297 IntRect absoluteBounds = ((RenderMenuList*)m_popupClient)->absoluteBoundingB oxRect();
298 IntRect absoluteScreenCoords(v->contentsToWindow(absoluteBounds.location()), absoluteBounds.size());
299 POINT absoluteLocation(absoluteScreenCoords.location());
300 if (!::ClientToScreen(v->hostWindow()->platformPageClient(), &absoluteLocati on))
301 return;
302 absoluteScreenCoords.setLocation(absoluteLocation);
303
304 // Now set the popup menu's location temporarily to these coordinates so we can determine which screen the popup should lie on.
305 // We create or move m_popup as necessary.
306 if (!m_popup) {
307 registerClass();
308 DWORD exStyle = WS_EX_LTRREADING;
309 m_popup = ::CreateWindowExW(exStyle, kPopupWindowClassName, L"PopupMenu" ,
310 WS_POPUP | WS_BORDER,
311 absoluteScreenCoords.x(), absoluteScreenCoords.y(), absoluteScreenCo ords.width(), absoluteScreenCoords.height(),
312 hostWindow, 0, WebCore::instanceHandle(), this);
313
314 if (!m_popup)
315 return;
316 } else
317 ::MoveWindow(m_popup, absoluteScreenCoords.x(), absoluteScreenCoords.y() , absoluteScreenCoords.width(), absoluteScreenCoords.height(), false);
318
319 FloatRect screen = monitorFromHwnd(m_popup);
320
321 // Now we determine the actual location and measurements of the popup itself .
322 // r is in absolute document coordinates, but we want to be in screen coordi nates.
323
324 // First, move to WebView coordinates
325 IntRect rScreenCoords(v->contentsToWindow(r.location()), r.size());
326
327 // Then, translate to screen coordinates
328 POINT location(rScreenCoords.location());
329 if (!::ClientToScreen(v->hostWindow()->platformPageClient(), &location))
330 return;
331
332 rScreenCoords.setLocation(location);
333
334 // First, determine the popup's height
335 int itemCount = client()->listSize();
336 m_itemHeight = client()->menuStyle().font().fontMetrics().height() + optionS pacingMiddle;
337 int naturalHeight = m_itemHeight * itemCount;
338 int popupHeight = min(maxPopupHeight, naturalHeight);
339 // The popup should show an integral number of items (i.e. no partial items should be visible)
340 popupHeight -= popupHeight % m_itemHeight;
341
342 // Next determine its width
343 int popupWidth = 0;
344 for (int i = 0; i < itemCount; ++i) {
345 String text = client()->itemText(i);
346 if (text.isEmpty())
347 continue;
348
349 Font itemFont = client()->menuStyle().font();
350 if (client()->itemIsLabel(i)) {
351 FontDescription d = itemFont.fontDescription();
352 d.setWeight(d.bolderWeight());
353 itemFont = Font(d, itemFont.letterSpacing(), itemFont.wordSpacing()) ;
354 itemFont.update(m_popupClient->fontSelector());
355 }
356
357 popupWidth = max(popupWidth, static_cast<int>(ceilf(itemFont.width(TextR un(text.characters(), text.length())))));
358 }
359
360 if (naturalHeight > maxPopupHeight)
361 // We need room for a scrollbar
362 popupWidth += ScrollbarTheme::theme()->scrollbarThickness(SmallScrollbar );
363
364 // Add padding to align the popup text with the <select> text
365 popupWidth += max<int>(0, client()->clientPaddingRight() - client()->clientI nsetRight()) + max<int>(0, client()->clientPaddingLeft() - client()->clientInset Left());
366
367 // Leave room for the border
368 popupWidth += 2 * popupWindowBorderWidth;
369 popupHeight += 2 * popupWindowBorderWidth;
370
371 // The popup should be at least as wide as the control on the page
372 popupWidth = max(rScreenCoords.width() - client()->clientInsetLeft() - clien t()->clientInsetRight(), popupWidth);
373
374 // Always left-align items in the popup. This matches popup menus on the ma c.
375 int popupX = rScreenCoords.x() + client()->clientInsetLeft();
376
377 IntRect popupRect(popupX, rScreenCoords.maxY(), popupWidth, popupHeight);
378
379 // Check that we don't go off the screen vertically
380 if (popupRect.maxY() > screen.height()) {
381 // The popup will go off the screen, so try placing it above the client
382 if (rScreenCoords.y() - popupRect.height() < 0) {
383 // The popup won't fit above, either, so place it whereever's bigger and resize it to fit
384 if ((rScreenCoords.y() + rScreenCoords.height() / 2) < (screen.heigh t() / 2)) {
385 // Below is bigger
386 popupRect.setHeight(screen.height() - popupRect.y());
387 } else {
388 // Above is bigger
389 popupRect.setY(0);
390 popupRect.setHeight(rScreenCoords.y());
391 }
392 } else {
393 // The popup fits above, so reposition it
394 popupRect.setY(rScreenCoords.y() - popupRect.height());
395 }
396 }
397
398 // Check that we don't go off the screen horizontally
399 if (popupRect.x() + popupRect.width() > screen.width() + screen.x())
400 popupRect.setX(screen.x() + screen.width() - popupRect.width());
401 if (popupRect.x() < screen.x())
402 popupRect.setX(screen.x());
403
404 m_windowRect = popupRect;
405 return;
406 }
407
408 bool PopupMenuWin::setFocusedIndex(int i, bool hotTracking)
409 {
410 if (i < 0 || i >= client()->listSize() || i == focusedIndex())
411 return false;
412
413 if (!client()->itemIsEnabled(i))
414 return false;
415
416 invalidateItem(focusedIndex());
417 invalidateItem(i);
418
419 m_focusedIndex = i;
420
421 if (!hotTracking)
422 client()->setTextFromItem(i);
423
424 if (!scrollToRevealSelection())
425 ::UpdateWindow(m_popup);
426
427 return true;
428 }
429
430 int PopupMenuWin::visibleItems() const
431 {
432 return clientRect().height() / m_itemHeight;
433 }
434
435 int PopupMenuWin::listIndexAtPoint(const IntPoint& point) const
436 {
437 return m_scrollOffset + point.y() / m_itemHeight;
438 }
439
440 int PopupMenuWin::focusedIndex() const
441 {
442 return m_focusedIndex;
443 }
444
445 void PopupMenuWin::focusFirst()
446 {
447 if (!client())
448 return;
449
450 int size = client()->listSize();
451
452 for (int i = 0; i < size; ++i)
453 if (client()->itemIsEnabled(i)) {
454 setFocusedIndex(i);
455 break;
456 }
457 }
458
459 void PopupMenuWin::focusLast()
460 {
461 if (!client())
462 return;
463
464 int size = client()->listSize();
465
466 for (int i = size - 1; i > 0; --i)
467 if (client()->itemIsEnabled(i)) {
468 setFocusedIndex(i);
469 break;
470 }
471 }
472
473 bool PopupMenuWin::down(unsigned lines)
474 {
475 if (!client())
476 return false;
477
478 int size = client()->listSize();
479
480 int lastSelectableIndex, selectedListIndex;
481 lastSelectableIndex = selectedListIndex = focusedIndex();
482 for (int i = selectedListIndex + 1; i >= 0 && i < size; ++i)
483 if (client()->itemIsEnabled(i)) {
484 lastSelectableIndex = i;
485 if (i >= selectedListIndex + (int)lines)
486 break;
487 }
488
489 return setFocusedIndex(lastSelectableIndex);
490 }
491
492 bool PopupMenuWin::up(unsigned lines)
493 {
494 if (!client())
495 return false;
496
497 int size = client()->listSize();
498
499 int lastSelectableIndex, selectedListIndex;
500 lastSelectableIndex = selectedListIndex = focusedIndex();
501 for (int i = selectedListIndex - 1; i >= 0 && i < size; --i)
502 if (client()->itemIsEnabled(i)) {
503 lastSelectableIndex = i;
504 if (i <= selectedListIndex - (int)lines)
505 break;
506 }
507
508 return setFocusedIndex(lastSelectableIndex);
509 }
510
511 void PopupMenuWin::invalidateItem(int index)
512 {
513 if (!m_popup)
514 return;
515
516 IntRect damageRect(clientRect());
517 damageRect.setY(m_itemHeight * (index - m_scrollOffset));
518 damageRect.setHeight(m_itemHeight);
519 if (m_scrollbar)
520 damageRect.setWidth(damageRect.width() - m_scrollbar->frameRect().width( ));
521
522 RECT r = damageRect;
523 ::InvalidateRect(m_popup, &r, TRUE);
524 }
525
526 IntRect PopupMenuWin::clientRect() const
527 {
528 IntRect clientRect = m_windowRect;
529 clientRect.inflate(-popupWindowBorderWidth);
530 clientRect.setLocation(IntPoint(0, 0));
531 return clientRect;
532 }
533
534 void PopupMenuWin::incrementWheelDelta(int delta)
535 {
536 m_wheelDelta += delta;
537 }
538
539 void PopupMenuWin::reduceWheelDelta(int delta)
540 {
541 ASSERT(delta >= 0);
542 ASSERT(delta <= abs(m_wheelDelta));
543
544 if (m_wheelDelta > 0)
545 m_wheelDelta -= delta;
546 else if (m_wheelDelta < 0)
547 m_wheelDelta += delta;
548 else
549 return;
550 }
551
552 bool PopupMenuWin::scrollToRevealSelection()
553 {
554 if (!m_scrollbar)
555 return false;
556
557 int index = focusedIndex();
558
559 if (index < m_scrollOffset) {
560 ScrollableArea::scrollToOffsetWithoutAnimation(VerticalScrollbar, index) ;
561 return true;
562 }
563
564 if (index >= m_scrollOffset + visibleItems()) {
565 ScrollableArea::scrollToOffsetWithoutAnimation(VerticalScrollbar, index - visibleItems() + 1);
566 return true;
567 }
568
569 return false;
570 }
571
572 void PopupMenuWin::updateFromElement()
573 {
574 if (!m_popup)
575 return;
576
577 m_focusedIndex = client()->selectedIndex();
578
579 ::InvalidateRect(m_popup, 0, TRUE);
580 if (!scrollToRevealSelection())
581 ::UpdateWindow(m_popup);
582 }
583
584 const int separatorPadding = 4;
585 const int separatorHeight = 1;
586 void PopupMenuWin::paint(const IntRect& damageRect, HDC hdc)
587 {
588 if (!m_popup)
589 return;
590
591 if (!m_DC) {
592 m_DC = ::CreateCompatibleDC(HWndDC(m_popup));
593 if (!m_DC)
594 return;
595 }
596
597 if (m_bmp) {
598 bool keepBitmap = false;
599 BITMAP bitmap;
600 if (GetObject(m_bmp, sizeof(bitmap), &bitmap))
601 keepBitmap = bitmap.bmWidth == clientRect().width()
602 && bitmap.bmHeight == clientRect().height();
603 if (!keepBitmap) {
604 DeleteObject(m_bmp);
605 m_bmp = 0;
606 }
607 }
608 if (!m_bmp) {
609 #if OS(WINCE)
610 BitmapInfo bitmapInfo = BitmapInfo::createBottomUp(clientRect().size(), BitmapInfo::BitCount16);
611 #else
612 BitmapInfo bitmapInfo = BitmapInfo::createBottomUp(clientRect().size());
613 #endif
614 void* pixels = 0;
615 m_bmp = ::CreateDIBSection(m_DC, &bitmapInfo, DIB_RGB_COLORS, &pixels, 0 , 0);
616 if (!m_bmp)
617 return;
618
619 ::SelectObject(m_DC, m_bmp);
620 }
621
622 GraphicsContext context(m_DC);
623
624 int itemCount = client()->listSize();
625
626 // listRect is the damageRect translated into the coordinates of the entire menu list (which is itemCount * m_itemHeight pixels tall)
627 IntRect listRect = damageRect;
628 listRect.move(IntSize(0, m_scrollOffset * m_itemHeight));
629
630 for (int y = listRect.y(); y < listRect.maxY(); y += m_itemHeight) {
631 int index = y / m_itemHeight;
632
633 Color optionBackgroundColor, optionTextColor;
634 PopupMenuStyle itemStyle = client()->itemStyle(index);
635 if (index == focusedIndex()) {
636 optionBackgroundColor = RenderTheme::defaultTheme()->activeListBoxSe lectionBackgroundColor();
637 optionTextColor = RenderTheme::defaultTheme()->activeListBoxSelectio nForegroundColor();
638 } else {
639 optionBackgroundColor = itemStyle.backgroundColor();
640 optionTextColor = itemStyle.foregroundColor();
641 }
642
643 // itemRect is in client coordinates
644 IntRect itemRect(0, (index - m_scrollOffset) * m_itemHeight, damageRect. width(), m_itemHeight);
645
646 // Draw the background for this menu item
647 if (itemStyle.isVisible())
648 context.fillRect(itemRect, optionBackgroundColor, ColorSpaceDeviceRG B);
649
650 if (client()->itemIsSeparator(index)) {
651 IntRect separatorRect(itemRect.x() + separatorPadding, itemRect.y() + (itemRect.height() - separatorHeight) / 2, itemRect.width() - 2 * separatorPad ding, separatorHeight);
652 context.fillRect(separatorRect, optionTextColor, ColorSpaceDeviceRGB );
653 continue;
654 }
655
656 String itemText = client()->itemText(index);
657
658 TextDirection direction = (itemText.defaultWritingDirection() == WTF::Un icode::RightToLeft) ? RTL : LTR;
659 TextRun textRun(itemText, 0, 0, TextRun::AllowTrailingExpansion, directi on);
660
661 context.setFillColor(optionTextColor, ColorSpaceDeviceRGB);
662
663 Font itemFont = client()->menuStyle().font();
664 if (client()->itemIsLabel(index)) {
665 FontDescription d = itemFont.fontDescription();
666 d.setWeight(d.bolderWeight());
667 itemFont = Font(d, itemFont.letterSpacing(), itemFont.wordSpacing()) ;
668 itemFont.update(m_popupClient->fontSelector());
669 }
670
671 // Draw the item text
672 if (itemStyle.isVisible()) {
673 int textX = max<int>(0, client()->clientPaddingLeft() - client()->cl ientInsetLeft());
674 if (RenderTheme::defaultTheme()->popupOptionSupportsTextIndent() && itemStyle.textDirection() == LTR)
675 textX += minimumIntValueForLength(itemStyle.textIndent(), itemRe ct.width());
676 int textY = itemRect.y() + itemFont.fontMetrics().ascent() + (itemRe ct.height() - itemFont.fontMetrics().height()) / 2;
677 context.drawBidiText(itemFont, textRun, IntPoint(textX, textY));
678 }
679 }
680
681 if (m_scrollbar)
682 m_scrollbar->paint(&context, damageRect);
683
684 HWndDC hWndDC;
685 HDC localDC = hdc ? hdc : hWndDC.setHWnd(m_popup);
686
687 ::BitBlt(localDC, damageRect.x(), damageRect.y(), damageRect.width(), damage Rect.height(), m_DC, damageRect.x(), damageRect.y(), SRCCOPY);
688 }
689
690 int PopupMenuWin::scrollSize(ScrollbarOrientation orientation) const
691 {
692 return ((orientation == VerticalScrollbar) && m_scrollbar) ? (m_scrollbar->t otalSize() - m_scrollbar->visibleSize()) : 0;
693 }
694
695 int PopupMenuWin::scrollPosition(Scrollbar*) const
696 {
697 return m_scrollOffset;
698 }
699
700 void PopupMenuWin::setScrollOffset(const IntPoint& offset)
701 {
702 scrollTo(offset.y());
703 }
704
705 void PopupMenuWin::scrollTo(int offset)
706 {
707 ASSERT(m_scrollbar);
708
709 if (!m_popup)
710 return;
711
712 if (m_scrollOffset == offset)
713 return;
714
715 int scrolledLines = m_scrollOffset - offset;
716 m_scrollOffset = offset;
717
718 UINT flags = SW_INVALIDATE;
719
720 #ifdef CAN_SET_SMOOTH_SCROLLING_DURATION
721 BOOL shouldSmoothScroll = FALSE;
722 ::SystemParametersInfo(SPI_GETLISTBOXSMOOTHSCROLLING, 0, &shouldSmoothScroll , 0);
723 if (shouldSmoothScroll)
724 flags |= MAKEWORD(SW_SMOOTHSCROLL, smoothScrollAnimationDuration);
725 #endif
726
727 IntRect listRect = clientRect();
728 if (m_scrollbar)
729 listRect.setWidth(listRect.width() - m_scrollbar->frameRect().width());
730 RECT r = listRect;
731 ::ScrollWindowEx(m_popup, 0, scrolledLines * m_itemHeight, &r, 0, 0, 0, flag s);
732 if (m_scrollbar) {
733 r = m_scrollbar->frameRect();
734 ::InvalidateRect(m_popup, &r, TRUE);
735 }
736 ::UpdateWindow(m_popup);
737 }
738
739 void PopupMenuWin::invalidateScrollbarRect(Scrollbar* scrollbar, const IntRect& rect)
740 {
741 IntRect scrollRect = rect;
742 scrollRect.move(scrollbar->x(), scrollbar->y());
743 RECT r = scrollRect;
744 ::InvalidateRect(m_popup, &r, false);
745 }
746
747 int PopupMenuWin::visibleHeight() const
748 {
749 return m_scrollbar ? m_scrollbar->visibleSize() : m_windowRect.height();
750 }
751
752 int PopupMenuWin::visibleWidth() const
753 {
754 return m_windowRect.width();
755 }
756
757 IntSize PopupMenuWin::contentsSize() const
758 {
759 return m_windowRect.size();
760 }
761
762 bool PopupMenuWin::scrollbarsCanBeActive() const
763 {
764 return m_showPopup;
765 }
766
767 IntRect PopupMenuWin::scrollableAreaBoundingBox() const
768 {
769 return m_windowRect;
770 }
771
772 void PopupMenuWin::registerClass()
773 {
774 static bool haveRegisteredWindowClass = false;
775
776 if (haveRegisteredWindowClass)
777 return;
778
779 #if OS(WINCE)
780 WNDCLASS wcex;
781 #else
782 WNDCLASSEX wcex;
783 wcex.cbSize = sizeof(WNDCLASSEX);
784 wcex.hIconSm = 0;
785 wcex.style = CS_DROPSHADOW;
786 #endif
787
788 wcex.lpfnWndProc = PopupMenuWndProc;
789 wcex.cbClsExtra = 0;
790 wcex.cbWndExtra = sizeof(PopupMenu*); // For the PopupMenu pointer
791 wcex.hInstance = WebCore::instanceHandle();
792 wcex.hIcon = 0;
793 wcex.hCursor = LoadCursor(0, IDC_ARROW);
794 wcex.hbrBackground = 0;
795 wcex.lpszMenuName = 0;
796 wcex.lpszClassName = kPopupWindowClassName;
797
798 haveRegisteredWindowClass = true;
799
800 #if OS(WINCE)
801 RegisterClass(&wcex);
802 #else
803 RegisterClassEx(&wcex);
804 #endif
805 }
806
807
808 LRESULT CALLBACK PopupMenuWin::PopupMenuWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
809 {
810 if (PopupMenuWin* popup = static_cast<PopupMenuWin*>(getWindowPointer(hWnd, 0)))
811 return popup->wndProc(hWnd, message, wParam, lParam);
812
813 if (message == WM_CREATE) {
814 LPCREATESTRUCT createStruct = reinterpret_cast<LPCREATESTRUCT>(lParam);
815
816 // Associate the PopupMenu with the window.
817 setWindowPointer(hWnd, 0, createStruct->lpCreateParams);
818 return 0;
819 }
820
821 return ::DefWindowProc(hWnd, message, wParam, lParam);
822 }
823
824 const int smoothScrollAnimationDuration = 5000;
825
826 LRESULT PopupMenuWin::wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lPa ram)
827 {
828 LRESULT lResult = 0;
829
830 switch (message) {
831 #if !OS(WINCE)
832 case WM_MOUSEACTIVATE:
833 return MA_NOACTIVATE;
834 #endif
835 case WM_SIZE: {
836 if (!scrollbar())
837 break;
838
839 IntSize size(LOWORD(lParam), HIWORD(lParam));
840 scrollbar()->setFrameRect(IntRect(size.width() - scrollbar()->width( ), 0, scrollbar()->width(), size.height()));
841
842 int visibleItems = this->visibleItems();
843 scrollbar()->setEnabled(visibleItems < client()->listSize());
844 scrollbar()->setSteps(1, max(1, visibleItems - 1));
845 scrollbar()->setProportion(visibleItems, client()->listSize());
846
847 break;
848 }
849 case WM_SYSKEYDOWN:
850 case WM_KEYDOWN: {
851 if (!client())
852 break;
853
854 bool altKeyPressed = GetKeyState(VK_MENU) & HIGH_BIT_MASK_SHORT;
855 bool ctrlKeyPressed = GetKeyState(VK_CONTROL) & HIGH_BIT_MASK_SHORT;
856
857 lResult = 0;
858 switch (LOWORD(wParam)) {
859 case VK_F4: {
860 if (!altKeyPressed && !ctrlKeyPressed) {
861 int index = focusedIndex();
862 ASSERT(index >= 0);
863 client()->valueChanged(index);
864 hide();
865 }
866 break;
867 }
868 case VK_DOWN:
869 if (altKeyPressed) {
870 int index = focusedIndex();
871 ASSERT(index >= 0);
872 client()->valueChanged(index);
873 hide();
874 } else
875 down();
876 break;
877 case VK_RIGHT:
878 down();
879 break;
880 case VK_UP:
881 if (altKeyPressed) {
882 int index = focusedIndex();
883 ASSERT(index >= 0);
884 client()->valueChanged(index);
885 hide();
886 } else
887 up();
888 break;
889 case VK_LEFT:
890 up();
891 break;
892 case VK_HOME:
893 focusFirst();
894 break;
895 case VK_END:
896 focusLast();
897 break;
898 case VK_PRIOR:
899 if (focusedIndex() != scrollOffset()) {
900 // Set the selection to the first visible item
901 int firstVisibleItem = scrollOffset();
902 up(focusedIndex() - firstVisibleItem);
903 } else {
904 // The first visible item is selected, so move the selec tion back one page
905 up(visibleItems());
906 }
907 break;
908 case VK_NEXT: {
909 int lastVisibleItem = scrollOffset() + visibleItems() - 1;
910 if (focusedIndex() != lastVisibleItem) {
911 // Set the selection to the last visible item
912 down(lastVisibleItem - focusedIndex());
913 } else {
914 // The last visible item is selected, so move the select ion forward one page
915 down(visibleItems());
916 }
917 break;
918 }
919 case VK_TAB:
920 ::SendMessage(client()->hostWindow()->platformPageClient(), message, wParam, lParam);
921 hide();
922 break;
923 case VK_ESCAPE:
924 hide();
925 break;
926 default:
927 if (isASCIIPrintable(wParam))
928 // Send the keydown to the WebView so it can be used for type-to-select.
929 // Since we know that the virtual key is ASCII printable , it's OK to convert this to
930 // a WM_CHAR message. (We don't want to call TranslateMe ssage because that will post a
931 // WM_CHAR message that will be stolen and redirected to the popup HWND.
932 ::PostMessage(m_popup, WM_HOST_WINDOW_CHAR, wParam, lPar am);
933 else
934 lResult = 1;
935 break;
936 }
937 break;
938 }
939 case WM_CHAR: {
940 if (!client())
941 break;
942
943 lResult = 0;
944 int index;
945 switch (wParam) {
946 case 0x0D: // Enter/Return
947 hide();
948 index = focusedIndex();
949 ASSERT(index >= 0);
950 client()->valueChanged(index);
951 break;
952 case 0x1B: // Escape
953 hide();
954 break;
955 case 0x09: // TAB
956 case 0x08: // Backspace
957 case 0x0A: // Linefeed
958 default: // Character
959 lResult = 1;
960 break;
961 }
962 break;
963 }
964 case WM_MOUSEMOVE: {
965 IntPoint mousePoint(MAKEPOINTS(lParam));
966 if (scrollbar()) {
967 IntRect scrollBarRect = scrollbar()->frameRect();
968 if (scrollbarCapturingMouse() || scrollBarRect.contains(mousePoi nt)) {
969 // Put the point into coordinates relative to the scroll bar
970 mousePoint.move(-scrollBarRect.x(), -scrollBarRect.y());
971 PlatformMouseEvent event(hWnd, message, wParam, MAKELPARAM(m ousePoint.x(), mousePoint.y()));
972 scrollbar()->mouseMoved(event);
973 break;
974 }
975 }
976
977 BOOL shouldHotTrack = FALSE;
978 #if !OS(WINCE)
979 ::SystemParametersInfo(SPI_GETHOTTRACKING, 0, &shouldHotTrack, 0);
980 #endif
981
982 RECT bounds;
983 GetClientRect(popupHandle(), &bounds);
984 if (!::PtInRect(&bounds, mousePoint) && !(wParam & MK_LBUTTON) && cl ient()) {
985 // When the mouse is not inside the popup menu and the left butt on isn't down, just
986 // repost the message to the web view.
987
988 // Translate the coordinate.
989 translatePoint(lParam, m_popup, client()->hostWindow()->platform PageClient());
990
991 ::PostMessage(m_popup, WM_HOST_WINDOW_MOUSEMOVE, wParam, lParam) ;
992 break;
993 }
994
995 if ((shouldHotTrack || wParam & MK_LBUTTON) && ::PtInRect(&bounds, m ousePoint))
996 setFocusedIndex(listIndexAtPoint(mousePoint), true);
997
998 break;
999 }
1000 case WM_LBUTTONDOWN: {
1001 IntPoint mousePoint(MAKEPOINTS(lParam));
1002 if (scrollbar()) {
1003 IntRect scrollBarRect = scrollbar()->frameRect();
1004 if (scrollBarRect.contains(mousePoint)) {
1005 // Put the point into coordinates relative to the scroll bar
1006 mousePoint.move(-scrollBarRect.x(), -scrollBarRect.y());
1007 PlatformMouseEvent event(hWnd, message, wParam, MAKELPARAM(m ousePoint.x(), mousePoint.y()));
1008 scrollbar()->mouseDown(event);
1009 setScrollbarCapturingMouse(true);
1010 break;
1011 }
1012 }
1013
1014 // If the mouse is inside the window, update the focused index. Othe rwise,
1015 // hide the popup.
1016 RECT bounds;
1017 GetClientRect(m_popup, &bounds);
1018 if (::PtInRect(&bounds, mousePoint))
1019 setFocusedIndex(listIndexAtPoint(mousePoint), true);
1020 else
1021 hide();
1022 break;
1023 }
1024 case WM_LBUTTONUP: {
1025 IntPoint mousePoint(MAKEPOINTS(lParam));
1026 if (scrollbar()) {
1027 IntRect scrollBarRect = scrollbar()->frameRect();
1028 if (scrollbarCapturingMouse() || scrollBarRect.contains(mousePoi nt)) {
1029 setScrollbarCapturingMouse(false);
1030 // Put the point into coordinates relative to the scroll bar
1031 mousePoint.move(-scrollBarRect.x(), -scrollBarRect.y());
1032 PlatformMouseEvent event(hWnd, message, wParam, MAKELPARAM(m ousePoint.x(), mousePoint.y()));
1033 scrollbar()->mouseUp(event);
1034 // FIXME: This is a hack to work around Scrollbar not invali dating correctly when it doesn't have a parent widget
1035 RECT r = scrollBarRect;
1036 ::InvalidateRect(popupHandle(), &r, TRUE);
1037 break;
1038 }
1039 }
1040 // Only hide the popup if the mouse is inside the popup window.
1041 RECT bounds;
1042 GetClientRect(popupHandle(), &bounds);
1043 if (client() && ::PtInRect(&bounds, mousePoint)) {
1044 hide();
1045 int index = focusedIndex();
1046 if (index >= 0)
1047 client()->valueChanged(index);
1048 }
1049 break;
1050 }
1051
1052 case WM_MOUSEWHEEL: {
1053 if (!scrollbar())
1054 break;
1055
1056 int i = 0;
1057 for (incrementWheelDelta(GET_WHEEL_DELTA_WPARAM(wParam)); abs(wheelD elta()) >= WHEEL_DELTA; reduceWheelDelta(WHEEL_DELTA)) {
1058 if (wheelDelta() > 0)
1059 ++i;
1060 else
1061 --i;
1062 }
1063
1064 ScrollableArea::scroll(i > 0 ? ScrollUp : ScrollDown, ScrollByLine, abs(i));
1065 break;
1066 }
1067
1068 case WM_PAINT: {
1069 PAINTSTRUCT paintInfo;
1070 ::BeginPaint(popupHandle(), &paintInfo);
1071 paint(paintInfo.rcPaint, paintInfo.hdc);
1072 ::EndPaint(popupHandle(), &paintInfo);
1073 lResult = 0;
1074 break;
1075 }
1076 #if !OS(WINCE)
1077 case WM_PRINTCLIENT:
1078 paint(clientRect(), (HDC)wParam);
1079 break;
1080 #endif
1081 default:
1082 lResult = DefWindowProc(hWnd, message, wParam, lParam);
1083 }
1084
1085 return lResult;
1086 }
1087
1088 }
OLDNEW
« no previous file with comments | « Source/WebCore/platform/win/PopupMenuWin.h ('k') | Source/WebCore/platform/win/RunLoopWin.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698