diff options
| author | Simon Hausmann <simon.hausmann@nokia.com> | 2012-06-20 13:01:08 +0200 |
|---|---|---|
| committer | Simon Hausmann <simon.hausmann@nokia.com> | 2012-06-20 13:01:08 +0200 |
| commit | 49233e234e5c787396cadb2cea33b31ae0cd65c1 (patch) | |
| tree | 5410cb9a8fd53168bb60d62c54b654d86f03c38d /Source/WebCore/rendering/RenderSearchField.cpp | |
| parent | b211c645d8ab690f713515dfdc84d80b11c27d2c (diff) | |
| download | qtwebkit-49233e234e5c787396cadb2cea33b31ae0cd65c1.tar.gz | |
Imported WebKit commit 3a8c29f35d00659d2ce7a0ccdfa8304f14e82327 (http://svn.webkit.org/repository/webkit/trunk@120813)
New snapshot with Windows build fixes
Diffstat (limited to 'Source/WebCore/rendering/RenderSearchField.cpp')
| -rw-r--r-- | Source/WebCore/rendering/RenderSearchField.cpp | 385 |
1 files changed, 385 insertions, 0 deletions
diff --git a/Source/WebCore/rendering/RenderSearchField.cpp b/Source/WebCore/rendering/RenderSearchField.cpp new file mode 100644 index 000000000..2704cdc03 --- /dev/null +++ b/Source/WebCore/rendering/RenderSearchField.cpp @@ -0,0 +1,385 @@ +/** + * Copyright (C) 2006, 2007, 2010 Apple Inc. All rights reserved. + * (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) + * Copyright (C) 2010 Google Inc. All rights reserved. + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "RenderSearchField.h" + +#include "CSSFontSelector.h" +#include "CSSValueKeywords.h" +#include "Chrome.h" +#include "Frame.h" +#include "FrameSelection.h" +#include "FrameView.h" +#include "HTMLInputElement.h" +#include "HTMLNames.h" +#include "HitTestResult.h" +#include "LocalizedStrings.h" +#include "Page.h" +#include "PlatformKeyboardEvent.h" +#include "RenderLayer.h" +#include "RenderScrollbar.h" +#include "RenderTheme.h" +#include "SearchPopupMenu.h" +#include "Settings.h" +#include "SimpleFontData.h" +#include "StyleResolver.h" +#include "TextControlInnerElements.h" + +using namespace std; + +namespace WebCore { + +using namespace HTMLNames; + +// ---------------------------- + +RenderSearchField::RenderSearchField(Node* node) + : RenderTextControlSingleLine(node) + , m_searchPopupIsVisible(false) + , m_searchPopup(0) +{ + ASSERT(node->isHTMLElement()); + ASSERT(node->toInputElement()); + ASSERT(node->toInputElement()->isSearchField()); +} + +RenderSearchField::~RenderSearchField() +{ + if (m_searchPopup) { + m_searchPopup->popupMenu()->disconnectClient(); + m_searchPopup = 0; + } +} + +inline HTMLElement* RenderSearchField::resultsButtonElement() const +{ + return inputElement()->resultsButtonElement(); +} + +inline HTMLElement* RenderSearchField::cancelButtonElement() const +{ + return inputElement()->cancelButtonElement(); +} + +void RenderSearchField::addSearchResult() +{ + HTMLInputElement* input = inputElement(); + if (input->maxResults() <= 0) + return; + + String value = input->value(); + if (value.isEmpty()) + return; + + Settings* settings = document()->settings(); + if (!settings || settings->privateBrowsingEnabled()) + return; + + int size = static_cast<int>(m_recentSearches.size()); + for (int i = size - 1; i >= 0; --i) { + if (m_recentSearches[i] == value) + m_recentSearches.remove(i); + } + + m_recentSearches.insert(0, value); + while (static_cast<int>(m_recentSearches.size()) > input->maxResults()) + m_recentSearches.removeLast(); + + const AtomicString& name = autosaveName(); + if (!m_searchPopup) + m_searchPopup = document()->page()->chrome()->createSearchPopupMenu(this); + + m_searchPopup->saveRecentSearches(name, m_recentSearches); +} + +void RenderSearchField::showPopup() +{ + if (m_searchPopupIsVisible) + return; + + if (!m_searchPopup) + m_searchPopup = document()->page()->chrome()->createSearchPopupMenu(this); + + if (!m_searchPopup->enabled()) + return; + + m_searchPopupIsVisible = true; + + const AtomicString& name = autosaveName(); + m_searchPopup->loadRecentSearches(name, m_recentSearches); + + // Trim the recent searches list if the maximum size has changed since we last saved. + HTMLInputElement* input = inputElement(); + if (static_cast<int>(m_recentSearches.size()) > input->maxResults()) { + do { + m_recentSearches.removeLast(); + } while (static_cast<int>(m_recentSearches.size()) > input->maxResults()); + + m_searchPopup->saveRecentSearches(name, m_recentSearches); + } + + m_searchPopup->popupMenu()->show(pixelSnappedIntRect(absoluteBoundingBoxRect()), document()->view(), -1); +} + +void RenderSearchField::hidePopup() +{ + if (m_searchPopup) + m_searchPopup->popupMenu()->hide(); +} + +LayoutUnit RenderSearchField::computeControlHeight(LayoutUnit lineHeight, LayoutUnit nonContentHeight) const +{ + HTMLElement* resultsButton = resultsButtonElement(); + if (RenderBox* resultsRenderer = resultsButton ? resultsButton->renderBox() : 0) { + resultsRenderer->computeLogicalHeight(); + nonContentHeight = max(nonContentHeight, resultsRenderer->borderAndPaddingHeight() + resultsRenderer->marginHeight()); + lineHeight = max(lineHeight, resultsRenderer->height()); + } + HTMLElement* cancelButton = cancelButtonElement(); + if (RenderBox* cancelRenderer = cancelButton ? cancelButton->renderBox() : 0) { + cancelRenderer->computeLogicalHeight(); + nonContentHeight = max(nonContentHeight, cancelRenderer->borderAndPaddingHeight() + cancelRenderer->marginHeight()); + lineHeight = max(lineHeight, cancelRenderer->height()); + } + + return lineHeight + nonContentHeight; +} + +void RenderSearchField::updateFromElement() +{ + RenderTextControlSingleLine::updateFromElement(); + + if (cancelButtonElement()) + updateCancelButtonVisibility(); + + if (m_searchPopupIsVisible) + m_searchPopup->popupMenu()->updateFromElement(); +} + +void RenderSearchField::updateCancelButtonVisibility() const +{ + RenderObject* cancelButtonRenderer = cancelButtonElement()->renderer(); + if (!cancelButtonRenderer) + return; + + const RenderStyle* curStyle = cancelButtonRenderer->style(); + EVisibility buttonVisibility = visibilityForCancelButton(); + if (curStyle->visibility() == buttonVisibility) + return; + + RefPtr<RenderStyle> cancelButtonStyle = RenderStyle::clone(curStyle); + cancelButtonStyle->setVisibility(buttonVisibility); + cancelButtonRenderer->setStyle(cancelButtonStyle); +} + +EVisibility RenderSearchField::visibilityForCancelButton() const +{ + return (style()->visibility() == HIDDEN || inputElement()->value().isEmpty()) ? HIDDEN : VISIBLE; +} + +const AtomicString& RenderSearchField::autosaveName() const +{ + return static_cast<Element*>(node())->getAttribute(autosaveAttr); +} + +// PopupMenuClient methods +void RenderSearchField::valueChanged(unsigned listIndex, bool fireEvents) +{ + ASSERT(static_cast<int>(listIndex) < listSize()); + HTMLInputElement* input = inputElement(); + if (static_cast<int>(listIndex) == (listSize() - 1)) { + if (fireEvents) { + m_recentSearches.clear(); + const AtomicString& name = autosaveName(); + if (!name.isEmpty()) { + if (!m_searchPopup) + m_searchPopup = document()->page()->chrome()->createSearchPopupMenu(this); + m_searchPopup->saveRecentSearches(name, m_recentSearches); + } + } + } else { + input->setValue(itemText(listIndex)); + if (fireEvents) + input->onSearch(); + input->select(); + } +} + +String RenderSearchField::itemText(unsigned listIndex) const +{ + int size = listSize(); + if (size == 1) { + ASSERT(!listIndex); + return searchMenuNoRecentSearchesText(); + } + if (!listIndex) + return searchMenuRecentSearchesText(); + if (itemIsSeparator(listIndex)) + return String(); + if (static_cast<int>(listIndex) == (size - 1)) + return searchMenuClearRecentSearchesText(); + return m_recentSearches[listIndex - 1]; +} + +String RenderSearchField::itemLabel(unsigned) const +{ + return String(); +} + +String RenderSearchField::itemIcon(unsigned) const +{ + return String(); +} + +bool RenderSearchField::itemIsEnabled(unsigned listIndex) const +{ + if (!listIndex || itemIsSeparator(listIndex)) + return false; + return true; +} + +PopupMenuStyle RenderSearchField::itemStyle(unsigned) const +{ + return menuStyle(); +} + +PopupMenuStyle RenderSearchField::menuStyle() const +{ + return PopupMenuStyle(style()->visitedDependentColor(CSSPropertyColor), style()->visitedDependentColor(CSSPropertyBackgroundColor), style()->font(), style()->visibility() == VISIBLE, + style()->display() == NONE, style()->textIndent(), style()->direction(), isOverride(style()->unicodeBidi())); +} + +int RenderSearchField::clientInsetLeft() const +{ + // Inset the menu by the radius of the cap on the left so that + // it only runs along the straight part of the bezel. + return height() / 2; +} + +int RenderSearchField::clientInsetRight() const +{ + // Inset the menu by the radius of the cap on the right so that + // it only runs along the straight part of the bezel (unless it needs + // to be wider). + return height() / 2; +} + +LayoutUnit RenderSearchField::clientPaddingLeft() const +{ + LayoutUnit padding = paddingLeft(); + if (RenderBox* box = innerBlockElement() ? innerBlockElement()->renderBox() : 0) + padding += box->x(); + return padding; +} + +LayoutUnit RenderSearchField::clientPaddingRight() const +{ + LayoutUnit padding = paddingRight(); + if (RenderBox* containerBox = containerElement() ? containerElement()->renderBox() : 0) { + if (RenderBox* innerBlockBox = innerBlockElement() ? innerBlockElement()->renderBox() : 0) + padding += containerBox->width() - (innerBlockBox->x() + innerBlockBox->width()); + } + return padding; +} + +int RenderSearchField::listSize() const +{ + // If there are no recent searches, then our menu will have 1 "No recent searches" item. + if (!m_recentSearches.size()) + return 1; + // Otherwise, leave room in the menu for a header, a separator, and the "Clear recent searches" item. + return m_recentSearches.size() + 3; +} + +int RenderSearchField::selectedIndex() const +{ + return -1; +} + +void RenderSearchField::popupDidHide() +{ + m_searchPopupIsVisible = false; +} + +bool RenderSearchField::itemIsSeparator(unsigned listIndex) const +{ + // The separator will be the second to last item in our list. + return static_cast<int>(listIndex) == (listSize() - 2); +} + +bool RenderSearchField::itemIsLabel(unsigned listIndex) const +{ + return !listIndex; +} + +bool RenderSearchField::itemIsSelected(unsigned) const +{ + return false; +} + +void RenderSearchField::setTextFromItem(unsigned listIndex) +{ + inputElement()->setValue(itemText(listIndex)); +} + +FontSelector* RenderSearchField::fontSelector() const +{ + return document()->styleResolver()->fontSelector(); +} + +HostWindow* RenderSearchField::hostWindow() const +{ + return document()->view()->hostWindow(); +} + +PassRefPtr<Scrollbar> RenderSearchField::createScrollbar(ScrollableArea* scrollableArea, ScrollbarOrientation orientation, ScrollbarControlSize controlSize) +{ + RefPtr<Scrollbar> widget; + bool hasCustomScrollbarStyle = style()->hasPseudoStyle(SCROLLBAR); + if (hasCustomScrollbarStyle) + widget = RenderScrollbar::createCustomScrollbar(scrollableArea, orientation, this->node()); + else + widget = Scrollbar::createNativeScrollbar(scrollableArea, orientation, controlSize); + return widget.release(); +} + +LayoutUnit RenderSearchField::computeHeightLimit() const +{ + return height(); +} + +void RenderSearchField::centerContainerIfNeeded(RenderBox* containerRenderer) const +{ + if (!containerRenderer) + return; + + if (containerRenderer->height() <= contentHeight()) + return; + + // A quirk for find-in-page box on Safari Windows. + // http://webkit.org/b/63157 + LayoutUnit heightDiff = containerRenderer->height() - contentHeight(); + containerRenderer->setY(containerRenderer->y() - (heightDiff / 2 + layoutMod(heightDiff, 2))); +} + +} |
