WebCore/rendering/RenderTextControl.cpp
changeset 0 4f2f89ce4247
equal deleted inserted replaced
-1:000000000000 0:4f2f89ce4247
       
     1 /**
       
     2  * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
       
     3  *           (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)  
       
     4  *
       
     5  * This library is free software; you can redistribute it and/or
       
     6  * modify it under the terms of the GNU Library General Public
       
     7  * License as published by the Free Software Foundation; either
       
     8  * version 2 of the License, or (at your option) any later version.
       
     9  *
       
    10  * This library is distributed in the hope that it will be useful,
       
    11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    13  * Library General Public License for more details.
       
    14  *
       
    15  * You should have received a copy of the GNU Library General Public License
       
    16  * along with this library; see the file COPYING.LIB.  If not, write to
       
    17  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
       
    18  * Boston, MA 02110-1301, USA.
       
    19  *
       
    20  */
       
    21 
       
    22 #include "config.h"
       
    23 #include "RenderTextControl.h"
       
    24 
       
    25 #include "AXObjectCache.h"
       
    26 #include "CharacterNames.h"
       
    27 #include "Editor.h"
       
    28 #include "Event.h"
       
    29 #include "EventNames.h"
       
    30 #include "Frame.h"
       
    31 #include "HTMLBRElement.h"
       
    32 #include "HTMLNames.h"
       
    33 #include "HitTestResult.h"
       
    34 #include "RenderLayer.h"
       
    35 #include "RenderText.h"
       
    36 #include "ScrollbarTheme.h"
       
    37 #include "SelectionController.h"
       
    38 #include "Text.h"
       
    39 #include "TextControlInnerElements.h"
       
    40 #include "TextIterator.h"
       
    41 
       
    42 using namespace std;
       
    43 
       
    44 namespace WebCore {
       
    45 
       
    46 using namespace HTMLNames;
       
    47 
       
    48 // Value chosen by observation.  This can be tweaked.
       
    49 static const int minColorContrastValue = 1300;
       
    50 
       
    51 static Color disabledTextColor(const Color& textColor, const Color& backgroundColor)
       
    52 {
       
    53     // The explicit check for black is an optimization for the 99% case (black on white).
       
    54     // This also means that black on black will turn into grey on black when disabled.
       
    55     Color disabledColor;
       
    56     if (textColor.rgb() == Color::black || differenceSquared(textColor, Color::white) > differenceSquared(backgroundColor, Color::white))
       
    57         disabledColor = textColor.light();
       
    58     else
       
    59         disabledColor = textColor.dark();
       
    60     
       
    61     // If there's not very much contrast between the disabled color and the background color,
       
    62     // just leave the text color alone.  We don't want to change a good contrast color scheme so that it has really bad contrast.
       
    63     // If the the contrast was already poor, then it doesn't do any good to change it to a different poor contrast color scheme.
       
    64     if (differenceSquared(disabledColor, backgroundColor) < minColorContrastValue)
       
    65         return textColor;
       
    66     
       
    67     return disabledColor;
       
    68 }
       
    69 
       
    70 RenderTextControl::RenderTextControl(Node* node, bool placeholderVisible)
       
    71     : RenderBlock(node)
       
    72     , m_placeholderVisible(placeholderVisible)
       
    73     , m_wasChangedSinceLastChangeEvent(false)
       
    74     , m_lastChangeWasUserEdit(false)
       
    75 {
       
    76 }
       
    77 
       
    78 RenderTextControl::~RenderTextControl()
       
    79 {
       
    80     // The children renderers have already been destroyed by destroyLeftoverChildren
       
    81     if (m_innerText)
       
    82         m_innerText->detach();
       
    83 }
       
    84 
       
    85 void RenderTextControl::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
       
    86 {
       
    87     RenderBlock::styleDidChange(diff, oldStyle);
       
    88 
       
    89     if (m_innerText) {
       
    90         RenderBlock* textBlockRenderer = toRenderBlock(m_innerText->renderer());
       
    91         RefPtr<RenderStyle> textBlockStyle = createInnerTextStyle(style());
       
    92         // We may have set the width and the height in the old style in layout().
       
    93         // Reset them now to avoid getting a spurious layout hint.
       
    94         textBlockRenderer->style()->setHeight(Length());
       
    95         textBlockRenderer->style()->setWidth(Length());
       
    96         setInnerTextStyle(textBlockStyle);
       
    97     }
       
    98 
       
    99     setReplaced(isInline());
       
   100 }
       
   101 
       
   102 void RenderTextControl::setInnerTextStyle(PassRefPtr<RenderStyle> style)
       
   103 {
       
   104     if (m_innerText) {
       
   105         RefPtr<RenderStyle> textStyle = style;
       
   106         m_innerText->renderer()->setStyle(textStyle);
       
   107         for (Node* n = m_innerText->firstChild(); n; n = n->traverseNextNode(m_innerText.get())) {
       
   108             if (n->renderer())
       
   109                 n->renderer()->setStyle(textStyle);
       
   110         }
       
   111     }
       
   112 }
       
   113 
       
   114 static inline bool updateUserModifyProperty(Node* node, RenderStyle* style)
       
   115 {
       
   116     bool isEnabled = true;
       
   117     bool isReadOnlyControl = false;
       
   118 
       
   119     if (node->isElementNode()) {
       
   120         Element* element = static_cast<Element*>(node);
       
   121         isEnabled = element->isEnabledFormControl();
       
   122         isReadOnlyControl = element->isReadOnlyFormControl();
       
   123     }
       
   124 
       
   125     style->setUserModify((isReadOnlyControl || !isEnabled) ? READ_ONLY : READ_WRITE_PLAINTEXT_ONLY);
       
   126     return !isEnabled;
       
   127 }
       
   128 
       
   129 void RenderTextControl::adjustInnerTextStyle(const RenderStyle* startStyle, RenderStyle* textBlockStyle) const
       
   130 {
       
   131     // The inner block, if present, always has its direction set to LTR,
       
   132     // so we need to inherit the direction from the element.
       
   133     textBlockStyle->setDirection(style()->direction());
       
   134 
       
   135     bool disabled = updateUserModifyProperty(node(), textBlockStyle);
       
   136     if (disabled)
       
   137         textBlockStyle->setColor(disabledTextColor(textBlockStyle->visitedDependentColor(CSSPropertyColor), startStyle->visitedDependentColor(CSSPropertyBackgroundColor)));
       
   138 }
       
   139 
       
   140 void RenderTextControl::createSubtreeIfNeeded(TextControlInnerElement* innerBlock)
       
   141 {
       
   142     if (!m_innerText) {
       
   143         // Create the text block element
       
   144         // For non-search fields, there is no intermediate innerBlock as the shadow node.
       
   145         // m_innerText will be the shadow node in that case.        
       
   146         RenderStyle* parentStyle = innerBlock ? innerBlock->renderer()->style() : style();
       
   147         m_innerText = TextControlInnerTextElement::create(document(), innerBlock ? 0 : node());
       
   148         m_innerText->attachInnerElement(innerBlock ? innerBlock : node(), createInnerTextStyle(parentStyle), renderArena());
       
   149     }
       
   150 }
       
   151 
       
   152 int RenderTextControl::textBlockHeight() const
       
   153 {
       
   154     return height() - borderAndPaddingHeight();
       
   155 }
       
   156 
       
   157 int RenderTextControl::textBlockWidth() const
       
   158 {
       
   159     return width() - borderAndPaddingWidth() - m_innerText->renderBox()->paddingLeft() - m_innerText->renderBox()->paddingRight();
       
   160 }
       
   161 
       
   162 void RenderTextControl::updateFromElement()
       
   163 {
       
   164     updateUserModifyProperty(node(), m_innerText->renderer()->style());
       
   165 }
       
   166 
       
   167 void RenderTextControl::setInnerTextValue(const String& innerTextValue)
       
   168 {
       
   169     String value = innerTextValue;
       
   170     if (value != text() || !m_innerText->hasChildNodes()) {
       
   171         if (value != text()) {
       
   172             if (Frame* frame = this->frame()) {
       
   173                 frame->editor()->clearUndoRedoOperations();
       
   174                 
       
   175                 if (AXObjectCache::accessibilityEnabled())
       
   176                     document()->axObjectCache()->postNotification(this, AXObjectCache::AXValueChanged, false);
       
   177             }
       
   178         }
       
   179 
       
   180         ExceptionCode ec = 0;
       
   181         m_innerText->setInnerText(value, ec);
       
   182         ASSERT(!ec);
       
   183 
       
   184         if (value.endsWith("\n") || value.endsWith("\r")) {
       
   185             m_innerText->appendChild(HTMLBRElement::create(document()), ec);
       
   186             ASSERT(!ec);
       
   187         }
       
   188 
       
   189         // We set m_lastChangeWasUserEdit to false since this change was not explicitly made by the user (say, via typing on the keyboard), see <rdar://problem/5359921>.
       
   190         m_lastChangeWasUserEdit = false;
       
   191     }
       
   192 
       
   193     static_cast<Element*>(node())->setFormControlValueMatchesRenderer(true);
       
   194 }
       
   195 
       
   196 void RenderTextControl::setLastChangeWasUserEdit(bool lastChangeWasUserEdit)
       
   197 {
       
   198     m_lastChangeWasUserEdit = lastChangeWasUserEdit;
       
   199     document()->setIgnoreAutofocus(lastChangeWasUserEdit);
       
   200 }
       
   201 
       
   202 int RenderTextControl::selectionStart()
       
   203 {
       
   204     Frame* frame = this->frame();
       
   205     if (!frame)
       
   206         return 0;
       
   207     return indexForVisiblePosition(frame->selection()->start());
       
   208 }
       
   209 
       
   210 int RenderTextControl::selectionEnd()
       
   211 {
       
   212     Frame* frame = this->frame();
       
   213     if (!frame)
       
   214         return 0;
       
   215     return indexForVisiblePosition(frame->selection()->end());
       
   216 }
       
   217 
       
   218 void RenderTextControl::setSelectionStart(int start)
       
   219 {
       
   220     setSelectionRange(start, max(start, selectionEnd()));
       
   221 }
       
   222 
       
   223 void RenderTextControl::setSelectionEnd(int end)
       
   224 {
       
   225     setSelectionRange(min(end, selectionStart()), end);
       
   226 }
       
   227 
       
   228 void RenderTextControl::select()
       
   229 {
       
   230     setSelectionRange(0, text().length());
       
   231 }
       
   232 
       
   233 void RenderTextControl::setSelectionRange(int start, int end)
       
   234 {
       
   235     end = max(end, 0);
       
   236     start = min(max(start, 0), end);
       
   237 
       
   238     ASSERT(!document()->childNeedsAndNotInStyleRecalc());
       
   239 
       
   240     if (style()->visibility() == HIDDEN || !m_innerText || !m_innerText->renderer() || !m_innerText->renderBox()->height()) {
       
   241         cacheSelection(start, end);
       
   242         return;
       
   243     }
       
   244     VisiblePosition startPosition = visiblePositionForIndex(start);
       
   245     VisiblePosition endPosition;
       
   246     if (start == end)
       
   247         endPosition = startPosition;
       
   248     else
       
   249         endPosition = visiblePositionForIndex(end);
       
   250 
       
   251     // startPosition and endPosition can be null position for example when
       
   252     // "-webkit-user-select: none" style attribute is specified.
       
   253     if (startPosition.isNotNull() && endPosition.isNotNull()) {
       
   254         ASSERT(startPosition.deepEquivalent().node()->shadowAncestorNode() == node() && endPosition.deepEquivalent().node()->shadowAncestorNode() == node());
       
   255     }
       
   256     VisibleSelection newSelection = VisibleSelection(startPosition, endPosition);
       
   257 
       
   258     if (Frame* frame = this->frame())
       
   259         frame->selection()->setSelection(newSelection);
       
   260 }
       
   261 
       
   262 VisibleSelection RenderTextControl::selection(int start, int end) const
       
   263 {
       
   264     return VisibleSelection(VisiblePosition(m_innerText.get(), start, VP_DEFAULT_AFFINITY),
       
   265                             VisiblePosition(m_innerText.get(), end, VP_DEFAULT_AFFINITY));
       
   266 }
       
   267 
       
   268 VisiblePosition RenderTextControl::visiblePositionForIndex(int index)
       
   269 {
       
   270     if (index <= 0)
       
   271         return VisiblePosition(m_innerText.get(), 0, DOWNSTREAM);
       
   272     ExceptionCode ec = 0;
       
   273     RefPtr<Range> range = Range::create(document());
       
   274     range->selectNodeContents(m_innerText.get(), ec);
       
   275     ASSERT(!ec);
       
   276     CharacterIterator it(range.get());
       
   277     it.advance(index - 1);
       
   278     Node* endContainer = it.range()->endContainer(ec);
       
   279     ASSERT(!ec);
       
   280     int endOffset = it.range()->endOffset(ec);
       
   281     ASSERT(!ec);
       
   282     return VisiblePosition(endContainer, endOffset, UPSTREAM);
       
   283 }
       
   284 
       
   285 int RenderTextControl::indexForVisiblePosition(const VisiblePosition& pos)
       
   286 {
       
   287     Position indexPosition = pos.deepEquivalent();
       
   288     if (!indexPosition.node() || indexPosition.node()->rootEditableElement() != m_innerText)
       
   289         return 0;
       
   290     ExceptionCode ec = 0;
       
   291     RefPtr<Range> range = Range::create(document());
       
   292     range->setStart(m_innerText.get(), 0, ec);
       
   293     ASSERT(!ec);
       
   294     range->setEnd(indexPosition.node(), indexPosition.deprecatedEditingOffset(), ec);
       
   295     ASSERT(!ec);
       
   296     return TextIterator::rangeLength(range.get());
       
   297 }
       
   298 
       
   299 void RenderTextControl::subtreeHasChanged()
       
   300 {
       
   301     m_wasChangedSinceLastChangeEvent = true;
       
   302     m_lastChangeWasUserEdit = true;
       
   303 }
       
   304 
       
   305 String RenderTextControl::finishText(Vector<UChar>& result) const
       
   306 {
       
   307     // Remove one trailing newline; there's always one that's collapsed out by rendering.
       
   308     size_t size = result.size();
       
   309     if (size && result[size - 1] == '\n')
       
   310         result.shrink(--size);
       
   311 
       
   312     return String::adopt(result);
       
   313 }
       
   314 
       
   315 String RenderTextControl::text()
       
   316 {
       
   317     if (!m_innerText)
       
   318         return "";
       
   319  
       
   320     Vector<UChar> result;
       
   321 
       
   322     for (Node* n = m_innerText.get(); n; n = n->traverseNextNode(m_innerText.get())) {
       
   323         if (n->hasTagName(brTag))
       
   324             result.append(&newlineCharacter, 1);
       
   325         else if (n->isTextNode()) {
       
   326             String data = static_cast<Text*>(n)->data();
       
   327             result.append(data.characters(), data.length());
       
   328         }
       
   329     }
       
   330 
       
   331     return finishText(result);
       
   332 }
       
   333 
       
   334 static void getNextSoftBreak(RootInlineBox*& line, Node*& breakNode, unsigned& breakOffset)
       
   335 {
       
   336     RootInlineBox* next;
       
   337     for (; line; line = next) {
       
   338         next = line->nextRootBox();
       
   339         if (next && !line->endsWithBreak()) {
       
   340             ASSERT(line->lineBreakObj());
       
   341             breakNode = line->lineBreakObj()->node();
       
   342             breakOffset = line->lineBreakPos();
       
   343             line = next;
       
   344             return;
       
   345         }
       
   346     }
       
   347     breakNode = 0;
       
   348     breakOffset = 0;
       
   349 }
       
   350 
       
   351 String RenderTextControl::textWithHardLineBreaks()
       
   352 {
       
   353     if (!m_innerText)
       
   354         return "";
       
   355     Node* firstChild = m_innerText->firstChild();
       
   356     if (!firstChild)
       
   357         return "";
       
   358 
       
   359     RenderObject* renderer = firstChild->renderer();
       
   360     if (!renderer)
       
   361         return "";
       
   362 
       
   363     InlineBox* box = renderer->isText() ? toRenderText(renderer)->firstTextBox() : toRenderBox(renderer)->inlineBoxWrapper();
       
   364     if (!box)
       
   365         return "";
       
   366 
       
   367     Node* breakNode;
       
   368     unsigned breakOffset;
       
   369     RootInlineBox* line = box->root();
       
   370     getNextSoftBreak(line, breakNode, breakOffset);
       
   371 
       
   372     Vector<UChar> result;
       
   373 
       
   374     for (Node* n = firstChild; n; n = n->traverseNextNode(m_innerText.get())) {
       
   375         if (n->hasTagName(brTag))
       
   376             result.append(&newlineCharacter, 1);
       
   377         else if (n->isTextNode()) {
       
   378             Text* text = static_cast<Text*>(n);
       
   379             String data = text->data();
       
   380             unsigned length = data.length();
       
   381             unsigned position = 0;
       
   382             while (breakNode == n && breakOffset <= length) {
       
   383                 if (breakOffset > position) {
       
   384                     result.append(data.characters() + position, breakOffset - position);
       
   385                     position = breakOffset;
       
   386                     result.append(&newlineCharacter, 1);
       
   387                 }
       
   388                 getNextSoftBreak(line, breakNode, breakOffset);
       
   389             }
       
   390             result.append(data.characters() + position, length - position);
       
   391         }
       
   392         while (breakNode == n)
       
   393             getNextSoftBreak(line, breakNode, breakOffset);
       
   394     }
       
   395 
       
   396     return finishText(result);
       
   397 }
       
   398 
       
   399 int RenderTextControl::scrollbarThickness() const
       
   400 {
       
   401     // FIXME: We should get the size of the scrollbar from the RenderTheme instead.
       
   402     return ScrollbarTheme::nativeTheme()->scrollbarThickness();
       
   403 }
       
   404 
       
   405 void RenderTextControl::calcHeight()
       
   406 {
       
   407     setHeight(m_innerText->renderBox()->borderTop() + m_innerText->renderBox()->borderBottom() +
       
   408               m_innerText->renderBox()->paddingTop() + m_innerText->renderBox()->paddingBottom() +
       
   409               m_innerText->renderBox()->marginTop() + m_innerText->renderBox()->marginBottom());
       
   410 
       
   411     adjustControlHeightBasedOnLineHeight(m_innerText->renderer()->lineHeight(true, true));
       
   412     setHeight(height() + borderAndPaddingHeight());
       
   413 
       
   414     // We are able to have a horizontal scrollbar if the overflow style is scroll, or if its auto and there's no word wrap.
       
   415     if (style()->overflowX() == OSCROLL ||  (style()->overflowX() == OAUTO && m_innerText->renderer()->style()->wordWrap() == NormalWordWrap))
       
   416         setHeight(height() + scrollbarThickness());
       
   417 
       
   418     RenderBlock::calcHeight();
       
   419 }
       
   420 
       
   421 void RenderTextControl::hitInnerTextElement(HitTestResult& result, int xPos, int yPos, int tx, int ty)
       
   422 {
       
   423     result.setInnerNode(m_innerText.get());
       
   424     result.setInnerNonSharedNode(m_innerText.get());
       
   425     result.setLocalPoint(IntPoint(xPos - tx - x() - m_innerText->renderBox()->x(),
       
   426                                   yPos - ty - y() - m_innerText->renderBox()->y()));
       
   427 }
       
   428 
       
   429 void RenderTextControl::forwardEvent(Event* event)
       
   430 {
       
   431     if (event->type() == eventNames().blurEvent || event->type() == eventNames().focusEvent)
       
   432         return;
       
   433     m_innerText->defaultEventHandler(event);
       
   434 }
       
   435 
       
   436 static const char* fontFamiliesWithInvalidCharWidth[] = {
       
   437     "American Typewriter",
       
   438     "Arial Hebrew",
       
   439     "Chalkboard",
       
   440     "Cochin",
       
   441     "Corsiva Hebrew",
       
   442     "Courier",
       
   443     "Euphemia UCAS",
       
   444     "Geneva",
       
   445     "Gill Sans",
       
   446     "Hei",
       
   447     "Helvetica",
       
   448     "Hoefler Text",
       
   449     "InaiMathi",
       
   450     "Kai",
       
   451     "Lucida Grande",
       
   452     "Marker Felt",
       
   453     "Monaco",
       
   454     "Mshtakan",
       
   455     "New Peninim MT",
       
   456     "Osaka",
       
   457     "Raanana",
       
   458     "STHeiti",
       
   459     "Symbol",
       
   460     "Times",
       
   461     "Apple Braille",
       
   462     "Apple LiGothic",
       
   463     "Apple LiSung",
       
   464     "Apple Symbols",
       
   465     "AppleGothic",
       
   466     "AppleMyungjo",
       
   467     "#GungSeo",
       
   468     "#HeadLineA",
       
   469     "#PCMyungjo",
       
   470     "#PilGi",
       
   471 };
       
   472 
       
   473 // For font families where any of the fonts don't have a valid entry in the OS/2 table
       
   474 // for avgCharWidth, fallback to the legacy webkit behavior of getting the avgCharWidth
       
   475 // from the width of a '0'. This only seems to apply to a fixed number of Mac fonts,
       
   476 // but, in order to get similar rendering across platforms, we do this check for
       
   477 // all platforms.
       
   478 bool RenderTextControl::hasValidAvgCharWidth(AtomicString family)
       
   479 {
       
   480     static HashSet<AtomicString>* fontFamiliesWithInvalidCharWidthMap = 0;
       
   481     
       
   482     if (!fontFamiliesWithInvalidCharWidthMap) {
       
   483         fontFamiliesWithInvalidCharWidthMap = new HashSet<AtomicString>;
       
   484         
       
   485         for (unsigned i = 0; i < sizeof(fontFamiliesWithInvalidCharWidth) / sizeof(fontFamiliesWithInvalidCharWidth[0]); i++)
       
   486             fontFamiliesWithInvalidCharWidthMap->add(AtomicString(fontFamiliesWithInvalidCharWidth[i]));
       
   487     }
       
   488 
       
   489     return !fontFamiliesWithInvalidCharWidthMap->contains(family);
       
   490 }
       
   491 
       
   492 float RenderTextControl::getAvgCharWidth(AtomicString family)
       
   493 {
       
   494     if (hasValidAvgCharWidth(family))
       
   495         return roundf(style()->font().primaryFont()->avgCharWidth());
       
   496 
       
   497     const UChar ch = '0'; 
       
   498     return style()->font().floatWidth(TextRun(&ch, 1, false, 0, 0, false, false, false));
       
   499 }
       
   500 
       
   501 float RenderTextControl::scaleEmToUnits(int x) const
       
   502 {
       
   503     // This matches the unitsPerEm value for MS Shell Dlg and Courier New from the "head" font table.
       
   504     float unitsPerEm = 2048.0f;
       
   505     return roundf(style()->font().size() * x / unitsPerEm);
       
   506 }
       
   507 
       
   508 void RenderTextControl::calcPrefWidths()
       
   509 {
       
   510     ASSERT(prefWidthsDirty());
       
   511 
       
   512     m_minPrefWidth = 0;
       
   513     m_maxPrefWidth = 0;
       
   514 
       
   515     if (style()->width().isFixed() && style()->width().value() > 0)
       
   516         m_minPrefWidth = m_maxPrefWidth = calcContentBoxWidth(style()->width().value());
       
   517     else {
       
   518         // Use average character width. Matches IE.
       
   519         AtomicString family = style()->font().family().family();
       
   520         m_maxPrefWidth = preferredContentWidth(getAvgCharWidth(family)) + m_innerText->renderBox()->paddingLeft() + m_innerText->renderBox()->paddingRight();
       
   521     }
       
   522 
       
   523     if (style()->minWidth().isFixed() && style()->minWidth().value() > 0) {
       
   524         m_maxPrefWidth = max(m_maxPrefWidth, calcContentBoxWidth(style()->minWidth().value()));
       
   525         m_minPrefWidth = max(m_minPrefWidth, calcContentBoxWidth(style()->minWidth().value()));
       
   526     } else if (style()->width().isPercent() || (style()->width().isAuto() && style()->height().isPercent()))
       
   527         m_minPrefWidth = 0;
       
   528     else
       
   529         m_minPrefWidth = m_maxPrefWidth;
       
   530 
       
   531     if (style()->maxWidth().isFixed() && style()->maxWidth().value() != undefinedLength) {
       
   532         m_maxPrefWidth = min(m_maxPrefWidth, calcContentBoxWidth(style()->maxWidth().value()));
       
   533         m_minPrefWidth = min(m_minPrefWidth, calcContentBoxWidth(style()->maxWidth().value()));
       
   534     }
       
   535 
       
   536     int toAdd = borderAndPaddingWidth();
       
   537 
       
   538     m_minPrefWidth += toAdd;
       
   539     m_maxPrefWidth += toAdd;
       
   540 
       
   541     setPrefWidthsDirty(false);
       
   542 }
       
   543 
       
   544 void RenderTextControl::selectionChanged(bool userTriggered)
       
   545 {
       
   546     cacheSelection(selectionStart(), selectionEnd());
       
   547 
       
   548     if (Frame* frame = this->frame()) {
       
   549         if (frame->selection()->isRange() && userTriggered)
       
   550             node()->dispatchEvent(Event::create(eventNames().selectEvent, true, false));
       
   551     }
       
   552 }
       
   553 
       
   554 void RenderTextControl::addFocusRingRects(Vector<IntRect>& rects, int tx, int ty)
       
   555 {
       
   556     if (width() && height())
       
   557         rects.append(IntRect(tx, ty, width(), height()));
       
   558 }
       
   559 
       
   560 HTMLElement* RenderTextControl::innerTextElement() const
       
   561 {
       
   562     return m_innerText.get();
       
   563 }
       
   564 
       
   565 void RenderTextControl::updatePlaceholderVisibility(bool placeholderShouldBeVisible, bool placeholderValueChanged)
       
   566 {
       
   567     bool oldPlaceholderVisible = m_placeholderVisible;
       
   568     m_placeholderVisible = placeholderShouldBeVisible;
       
   569     if (oldPlaceholderVisible != m_placeholderVisible || placeholderValueChanged) {
       
   570         // Sets the inner text style to the normal style or :placeholder style.
       
   571         setInnerTextStyle(createInnerTextStyle(textBaseStyle()));
       
   572 
       
   573         // updateFromElement() of the subclasses updates the text content
       
   574         // to the element's value(), placeholder(), or the empty string.
       
   575         updateFromElement();
       
   576     }
       
   577 }
       
   578 
       
   579 } // namespace WebCore