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

Unified Diff: webkit/port/platform/PopupMenuWin.cpp

Issue 7419: Move many files that were suffixed Win.cpp to Chromium.cpp, and place them in... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 12 years, 2 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « webkit/port/platform/PlatformScrollBarWin.cpp ('k') | webkit/port/platform/SSLKeyGeneratorWin.cpp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: webkit/port/platform/PopupMenuWin.cpp
===================================================================
--- webkit/port/platform/PopupMenuWin.cpp (revision 3423)
+++ webkit/port/platform/PopupMenuWin.cpp (working copy)
@@ -1,1115 +0,0 @@
-// Copyright (c) 2008, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#include "config.h"
-
-#pragma warning(push, 0)
-#include "PopupMenu.h"
-
-#include "CharacterNames.h"
-#include "ChromeClientWin.h"
-#include "Document.h"
-#include "Font.h"
-#include "Frame.h"
-#include "FontSelector.h"
-#include "FramelessScrollView.h"
-#include "GraphicsContext.h"
-#include "IntRect.h"
-#include "Page.h"
-#include "PlatformKeyboardEvent.h"
-#include "PlatformMouseEvent.h"
-#include "PlatformScreen.h"
-#include "PlatformScrollbar.h"
-#include "PlatformWheelEvent.h"
-#include "SystemTime.h"
-#include "RenderBlock.h"
-#include "RenderTheme.h"
-#include "Widget.h"
-#include "WidgetClientWin.h"
-#pragma warning(pop)
-
-//#define LOG_ENABLE
-#include "LogWin.h"
-
-using namespace WTF;
-using namespace Unicode;
-
-using std::min;
-using std::max;
-
-namespace WebCore {
-
-typedef unsigned long long TimeStamp;
-
-static const int kMaxVisibleRows = 20;
-static const int kMaxHeight = 500;
-static const int kBorderSize = 1;
-static const TimeStamp kTypeAheadTimeoutMs = 1000;
-
-class PopupListBox;
-
-// This class holds a PopupListBox. Its sole purpose is to be able to draw
-// a border around its child. All its paint/event handling is just forwarded
-// to the child listBox (with the appropriate transforms).
-class PopupContainer : public FramelessScrollView {
-public:
- static HWND Create(PopupMenuClient* client);
-
- // FramelessScrollView
- virtual void paint(GraphicsContext* gc, const IntRect& rect);
- virtual void hide();
- virtual bool handleMouseDownEvent(const PlatformMouseEvent& event);
- virtual bool handleMouseMoveEvent(const PlatformMouseEvent& event);
- virtual bool handleMouseReleaseEvent(const PlatformMouseEvent& event);
- virtual bool handleWheelEvent(const PlatformWheelEvent& event);
- virtual bool handleKeyEvent(const PlatformKeyboardEvent& event);
-
- // PopupContainer methods
-
- // Show the popup
- void showPopup(FrameView* view);
-
- // Hide the popup. Do not call this directly: use client->hidePopup().
- void hidePopup();
-
- // Compute size of widget and children.
- void layout();
-
- PopupListBox* listBox() const { return m_listBox.get(); }
-
-private:
- PopupContainer(PopupMenuClient* client);
- ~PopupContainer();
-
- // Paint the border.
- void paintBorder(GraphicsContext* gc, const IntRect& rect);
-
- RefPtr<PopupListBox> m_listBox;
-};
-
-// This class uses WebCore code to paint and handle events for a drop-down list
-// box ("combobox" on Windows).
-class PopupListBox : public FramelessScrollView {
-public:
- // FramelessScrollView
- virtual void paint(GraphicsContext* gc, const IntRect& rect);
- virtual bool handleMouseDownEvent(const PlatformMouseEvent& event);
- virtual bool handleMouseMoveEvent(const PlatformMouseEvent& event);
- virtual bool handleMouseReleaseEvent(const PlatformMouseEvent& event);
- virtual bool handleWheelEvent(const PlatformWheelEvent& event);
- virtual bool handleKeyEvent(const PlatformKeyboardEvent& event);
-
- // PopupListBox methods
-
- // Show the popup
- void showPopup();
-
- // Hide the popup. Do not call this directly: use client->hidePopup().
- void hidePopup();
-
- // Update our internal list to match the client.
- void updateFromElement();
-
- // Free any allocated resources used in a particular popup session.
- void clear();
-
- // Set the index of the option that is displayed in the <select> widget in the page
- void setOriginalIndex(int index);
-
- // Get the index of the item that the user is currently moused over or has selected with
- // the keyboard. This is not the same as the original index, since the user has not yet
- // accepted this input.
- int selectedIndex() const { return m_selectedIndex; }
-
- // Move selection down/up the given number of items, scrolling if necessary.
- // Positive is down. The resulting index will be clamped to the range
- // [0, numItems), and non-option items will be skipped.
- void adjustSelectedIndex(int delta);
-
- // Returns the number of items in the list.
- int numItems() const { return static_cast<int>(m_items.size()); }
-
- void setBaseWidth(int width)
- {
- m_baseWidth = width;
- }
-
- // Compute size of widget and children.
- void layout();
-
-private:
- friend class PopupContainer;
-
- // A type of List Item
- enum ListItemType {
- TYPE_OPTION,
- TYPE_GROUP,
- TYPE_SEPARATOR
- };
-
- // A item (represented by <option> or <optgroup>) in the <select> widget.
- struct ListItem {
- ListItem(const String& label, ListItemType type)
- : label(label.copy()), type(type), y(0) {}
- String label;
- ListItemType type;
- int y; // y offset of this item, relative to the top of the popup.
- };
-
- PopupListBox(PopupMenuClient* client)
- : m_originalIndex(0)
- , m_selectedIndex(0)
- , m_visibleRows(0)
- , m_popupClient(client)
- , m_repeatingChar(0)
- , m_lastCharTime(0)
- , m_acceptOnAbandon(false)
- {
- setScrollbarsMode(ScrollbarAlwaysOff);
- }
-
- ~PopupListBox()
- {
- clear();
- }
-
- void disconnectClient() { m_popupClient = 0; }
-
- // Closes the popup
- void abandon();
- // Select an index in the list, scrolling if necessary.
- void selectIndex(int index);
- // Accepts the selected index as the value to be displayed in the <select> widget on
- // the web page, and closes the popup.
- void acceptIndex(int index);
-
- // Returns true if the selection can be changed to index.
- // Disabled items, or labels cannot be selected.
- bool isSelectableItem(int index);
-
- // Scrolls to reveal the given index.
- void scrollToRevealRow(int index);
- void scrollToRevealSelection() { scrollToRevealRow(m_selectedIndex); }
-
- // Invalidates the row at the given index.
- void invalidateRow(int index);
-
- // Gets the height of a row.
- int getRowHeight(int index);
- // Get the bounds of a row.
- IntRect getRowBounds(int index);
-
- // Converts a point to an index of the row the point is over
- int pointToRowIndex(const IntPoint& point);
-
- // Paint an individual row
- void paintRow(GraphicsContext* gc, const IntRect& rect, int rowIndex);
-
- // Test if the given point is within the bounds of the popup window.
- bool isPointInBounds(const IntPoint& point);
-
- // Called when the user presses a text key. Does a prefix-search of the items.
- void typeAheadFind(const PlatformKeyboardEvent& event);
-
- // Returns the font to use for the given row
- Font getRowFont(int index);
-
- // This is the index of the item marked as "selected" - i.e. displayed in the widget on the
- // page.
- int m_originalIndex;
-
- // This is the index of the item that the user is hovered over or has selected using the
- // keyboard in the list. They have not confirmed this selection by clicking or pressing
- // enter yet however.
- int m_selectedIndex;
-
- // True if we should accept the selectedIndex as chosen, even if the popup
- // is "abandoned". This is used for keyboard navigation, where we want the
- // selection to change immediately.
- bool m_acceptOnAbandon;
-
- // This is the number of rows visible in the popup. The maximum number visible at a time is
- // defined as being kMaxVisibleRows. For a scrolled popup, this can be thought of as the
- // page size in data units.
- int m_visibleRows;
-
- // Our suggested width, not including scrollbar.
- int m_baseWidth;
-
- // A list of the options contained within the <select>
- Vector<ListItem*> m_items;
-
- // The <select> PopupMenuClient that opened us.
- PopupMenuClient* m_popupClient;
-
- // The scrollbar which has mouse capture. Mouse events go straight to this
- // if non-NULL.
- RefPtr<PlatformScrollbar> m_capturingScrollbar;
-
- // The last scrollbar that the mouse was over. Used for mouseover highlights.
- RefPtr<PlatformScrollbar> m_lastScrollbarUnderMouse;
-
- // The string the user has typed so far into the popup. Used for typeAheadFind.
- String m_typedString;
-
- // The char the user has hit repeatedly. Used for typeAheadFind.
- UChar m_repeatingChar;
-
- // The last time the user hit a key. Used for typeAheadFind.
- TimeStamp m_lastCharTime;
-};
-
-static PlatformMouseEvent constructRelativeMouseEvent(const PlatformMouseEvent& e,
- FrameView* parent,
- FrameView* child)
-{
- IntPoint pos = parent->convertSelfToChild(child, e.pos());
-
- // FIXME(beng): This is a horrible hack since PlatformWheelEvent has no setters for x/y.
- // Need to add setters and get patch back upstream to webkit source.
- PlatformMouseEvent relativeEvent = e;
- IntPoint& relativePos = const_cast<IntPoint&>(relativeEvent.pos());
- relativePos.setX(pos.x());
- relativePos.setY(pos.y());
- return relativeEvent;
-}
-
-static PlatformWheelEvent constructRelativeWheelEvent(const PlatformWheelEvent& e,
- FrameView* parent,
- FrameView* child)
-{
- IntPoint pos = parent->convertSelfToChild(child, e.pos());
-
- // FIXME(beng): This is a horrible hack since PlatformWheelEvent has no setters for x/y.
- // Need to add setters and get patch back upstream to webkit source.
- PlatformWheelEvent relativeEvent = e;
- IntPoint& relativePos = const_cast<IntPoint&>(relativeEvent.pos());
- relativePos.setX(pos.x());
- relativePos.setY(pos.y());
- return relativeEvent;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// PopupContainer implementation
-
-// Get a pointer to the PopupContainer instance for the m_popup HWND, since we
-// can't augment the PopupMenu class (above the portability layer). We store the
-// PopupContainer in the HWND member, which is fairly hacky.
-static PopupContainer* popupWindow(HWND popup)
-{
- return reinterpret_cast<PopupContainer*>(popup);
-}
-
-// static
-HWND PopupContainer::Create(PopupMenuClient* client)
-{
- PopupContainer* container = new PopupContainer(client);
- return reinterpret_cast<HWND>(container);
-}
-
-PopupContainer::PopupContainer(PopupMenuClient* client)
- : m_listBox(new PopupListBox(client))
-{
- // FrameViews are created with a refcount of 1 so it needs releasing after we
- // assign it to a RefPtr.
- m_listBox->deref();
-
- setScrollbarsMode(ScrollbarAlwaysOff);
-}
-
-PopupContainer::~PopupContainer()
-{
- if (m_listBox)
- removeChild(m_listBox.get());
-}
-
-void PopupContainer::showPopup(FrameView* view)
-{
- // Pre-layout, our size matches the <select> dropdown control.
- int selectHeight = frameGeometry().height();
-
- // Lay everything out to figure out our preferred size, then tell the view's
- // WidgetClient about it. It should assign us a client.
- layout();
-
- WidgetClientWin* widgetClient =
- static_cast<WidgetClientWin*>(view->client());
- ChromeClientWin* chromeClient =
- static_cast<ChromeClientWin*>(view->frame()->page()->chrome()->client());
- if (widgetClient && chromeClient) {
- // If the popup would extend past the bottom of the screen, open upwards
- // instead.
- FloatRect screen = screenRect(view);
- IntRect widgetRect = chromeClient->windowToScreen(frameGeometry());
- if (widgetRect.bottom() > static_cast<int>(screen.bottom()))
- widgetRect.move(0, -(widgetRect.height() + selectHeight));
-
- widgetClient->popupOpened(this, widgetRect);
- }
-
- // Must get called after we have a client and containingWindow.
- addChild(m_listBox.get());
-
- // Enable scrollbars after the listbox is inserted into the hierarchy, so
- // it has a proper WidgetClient.
- m_listBox->setVScrollbarMode(ScrollbarAuto);
-
- m_listBox->scrollToRevealSelection();
-
- invalidate();
-}
-
-void PopupContainer::hidePopup()
-{
- invalidate();
-
- m_listBox->disconnectClient();
- removeChild(m_listBox.get());
-
- if (client())
- static_cast<WidgetClientWin*>(client())->popupClosed(this);
-}
-
-void PopupContainer::layout()
-{
- m_listBox->layout();
-
- // Place the listbox within our border.
- m_listBox->move(kBorderSize, kBorderSize);
-
- // Size ourselves to contain listbox + border.
- resize(m_listBox->width() + kBorderSize*2, m_listBox->height() + kBorderSize*2);
-
- invalidate();
-}
-
-bool PopupContainer::handleMouseDownEvent(const PlatformMouseEvent& event)
-{
- return m_listBox->handleMouseDownEvent(
- constructRelativeMouseEvent(event, this, m_listBox.get()));
-}
-
-bool PopupContainer::handleMouseMoveEvent(const PlatformMouseEvent& event)
-{
- return m_listBox->handleMouseMoveEvent(
- constructRelativeMouseEvent(event, this, m_listBox.get()));
-}
-
-bool PopupContainer::handleMouseReleaseEvent(const PlatformMouseEvent& event)
-{
- return m_listBox->handleMouseReleaseEvent(
- constructRelativeMouseEvent(event, this, m_listBox.get()));
-}
-
-bool PopupContainer::handleWheelEvent(const PlatformWheelEvent& event)
-{
- return m_listBox->handleWheelEvent(
- constructRelativeWheelEvent(event, this, m_listBox.get()));
-}
-
-bool PopupContainer::handleKeyEvent(const PlatformKeyboardEvent& event)
-{
- return m_listBox->handleKeyEvent(event);
-}
-
-void PopupContainer::hide() {
- m_listBox->abandon();
-}
-
-void PopupContainer::paint(GraphicsContext* gc, const IntRect& rect)
-{
- // adjust coords for scrolled frame
- IntRect r = intersection(rect, frameGeometry());
- int tx = x();
- int ty = y();
-
- r.move(-tx, -ty);
-
- gc->translate(static_cast<float>(tx), static_cast<float>(ty));
- m_listBox->paint(gc, r);
- gc->translate(-static_cast<float>(tx), -static_cast<float>(ty));
-
- paintBorder(gc, rect);
-}
-
-void PopupContainer::paintBorder(GraphicsContext* gc, const IntRect& rect)
-{
- // FIXME(mpcomplete): where do we get the border color from?
- Color borderColor(127, 157, 185);
-
- gc->setStrokeStyle(NoStroke);
- gc->setFillColor(borderColor);
-
- int tx = x();
- int ty = y();
-
- // top, left, bottom, right
- gc->drawRect(IntRect(tx, ty, width(), kBorderSize));
- gc->drawRect(IntRect(tx, ty, kBorderSize, height()));
- gc->drawRect(IntRect(tx, ty + height() - kBorderSize, width(), kBorderSize));
- gc->drawRect(IntRect(tx + width() - kBorderSize, ty, kBorderSize, height()));
-}
-
-
-///////////////////////////////////////////////////////////////////////////////
-// PopupListBox implementation
-
-bool PopupListBox::handleMouseDownEvent(const PlatformMouseEvent& event)
-{
- PlatformScrollbar* scrollbar = scrollbarUnderMouse(event);
- if (scrollbar) {
- m_capturingScrollbar = scrollbar;
- m_capturingScrollbar->handleMousePressEvent(event);
- return true;
- }
-
- if (!isPointInBounds(event.pos()))
- abandon();
-
- return true;
-}
-
-bool PopupListBox::handleMouseMoveEvent(const PlatformMouseEvent& event)
-{
- if (m_capturingScrollbar) {
- m_capturingScrollbar->handleMouseMoveEvent(event);
- return true;
- }
-
- PlatformScrollbar* scrollbar = scrollbarUnderMouse(event);
- if (m_lastScrollbarUnderMouse != scrollbar) {
- // Send mouse exited to the old scrollbar.
- if (m_lastScrollbarUnderMouse)
- m_lastScrollbarUnderMouse->handleMouseOutEvent(event);
- m_lastScrollbarUnderMouse = scrollbar;
- }
-
- if (scrollbar) {
- scrollbar->handleMouseMoveEvent(event);
- return true;
- }
-
- if (!isPointInBounds(event.pos()))
- return false;
-
- selectIndex(pointToRowIndex(event.pos()));
- return true;
-}
-
-bool PopupListBox::handleMouseReleaseEvent(const PlatformMouseEvent& event)
-{
- if (m_capturingScrollbar) {
- m_capturingScrollbar->handleMouseReleaseEvent(event);
- m_capturingScrollbar = 0;
- return true;
- }
-
- if (!isPointInBounds(event.pos()))
- return true;
-
- acceptIndex(pointToRowIndex(event.pos()));
- return true;
-}
-
-bool PopupListBox::handleWheelEvent(const PlatformWheelEvent& event)
-{
- if (!isPointInBounds(event.pos())) {
- abandon();
- return true;
- }
-
- // Pass it off to the scroll view.
- // Sadly, WebCore devs don't understand the whole "const" thing.
- wheelEvent(const_cast<PlatformWheelEvent&>(event));
- return true;
-}
-
-bool PopupListBox::handleKeyEvent(const PlatformKeyboardEvent& event)
-{
- if (event.type() == PlatformKeyboardEvent::KeyUp)
- return true;
-
- if (numItems() == 0 && event.windowsVirtualKeyCode() != VK_ESCAPE)
- return true;
-
- int oldIndex = m_selectedIndex;
-
- switch (event.windowsVirtualKeyCode()) {
- case VK_ESCAPE:
- abandon(); // may delete this
- return true;
- case VK_RETURN:
- acceptIndex(m_selectedIndex); // may delete this
- return true;
- case VK_UP:
- adjustSelectedIndex(-1);
- break;
- case VK_DOWN:
- adjustSelectedIndex(1);
- break;
- case VK_PRIOR:
- adjustSelectedIndex(-m_visibleRows);
- break;
- case VK_NEXT:
- adjustSelectedIndex(m_visibleRows);
- break;
- case VK_HOME:
- adjustSelectedIndex(-m_selectedIndex);
- break;
- case VK_END:
- adjustSelectedIndex(m_items.size());
- break;
- default:
- if (!event.ctrlKey() && !event.altKey() && !event.metaKey() &&
- isPrintableChar(event.windowsVirtualKeyCode())) {
- typeAheadFind(event);
- }
- break;
- }
-
- if (m_originalIndex != m_selectedIndex) {
- // Keyboard events should update the selection immediately (but we don't
- // want to fire the onchange event until the popup is closed, to match
- // IE). We change the original index so we revert to that when the
- // popup is closed.
- m_acceptOnAbandon = true;
- setOriginalIndex(m_selectedIndex);
- m_popupClient->setTextFromItem(m_selectedIndex);
- }
-
- return true;
-}
-
-// From HTMLSelectElement.cpp
-static String stripLeadingWhiteSpace(const String& string)
-{
- int length = string.length();
- int i;
- for (i = 0; i < length; ++i)
- if (string[i] != noBreakSpace &&
- (string[i] <= 0x7F ? !isspace(string[i]) : (direction(string[i]) != WhiteSpaceNeutral)))
- break;
-
- return string.substring(i, length - i);
-}
-
-// From HTMLSelectElement.cpp, with modifications
-void PopupListBox::typeAheadFind(const PlatformKeyboardEvent& event)
-{
- TimeStamp now = static_cast<TimeStamp>(currentTime() * 1000.0f);
- TimeStamp delta = now - m_lastCharTime;
-
- m_lastCharTime = now;
-
- UChar c = event.windowsVirtualKeyCode();
-
- String prefix;
- int searchStartOffset = 1;
- if (delta > kTypeAheadTimeoutMs) {
- m_typedString = prefix = String(&c, 1);
- m_repeatingChar = c;
- } else {
- m_typedString.append(c);
-
- if (c == m_repeatingChar)
- // The user is likely trying to cycle through all the items starting with this character, so just search on the character
- prefix = String(&c, 1);
- else {
- m_repeatingChar = 0;
- prefix = m_typedString;
- searchStartOffset = 0;
- }
- }
-
- int itemCount = numItems();
- int index = (m_selectedIndex + searchStartOffset) % itemCount;
- for (int i = 0; i < itemCount; i++, index = (index + 1) % itemCount) {
- if (!isSelectableItem(index))
- continue;
-
- if (stripLeadingWhiteSpace(m_items[index]->label).startsWith(prefix, false)) {
- selectIndex(index);
- return;
- }
- }
-}
-
-void PopupListBox::paint(GraphicsContext* gc, const IntRect& rect)
-{
- // adjust coords for scrolled frame
- IntRect r = intersection(rect, frameGeometry());
- int tx = x() - contentsX();
- int ty = y() - contentsY();
-
- r.move(-tx, -ty);
-
- LOG(("PopupListBox::paint [%d,%d] [r: %d,%d,%d,%d]", tx, ty,
- r.x(), r.y(), r.width(), r.height()));
-
- // set clip rect to match revised damage rect
- gc->save();
- gc->translate(static_cast<float>(tx), static_cast<float>(ty));
- gc->clip(r);
-
- // TODO(mpcomplete): Can we optimize scrolling to not require repainting the
- // entire window? Should we?
- for (int i = 0; i < numItems(); ++i)
- paintRow(gc, r, i);
-
- // Special case for an empty popup.
- if (numItems() == 0)
- gc->fillRect(r, Color::white);
-
- gc->restore();
-
- ScrollView::paint(gc, rect);
-}
-
-static RenderStyle* getPopupClientStyleForRow(PopupMenuClient* client, int rowIndex) {
- RenderStyle* style = client->itemStyle(rowIndex);
- if (!style)
- style = client->clientStyle();
- return style;
-}
-
-void PopupListBox::paintRow(GraphicsContext* gc, const IntRect& rect, int rowIndex)
-{
- // This code is based largely on RenderListBox::paint* methods.
-
- IntRect rowRect = getRowBounds(rowIndex);
- if (!rowRect.intersects(rect))
- return;
-
- RenderStyle* style = getPopupClientStyleForRow(m_popupClient, rowIndex);
-
- // Paint background
- Color backColor, textColor;
- if (rowIndex == m_selectedIndex) {
- backColor = theme()->activeListBoxSelectionBackgroundColor();
- textColor = theme()->activeListBoxSelectionForegroundColor();
- } else {
- backColor = m_popupClient->itemBackgroundColor(rowIndex);
- textColor = style->color();
- }
-
- // If we have a transparent background, make sure it has a color to blend
- // against.
- if (backColor.hasAlpha())
- gc->fillRect(rowRect, Color::white);
-
- gc->fillRect(rowRect, backColor);
- gc->setFillColor(textColor);
-
- LOG(("paintRow %d, [%d, %d, %d, %d] %x on %x", rowIndex,
- rowRect.x(), rowRect.y(), rowRect.width(), rowRect.height(),
- textColor.rgb(), backColor.rgb()));
-
- Font itemFont = getRowFont(rowIndex);
- gc->setFont(itemFont);
-
- // Bunch of shit to deal with RTL text...
- String itemText = m_popupClient->itemText(rowIndex);
- unsigned length = itemText.length();
- const UChar* str = itemText.characters();
-
- TextRun textRun(str, length, false, 0, 0, style->direction() == RTL, style->unicodeBidi() == Override);
-
- // Draw the item text
- // TODO(ojan): http://b/1210481 We should get the padding of individual option elements.
- rowRect.move(theme()->popupInternalPaddingLeft(style), itemFont.ascent());
- if (style->direction() == RTL) {
- // Right-justify the text for RTL style.
- rowRect.move(rowRect.width() - itemFont.width(textRun) -
- 2 * theme()->popupInternalPaddingLeft(style), 0);
- }
- gc->drawBidiText(textRun, rowRect.location());
-}
-
-Font PopupListBox::getRowFont(int rowIndex)
-{
- Font itemFont = m_popupClient->itemStyle(rowIndex)->font();
- if (m_popupClient->itemIsLabel(rowIndex)) {
- // Bold-ify labels (ie, an <optgroup> heading).
- FontDescription d = itemFont.fontDescription();
- d.setWeight(FontWeightBold);
- Font font(d, itemFont.letterSpacing(), itemFont.wordSpacing());
- font.update(0);
- return font;
- }
-
- return itemFont;
-}
-
-void PopupListBox::abandon()
-{
- RefPtr<PopupListBox> keepAlive(this);
-
- m_selectedIndex = m_originalIndex;
-
- if (m_acceptOnAbandon)
- m_popupClient->valueChanged(m_selectedIndex);
-
- // valueChanged may have torn down the popup!
- if (m_popupClient)
- m_popupClient->hidePopup();
-}
-
-int PopupListBox::pointToRowIndex(const IntPoint& point)
-{
- int y = contentsY() + point.y();
-
- // TODO(mpcomplete): binary search if perf matters.
- for (int i = 0; i < numItems(); ++i) {
- if (y < m_items[i]->y)
- return i-1;
- }
-
- // Last item?
- if (y < contentsHeight())
- return m_items.size()-1;
-
- return -1;
-}
-
-void PopupListBox::acceptIndex(int index)
-{
- ASSERT(index >= 0 && index < numItems());
-
- if (isSelectableItem(index)) {
- RefPtr<PopupListBox> keepAlive(this);
-
- // Tell the <select> PopupMenuClient what index was selected, and hide ourself.
- m_popupClient->valueChanged(index);
-
- // valueChanged may have torn down the popup!
- if (m_popupClient)
- m_popupClient->hidePopup();
- }
-}
-
-void PopupListBox::selectIndex(int index)
-{
- ASSERT(index >= 0 && index < numItems());
-
- if (index != m_selectedIndex && isSelectableItem(index)) {
- invalidateRow(m_selectedIndex);
- m_selectedIndex = index;
- invalidateRow(m_selectedIndex);
-
- scrollToRevealSelection();
- }
-}
-
-void PopupListBox::setOriginalIndex(int index)
-{
- m_originalIndex = m_selectedIndex = index;
-}
-
-int PopupListBox::getRowHeight(int index)
-{
- RenderStyle* style;
- if ((index < 0) || (!(style = m_popupClient->itemStyle(index))))
- style = m_popupClient->clientStyle();
- return style->font().height();
-}
-
-IntRect PopupListBox::getRowBounds(int index)
-{
- if (index >= 0) {
- return IntRect(0, m_items[index]->y, visibleWidth(), getRowHeight(index));
- } else {
- return IntRect(0, 0, visibleWidth(), getRowHeight(index));
- }
-}
-
-void PopupListBox::invalidateRow(int index)
-{
- if (index < 0)
- return;
-
- updateContents(getRowBounds(index));
-}
-
-void PopupListBox::scrollToRevealRow(int index)
-{
- if (index < 0)
- return;
-
- IntRect rowRect = getRowBounds(index);
-
- if (rowRect.y() < contentsY()) {
- // Row is above current scroll position, scroll up.
- ScrollView::setContentsPos(0, rowRect.y());
- } else if (rowRect.bottom() > contentsY() + visibleHeight()) {
- // Row is below current scroll position, scroll down.
- ScrollView::setContentsPos(0, rowRect.bottom() - visibleHeight());
- }
-}
-
-bool PopupListBox::isSelectableItem(int index) {
- return m_items[index]->type == TYPE_OPTION &&
- m_popupClient->itemIsEnabled(index);
-}
-
-void PopupListBox::adjustSelectedIndex(int delta)
-{
- int targetIndex = m_selectedIndex + delta;
- targetIndex = min(max(targetIndex, 0), numItems() - 1);
- if (!isSelectableItem(targetIndex)) {
- // We didn't land on an option. Try to find one.
- // We try to select the closest index to target, prioritizing any in
- // the range [current, target].
-
- int dir = delta > 0 ? 1 : -1;
- int testIndex = m_selectedIndex;
- int bestIndex = m_selectedIndex;
- bool passedTarget = false;
- while (testIndex >= 0 && testIndex < numItems()) {
- if (isSelectableItem(testIndex))
- bestIndex = testIndex;
- if (testIndex == targetIndex)
- passedTarget = true;
- if (passedTarget && bestIndex != m_selectedIndex)
- break;
-
- testIndex += dir;
- }
-
- // Pick the best index, which may mean we don't change.
- targetIndex = bestIndex;
- }
-
- // Select the new index, and ensure its visible. We do this regardless of
- // whether the selection changed to ensure keyboard events always bring the
- // selection into view.
- selectIndex(targetIndex);
- scrollToRevealSelection();
-}
-
-void PopupListBox::updateFromElement()
-{
- // It happens when pressing a key to jump to an item, then use tab or
- // mouse to get away from the select box. In that case, updateFromElement
- // is called before abandon, which causes discarding of the select result.
- if (m_acceptOnAbandon) {
- m_popupClient->valueChanged(m_selectedIndex);
- m_acceptOnAbandon = false;
- }
-
- clear();
-
- int size = m_popupClient->listSize();
- for (int i = 0; i < size; ++i) {
- ListItemType type;
- if (m_popupClient->itemIsSeparator(i))
- type = PopupListBox::TYPE_SEPARATOR;
- else if (m_popupClient->itemIsLabel(i))
- type = PopupListBox::TYPE_GROUP;
- else
- type = PopupListBox::TYPE_OPTION;
- m_items.append(new ListItem(m_popupClient->itemText(i), type));
- }
-
- m_selectedIndex = m_popupClient->selectedIndex();
- setOriginalIndex(m_selectedIndex);
-
- layout();
-}
-
-void PopupListBox::layout()
-{
- // Size our child items.
- int baseWidth = 0;
- int paddingWidth = 0;
- int y = 0;
- for (int i = 0; i < numItems(); ++i) {
- Font itemFont = getRowFont(i);
-
- // Place the item vertically.
- m_items[i]->y = y;
- y += itemFont.height();
-
- // Ensure the popup is wide enough to fit this item.
- String text = m_popupClient->itemText(i);
- if (!text.isEmpty()) {
- int width = itemFont.width(TextRun(text));
- baseWidth = max(baseWidth, width);
- }
- RenderStyle* style = getPopupClientStyleForRow(m_popupClient, i);
- // TODO(ojan): http://b/1210481 We should get the padding of individual option elements.
- paddingWidth = max(paddingWidth,
- theme()->popupInternalPaddingLeft(style) + theme()->popupInternalPaddingRight(style));
- }
-
- int windowHeight = 0;
- m_visibleRows = min(numItems(), kMaxVisibleRows);
- for (int i = 0; i < m_visibleRows; ++i) {
- int rowHeight = getRowHeight(i);
- if (windowHeight + rowHeight > kMaxHeight) {
- m_visibleRows = i;
- break;
- }
-
- windowHeight += rowHeight;
- }
-
- if (windowHeight == 0)
- windowHeight = min(getRowHeight(-1), kMaxHeight);
-
- // Set our widget and scrollable contents sizes.
- int scrollbarWidth = 0;
- if (m_visibleRows < numItems())
- scrollbarWidth = PlatformScrollbar::verticalScrollbarWidth();
-
- int windowWidth = baseWidth + scrollbarWidth + paddingWidth;
- int contentWidth = baseWidth;
-
- if (windowWidth < m_baseWidth) {
- windowWidth = m_baseWidth;
- contentWidth = m_baseWidth - scrollbarWidth - paddingWidth;
- } else {
- m_baseWidth = baseWidth;
- }
-
- resize(windowWidth, windowHeight);
- resizeContents(contentWidth, getRowBounds(numItems() - 1).bottom());
- scrollToRevealSelection();
-
- invalidate();
-}
-
-void PopupListBox::clear()
-{
- for (Vector<ListItem*>::iterator it = m_items.begin(); it != m_items.end(); ++it)
- delete *it;
- m_items.clear();
-}
-
-bool PopupListBox::isPointInBounds(const IntPoint& point)
-{
- return numItems() != 0 && IntRect(0, 0, width(), height()).contains(point);
-}
-
-
-///////////////////////////////////////////////////////////////////////////////
-// PopupMenu implementation
-//
-// Note: you cannot add methods to this class, since it is defined above the
-// portability layer. To access methods and properties on the
-// popup widgets, use |popupWindow| above.
-
-PopupMenu::PopupMenu(PopupMenuClient* client)
- : m_popupClient(client)
- , m_popup(0)
- , m_wasClicked(false)
-{
-}
-
-PopupMenu::~PopupMenu()
-{
- hide();
-}
-
-void PopupMenu::show(const IntRect& r, FrameView* v, int index)
-{
- m_popup = PopupContainer::Create(client());
-
- PopupContainer* popup = popupWindow(m_popup);
- // The rect is the size of the select box. It's usually larger than we need.
- // subtract border size so that usually the container will be displayed
- // exactly the same width as the select box.
- popup->listBox()->setBaseWidth(max(r.width() - kBorderSize * 2, 0));
-
- updateFromElement();
-
- // We set the selected item in updateFromElement(), and disregard the
- // index passed into this function (same as Webkit's PopupMenuWin.cpp)
- // TODO(ericroman): make sure this is correct, and add an assertion.
- // DCHECK(popupWindow(m_popup)->listBox()->selectedIndex() == index);
-
- // Convert point to main window coords.
- IntPoint location = v->contentsToWindow(r.location());
-
- // Move it below the select widget.
- location.move(0, r.height());
-
- IntRect popupRect(location, r.size());
- popup->setFrameGeometry(popupRect);
- popup->showPopup(v);
-}
-
-void PopupMenu::hide()
-{
- if (m_popup) {
- PopupContainer* popup = popupWindow(m_popup);
- popup->hidePopup();
- popup->deref();
- m_popup = 0;
- }
-}
-
-void PopupMenu::updateFromElement()
-{
- popupWindow(m_popup)->listBox()->updateFromElement();
-}
-
-bool PopupMenu::itemWritingDirectionIsNatural()
-{
- return false;
-}
-
-bool PopupMenu::up(unsigned lines)
-{
- popupWindow(m_popup)->listBox()->adjustSelectedIndex(-static_cast<int>(lines));
- return true;
-}
-
-bool PopupMenu::down(unsigned lines)
-{
- popupWindow(m_popup)->listBox()->adjustSelectedIndex(static_cast<int>(lines));
- return true;
-}
-
-int PopupMenu::focusedIndex() const
-{
- return popupWindow(m_popup)->listBox()->selectedIndex();
-}
-
-void PopupMenu::valueChanged(Scrollbar*)
-{
- // FIXME
-}
-
-WebCore::IntRect PopupMenu::windowClipRect() const
-{
- // FIXME
- return WebCore::IntRect();
-}
-
-} // namespace WebCore
« no previous file with comments | « webkit/port/platform/PlatformScrollBarWin.cpp ('k') | webkit/port/platform/SSLKeyGeneratorWin.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698