📄 rendertextcontrol.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 "RenderTextControl.h"#include "CharacterNames.h"#include "Editor.h"#include "Event.h"#include "EventNames.h"#include "Frame.h"#include "HTMLBRElement.h"#include "HTMLFormControlElement.h"#include "HTMLNames.h"#include "HitTestResult.h"#include "RenderLayer.h"#include "RenderText.h"#include "ScrollbarTheme.h"#include "SelectionController.h"#include "Text.h"#include "TextControlInnerElements.h"#include "TextIterator.h"using namespace std;namespace WebCore {using namespace HTMLNames;// Value chosen by observation. This can be tweaked.static const int minColorContrastValue = 1300;static Color disabledTextColor(const Color& textColor, const Color& backgroundColor){ // The explicit check for black is an optimization for the 99% case (black on white). // This also means that black on black will turn into grey on black when disabled. Color disabledColor; if (textColor.rgb() == Color::black || differenceSquared(textColor, Color::white) > differenceSquared(backgroundColor, Color::white)) disabledColor = textColor.light(); else disabledColor = textColor.dark(); // If there's not very much contrast between the disabled color and the background color, // just leave the text color alone. We don't want to change a good contrast color scheme so that it has really bad contrast. // If the the contrast was already poor, then it doesn't do any good to change it to a different poor contrast color scheme. if (differenceSquared(disabledColor, backgroundColor) < minColorContrastValue) return textColor; return disabledColor;}RenderTextControl::RenderTextControl(Node* node) : RenderBlock(node) , m_edited(false) , m_userEdited(false){}RenderTextControl::~RenderTextControl(){ // The children renderers have already been destroyed by destroyLeftoverChildren if (m_innerText) m_innerText->detach();}void RenderTextControl::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle){ RenderBlock::styleDidChange(diff, oldStyle); if (m_innerText) { RenderBlock* textBlockRenderer = toRenderBlock(m_innerText->renderer()); RefPtr<RenderStyle> textBlockStyle = createInnerTextStyle(style()); // 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. textBlockRenderer->style()->setHeight(Length()); textBlockRenderer->style()->setWidth(Length()); textBlockRenderer->setStyle(textBlockStyle); for (Node* n = m_innerText->firstChild(); n; n = n->traverseNextNode(m_innerText.get())) { if (n->renderer()) n->renderer()->setStyle(textBlockStyle); } } setHasOverflowClip(false); setReplaced(isInline());}static inline bool updateUserModifyProperty(Node* node, RenderStyle* style){ bool isEnabled = true; bool isReadOnlyControl = false; if (node->isElementNode()) { FormControlElement* formControlElement = toFormControlElement(static_cast<Element*>(node)); ASSERT(formControlElement); isEnabled = formControlElement->isEnabled(); isReadOnlyControl = formControlElement->isReadOnlyControl(); } style->setUserModify((isReadOnlyControl || !isEnabled) ? READ_ONLY : READ_WRITE_PLAINTEXT_ONLY); return !isEnabled;}void RenderTextControl::adjustInnerTextStyle(const RenderStyle* startStyle, RenderStyle* textBlockStyle) const{ // The inner block, if present, always has its direction set to LTR, // so we need to inherit the direction from the element. textBlockStyle->setDirection(style()->direction()); bool disabled = updateUserModifyProperty(node(), textBlockStyle); if (disabled) textBlockStyle->setColor(disabledTextColor(textBlockStyle->color(), startStyle->backgroundColor()));}void RenderTextControl::createSubtreeIfNeeded(TextControlInnerElement* innerBlock){ if (!m_innerText) { // Create the text block element // For non-search fields, there is no intermediate innerBlock as the shadow node. // m_innerText will be the shadow node in that case. RenderStyle* parentStyle = innerBlock ? innerBlock->renderer()->style() : style(); m_innerText = new TextControlInnerTextElement(document(), innerBlock ? 0 : node()); m_innerText->attachInnerElement(innerBlock ? innerBlock : node(), createInnerTextStyle(parentStyle), renderArena()); }}int RenderTextControl::textBlockHeight() const{ return height() - paddingTop() - paddingBottom() - borderTop() - borderBottom();}int RenderTextControl::textBlockWidth() const{ return width() - paddingLeft() - paddingRight() - borderLeft() - borderRight() - m_innerText->renderBox()->paddingLeft() - m_innerText->renderBox()->paddingRight();}void RenderTextControl::updateFromElement(){ updateUserModifyProperty(node(), m_innerText->renderer()->style());}void RenderTextControl::setInnerTextValue(const String& innerTextValue){ String value; if (innerTextValue.isNull()) value = ""; else { value = innerTextValue; value = document()->displayStringModifiedByEncoding(value); } if (value != text() || !m_innerText->hasChildNodes()) { if (value != text()) { if (Frame* frame = document()->frame()) frame->editor()->clearUndoRedoOperations(); } ExceptionCode ec = 0; m_innerText->setInnerText(value, ec); ASSERT(!ec); if (value.endsWith("\n") || value.endsWith("\r")) { m_innerText->appendChild(new HTMLBRElement(brTag, document()), ec); ASSERT(!ec); } m_edited = false; m_userEdited = false; } formControlElement()->setValueMatchesRenderer();}void RenderTextControl::setUserEdited(bool isUserEdited){ m_userEdited = isUserEdited; document()->setIgnoreAutofocus(isUserEdited);}int RenderTextControl::selectionStart(){ Frame* frame = document()->frame(); if (!frame) return 0; return indexForVisiblePosition(frame->selection()->start());}int RenderTextControl::selectionEnd(){ Frame* frame = document()->frame(); if (!frame) return 0; return indexForVisiblePosition(frame->selection()->end());}void RenderTextControl::setSelectionStart(int start){ setSelectionRange(start, max(start, selectionEnd()));}void RenderTextControl::setSelectionEnd(int end){ setSelectionRange(min(end, selectionStart()), end);}void RenderTextControl::select(){ setSelectionRange(0, text().length());}void RenderTextControl::setSelectionRange(int start, int end){ end = max(end, 0); start = min(max(start, 0), end); document()->updateLayout(); if (style()->visibility() == HIDDEN || !m_innerText || !m_innerText->renderer() || !m_innerText->renderBox()->height()) { cacheSelection(start, end); return; } VisiblePosition startPosition = visiblePositionForIndex(start); VisiblePosition endPosition; if (start == end) endPosition = startPosition; else endPosition = visiblePositionForIndex(end); ASSERT(startPosition.isNotNull() && endPosition.isNotNull()); ASSERT(startPosition.deepEquivalent().node()->shadowAncestorNode() == node() && endPosition.deepEquivalent().node()->shadowAncestorNode() == node()); VisibleSelection newSelection = VisibleSelection(startPosition, endPosition); if (Frame* frame = document()->frame()) frame->selection()->setSelection(newSelection); // FIXME: Granularity is stored separately on the frame, but also in the selection controller. // The granularity in the selection controller should be used, and then this line of code would not be needed. if (Frame* frame = document()->frame()) frame->setSelectionGranularity(CharacterGranularity);}VisibleSelection RenderTextControl::selection(int start, int end) const{ return VisibleSelection(VisiblePosition(m_innerText.get(), start, VP_DEFAULT_AFFINITY), VisiblePosition(m_innerText.get(), end, VP_DEFAULT_AFFINITY));}VisiblePosition RenderTextControl::visiblePositionForIndex(int index){ if (index <= 0) return VisiblePosition(m_innerText.get(), 0, DOWNSTREAM); ExceptionCode ec = 0; RefPtr<Range> range = Range::create(document()); range->selectNodeContents(m_innerText.get(), ec); ASSERT(!ec); CharacterIterator it(range.get()); it.advance(index - 1); Node* endContainer = it.range()->endContainer(ec); ASSERT(!ec); int endOffset = it.range()->endOffset(ec); ASSERT(!ec); return VisiblePosition(endContainer, endOffset, UPSTREAM);}int RenderTextControl::indexForVisiblePosition(const VisiblePosition& pos){ Position indexPosition = pos.deepEquivalent(); if (!indexPosition.node() || indexPosition.node()->rootEditableElement() != m_innerText) return 0; ExceptionCode ec = 0; RefPtr<Range> range = Range::create(document()); range->setStart(m_innerText.get(), 0, ec); ASSERT(!ec); range->setEnd(indexPosition.node(), indexPosition.offset(), ec); ASSERT(!ec);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -