📄 rendertextcontrolsingleline.cpp
字号:
/** * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. * (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) * * 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 "RenderTextControlSingleLine.h"#include "CSSStyleSelector.h"#include "Event.h"#include "EventNames.h"#include "Frame.h"#include "FrameView.h"#include "HitTestResult.h"#include "HTMLInputElement.h"#include "HTMLNames.h"#include "InputElement.h"#include "LocalizedStrings.h"#include "MouseEvent.h"#include "PlatformKeyboardEvent.h"#include "RenderScrollbar.h"#include "RenderTheme.h"#include "SearchPopupMenu.h"#include "SelectionController.h"#include "Settings.h"#include "TextControlInnerElements.h"using namespace std;namespace WebCore {using namespace HTMLNames;RenderTextControlSingleLine::RenderTextControlSingleLine(Node* node) : RenderTextControl(node) , m_placeholderVisible(false) , m_searchPopupIsVisible(false) , m_shouldDrawCapsLockIndicator(false) , m_searchEventTimer(this, &RenderTextControlSingleLine::searchEventTimerFired) , m_searchPopup(0){}RenderTextControlSingleLine::~RenderTextControlSingleLine(){ if (m_searchPopup) { m_searchPopup->disconnectClient(); m_searchPopup = 0; } if (m_innerBlock) m_innerBlock->detach();}bool RenderTextControlSingleLine::placeholderShouldBeVisible() const{ return inputElement()->placeholderShouldBeVisible();}void RenderTextControlSingleLine::updatePlaceholderVisibility(){ RenderStyle* parentStyle = m_innerBlock ? m_innerBlock->renderer()->style() : style(); RefPtr<RenderStyle> textBlockStyle = createInnerTextStyle(parentStyle); HTMLElement* innerText = innerTextElement(); innerText->renderer()->setStyle(textBlockStyle); for (Node* n = innerText->firstChild(); n; n = n->traverseNextNode(innerText)) { if (RenderObject* renderer = n->renderer()) renderer->setStyle(textBlockStyle); } updateFromElement();}void RenderTextControlSingleLine::addSearchResult(){ ASSERT(node()->isHTMLElement()); HTMLInputElement* input = static_cast<HTMLInputElement*>(node()); 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 = SearchPopupMenu::create(this); m_searchPopup->saveRecentSearches(name, m_recentSearches);}void RenderTextControlSingleLine::stopSearchEventTimer(){ ASSERT(node()->isHTMLElement()); m_searchEventTimer.stop();}void RenderTextControlSingleLine::showPopup(){ ASSERT(node()->isHTMLElement()); if (m_searchPopupIsVisible) return; if (!m_searchPopup) m_searchPopup = SearchPopupMenu::create(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 = static_cast<HTMLInputElement*>(node()); 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->show(absoluteBoundingBoxRect(true), document()->view(), -1);}void RenderTextControlSingleLine::hidePopup(){ ASSERT(node()->isHTMLElement()); if (m_searchPopup) m_searchPopup->hide(); m_searchPopupIsVisible = false;}void RenderTextControlSingleLine::subtreeHasChanged(){ bool wasEdited = isEdited(); RenderTextControl::subtreeHasChanged(); InputElement* input = inputElement(); input->setValueFromRenderer(input->constrainValue(text())); if (RenderObject* cancelButtonRenderer = m_cancelButton ? m_cancelButton->renderer() : 0) updateCancelButtonVisibility(cancelButtonRenderer->style()); // If the incremental attribute is set, then dispatch the search event if (input->searchEventsShouldBeDispatched()) startSearchEventTimer(); if (!wasEdited && node()->focused()) { if (Frame* frame = document()->frame()) frame->textFieldDidBeginEditing(static_cast<Element*>(node())); } if (node()->focused()) { if (Frame* frame = document()->frame()) frame->textDidChangeInTextField(static_cast<Element*>(node())); }}void RenderTextControlSingleLine::paint(PaintInfo& paintInfo, int tx, int ty){ RenderTextControl::paint(paintInfo, tx, ty); if (paintInfo.phase == PaintPhaseBlockBackground && m_shouldDrawCapsLockIndicator) { IntRect contentsRect = contentBoxRect(); // Convert the rect into the coords used for painting the content contentsRect.move(tx + x(), ty + y()); theme()->paintCapsLockIndicator(this, paintInfo, contentsRect); }}void RenderTextControlSingleLine::layout(){ int oldHeight = height(); calcHeight(); int oldWidth = width(); calcWidth(); bool relayoutChildren = oldHeight != height() || oldWidth != width(); RenderBox* innerTextRenderer = innerTextElement()->renderBox(); RenderBox* innerBlockRenderer = m_innerBlock ? m_innerBlock->renderBox() : 0; // Set the text block height int desiredHeight = textBlockHeight(); int currentHeight = innerTextRenderer->height(); if (m_innerBlock || currentHeight > height()) { if (desiredHeight != currentHeight) relayoutChildren = true; innerTextRenderer->style()->setHeight(Length(desiredHeight, Fixed)); } if (m_innerBlock) { ASSERT(innerBlockRenderer); if (desiredHeight != innerBlockRenderer->height()) relayoutChildren = true; innerBlockRenderer->style()->setHeight(Length(desiredHeight, Fixed)); } // Set the text block width int desiredWidth = textBlockWidth(); if (desiredWidth != innerTextRenderer->width()) relayoutChildren = true; innerTextRenderer->style()->setWidth(Length(desiredWidth, Fixed)); if (m_innerBlock) { int innerBlockWidth = width() - paddingLeft() - paddingRight() - borderLeft() - borderRight(); if (innerBlockWidth != innerBlockRenderer->width()) relayoutChildren = true; innerBlockRenderer->style()->setWidth(Length(innerBlockWidth, Fixed)); } RenderBlock::layoutBlock(relayoutChildren); // For text fields, center the inner text vertically // Don't do this for search fields, since we don't honor height for them if (!m_innerBlock) { currentHeight = innerTextRenderer->height(); if (currentHeight < height()) innerTextRenderer->setLocation(innerTextRenderer->x(), (height() - currentHeight) / 2); }}bool RenderTextControlSingleLine::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int xPos, int yPos, int tx, int ty, HitTestAction hitTestAction){ // If we're within the text control, we want to act as if we've hit the inner text block element, in case the point // was on the control but not on the inner element (see Radar 4617841). // In a search field, we want to act as if we've hit the results block if we're to the left of the inner text block, // and act as if we've hit the close block if we're to the right of the inner text block. if (!RenderTextControl::nodeAtPoint(request, result, xPos, yPos, tx, ty, hitTestAction)) return false; if (result.innerNode() != node() && result.innerNode() != innerTextElement()) return false; hitInnerTextBlock(result, xPos, yPos, tx, ty); if (!m_innerBlock) return true; Node* innerNode = 0; RenderBox* innerBlockRenderer = m_innerBlock->renderBox(); RenderBox* innerTextRenderer = innerTextElement()->renderBox(); IntPoint localPoint = result.localPoint(); localPoint.move(-innerBlockRenderer->x(), -innerBlockRenderer->y()); int textLeft = tx + x() + innerBlockRenderer->x() + innerTextRenderer->x(); if (m_resultsButton && m_resultsButton->renderer() && xPos < textLeft) innerNode = m_resultsButton.get(); if (!innerNode) { int textRight = textLeft + innerTextRenderer->width(); if (m_cancelButton && m_cancelButton->renderer() && xPos > textRight) innerNode = m_cancelButton.get(); } if (innerNode) { result.setInnerNode(innerNode); localPoint.move(-innerNode->renderBox()->x(), -innerNode->renderBox()->y()); } result.setLocalPoint(localPoint); return true;}void RenderTextControlSingleLine::forwardEvent(Event* event){ RenderBox* innerTextRenderer = innerTextElement()->renderBox(); if (event->type() == eventNames().blurEvent) { if (innerTextRenderer) { if (RenderLayer* innerLayer = innerTextRenderer->layer()) innerLayer->scrollToOffset(style()->direction() == RTL ? innerLayer->scrollWidth() : 0, 0); } capsLockStateMayHaveChanged(); } else if (event->type() == eventNames().focusEvent) capsLockStateMayHaveChanged(); if (!event->isMouseEvent()) { RenderTextControl::forwardEvent(event); return; } FloatPoint localPoint = innerTextRenderer->absoluteToLocal(FloatPoint(static_cast<MouseEvent*>(event)->pageX(), static_cast<MouseEvent*>(event)->pageY()), false, true); if (m_resultsButton && localPoint.x() < innerTextRenderer->borderBoxRect().x()) m_resultsButton->defaultEventHandler(event); else if (m_cancelButton && localPoint.x() > innerTextRenderer->borderBoxRect().right()) m_cancelButton->defaultEventHandler(event); else RenderTextControl::forwardEvent(event);}void RenderTextControlSingleLine::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle){ RenderTextControl::styleDidChange(diff, oldStyle); if (RenderObject* innerBlockRenderer = m_innerBlock ? m_innerBlock->renderer() : 0) { // We may have set the width and the height in the old style in layout(). // Reset them now to avoid getting a spurious layout hint. innerBlockRenderer->style()->setHeight(Length()); innerBlockRenderer->style()->setWidth(Length()); innerBlockRenderer->setStyle(createInnerBlockStyle(style())); } if (RenderObject* resultsRenderer = m_resultsButton ? m_resultsButton->renderer() : 0) resultsRenderer->setStyle(createResultsButtonStyle(style())); if (RenderObject* cancelRenderer = m_cancelButton ? m_cancelButton->renderer() : 0) cancelRenderer->setStyle(createCancelButtonStyle(style()));}void RenderTextControlSingleLine::capsLockStateMayHaveChanged(){ if (!node() || !document()) return; // Only draw the caps lock indicator if these things are true: // 1) The field is a password field // 2) The frame is active // 3) The element is focused // 4) The caps lock is on bool shouldDrawCapsLockIndicator = false; if (Frame* frame = document()->frame()) shouldDrawCapsLockIndicator = inputElement()->isPasswordField() && frame->selection()->isFocusedAndActive() && document()->focusedNode() == node() && PlatformKeyboardEvent::currentCapsLockState(); if (shouldDrawCapsLockIndicator != m_shouldDrawCapsLockIndicator) { m_shouldDrawCapsLockIndicator = shouldDrawCapsLockIndicator; repaint(); }}int RenderTextControlSingleLine::textBlockWidth() const{ int width = RenderTextControl::textBlockWidth(); if (RenderBox* resultsRenderer = m_resultsButton ? m_resultsButton->renderBox() : 0) { resultsRenderer->calcWidth(); width -= resultsRenderer->width() + resultsRenderer->marginLeft() + resultsRenderer->marginRight(); } if (RenderBox* cancelRenderer = m_cancelButton ? m_cancelButton->renderBox() : 0) { cancelRenderer->calcWidth(); width -= cancelRenderer->width() + cancelRenderer->marginLeft() + cancelRenderer->marginRight();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -