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

Unified Diff: third_party/WebKit/WebCore/rendering/RenderTextControl.cpp

Issue 21165: Revert the merge. Mac build is mysteriously broken. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 11 years, 10 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
Index: third_party/WebKit/WebCore/rendering/RenderTextControl.cpp
===================================================================
--- third_party/WebKit/WebCore/rendering/RenderTextControl.cpp (revision 9383)
+++ third_party/WebKit/WebCore/rendering/RenderTextControl.cpp (working copy)
@@ -1,591 +1,591 @@
-/**
- * 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 "RenderText.h"
-#include "ScrollbarTheme.h"
-#include "SelectionController.h"
-#include "SimpleFontData.h"
-#include "TextControlInnerElements.h"
-#include "Text.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);
- }
- }
-
- 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());
-
- Selection newSelection = Selection(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);
-}
-
-Selection RenderTextControl::selection(int start, int end) const
-{
- return Selection(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);
- return TextIterator::rangeLength(range.get());
-}
-
-void RenderTextControl::subtreeHasChanged()
-{
- m_edited = true;
- m_userEdited = true;
-}
-
-String RenderTextControl::finishText(Vector<UChar>& result) const
-{
- // Remove one trailing newline; there's always one that's collapsed out by rendering.
- size_t size = result.size();
- if (size && result[size - 1] == '\n')
- result.shrink(--size);
-
- // Convert backslash to currency symbol.
- document()->displayBufferModifiedByEncoding(result.data(), result.size());
-
- return String::adopt(result);
-}
-
-String RenderTextControl::text()
-{
- if (!m_innerText)
- return "";
-
- Frame* frame = document()->frame();
- Text* compositionNode = frame ? frame->editor()->compositionNode() : 0;
-
- Vector<UChar> result;
-
- for (Node* n = m_innerText.get(); n; n = n->traverseNextNode(m_innerText.get())) {
- if (n->hasTagName(brTag))
- result.append(&newlineCharacter, 1);
- else if (n->isTextNode()) {
- Text* text = static_cast<Text*>(n);
- String data = text->data();
- unsigned length = data.length();
- if (text != compositionNode)
- result.append(data.characters(), length);
- else {
- unsigned compositionStart = min(frame->editor()->compositionStart(), length);
- unsigned compositionEnd = min(max(compositionStart, frame->editor()->compositionEnd()), length);
- result.append(data.characters(), compositionStart);
- result.append(data.characters() + compositionEnd, length - compositionEnd);
- }
- }
- }
-
- return finishText(result);
-}
-
-static void getNextSoftBreak(RootInlineBox*& line, Node*& breakNode, unsigned& breakOffset)
-{
- RootInlineBox* next;
- for (; line; line = next) {
- next = line->nextRootBox();
- if (next && !line->endsWithBreak()) {
- ASSERT(line->lineBreakObj());
- breakNode = line->lineBreakObj()->node();
- breakOffset = line->lineBreakPos();
- line = next;
- return;
- }
- }
- breakNode = 0;
-}
-
-String RenderTextControl::textWithHardLineBreaks()
-{
- if (!m_innerText)
- return "";
- Node* firstChild = m_innerText->firstChild();
- if (!firstChild)
- return "";
-
- document()->updateLayout();
-
- RenderObject* renderer = firstChild->renderer();
- if (!renderer)
- return "";
-
- InlineBox* box = renderer->isText() ? toRenderText(renderer)->firstTextBox() : renderer->inlineBoxWrapper();
- if (!box)
- return "";
-
- Frame* frame = document()->frame();
- Text* compositionNode = frame ? frame->editor()->compositionNode() : 0;
-
- Node* breakNode;
- unsigned breakOffset;
- RootInlineBox* line = box->root();
- getNextSoftBreak(line, breakNode, breakOffset);
-
- Vector<UChar> result;
-
- for (Node* n = firstChild; n; n = n->traverseNextNode(m_innerText.get())) {
- if (n->hasTagName(brTag))
- result.append(&newlineCharacter, 1);
- else if (n->isTextNode()) {
- Text* text = static_cast<Text*>(n);
- String data = text->data();
- unsigned length = data.length();
- unsigned compositionStart = (text == compositionNode)
- ? min(frame->editor()->compositionStart(), length) : 0;
- unsigned compositionEnd = (text == compositionNode)
- ? min(max(compositionStart, frame->editor()->compositionEnd()), length) : 0;
- unsigned position = 0;
- while (breakNode == n && breakOffset < compositionStart) {
- result.append(data.characters() + position, breakOffset - position);
- position = breakOffset;
- result.append(&newlineCharacter, 1);
- getNextSoftBreak(line, breakNode, breakOffset);
- }
- result.append(data.characters() + position, compositionStart - position);
- position = compositionEnd;
- while (breakNode == n && breakOffset <= length) {
- if (breakOffset > position) {
- result.append(data.characters() + position, breakOffset - position);
- position = breakOffset;
- result.append(&newlineCharacter, 1);
- }
- getNextSoftBreak(line, breakNode, breakOffset);
- }
- result.append(data.characters() + position, length - position);
- }
- while (breakNode == n)
- getNextSoftBreak(line, breakNode, breakOffset);
- }
-
- return finishText(result);
-}
-
-int RenderTextControl::scrollbarThickness() const
-{
- // FIXME: We should get the size of the scrollbar from the RenderTheme instead.
- return ScrollbarTheme::nativeTheme()->scrollbarThickness();
-}
-
-void RenderTextControl::calcHeight()
-{
- setHeight(m_innerText->renderBox()->borderTop() + m_innerText->renderBox()->borderBottom() +
- m_innerText->renderBox()->paddingTop() + m_innerText->renderBox()->paddingBottom() +
- m_innerText->renderBox()->marginTop() + m_innerText->renderBox()->marginBottom());
-
- adjustControlHeightBasedOnLineHeight(m_innerText->renderer()->lineHeight(true, true));
- setHeight(height() + paddingTop() + paddingBottom() + borderTop() + borderBottom());
-
- // We are able to have a horizontal scrollbar if the overflow style is scroll, or if its auto and there's no word wrap.
- if (style()->overflowX() == OSCROLL || (style()->overflowX() == OAUTO && m_innerText->renderer()->style()->wordWrap() == NormalWordWrap))
- setHeight(height() + scrollbarThickness());
-
- RenderBlock::calcHeight();
-}
-
-void RenderTextControl::hitInnerTextBlock(HitTestResult& result, int xPos, int yPos, int tx, int ty)
-{
- result.setInnerNode(m_innerText.get());
- result.setInnerNonSharedNode(m_innerText.get());
- result.setLocalPoint(IntPoint(xPos - tx - x() - m_innerText->renderBox()->x(),
- yPos - ty - y() - m_innerText->renderBox()->y()));
-}
-
-void RenderTextControl::forwardEvent(Event* event)
-{
- if (event->type() == eventNames().blurEvent || event->type() == eventNames().focusEvent)
- return;
- m_innerText->defaultEventHandler(event);
-}
-
-IntRect RenderTextControl::controlClipRect(int tx, int ty) const
-{
- IntRect clipRect = contentBoxRect();
- clipRect.move(tx, ty);
- return clipRect;
-}
-
-void RenderTextControl::calcPrefWidths()
-{
- ASSERT(prefWidthsDirty());
-
- m_minPrefWidth = 0;
- m_maxPrefWidth = 0;
-
- if (style()->width().isFixed() && style()->width().value() > 0)
- m_minPrefWidth = m_maxPrefWidth = calcContentBoxWidth(style()->width().value());
- else {
- // Use average character width. Matches IE.
- int charWidth = style()->font().primaryFont()->avgCharWidth();
- m_maxPrefWidth = preferredContentWidth(charWidth) + m_innerText->renderBox()->paddingLeft() + m_innerText->renderBox()->paddingRight();
- }
-
- if (style()->minWidth().isFixed() && style()->minWidth().value() > 0) {
- m_maxPrefWidth = max(m_maxPrefWidth, calcContentBoxWidth(style()->minWidth().value()));
- m_minPrefWidth = max(m_minPrefWidth, calcContentBoxWidth(style()->minWidth().value()));
- } else if (style()->width().isPercent() || (style()->width().isAuto() && style()->height().isPercent()))
- m_minPrefWidth = 0;
- else
- m_minPrefWidth = m_maxPrefWidth;
-
- if (style()->maxWidth().isFixed() && style()->maxWidth().value() != undefinedLength) {
- m_maxPrefWidth = min(m_maxPrefWidth, calcContentBoxWidth(style()->maxWidth().value()));
- m_minPrefWidth = min(m_minPrefWidth, calcContentBoxWidth(style()->maxWidth().value()));
- }
-
- int toAdd = paddingLeft() + paddingRight() + borderLeft() + borderRight();
-
- m_minPrefWidth += toAdd;
- m_maxPrefWidth += toAdd;
-
- setPrefWidthsDirty(false);
-}
-
-void RenderTextControl::selectionChanged(bool userTriggered)
-{
- cacheSelection(selectionStart(), selectionEnd());
-
- if (Frame* frame = document()->frame()) {
- if (frame->selection()->isRange() && userTriggered)
- node()->dispatchEventForType(eventNames().selectEvent, true, false);
- }
-}
-
-void RenderTextControl::addFocusRingRects(GraphicsContext* graphicsContext, int tx, int ty)
-{
- graphicsContext->addFocusRingRect(IntRect(tx, ty, width(), height()));
-}
-
-void RenderTextControl::autoscroll()
-{
- RenderLayer* layer = m_innerText->renderBox()->layer();
- if (layer)
- layer->autoscroll();
-}
-
-int RenderTextControl::scrollWidth() const
-{
- if (m_innerText)
- return m_innerText->scrollWidth();
- return RenderBlock::scrollWidth();
-}
-
-int RenderTextControl::scrollHeight() const
-{
- if (m_innerText)
- return m_innerText->scrollHeight();
- return RenderBlock::scrollHeight();
-}
-
-int RenderTextControl::scrollLeft() const
-{
- if (m_innerText)
- return m_innerText->scrollLeft();
- return RenderBlock::scrollLeft();
-}
-
-int RenderTextControl::scrollTop() const
-{
- if (m_innerText)
- return m_innerText->scrollTop();
- return RenderBlock::scrollTop();
-}
-
-void RenderTextControl::setScrollLeft(int newLeft)
-{
- if (m_innerText)
- m_innerText->setScrollLeft(newLeft);
-}
-
-void RenderTextControl::setScrollTop(int newTop)
-{
- if (m_innerText)
- m_innerText->setScrollTop(newTop);
-}
-
-bool RenderTextControl::scroll(ScrollDirection direction, ScrollGranularity granularity, float multiplier)
-{
- RenderLayer* layer = m_innerText->renderBox()->layer();
- if (layer && layer->scroll(direction, granularity, multiplier))
- return true;
- return RenderBlock::scroll(direction, granularity, multiplier);
-}
-
-HTMLElement* RenderTextControl::innerTextElement() const
-{
- return m_innerText.get();
-}
-
-FormControlElement* RenderTextControl::formControlElement() const
-{
- return toFormControlElement(static_cast<Element*>(node()));
-}
-
-} // namespace WebCore
+/**
+ * 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 "RenderText.h"
+#include "ScrollbarTheme.h"
+#include "SelectionController.h"
+#include "SimpleFontData.h"
+#include "TextControlInnerElements.h"
+#include "Text.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);
+ }
+ }
+
+ 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());
+
+ Selection newSelection = Selection(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);
+}
+
+Selection RenderTextControl::selection(int start, int end) const
+{
+ return Selection(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);
+ return TextIterator::rangeLength(range.get());
+}
+
+void RenderTextControl::subtreeHasChanged()
+{
+ m_edited = true;
+ m_userEdited = true;
+}
+
+String RenderTextControl::finishText(Vector<UChar>& result) const
+{
+ // Remove one trailing newline; there's always one that's collapsed out by rendering.
+ size_t size = result.size();
+ if (size && result[size - 1] == '\n')
+ result.shrink(--size);
+
+ // Convert backslash to currency symbol.
+ document()->displayBufferModifiedByEncoding(result.data(), result.size());
+
+ return String::adopt(result);
+}
+
+String RenderTextControl::text()
+{
+ if (!m_innerText)
+ return "";
+
+ Frame* frame = document()->frame();
+ Text* compositionNode = frame ? frame->editor()->compositionNode() : 0;
+
+ Vector<UChar> result;
+
+ for (Node* n = m_innerText.get(); n; n = n->traverseNextNode(m_innerText.get())) {
+ if (n->hasTagName(brTag))
+ result.append(&newlineCharacter, 1);
+ else if (n->isTextNode()) {
+ Text* text = static_cast<Text*>(n);
+ String data = text->data();
+ unsigned length = data.length();
+ if (text != compositionNode)
+ result.append(data.characters(), length);
+ else {
+ unsigned compositionStart = min(frame->editor()->compositionStart(), length);
+ unsigned compositionEnd = min(max(compositionStart, frame->editor()->compositionEnd()), length);
+ result.append(data.characters(), compositionStart);
+ result.append(data.characters() + compositionEnd, length - compositionEnd);
+ }
+ }
+ }
+
+ return finishText(result);
+}
+
+static void getNextSoftBreak(RootInlineBox*& line, Node*& breakNode, unsigned& breakOffset)
+{
+ RootInlineBox* next;
+ for (; line; line = next) {
+ next = line->nextRootBox();
+ if (next && !line->endsWithBreak()) {
+ ASSERT(line->lineBreakObj());
+ breakNode = line->lineBreakObj()->node();
+ breakOffset = line->lineBreakPos();
+ line = next;
+ return;
+ }
+ }
+ breakNode = 0;
+}
+
+String RenderTextControl::textWithHardLineBreaks()
+{
+ if (!m_innerText)
+ return "";
+ Node* firstChild = m_innerText->firstChild();
+ if (!firstChild)
+ return "";
+
+ document()->updateLayout();
+
+ RenderObject* renderer = firstChild->renderer();
+ if (!renderer)
+ return "";
+
+ InlineBox* box = renderer->isText() ? toRenderText(renderer)->firstTextBox() : renderer->inlineBoxWrapper();
+ if (!box)
+ return "";
+
+ Frame* frame = document()->frame();
+ Text* compositionNode = frame ? frame->editor()->compositionNode() : 0;
+
+ Node* breakNode;
+ unsigned breakOffset;
+ RootInlineBox* line = box->root();
+ getNextSoftBreak(line, breakNode, breakOffset);
+
+ Vector<UChar> result;
+
+ for (Node* n = firstChild; n; n = n->traverseNextNode(m_innerText.get())) {
+ if (n->hasTagName(brTag))
+ result.append(&newlineCharacter, 1);
+ else if (n->isTextNode()) {
+ Text* text = static_cast<Text*>(n);
+ String data = text->data();
+ unsigned length = data.length();
+ unsigned compositionStart = (text == compositionNode)
+ ? min(frame->editor()->compositionStart(), length) : 0;
+ unsigned compositionEnd = (text == compositionNode)
+ ? min(max(compositionStart, frame->editor()->compositionEnd()), length) : 0;
+ unsigned position = 0;
+ while (breakNode == n && breakOffset < compositionStart) {
+ result.append(data.characters() + position, breakOffset - position);
+ position = breakOffset;
+ result.append(&newlineCharacter, 1);
+ getNextSoftBreak(line, breakNode, breakOffset);
+ }
+ result.append(data.characters() + position, compositionStart - position);
+ position = compositionEnd;
+ while (breakNode == n && breakOffset <= length) {
+ if (breakOffset > position) {
+ result.append(data.characters() + position, breakOffset - position);
+ position = breakOffset;
+ result.append(&newlineCharacter, 1);
+ }
+ getNextSoftBreak(line, breakNode, breakOffset);
+ }
+ result.append(data.characters() + position, length - position);
+ }
+ while (breakNode == n)
+ getNextSoftBreak(line, breakNode, breakOffset);
+ }
+
+ return finishText(result);
+}
+
+int RenderTextControl::scrollbarThickness() const
+{
+ // FIXME: We should get the size of the scrollbar from the RenderTheme instead.
+ return ScrollbarTheme::nativeTheme()->scrollbarThickness();
+}
+
+void RenderTextControl::calcHeight()
+{
+ setHeight(m_innerText->renderBox()->borderTop() + m_innerText->renderBox()->borderBottom() +
+ m_innerText->renderBox()->paddingTop() + m_innerText->renderBox()->paddingBottom() +
+ m_innerText->renderBox()->marginTop() + m_innerText->renderBox()->marginBottom());
+
+ adjustControlHeightBasedOnLineHeight(m_innerText->renderer()->lineHeight(true, true));
+ setHeight(height() + paddingTop() + paddingBottom() + borderTop() + borderBottom());
+
+ // We are able to have a horizontal scrollbar if the overflow style is scroll, or if its auto and there's no word wrap.
+ if (style()->overflowX() == OSCROLL || (style()->overflowX() == OAUTO && m_innerText->renderer()->style()->wordWrap() == NormalWordWrap))
+ setHeight(height() + scrollbarThickness());
+
+ RenderBlock::calcHeight();
+}
+
+void RenderTextControl::hitInnerTextBlock(HitTestResult& result, int xPos, int yPos, int tx, int ty)
+{
+ result.setInnerNode(m_innerText.get());
+ result.setInnerNonSharedNode(m_innerText.get());
+ result.setLocalPoint(IntPoint(xPos - tx - x() - m_innerText->renderBox()->x(),
+ yPos - ty - y() - m_innerText->renderBox()->y()));
+}
+
+void RenderTextControl::forwardEvent(Event* event)
+{
+ if (event->type() == eventNames().blurEvent || event->type() == eventNames().focusEvent)
+ return;
+ m_innerText->defaultEventHandler(event);
+}
+
+IntRect RenderTextControl::controlClipRect(int tx, int ty) const
+{
+ IntRect clipRect = contentBoxRect();
+ clipRect.move(tx, ty);
+ return clipRect;
+}
+
+void RenderTextControl::calcPrefWidths()
+{
+ ASSERT(prefWidthsDirty());
+
+ m_minPrefWidth = 0;
+ m_maxPrefWidth = 0;
+
+ if (style()->width().isFixed() && style()->width().value() > 0)
+ m_minPrefWidth = m_maxPrefWidth = calcContentBoxWidth(style()->width().value());
+ else {
+ // Use average character width. Matches IE.
+ int charWidth = style()->font().primaryFont()->avgCharWidth();
+ m_maxPrefWidth = preferredContentWidth(charWidth) + m_innerText->renderBox()->paddingLeft() + m_innerText->renderBox()->paddingRight();
+ }
+
+ if (style()->minWidth().isFixed() && style()->minWidth().value() > 0) {
+ m_maxPrefWidth = max(m_maxPrefWidth, calcContentBoxWidth(style()->minWidth().value()));
+ m_minPrefWidth = max(m_minPrefWidth, calcContentBoxWidth(style()->minWidth().value()));
+ } else if (style()->width().isPercent() || (style()->width().isAuto() && style()->height().isPercent()))
+ m_minPrefWidth = 0;
+ else
+ m_minPrefWidth = m_maxPrefWidth;
+
+ if (style()->maxWidth().isFixed() && style()->maxWidth().value() != undefinedLength) {
+ m_maxPrefWidth = min(m_maxPrefWidth, calcContentBoxWidth(style()->maxWidth().value()));
+ m_minPrefWidth = min(m_minPrefWidth, calcContentBoxWidth(style()->maxWidth().value()));
+ }
+
+ int toAdd = paddingLeft() + paddingRight() + borderLeft() + borderRight();
+
+ m_minPrefWidth += toAdd;
+ m_maxPrefWidth += toAdd;
+
+ setPrefWidthsDirty(false);
+}
+
+void RenderTextControl::selectionChanged(bool userTriggered)
+{
+ cacheSelection(selectionStart(), selectionEnd());
+
+ if (Frame* frame = document()->frame()) {
+ if (frame->selection()->isRange() && userTriggered)
+ static_cast<EventTargetNode*>(node())->dispatchEventForType(eventNames().selectEvent, true, false);
+ }
+}
+
+void RenderTextControl::addFocusRingRects(GraphicsContext* graphicsContext, int tx, int ty)
+{
+ graphicsContext->addFocusRingRect(IntRect(tx, ty, width(), height()));
+}
+
+void RenderTextControl::autoscroll()
+{
+ RenderLayer* layer = m_innerText->renderBox()->layer();
+ if (layer)
+ layer->autoscroll();
+}
+
+int RenderTextControl::scrollWidth() const
+{
+ if (m_innerText)
+ return m_innerText->scrollWidth();
+ return RenderBlock::scrollWidth();
+}
+
+int RenderTextControl::scrollHeight() const
+{
+ if (m_innerText)
+ return m_innerText->scrollHeight();
+ return RenderBlock::scrollHeight();
+}
+
+int RenderTextControl::scrollLeft() const
+{
+ if (m_innerText)
+ return m_innerText->scrollLeft();
+ return RenderBlock::scrollLeft();
+}
+
+int RenderTextControl::scrollTop() const
+{
+ if (m_innerText)
+ return m_innerText->scrollTop();
+ return RenderBlock::scrollTop();
+}
+
+void RenderTextControl::setScrollLeft(int newLeft)
+{
+ if (m_innerText)
+ m_innerText->setScrollLeft(newLeft);
+}
+
+void RenderTextControl::setScrollTop(int newTop)
+{
+ if (m_innerText)
+ m_innerText->setScrollTop(newTop);
+}
+
+bool RenderTextControl::scroll(ScrollDirection direction, ScrollGranularity granularity, float multiplier)
+{
+ RenderLayer* layer = m_innerText->renderBox()->layer();
+ if (layer && layer->scroll(direction, granularity, multiplier))
+ return true;
+ return RenderBlock::scroll(direction, granularity, multiplier);
+}
+
+HTMLElement* RenderTextControl::innerTextElement() const
+{
+ return m_innerText.get();
+}
+
+FormControlElement* RenderTextControl::formControlElement() const
+{
+ return toFormControlElement(static_cast<Element*>(node()));
+}
+
+} // namespace WebCore
« no previous file with comments | « third_party/WebKit/WebCore/rendering/RenderText.cpp ('k') | third_party/WebKit/WebCore/rendering/RenderTreeAsText.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698